11 Commits
v1.1.1 ... main

Author SHA1 Message Date
oxmc
1bf59bcbde Merge pull request #15 from oxmc/dependabot/npm_and_yarn/axios-1.8.2
Bump axios from 1.7.8 to 1.8.2
2025-03-25 03:35:45 -04:00
dependabot[bot]
47d549b991 Bump axios from 1.7.8 to 1.8.2
Bumps [axios](https://github.com/axios/axios) from 1.7.8 to 1.8.2.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.7.8...v1.8.2)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 07:34:47 +00:00
oxmc
c7515830d6 Merge pull request #14 from ploszukiwacz/main
rpm building support for the gh action
2025-03-25 03:33:24 -04:00
oxmc
d4a08a9ed1 remove xhook and make winreg optional dep 2025-03-25 03:32:18 -04:00
deepsource-io[bot]
8b8fe086ee ci: add .deepsource.toml 2025-02-22 19:41:51 +00:00
oxmc
25bf2cbd21 update readme (forgot) 2025-02-13 07:16:30 -08:00
ploszukiwacz
fbb22e766c workflow 2025-02-13 16:08:15 +01:00
IGoByARealyLongNickName
595bde4e8a Merge branch 'oxmc:main' into main 2025-02-13 16:03:15 +01:00
oxmc
b32fcbd8f1 Fix auto update (win tested) and add stylus 2025-02-13 06:34:03 -08:00
oxmc
ab6fe350d3 Change linux ia32 build to armv7l 2024-12-28 12:19:56 -08:00
PlOszukiwacz
ce9830bfbe rpm bulding 2024-12-28 13:16:16 +01:00
22 changed files with 1600 additions and 536 deletions

7
.deepsource.toml Normal file
View File

@@ -0,0 +1,7 @@
version = 1
[[analyzers]]
name = "javascript"
[analyzers.meta]
environment = ["nodejs"]

View File

@@ -1,9 +1,9 @@
name: Bug
description: Make sure you complete the template. Otherwise, it will be closed without further explanation!
title: "[v<replace_this_with_your_bsky-desktop_version>] Replace this with your title"
labels: bug
labels: [bug]
body:
- type: checkboxes
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: _Please check the [**issues**](https://github.com/oxmc/bsky-desktop/issues) page to see if someone has already reported the bug. **I DIDN\'T MAKE THIS CHECKBOX FOR COSMETIC.**_
@@ -11,10 +11,10 @@ body:
- label: I have searched the existing issues
required: true
- type: textarea
- type: textarea
attributes:
label: Device information
description:
description: "_Please provide the following information:_"
value: |
- OS:
- Hardware Specs:
@@ -22,14 +22,14 @@ body:
validations:
required: true
- type: textarea
- type: textarea
attributes:
label: Describe the issue
description: _Please attach videos or screenshots if possible_
validations:
required: true
- type: textarea
- type: textarea
attributes:
label: Steps to reproduce
description: _Please attach videos or screenshots if possible_
@@ -39,14 +39,14 @@ body:
validations:
required: true
- type: textarea
- type: textarea
id: logs
attributes:
label: Crash log
description: _If the app crashes, **please provide the crash log**.
render: shell
- type: dropdown
- type: dropdown
attributes:
label: Are you using the latest version of bsky-destop? If not, why?
description: _Developers spent loads of time and effort to fix bugs & make improvements with every release. You might want to try and update to the [latest version](https://github.com/oxmc/bsky-desktop/releases) before reporting an issue._
@@ -57,9 +57,8 @@ body:
validations:
required: true
- type: textarea
- type: textarea
attributes:
label: Additional information
validations:
required: false

View File

@@ -31,8 +31,8 @@ jobs:
- name: Install dependencies
run: npm install
- name: Build (ia32)
run: npm run build -- --arch ia32
- name: Build (armv7l)
run: npm run build -- --arch armv7l
- name: Build (x64)
run: npm run build -- --arch x64
@@ -54,6 +54,7 @@ jobs:
sha256sum dist/*.AppImage > dist/sha256sum.txt
sha256sum dist/*.deb >> dist/sha256sum.txt
sha256sum dist/*.zip >> dist/sha256sum.txt
sha256sum dist/*.rpm >> dist/sha256sum.txt
- name: Upload Linux Artifacts
uses: actions/upload-artifact@v4
@@ -64,6 +65,7 @@ jobs:
dist/*.AppImage
dist/*.deb
dist/*.zip
dist/*.rpm
dist/latest*.yml
dist/sha256sum.txt
@@ -209,6 +211,7 @@ jobs:
dist/linux/*.AppImage
dist/linux/*.deb
dist/linux/*.zip
dist/linux/*.rpm
dist/windows/*.exe
dist/windows/*.msi
dist/windows/*.appx

View File

@@ -3,7 +3,7 @@
Bsky Desktop is an Electron-based application for Bsky that allows users to manage their accounts and feeds directly from the app, rather than through the web interface.
### Features:
- Support for user styles (work in progress; currently only LESS preprocessor is supported)
- Support for user styles (work in progress; currently only LESS and Stylus preprocessor is supported)
- Compatibility with both Manifest V2 and V3 Chrome extensions, though only a limited set of Chrome extension APIs are supported. For more information, visit: [Electron Extensions API Documentation](https://www.electronjs.org/docs/latest/api/extensions#supported-extensions-apis)
### Working on:

View File

@@ -10,6 +10,7 @@ const args = process.argv.slice(2);
const carch = args.includes('--arch') ? args[args.indexOf('--arch') + 1] : null;
const cplatform = args.includes('--platform') ? args[args.indexOf('--platform') + 1] : null;
const pack = args.includes('--pack'); // Keep track of --pack as a boolean flag
const nobc = args.includes('--no-bc'); // Keep track of --nobc as a boolean flag
// Determine platform
let platform;
@@ -59,14 +60,38 @@ if (pack) {
buildArgs.push('--dir');
}
// Read build-config.json
// Default build configuration (used when --no-bc is passed) [Default values are for bskyDesktop]
const defaultBuildConfig = {
"appId": "com.oxmc.bskyDesktop",
"productName": "bskyDesktop",
"asarUnpack": [
"./node_modules/node-notifier/**/*"
],
"win": {
"icon": "src/ui/images/logo.ico",
},
"mac": {
"icon": "src/ui/images/mac.icns",
},
"linux": {
"icon": "src/ui/images/icons",
},
};
// Read build-config.json if it exists and --no-bc is not present
const buildConfigPath = path.join(__dirname, 'build-config.json');
let buildConfig;
try {
let buildConfig = defaultBuildConfig;
if (!nobc) {
if (!require('fs').existsSync(buildConfigPath)) {
console.error('build-config.json not found');
process.exit(1);
}
try {
buildConfig = require(buildConfigPath);
} catch (err) {
} catch (err) {
console.error(`Failed to read build-config.json: ${err.message}`);
process.exit(1);
}
}
// Generate artifact name
@@ -84,12 +109,12 @@ const options = {
oneClick: true,
perMachine: false
},
dmg: {
/*dmg: {
contents: [
{ type: 'file', x: 255, y: 85 },
{ type: 'link', path: '/Applications', x: 253, y: 325 }
]
},
},*/
...buildConfig
};

View File

@@ -27,6 +27,7 @@
"target": [
"appimage",
"deb",
"rpm",
"zip"
],
"icon": "src/ui/images/icons",

329
package-lock.json generated
View File

@@ -1,31 +1,40 @@
{
"name": "bsky-desktop",
"version": "1.1.0",
"version": "1.1.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "bsky-desktop",
"version": "1.1.0",
"version": "1.1.3",
"license": "AGPL-3.0-only",
"dependencies": {
"@electron/asar": "^3.2.17",
"@electron/remote": "^2.1.2",
"adm-zip": "^0.5.12",
"axios": "^1.6.8",
"electron-window-state": "^5.0.3",
"axios": "^1.8.2",
"less": "^4.2.1",
"log4js": "^6.9.1",
"node-notifier": "^10.0.0",
"semver": "^7.6.3",
"stylus": "^0.64.0",
"usercss-meta": "^0.12.0",
"v8-compile-cache": "^2.3.0"
},
"devDependencies": {
"electron": "^29.4.6",
"electron-builder": "^24.13.3"
},
"optionalDependencies": {
"winreg": "^1.2.5"
}
},
"node_modules/@adobe/css-tools": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz",
"integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==",
"license": "MIT"
},
"node_modules/@develar/schema-utils": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz",
@@ -254,7 +263,6 @@
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"dev": true,
"license": "ISC",
"dependencies": {
"string-width": "^5.1.2",
@@ -272,7 +280,6 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -285,7 +292,6 @@
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -298,14 +304,12 @@
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true,
"license": "MIT"
},
"node_modules/@isaacs/cliui/node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"eastasianwidth": "^0.2.0",
@@ -323,7 +327,6 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
@@ -339,7 +342,6 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.1.0",
@@ -425,7 +427,6 @@
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
@@ -637,7 +638,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -647,7 +647,6 @@
"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"
@@ -879,9 +878,9 @@
}
},
"node_modules/axios": {
"version": "1.7.8",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz",
"integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==",
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
@@ -1191,7 +1190,6 @@
"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"
@@ -1204,7 +1202,6 @@
"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/combined-stream": {
@@ -1389,7 +1386,6 @@
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
@@ -1588,7 +1584,6 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true,
"license": "MIT"
},
"node_modules/ejs": {
@@ -1682,22 +1677,10 @@
"mime": "^2.5.2"
}
},
"node_modules/electron-window-state": {
"version": "5.0.3",
"license": "MIT",
"dependencies": {
"jsonfile": "^4.0.0",
"mkdirp": "^0.5.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
"license": "MIT"
},
"node_modules/end-of-stream": {
@@ -1903,7 +1886,6 @@
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
"integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
"dev": true,
"license": "ISC",
"dependencies": {
"cross-spawn": "^7.0.0",
@@ -1920,7 +1902,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=14"
@@ -2377,7 +2358,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -2428,7 +2408,6 @@
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
@@ -2779,13 +2758,13 @@
},
"node_modules/minimist": {
"version": "1.2.6",
"dev": true,
"license": "MIT"
},
"node_modules/minipass": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=8"
@@ -2818,16 +2797,6 @@
"node": ">=8"
}
},
"node_modules/mkdirp": {
"version": "0.5.6",
"license": "MIT",
"dependencies": {
"minimist": "^1.2.6"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/ms": {
"version": "2.1.2",
"license": "MIT"
@@ -2920,7 +2889,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"dev": true,
"license": "BlueOak-1.0.0"
},
"node_modules/parse-node-version": {
@@ -2943,7 +2911,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -2953,7 +2920,6 @@
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^10.2.0",
@@ -2970,7 +2936,6 @@
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"dev": true,
"license": "ISC"
},
"node_modules/pend": {
@@ -3057,10 +3022,11 @@
}
},
"node_modules/punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"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"
}
@@ -3232,7 +3198,6 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
"devOptional": true,
"license": "ISC"
},
"node_modules/semver": {
@@ -3273,7 +3238,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
@@ -3286,7 +3250,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -3449,7 +3412,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
@@ -3465,7 +3427,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
@@ -3480,7 +3441,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -3494,7 +3454,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -3503,6 +3462,90 @@
"node": ">=8"
}
},
"node_modules/stylus": {
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/stylus/-/stylus-0.64.0.tgz",
"integrity": "sha512-ZIdT8eUv8tegmqy1tTIdJv9We2DumkNZFdCF5mz/Kpq3OcTaxSuCAYZge6HKK2CmNC02G1eJig2RV7XTw5hQrA==",
"license": "MIT",
"dependencies": {
"@adobe/css-tools": "~4.3.3",
"debug": "^4.3.2",
"glob": "^10.4.5",
"sax": "~1.4.1",
"source-map": "^0.7.3"
},
"bin": {
"stylus": "bin/stylus"
},
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://opencollective.com/stylus"
}
},
"node_modules/stylus/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/stylus/node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
"license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
"minimatch": "^9.0.4",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^1.11.1"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/stylus/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/stylus/node_modules/minipass": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/stylus/node_modules/source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
"license": "BSD-3-Clause",
"engines": {
"node": ">= 8"
}
},
"node_modules/sumchecker": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
@@ -3739,6 +3782,13 @@
"node": ">= 8"
}
},
"node_modules/winreg": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.5.tgz",
"integrity": "sha512-uf7tHf+tw0B1y+x+mKTLHkykBgK2KMs3g+KlzmyMbLvICSHQyB/xOFjTT8qZ3oeTFyU7Bbj4FzXitGG6jvKhYw==",
"license": "BSD-2-Clause",
"optional": true
},
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -3762,7 +3812,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
@@ -3883,6 +3932,11 @@
}
},
"dependencies": {
"@adobe/css-tools": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz",
"integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ=="
},
"@develar/schema-utils": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz",
@@ -4046,7 +4100,6 @@
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"dev": true,
"requires": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
@@ -4059,26 +4112,22 @@
"ansi-regex": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"dev": true
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="
},
"ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="
},
"emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
},
"string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"requires": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
@@ -4089,7 +4138,6 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"requires": {
"ansi-regex": "^6.0.1"
}
@@ -4098,7 +4146,6 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"requires": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
@@ -4156,7 +4203,6 @@
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"dev": true,
"optional": true
},
"@sindresorhus/is": {
@@ -4317,14 +4363,12 @@
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
},
"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,
"requires": {
"color-convert": "^2.0.1"
}
@@ -4508,9 +4552,9 @@
"dev": true
},
"axios": {
"version": "1.7.8",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz",
"integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==",
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
"requires": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
@@ -4718,7 +4762,6 @@
"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,
"requires": {
"color-name": "~1.1.4"
}
@@ -4726,8 +4769,7 @@
"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
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"combined-stream": {
"version": "1.0.8",
@@ -4860,7 +4902,6 @@
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -4988,8 +5029,7 @@
"eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
},
"ejs": {
"version": "3.1.10",
@@ -5057,18 +5097,10 @@
"mime": "^2.5.2"
}
},
"electron-window-state": {
"version": "5.0.3",
"requires": {
"jsonfile": "^4.0.0",
"mkdirp": "^0.5.1"
}
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"end-of-stream": {
"version": "1.4.4",
@@ -5210,7 +5242,6 @@
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
"integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
"signal-exit": "^4.0.1"
@@ -5219,8 +5250,7 @@
"signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="
}
}
},
@@ -5515,8 +5545,7 @@
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"is-what": {
"version": "3.14.1",
@@ -5549,7 +5578,6 @@
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
"dev": true,
"requires": {
"@isaacs/cliui": "^8.0.2",
"@pkgjs/parseargs": "^0.11.0"
@@ -5805,13 +5833,13 @@
}
},
"minimist": {
"version": "1.2.6"
"version": "1.2.6",
"dev": true
},
"minipass": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
"dev": true
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="
},
"minizlib": {
"version": "2.1.2",
@@ -5834,12 +5862,6 @@
}
}
},
"mkdirp": {
"version": "0.5.6",
"requires": {
"minimist": "^1.2.6"
}
},
"ms": {
"version": "2.1.2"
},
@@ -5901,8 +5923,7 @@
"package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"dev": true
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
},
"parse-node-version": {
"version": "1.0.1",
@@ -5915,14 +5936,12 @@
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
},
"path-scurry": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
"dev": true,
"requires": {
"lru-cache": "^10.2.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
@@ -5931,8 +5950,7 @@
"lru-cache": {
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"dev": true
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
}
}
},
@@ -5999,9 +6017,9 @@
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true
},
"quick-lru": {
@@ -6130,8 +6148,7 @@
"sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
"devOptional": true
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
},
"semver": {
"version": "7.6.3",
@@ -6157,7 +6174,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"requires": {
"shebang-regex": "^3.0.0"
}
@@ -6165,8 +6181,7 @@
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
},
"shellwords": {
"version": "0.1.1"
@@ -6277,7 +6292,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -6288,7 +6302,6 @@
"version": "npm:string-width@4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -6299,7 +6312,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
@@ -6308,11 +6320,63 @@
"version": "npm:strip-ansi@6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
},
"stylus": {
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/stylus/-/stylus-0.64.0.tgz",
"integrity": "sha512-ZIdT8eUv8tegmqy1tTIdJv9We2DumkNZFdCF5mz/Kpq3OcTaxSuCAYZge6HKK2CmNC02G1eJig2RV7XTw5hQrA==",
"requires": {
"@adobe/css-tools": "~4.3.3",
"debug": "^4.3.2",
"glob": "^10.4.5",
"sax": "~1.4.1",
"source-map": "^0.7.3"
},
"dependencies": {
"brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"requires": {
"balanced-match": "^1.0.0"
}
},
"glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
"requires": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
"minimatch": "^9.0.4",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^1.11.1"
}
},
"minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"requires": {
"brace-expansion": "^2.0.1"
}
},
"minipass": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="
},
"source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="
}
}
},
"sumchecker": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
@@ -6479,6 +6543,12 @@
"isexe": "^2.0.0"
}
},
"winreg": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.5.tgz",
"integrity": "sha512-uf7tHf+tw0B1y+x+mKTLHkykBgK2KMs3g+KlzmyMbLvICSHQyB/xOFjTT8qZ3oeTFyU7Bbj4FzXitGG6jvKhYw==",
"optional": true
},
"wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -6494,7 +6564,6 @@
"version": "npm:wrap-ansi@7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",

View File

@@ -1,6 +1,6 @@
{
"name": "bsky-desktop",
"version": "1.1.1",
"version": "1.1.3",
"description": "A desktop app of bsky.app",
"main": "src/app/main.js",
"scripts": {
@@ -19,16 +19,19 @@
"electron": "^29.4.6",
"electron-builder": "^24.13.3"
},
"optionalDependencies": {
"winreg": "^1.2.5"
},
"dependencies": {
"@electron/asar": "^3.2.17",
"@electron/remote": "^2.1.2",
"adm-zip": "^0.5.12",
"axios": "^1.6.8",
"electron-window-state": "^5.0.3",
"axios": "^1.8.2",
"less": "^4.2.1",
"log4js": "^6.9.1",
"node-notifier": "^10.0.0",
"semver": "^7.6.3",
"stylus": "^0.64.0",
"usercss-meta": "^0.12.0",
"v8-compile-cache": "^2.3.0"
}

View File

@@ -1,30 +1,26 @@
const { app, BrowserWindow, BrowserView, globalShortcut, ipcMain, Tray, Menu, protocol, session, dialog } = require("electron");
const electronremote = require("@electron/remote/main");
//const asar = require('@electron/asar');
const windowStateKeeper = require("electron-window-state");
const windowStateKeeper = require("./window-state/index");
const { setupTitlebar, attachTitlebarToWindow } = require("./titlebar/main");
const openAboutWindow = require("./about-window/src/index").default;
const badge = require('./badge');
const nodeNotifier = require('node-notifier');
const contextMenu = require('./context-menu');
const autoUpdater = require('./utils/auto-update');
const loadCRX = require('./utils/loadCRX');
const userStyles = require('./utils/userStyles');
const log4js = require("log4js");
//const axios = require("axios");
const path = require("path");
const fs = require("fs");
const os = require("os");
require('v8-compile-cache');
// Load package.json and contributors.json
const packageJson = require(path.join(__dirname, '..', '..', 'package.json'));
const contributors = require(path.join(__dirname, 'contributors.json'));
// Check if app is ran from the installer dmg (macOS)
if (process.platform === 'darwin' && app.isPackaged && app.isInApplicationsFolder()) {
// Creeate a dialog to ask the user to move the app to the Applications folder
dialog.showErrorBox('Move to Applications folder', 'Please move the app to the Applications folder to ensure it works correctly.');
app.quit();
};
// isUpdaing:
global.isUpdating = false;
@@ -44,9 +40,10 @@ global.paths = {
home: os.homedir(),
temp: path.join(os.tmpdir(), global.appInfo.name),
};
global.paths.updateDir = path.join(global.paths.data, 'update');
global.paths.extensions = path.join(global.paths.data, 'extensions');
global.paths.userstyles = path.join(global.paths.data, 'userstyles');
global.paths.user = path.join(global.paths.data, 'user');
global.paths.updateDir = path.join(global.paths.user, 'update');
global.paths.extensions = path.join(global.paths.user, 'extensions');
global.paths.userstyles = path.join(global.paths.user, 'userstyles');
// URLs:
global.urls = {
@@ -61,6 +58,36 @@ global.settings.account = `${global.settings.general}/account`;
global.settings.appearance = `${global.settings.general}/appearance`;
global.settings.privacy = `${global.settings.general}/privacy-and-security`;
// Check if app is run from the installer dmg (macOS)
if (process.platform === 'darwin' && app.isPackaged && !app.isInApplicationsFolder()) {
const response = dialog.showMessageBoxSync({
type: 'question',
buttons: ['Yes', 'No'],
title: 'Move to Applications folder',
message: 'Please move the app to the Applications folder to ensure it works correctly. Would you like to move it now?'
});
if (response === 0) { // User clicked 'Yes'
const appPath = app.getPath('exe');
const applicationsFolder = '/Applications';
const appName = path.basename(appPath);
const destinationPath = path.join(applicationsFolder, appName);
// Try to move the app
fs.rename(appPath, destinationPath, (err) => {
if (err) {
dialog.showErrorBox('Move Failed', 'Failed to move the app to the Applications folder.');
} else {
dialog.showInformationBox({ message: 'The app has been moved to the Applications folder. Please restart it.' });
app.quit();
}
});
} else {
dialog.showErrorBox('Move to Applications folder', 'Please move the app to the Applications folder to ensure it works correctly.');
app.quit();
}
}
// Badge options:
const badgeOptions = {
fontColor: '#FFFFFF', // The font color
@@ -124,10 +151,10 @@ if (!fs.existsSync(global.paths.temp)) {
fs.mkdirSync(global.paths.temp, { recursive: true });
};
// Create update directory if it does not exist:
if (!fs.existsSync(global.paths.updateDir)) {
logger.info("Creating Update Directory");
fs.mkdirSync(global.paths.updateDir, { recursive: true });
// Create user directory if it does not exist:
if (!fs.existsSync(global.paths.data, 'user')) {
logger.info("Creating User Directory");
fs.mkdirSync(global.paths.user, { recursive: true });
};
// Create extensions directory if it does not exist:
@@ -142,6 +169,12 @@ if (!fs.existsSync(global.paths.userstyles)) {
fs.mkdirSync(global.paths.userstyles, { recursive: true });
};
// Create update directory if it does not exist:
if (!fs.existsSync(global.paths.updateDir)) {
logger.info("Creating Update Directory");
fs.mkdirSync(global.paths.updateDir, { recursive: true });
};
// improve performance on linux?
if (process.platform !== "win32" && process.platform !== "darwin") {
logger.log("Disabling Hardware Acceleration and Transparent Visuals");
@@ -156,16 +189,16 @@ setupTitlebar();
// Disable reload and F5 if not in dev mode:
if (process.env.NODE_ENV !== 'development') {
app.on('browser-window-focus', function () {
globalShortcut.register("CommandOrControl+R", () => {
/*globalShortcut.register("CommandOrControl+R", () => {
//console.log("CommandOrControl+R is pressed: Shortcut Disabled");
});
globalShortcut.register("F5", () => {
//console.log("F5 is pressed: Shortcut Disabled");
});
});*/
});
app.on('browser-window-blur', function () {
globalShortcut.unregister('CommandOrControl+R');
globalShortcut.unregister('F5');
/*globalShortcut.unregister('CommandOrControl+R');
globalShortcut.unregister('F5');*/
});
};
@@ -228,14 +261,14 @@ function createWindow() {
PageView.setBounds({
x: 0,
y: 30,
width: mainWindow.getBounds().width,
width: mainWindow.isMaximized() ? mainWindow.getBounds().width - 16 : mainWindow.getBounds().width,
height: mainWindow.getBounds().height - 30,
});
mainWindow.on("resize", () => {
PageView.setBounds({
x: 0,
y: 30,
width: mainWindow.getBounds().width,
width: mainWindow.isMaximized() ? mainWindow.getBounds().width - 16 : mainWindow.getBounds().width,
height: mainWindow.getBounds().height - 30,
});
});
@@ -505,24 +538,130 @@ app.whenReady().then(() => {
// Set session:
global.session = ses;
// Initialize the updater:
logger.log("Initializing Updater");
autoUpdater();
// Handle ipc for render:
ipcMain.on('close-app', (event, arg) => {
app.quit();
});
ipcMain.on('app:restart', (event, arg) => {
app.relaunch();
app.quit();
});
// Create windows and tray:
createWindow();
createTray();
// Wait for splash screen to load before checking for updates, loading extensions and userstyles
global.splash.webContents.on('did-finish-load', async () => {
// Check for internet connection:
logger.log("Checking for internet connection");
require('dns').lookup('google.com', err => {
if (err) {
logger.log('No internet connection, showing not connected message');
global.PageView.webContents.loadFile(path.join(global.paths.app, 'ui', 'offline.html'));
return;
}
logger.log('Internet available, checking for updates');
// Initialize the updater:
logger.log("Initializing Updater");
global.splash.webContents.send('ui:progtext', { title: 'Checking for updates...', subtitle: 'Awaiting response' });
autoUpdater.checkForUpdates().then(async (result) => {
//console.log(result);
switch (result.code) {
case 'update-available':
global.isUpdating = true;
logger.log("Update available, downloading");
global.splash.webContents.send('ui:progtext', { title: 'Update available', subtitle: 'Downloading update' });
try {
const update = await autoUpdater.downloadUpdate();
//console.log(update);
if (update.err && update.err.code === 'unpackaged') {
logger.warn("Update failed to download, unpackaged app");
global.splash.webContents.send('ui:progtext', { title: 'Not downloading update', subtitle: 'Unpackaged app' });
global.isUpdating = false;
} else {
if (update.err) {
logger.error("Update failed to download");
console.log(update.err);
global.splash.webContents.send('ui:progtext', { title: 'Failed to download update', subtitle: 'Continuing as normal...' });
};
switch (update.code) {
case 'downloaded':
logger.log("Update downloaded, installing");
global.splash.webContents.send('ui:progtext', { title: 'Update downloaded', subtitle: 'Installing update' });
try {
const install = await autoUpdater.installUpdate(update.path);
//console.log(install);
if (install.err) {
logger.error("Failed to install update");
console.log(install.err);
global.splash.webContents.send('ui:progtext', { title: 'Failed to install update', subtitle: 'Continuing as normal...' });
} else {
if (install.code === 'update-installed') {
logger.log("Update installed, restarting");
global.splash.webContents.send('ui:progtext', { title: 'Update installed', subtitle: 'Restarting...' });
app.relaunch();
app.quit();
} else {
logger.error("Failed to install update");
global.splash.webContents.send('ui:progtext', { title: 'Failed to install update', subtitle: 'Continuing as normal...' });
};
};
} catch (error) {
logger.error(`Error installing update:`, error);
global.splash.webContents.send('ui:progtext', { title: 'Error installing update', subtitle: ' ' });
};
break;
case 'download-failed':
logger.error("Failed to download update");
global.splash.webContents.send('ui:progtext', { title: 'Failed to download update', subtitle: 'Continuing as normal...' });
global.isUpdating = false;
global.mainWindow.show();
global.splash.destroy();
break;
default:
logger.error("Unknown update download status");
global.splash.webContents.send('ui:progtext', { title: 'Unknown update download status', subtitle: ' ' });
break;
};
};
} catch (error) {
logger.error(`Error downloading update:`, error);
global.splash.webContents.send('ui:progtext', { title: 'Error downloading update', subtitle: ' ' });
};
break;
case 'no-update':
logger.log("No update available");
global.splash.webContents.send('ui:progtext', { title: 'Checking for updates...', subtitle: 'Up to date!' });
break;
case 'check-failed':
logger.warn("Failed to check for updates");
global.splash.webContents.send('ui:progtext', { title: 'Failed to check for updates', subtitle: ' ' });
break;
case 'old-os':
logger.warn("Old OS, unable to update");
global.splash.webContents.send('ui:progtext', { title: 'Update not available', subtitle: 'Old OS' });
break;
default:
logger.warn("Unknown update status");
global.splash.webContents.send('ui:progtext', { title: 'Unknown update status', subtitle: ' ' });
break;
};
}).catch((error) => {
logger.error(`Error checking for updates: ${error}`);
global.splash.webContents.send('ui:progtext', { title: 'Error checking for updates', subtitle: ' ' });
}).finally(async () => {
// Load extensions (.crx files):
logger.log("Checking for extensions");
global.splash.webContents.send('ui:progtext', { title: 'Checking for extensions', subtitle: ' ' });
const extensions = fs.readdirSync(global.paths.extensions).filter((file) => file.endsWith('.crx'));
if (extensions.length > 0) {
logger.log(`Unpacking ${extensions.length} extensions and loading them`);
global.splash.webContents.send('ui:progtext', { title: `Unpacking ${extensions.length} extensions` });
extensions.forEach((extension) => {
logger.log(`Loading extension: ${extension}`);
global.splash.webContents.send('ui:progtext', { title: `Loading extension: ${extension}` });
loadCRX(path.join(global.paths.extensions, extension));
});
} else {
@@ -534,6 +673,7 @@ app.whenReady().then(() => {
const manifestPath = path.join(global.paths.extensions, extension, 'manifest.json');
if (fs.existsSync(manifestPath)) {
logger.log(`Loading unpacked extension: ${extension}`);
global.splash.webContents.send('ui:progtext', { title: `Loading unpacked extension: ${extension}` });
session.defaultSession.loadExtension(path.join(global.paths.extensions, extension)).then(({ id }) => {
logger.log(`Extension loaded with ID: ${id}`);
}).catch((error) => {
@@ -547,10 +687,12 @@ app.whenReady().then(() => {
// Load userstyles
logger.log("Checking for userstyles");
global.splash.webContents.send('ui:progtext', { title: 'Checking for userstyles' });
const userStylesDir = path.join(global.paths.userstyles);
if (fs.existsSync(userStylesDir)) {
const files = fs.readdirSync(userStylesDir);
const files = fs.readdirSync(userStylesDir).filter((file) => file.endsWith('.css'));
if (files.length > 0) {
logger.log(`Loading ${files.length} userstyles`);
const userStylePromises = files.map(async file => {
const cssFile = path.join(userStylesDir, file);
// Parse the CSS file
@@ -569,17 +711,25 @@ app.whenReady().then(() => {
await PageView.webContents.insertCSS(compiled.sites['bsky.app']);
logger.info(`Applied userstyle: ${result.metadata.name}`);
global.splash.webContents.send('ui:progtext', { title: `Applied userstyle: ${result.metadata.name}` });
} else {
if (compiled.error) {
logger.warn(`Error loading userstyle: ${compiled.error.message}`);
} else {
logger.warn(`Userstyle ${result.metadata.name} does not target 'bsky.app'`);
}
}
} catch (error) {
logger.error(`Error loading userstyle: ${file}`, error);
}
});
Promise.all(userStylePromises);
await Promise.all(userStylePromises);
}
}
});
});
});
} else {
logger.log("Failed to get singleInstanceLock, Quitting");
app.quit();

View File

@@ -90,7 +90,7 @@ class Updater extends EventEmitter {
};
this.options = Object.assign({}, def, options);
this.options.cacheDirectory = path.resolve(this.options.tmpdir, this.options.name);
this.options.headers['user-agent'] = this.options.headers['user-agent'] || 'asar-updater/v0.0.2 (https://github.com/zce/asar-updater)';
this.options.headers['user-agent'] = this.options.headers['user-agent'] || 'Mozilla/5.0 asar-updater/v0.3.3 (https://github.com/zce/asar-updater)';
fs.existsSync(this.options.cacheDirectory) || fs.mkdirSync(this.options.cacheDirectory);
}
@@ -207,7 +207,7 @@ class Updater extends EventEmitter {
quitAndInstall(timeout) {
setTimeout(() => {
app.relaunch({ args: process.argv.slice(1) + ['--relaunch'] });
app.relaunch({ args: process.argv.slice(1) + ['--relaunch', '--update-installed'] });
app.exit(0);
}, timeout || 100);
}

View File

@@ -1,9 +1,11 @@
const path = require('path');
const os = require('os');
const fs = require('fs');
const childProcess = require('child_process');
const { app } = require('electron');
const log4js = require('log4js');
const SemVer = require('semver');
const axios = require('axios');
const path = require('path');
const os = require('os');
const fs = require('fs');
// import the asarUpdater module
const asarUpdater = require('./asarUpdater');
@@ -14,9 +16,73 @@ const SystemInfo = require('./sysInfo');
// Get the current system platform
const sys = new SystemInfo();
// Detect the app install type
const installType = require('./installType');
// Setup the logger
const logger = log4js.getLogger("bskydesktop");
// System architecture / Platform
const systemArch = sys.isARM64() ? 'arm64' : sys.isX64() ? '64' : sys.isX86() ? '86' : 'unknown';
const systemPlatform = sys.isWin() ? 'win' : sys.isMac() ? 'mac' : sys.isLinux() ? 'linux' : 'unknown';
// Download url: (arch, platform, installer)
const downloadUrl = 'https://cdn.oxmc.me/apps/bsky-desktop/dl';
// Installer path (used to save the installer)
var installerPath = '';
var installerType = '';
async function detectInstallerType() {
let installerType = 'unknown';
// First check if the app is paclaged
if (!app.isPackaged) {
logger.warn('App is not packaged, cannot detect installer type.');
return 'unpackaged';
}
try {
// Check if system is Windows
if (sys.isWin()) {
//console.log('Checking for Windows installer type...');
const res = await installType.getUninstallEntries({ DisplayName: 'bskyDesktop' });
//console.log(res);
// Ensure result is valid before checking properties
if (res.length > 0) {
installerType = res[0].WindowsInstaller === 'MSI' ? 'msi' : 'exe';
} else {
// Default to exe if no installer type is found
installerType = 'exe';
}
}
// Check if system is macOS
if (sys.isMac()) {
const res = await installType.checkAppInstallationMethod();
switch (res.type) { // Use res.type instead of res directly
case 'MAS':
installerType = 'mas';
break;
case 'PKG':
installerType = 'pkg';
break;
case 'ZIP/DMG':
installerType = 'dmg';
break;
}
}
} catch (err) {
logger.error('Failed to detect installer type:', err);
}
return installerType;
}
// Asar updater
function asarUpdate() {
asarUpdater.init();
@@ -62,7 +128,7 @@ function asarUpdate() {
// Set the feed URL (only works in packaged app):
if (app.isPackaged) {
logger.log("Setting Feed URL for app.asar");
asarUpdater.setFeedURL(path.join(global.paths.app_root), 'https://cdn.oxmc.me/internal/bsky-desktop/update/core');
asarUpdater.setFeedURL(path.join(global.paths.app_root), 'https://cdn.oxmc.me/apps/bsky-desktop/update/core');
};
//Check for updates:
@@ -70,15 +136,17 @@ function asarUpdate() {
if (app.isPackaged) {
const UPDATE_CHECK = 1000 * 60 * 60 * 4 // 4 hours
setInterval(() => {
//asarUpdater.checkForUpdates();
asarUpdater.checkForUpdates();
}, UPDATE_CHECK);
//asarUpdater.checkForUpdates();
asarUpdater.checkForUpdates();
} else {
logger.warn("Not checking for updates as app is not packaged");
};
}
function checkForUpdates() {
// Check for updates
async function checkForUpdates() {
return new Promise((resolve, reject) => {
// Current system information
logger.log('Current system information:', sys.platform, sys.getVersion(), sys.arch);
@@ -88,59 +156,59 @@ function checkForUpdates() {
if (sys.earlierThan('10.0.0')) {
// Windows 10 and above are supported, but windows 7 and 8 are not supported
logger.error('Windows 7 and 8 are not supported, please upgrade to Windows 10 or above, not updating...');
resolve({ err: 'old-os', msg: 'Windows 7 and 8 are not supported, please upgrade to Windows 10 or above, not updating...' });
} else {
// Check for updates, and if there are updates, download and install them
logger.log('Checking for updates (win)...');
axios.get('https://cdn.oxmc.me/apps/bsky-desktop/update/core').then((res) => {
//console.log(res.data);
const latestVersion = res.data.version;
const currentVersion = app.getVersion();
if (SemVer.gt(latestVersion, currentVersion)) {
//logger.log('Update available:', latestVersion);
global.PageView.webContents.send('ui:notif', JSON.stringify({ title: 'Update', message: 'An update is available' }));
if (global.splash) global.splash.webContents.send('ui:progtext', { title: 'Update Available', subtitle: 'An update is available! Downloading...' });
resolve({ code: 'update-available', msg: 'An update is available.', info: { latest: latestVersion, current: currentVersion, response: res.data } });
} else {
//logger.log('No updates available.');
resolve({ code: 'no-update', msg: 'No updates available.' });
}
}).catch((err) => {
logger.error('Failed to check for updates:', err);
resolve({ code: 'check-failed', msg: 'Failed to check for updates.' });
});
}
}
// Check if the current system is macOS
if (sys.isMac()) {
let macArch = '';
// Check the current version of macOS, and whether we can use the pkg installer
if (sys.laterThan('10.0.0')) {
// Check if system is after macOS 10 (11, 12, etc.)
if (sys.laterThan('11.0.0')) {
// macOS 11 and above support ARM64, check if system is ARM64
logger.log('Checkking system architecture...');
if (sys.isARM64()) {
// System is ARM64 (mac-arm64)
macArch = 'arm64';
} else {
// System is x64 (mac-x64)
macArch = 'x64';
}
} else {
// macOS 10 is mostly x64, but some versions are ARM64
macArch = 'x64';
}
logger.log('System architecture:', macArch);
// Check for updates, and if there are updates, download and install them
logger.log('Checking for updates (mac)...');
// Run the .pkg installer
const pkgPath = path.join(global.paths.updateDir, 'bsky-desktop.pkg');
const command = `sudo installer -pkg ${pkgPath} -target /`;
// Spawn a new shell
/*const shellProcess = spawn('sh', ['-c', command], {
stdio: 'inherit', // Pipe input/output to/from the shell
});
shellProcess.on('error', (err) => {
console.error('Failed to spawn shell:', err);
});
shellProcess.on('close', (code) => {
if (code === 0) {
console.log('Update installed successfully.');
// Check for updates
axios.get('https://cdn.oxmc.me/apps/bsky-desktop/update/core').then((res) => {
//console.log(res.data);
const latestVersion = res.data.version;
const currentVersion = app.getVersion();
if (SemVer.gt(latestVersion, currentVersion)) {
//logger.log('Update available:', latestVersion);
global.PageView.webContents.send('ui:notif', JSON.stringify({ title: 'Update', message: 'An update is available' }));
if (global.splash) global.splash.webContents.send('ui:progtext', { title: 'Update Available', subtitle: 'An update is available! Downloading...' });
resolve({ code: 'update-available', msg: 'An update is available.', info: { latest: latestVersion, current: currentVersion, response: res.data } });
} else {
console.error(`Shell process exited with code ${code}.`);
//logger.log('No updates available.');
resolve({ code: 'no-update', msg: 'No updates available.' });
}
});*/
}).catch((err) => {
logger.error('Failed to check for updates:', err);
resolve({ code: 'check-failed', msg: 'Failed to check for updates.' });
});
} else {
// macOS versions before 10 are not supported
logger.error('macOS versions before 10 are not supported, not updating...');
resolve({ err: 'old-os', msg: 'macOS versions before 10 are not supported, not updating...' });
}
}
@@ -152,6 +220,295 @@ function checkForUpdates() {
logger.log('Checking for updates (linux)...');
asarUpdate();
}
}).catch((err) => {
logger.error('Failed to check for updates:', err);
});
}
module.exports = checkForUpdates;
// Download the update installer
async function downloadUpdate() {
return new Promise(async (resolve, reject) => {
// download the update installer
//logger.log('Downloading update...');
// Create the update directory if it doesn't exist
if (!fs.existsSync(global.paths.updateDir)) {
fs.mkdirSync(global.paths.updateDir);
}
// Get the installer name
const installerName = `bsky-desktop-${sys.platform}-${systemArch}.exe`;
installerPath = path.join(global.paths.updateDir, installerName);
// Detect the installer type
installerType = await detectInstallerType();
//installerType = 'exe'; // For testing purposes
//logger.info('Installer type:', installerType);
// if the installer type is unknown, return an error
if (installerType === 'unknown') {
//logger.error('Failed to detect installer type:', installerType);
reject({ code: 'unknown-installer', msg: 'Failed to detect installer type.', err: installerType });
return;
}
// If the installer type is unpackaged, return and continue
if (installerType === 'unpackaged') {
//logger.warn('App is not packaged, cannot download update.');
reject({ code: 'unpackaged', msg: 'App is not packaged, cannot download update.' });
return;
}
// download the installer as a stream
const installerStream = fs.createWriteStream(installerPath);
// download the installer
axios({
method: 'get',
url: downloadUrl,
responseType: 'stream',
headers: {
"x-platform": systemPlatform,
"x-arch": systemArch,
"x-installMethod": installerType
}
}).then((res) => {
// pipe the installer stream to the installer file
res.data.pipe(installerStream);
// close the installer stream
installerStream.on('finish', () => {
installerStream.close();
// resolve the promise
resolve({ code: 'downloaded', msg: 'Update downloaded successfully.', path: installerPath });
});
// handle errors
installerStream.on('error', (err) => {
//logger.error('Failed to download and save update:', err);
reject({ code: 'download-save-failed', msg: 'Failed to download and save update.', err: err });
});
// handle close
installerStream.on('close', () => {
//logger.log('Installer stream closed.');
});
}).catch((err) => {
logger.error('Failed to download and save update:', err);
reject({ code: 'download-failed', msg: 'Failed to download update.', err: err });
});
}).catch((err) => {
//logger.error('Failed to download update:', err);
return { code: 'download-failed', msg: 'Failed to download update.', err: err };
});
}
async function installUpdate(installer) {
return new Promise((resolve, reject) => {
try {
// Current system information
//logger.log('Current system information:', sys.platform, sys.getVersion(), sys.arch);
// Check if the current system is Windows
if (sys.isWin()) {
// Check if the system is before Windows 10
if (sys.earlierThan('10.0.0')) {
// Windows 10 and above are supported, but windows 7 and 8 are not supported
logger.error('Windows 7 and 8 are not supported, please upgrade to Windows 10 or above, not installing updating...');
reject({ err: 'old-os', msg: 'Windows 7 and 8 are not supported, please upgrade to Windows 10 or above, not installing update...' });
} else {
// Install the update
logger.log('Installing update (win)...');
// Check if the installer path is valid
installerPath = path.resolve(installer);
if (!fs.existsSync(installerPath)) {
logger.error('Installer path is invalid:', installerPath);
reject({ code: 'invalid-installer', msg: 'Installer path is invalid.', path: installerPath });
}
// Create the log file
const logStream = fs.createWriteStream(path.join(global.paths.updateDir, 'install.log'), { flags: 'a' });
// Run the installer (msi or exe)
switch (installerType) {
case 'msi':
// Run the msi installer /passive, /quiet, /qn, /norestart
const msiExec = childProcess.spawn('cmd.exe', ['/c', 'msiexec', '/i "${installerPath}"', '/qn', '/norestart', `/log ${path.join(global.paths.updateDir, 'installer-exec.log')}`], {
detached: true,
stdio: ['ignore', 'pipe', 'pipe']
});
msiExec.on('error', (err) => {
//console.error('Failed to start process:', err);
reject({ code: 'process-failed', msg: 'Failed to start installation process.', err: err });
});
msiExec.on('exit', (code, signal) => {
if (code === 0) {
//console.log('Update installed successfully.');
resolve({ code: 'update-installed', msg: 'Update installed successfully.' });
} else {
//console.error(`Installer process exited with code: ${code}, signal: ${signal}`);
reject({ code: 'install-failed', msg: 'Installer process failed.', exitCode: code, signal: signal });
}
});
msiExec.stdout.on('data', (data) => {
//console.log(`stdout: ${data}`);
logStream.write(data);
});
msiExec.stderr.on('data', (data) => {
//console.error(`stderr: ${data}`);
logStream.write(data);
});
app.quit();
break;
case 'exe':
// Run the exe installer /s
const exeExec = childProcess.spawn('cmd.exe', ['/c', installerPath], {
detached: true,
stdio: ['ignore', 'pipe', 'pipe']
});
exeExec.on('error', (err) => {
//console.error('Failed to start process:', err);
reject({ code: 'process-failed', msg: 'Failed to start installation process.', err: err });
});
exeExec.on('exit', (code, signal) => {
if (code === 0) {
//console.log('Update installed successfully.');
resolve({ code: 'update-installed', msg: 'Update installed successfully.' });
} else {
//console.error(`Installer process exited with code: ${code}, signal: ${signal}`);
reject({ code: 'install-failed', msg: 'Installer process failed.', exitCode: code, signal: signal });
}
});
exeExec.stdout.on('data', (data) => {
//console.log(`stdout: ${data}`);
logStream.write(data);
});
exeExec.stderr.on('data', (data) => {
//console.error(`stderr: ${data}`);
logStream.write(data);
});
app.quit();
break;
default:
//logger.error('Installer type is invalid:', installerType);
reject({ code: 'invalid-installer-type', msg: 'Installer type is invalid.', type: installerType });
break;
}
}
}
// Check if the current system is macOS
if (sys.isMac()) {
// Check the current version of macOS, and whether we can use the pkg installer
if (sys.laterThan('10.0.0')) {
// Install the update
logger.log('Installing update (mac)...');
// Check if the installer path is valid
installerPath = path.resolve(installer);
if (!fs.existsSync(installerPath)) {
logger.error('Installer path is invalid:', installerPath);
reject({ code: 'invalid-installer', msg: 'Installer path is invalid.', path: installerPath });
}
// Create the log file
const logStream = fs.createWriteStream(path.join(global.paths.updateDir, 'install.log'), { flags: 'a' });
// Run the .pkg installer
const command = `sudo installer -pkg ${installerPath} -target /`;
const shellProcess = childProcess.spawn('sh', ['-c', command], {
detached: true,
stdio: ['ignore', 'pipe', 'pipe']
});
shellProcess.on('error', (err) => {
//console.error('Failed to start process:', err);
reject({ code: 'process-failed', msg: 'Failed to start installation process.', err: err });
});
shellProcess.on('exit', (code, signal) => {
if (code === 0) {
//console.log('Update installed successfully.');
resolve({ code: 'update-installed', msg: 'Update installed successfully.' });
} else {
//console.error(`Installer process exited with code: ${code}, signal: ${signal}`);
reject({ code: 'install-failed', msg: 'Installer process failed.', exitCode: code, signal: signal });
}
});
shellProcess.stdout.on('data', (data) => {
//console.log(`stdout: ${data}`);
logStream.write(data);
});
shellProcess.stderr.on('data', (data) => {
//console.error(`stderr: ${data}`);
logStream.write(data);
});
} else {
// macOS versions before 10 are not supported
logger.error('macOS versions before 10 are not supported, not installing update...');
reject({ err: 'old-os', msg: 'macOS versions before 10 are not supported, not installing update...' });
}
}
// Check if the current system is Linux (This should be handled via asarUpdater)
if (sys.isLinux()) {
// Check for updates, and if there are updates, download and install them (no system version check)
// Linux versions use AppImage, so we instead need to check for a new asar file so that the app can
// load the new asar instead of the packaged one (or even just delete the old appimage and download a new one)
//logger.log('Checking for updates (linux)...');
logger.log('This is not implemented yet, please update manually.');
//asarUpdate();
}
} catch (err) {
logger.error('Failed to install update:', err);
reject({ code: 'install-failed', msg: 'Failed to install update.', err: err });
}
});
};
async function downloadAndInstall() {
return new Promise((resolve, reject) => {
// Download the update installer
downloadUpdate().then((res) => {
if (res.code === 'downloaded') {
// Install the update
installUpdate(res.path).then((res) => {
if (res.code === 'install-failed') {
//logger.error('Failed to install update:', res.err);
reject({ code: 'install-failed', msg: 'Failed to install update.', err: res.err });
} else {
//logger.log('Update installed successfully.');
resolve({ code: 'update-installed', msg: 'Update installed successfully.' });
}
});
} else {
//logger.error('Failed to download update:', res.err);
reject({ code: 'download-failed', msg: 'Failed to download update.', err: res.err });
}
}).catch((err) => {
//logger.error('Failed to download and install update:', err);
reject({ code: 'download-install-failed', msg: 'Failed to download and install update.', err: err });
});
});
}
module.exports = {
checkForUpdates,
downloadUpdate,
installUpdate,
downloadAndInstall
};

View File

@@ -0,0 +1,121 @@
const path = require('path');
const { exec } = require('child_process');
const os = require('os');
const fs = require('fs');
// Get system information
const SystemInfo = require('./sysInfo');
// Get the current system platform
const sys = new SystemInfo();
// Only import the registry package if the system is Windows
let Registry;
if (sys.platform === 'win32') {
Registry = require('winreg');
}
// Get the uninstall entries from the registry
async function getUninstallEntries(filter = {}) {
if (sys.platform !== 'win32') {
console.error('This function only works on Windows.');
return [];
}
const registryPaths = [
'HKLM\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall',
'HKLM\\\\Software\\\\Wow6432Node\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall'
];
let results = [];
for (const regPath of registryPaths) {
const regKey = new Registry({ hive: Registry.HKLM, key: regPath });
try {
const subkeys = await new Promise((resolve, reject) => {
regKey.keys((err, keys) => {
if (err) reject(err);
else resolve(keys);
});
});
for (const subkey of subkeys) {
const values = await new Promise((resolve, reject) => {
subkey.values((err, items) => {
if (err) reject(err);
else resolve(items);
});
});
let entry = {};
values.forEach(item => {
if (item.name === 'DisplayName') entry.DisplayName = item.value;
if (item.name === 'Publisher') entry.Publisher = item.value;
if (item.name === 'InstallDate') entry.InstallDate = item.value;
if (item.name === 'DisplayVersion') entry.DisplayVersion = item.value;
if (item.name === 'HelpLink') entry.HelpLink = item.value;
if (item.name === 'UninstallString') entry.UninstallString = item.value;
if (item.name === 'WindowsInstaller') entry.WindowsInstaller = item.value === '1' ? 'MSI' : 'EXE';
});
if (entry.DisplayName && entry.UninstallString) {
// If WindowsInstaller value is missing, check UninstallString
if (!entry.WindowsInstaller) {
entry.WindowsInstaller = entry.UninstallString.includes('msiexec') ? 'MSI' : 'EXE';
}
results.push(entry);
}
}
} catch (error) {
console.error(`Error accessing registry path ${regPath}:`, error);
}
}
results.sort((a, b) => a.DisplayName.localeCompare(b.DisplayName));
// Filter results based on the provided filter (e.g., { DisplayName: 'bskyDesktop' })
if (filter.DisplayName) {
return results.filter(entry => entry.DisplayName?.includes(filter.DisplayName));
}
//console.log(results);
return results;
}
async function checkAppInstallationMethod(appPath, bundleId) {
if (!fs.existsSync(appPath)) {
return { error: "App does not exist at the specified path." };
}
try {
// Check for Mac App Store receipt
const { stdout: masOutput } = await execPromise(`mdls -name kMDItemAppStoreReceiptURL "${appPath}"`);
if (!masOutput.includes("(null)")) {
return { type: "MAS" };
}
// Check for PKG installation
try {
const { stdout: pkgOutput } = await execPromise(`pkgutil --pkg-info "${bundleId}"`);
return { type: "PKG", stdout: pkgOutput };
} catch {
// Ignore error; means PKG is not found
}
// Check if manually installed (ZIP/DMG)
const receiptPath = path.join(appPath, 'Contents', '_MASReceipt', 'receipt');
if (!fs.existsSync(receiptPath)) {
return { type: "ZIP/DMG" };
}
} catch (error) {
return { error: error.message };
}
}
module.exports = {
getUninstallEntries,
checkAppInstallationMethod
};

View File

@@ -61,6 +61,16 @@ class SystemInfo {
return !this.laterThan(compareVersion);
}
// Get edition of the os
getEdition() {
if (this.isWin()) {
const edition = childProcess.execSync('wmic os get Caption').toString().trim();
return edition.split('\n')[1].trim();
} else {
return 'N/A';
}
}
// Private: Parse version strings (e.g., "10.0.19045" -> [10, 0, 19045])
_parseVersion(version) {
return version.split('.').map((num) => parseInt(num, 10) || 0);

View File

@@ -1,5 +1,6 @@
const usercssMeta = require('usercss-meta');
const less = require('less');
const stylus = require('stylus');
/**
* Extracts all global variable and mixin definitions from CSS.
@@ -72,8 +73,8 @@ function parseDomainRule(css, startPos) {
if (!match) return null;
const domains = match[0]
.match(/'[^']+'/g) // Extract all single-quoted domain values
.map(domain => domain.replace(/'/g, '').trim());
.match(/['"][^'"]+['"]/g) // Extract all single- or double-quoted domain values
.map(domain => domain.replace(/['"]/g, '').trim()); // Remove quotes and trim whitespace
return {
domains,
@@ -90,17 +91,26 @@ function parseMozRules(css) {
const rules = {};
let currentPos = 0;
// Helper to extract global definitions (CSS outside @-moz-document)
const globalCode = extractGlobalDefinitions(css);
while (true) {
const domainRule = parseDomainRule(css, currentPos);
if (!domainRule) break;
while (currentPos < css.length) {
// Match @-moz-document syntax and extract domains
const domainMatch = css.slice(currentPos).match(/@-moz-document\s+(.*?){/s);
if (!domainMatch) break;
const bracedContent = extractBracedContent(css, domainRule.ruleStart);
const domainsStr = domainMatch[1];
const ruleStart = currentPos + domainMatch.index + domainMatch[0].length - 1;
// Extract the content inside the braces for this @-moz-document rule
const bracedContent = extractBracedContent(css, ruleStart);
if (!bracedContent) break;
// Add the CSS to all matched domains
for (const domain of domainRule.domains) {
// Parse the domains and add the CSS to each
const domainList = domainsStr.match(/domain\("([^"]+)"\)/g) || [];
const domains = domainList.map((d) => d.match(/domain\("([^"]+)"\)/)[1]);
for (const domain of domains) {
rules[domain] = `${globalCode}\n${bracedContent.content}`;
}
@@ -155,10 +165,17 @@ async function compileStyle(code, metadata, userVars = {}) {
switch (metadata?.preprocessor?.toLowerCase()) {
case 'less':
compiledCode = await compileLess(fullCode);
compiledCode = await compileLess(fullCode, vars);
break;
case 'stylus':
compiledCode = await compileStylus(fullCode, vars);
break;
case 'sass':
throw Error('SASS preprocessor not supported yet. Skipping compilation.');
case 'scss':
throw Error('SCSS preprocessor not supported yet. Skipping compilation.');
default:
compiledCode = code; // Return unmodified for unknown preprocessors
compiledCode = code; // Return unmodified for plain CSS/unknown preprocessor
}
// Parse domain rules
@@ -167,9 +184,14 @@ async function compileStyle(code, metadata, userVars = {}) {
// Compile each domain's CSS if needed
const compiledRules = {};
for (const [domain, css] of Object.entries(domainRules)) {
if (metadata.preprocessor === 'less') {
switch (metadata.preprocessor?.toLowerCase()) {
case 'less':
compiledRules[domain] = await compileLess(css, vars);
} else {
break;
case 'stylus':
compiledRules[domain] = await compileStylus(css, vars);
break;
default:
compiledRules[domain] = css;
}
}
@@ -181,27 +203,55 @@ async function compileStyle(code, metadata, userVars = {}) {
return {
compiledCss: combinedCss,
sites: compiledRules // Map of domains to their CSS
sites: compiledRules, // Map of domains to their CSS
};
} catch (error) {
console.error('Style compilation error:', error);
throw error;
//console.error('Style compilation error:', error);
return {
error
};
}
}
/**
* Compiles LESS code to CSS.
* @param {string} code - The LESS code.
* @param {object} vars - User-defined variables.
* @returns {Promise<string>} The compiled CSS.
*/
async function compileLess(code) {
const { css } = await less.render(code, {
async function compileLess(code, vars = {}) {
return new Promise((resolve, reject) => {
less.render(code, {
math: 'parens-division',
javascriptEnabled: true,
compress: false
compress: false,
globalVars: vars
}, (err, output) => {
if (err) return reject(err);
resolve(output.css);
});
});
}
/**
* Compiles Stylus code to CSS.
* @param {string} code - The Stylus code.
* @returns {Promise<string>} The compiled CSS.
*/
async function compileStylus(code, vars = {}) {
console.log(vars, code);
return new Promise((resolve, reject) => {
var stlus = stylus(code);
stlus.set('compress', false);
for (const [key, value] of Object.entries(vars)) {
stlus.define(key, value);
}
stlus.render((err, output) => {
if (err) return reject(err);
resolve(output);
});
});
return css;
}
module.exports = {

View File

@@ -0,0 +1,224 @@
'use strict';
const path = require('path');
const fs = require('fs');
const electron = require('electron');
let remote;
try {
remote = require('@electron/remote');
} catch (err) {
remote = electron.remote; // Fallback for older Electron versions
}
module.exports = function (options) {
const app = electron.app || (remote ? remote.app : null);
const screen = electron.screen || (remote ? remote.screen : null);
let state;
let winRef;
let stateChangeTimer;
const eventHandlingDelay = 100;
const config = Object.assign({
file: 'window-state.json',
path: app.getPath('userData'),
maximize: true,
fullScreen: true
}, options);
const fullStoreFileName = path.join(config.path, config.file);
function isNormal(win) {
return !win.isMaximized() && !win.isMinimized() && !win.isFullScreen();
}
function hasBounds() {
return state &&
Number.isInteger(state.x) &&
Number.isInteger(state.y) &&
Number.isInteger(state.width) && state.width > 0 &&
Number.isInteger(state.height) && state.height > 0;
}
function resetStateToDefault() {
const displayBounds = screen.getPrimaryDisplay().bounds;
// Reset state to default values on the primary display
state = {
width: config.defaultWidth || 800,
height: config.defaultHeight || 600,
x: 0,
y: 0,
displayBounds
};
}
function windowWithinBounds(bounds) {
return (
state.x >= bounds.x &&
state.y >= bounds.y &&
state.x + state.width <= bounds.x + bounds.width &&
state.y + state.height <= bounds.y + bounds.height
);
}
function ensureWindowVisibleOnSomeDisplay() {
const visible = screen.getAllDisplays().some(display => {
return windowWithinBounds(display.bounds);
});
if (!visible) {
// Window is partially or fully not visible now.
// Reset it to safe defaults.
return resetStateToDefault();
}
}
function validateState() {
const isValid = state && (hasBounds() || state.isMaximized || state.isFullScreen);
if (!isValid) {
state = null;
return;
}
if (hasBounds() && state.displayBounds) {
ensureWindowVisibleOnSomeDisplay();
}
}
function updateState(win) {
win = win || winRef;
if (!win || !state) return;
// Don't throw an error when window was closed
try {
const winBounds = win.getBounds();
if (isNormal(win)) {
state.x = winBounds.x;
state.y = winBounds.y;
state.width = winBounds.width;
state.height = winBounds.height;
}
state.isMaximized = win.isMaximized();
state.isFullScreen = win.isFullScreen();
state.displayBounds = screen.getDisplayMatching(winBounds).bounds;
} catch (err) { }
}
function saveState(win) {
// Update window state only if it was provided
if (win) {
updateState(win);
}
// Save state
try {
fs.mkdirSync(path.dirname(fullStoreFileName), { recursive: true });
fs.writeFileSync(fullStoreFileName, JSON.stringify(state));
} catch (err) {
// Don't care
}
}
function stateChangeHandler() {
// Handles both 'resize' and 'move'
clearTimeout(stateChangeTimer);
stateChangeTimer = setTimeout(() => saveState(winRef), eventHandlingDelay);
}
function closeHandler() {
updateState();
}
function closedHandler() {
// Unregister listeners and save state
unmanage();
saveState();
}
function manage(win) {
if (config.maximize && state.isMaximized) {
win.maximize();
}
if (config.fullScreen && state.isFullScreen) {
win.setFullScreen(true);
}
function resizeBrowserView() {
try {
const view = win.getBrowserView();
if (view) {
const windowBounds = win.getBounds(); // Full window size
const screenBounds = screen.getPrimaryDisplay().bounds; // Screen size
// Calculate the usable area by subtracting window chrome and any borders
const width = windowBounds.width; // Width of the full window
const height = windowBounds.height; // Height of the full window
// Ensure BrowserView fits within the screen size and window size
view.setBounds({
x: 0,
y: 0,
width: Math.min(width, screenBounds.width), // Prevent overflow horizontally
height: Math.min(height, screenBounds.height) // Prevent overflow vertically
});
}
} catch (err) {
// Ignore errors if BrowserView is not present
}
}
function stateChangeHandlerWithBrowserView() {
stateChangeHandler(); // Preserve original behavior
resizeBrowserView(); // Resize BrowserView if applicable
}
win.on('resize', stateChangeHandler);
win.on('move', stateChangeHandler);
win.on('close', closeHandler);
win.on('closed', closedHandler);
// Initial BrowserView resize in case window is already open
resizeBrowserView();
winRef = win;
}
function unmanage() {
if (winRef) {
winRef.removeListener('resize', stateChangeHandler);
winRef.removeListener('move', stateChangeHandler);
clearTimeout(stateChangeTimer);
winRef.removeListener('close', closeHandler);
winRef.removeListener('closed', closedHandler);
winRef = null;
}
}
// Load previous state
try {
state = JSON.parse(fs.readFileSync(fullStoreFileName, 'utf8'));
} catch (err) {
// Don't care
}
// Check state validity
validateState();
// Set state fallback values
state = Object.assign({
width: config.defaultWidth || 800,
height: config.defaultHeight || 600
}, state || {});
return {
get x() { return state.x; },
get y() { return state.y; },
get width() { return state.width; },
get height() { return state.height; },
get displayBounds() { return state.displayBounds; },
get isMaximized() { return state.isMaximized; },
get isFullScreen() { return state.isFullScreen; },
saveState,
unmanage,
manage,
resetStateToDefault
};
};

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Jakub Szwacz
Copyright (c) Marcel Wiehle <marcel@wiehle.me> (http://marcel.wiehle.me)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

105
src/ui/css/offline.css Normal file
View File

@@ -0,0 +1,105 @@
html,
body {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden; /* Prevent overflow from the body */
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background-color: #082032;
color: white;
}
.container {
display: flex;
justify-content: center;
align-items: flex-start; /* Align items to the top */
height: 100vh; /* Full viewport height */
overflow-y: auto; /* Allow vertical scrolling */
margin: 0;
}
.divround {
background-color: #2c394b;
height: auto; /* Let it grow with content */
width: 90vw; /* or set a max-width if preferred */
max-width: 510px; /* Fixed width for your content */
margin: auto;
padding: 2.375vh; /* Converted from 19px to vh */
border-radius: 0.5em;
box-shadow: 2px 3px 7px 2px rgba(0, 0, 0, 0.02);
text-align: center;
overflow-y: auto; /* Allow scrolling inside the element if needed */
}
.circular {
border-radius: 125px;
-webkit-border-radius: 125px;
-moz-border-radius: 125px;
background-size: cover;
display: inline-block;
width: 250px;
height: 250px;
}
.btn {
background-color: DodgerBlue;
border: none;
color: white;
padding: 10px 20px;
cursor: pointer;
font-size: 20px;
border-radius: 8px;
}
/* Non-rounded border */
.btn.nr {
border-radius: 0px;
}
/* Full width */
.btn.fw {
width: 100%
}
/* Darker background on mouse-over */
.btn:hover {
background-color: RoyalBlue;
}
/* Success btn */
.btn.success {
background-color: #a6efb8e6;
}
/* Danger btn */
.btn.danger {
background-color: #ffafb4e6;
}
/* Warning btn */
.btn.warning {
background-color: #ffefb4e6;
}
/* Info btn */
.btn.info {
background-color: #b4e4f9e6;
}
/* button (input style) */
.btn.input {
background-color: rgb(82, 124, 165);
}
/* Darker on mouse-over */
.btn.input:hover {
background-color: rgb(72, 109, 146);
}
/* Darker on active */
.btn.input:active {
background-color: rgb(66, 111, 155);
}

View File

@@ -6,6 +6,7 @@
-webkit-user-drag: none;
/* Disable selection */
-webkit-user-select: none;
user-select: none;
}
html,

31
src/ui/offline.html Normal file
View File

@@ -0,0 +1,31 @@
<html>
<head>
<title>No internet connection</title>
<link rel="stylesheet" href="./css/offline.css">
<link rel="stylesheet" href="./css/fa/6.7.1/css/all.min.css">
</head>
<body>
<div class="container">
<div class="divround" style="width: 510px;">
<h1>No internet connection</h1>
<p>We couldn't detect an internet connection. Please check your network and try again.</p>
<button class="btn" id="refresh-app"><i class="fa fa-refresh"></i> Reload</button>
</div>
</div>
<script>
// When the reload button is clicked, send a message to the main process to reload the app
document.getElementById('refresh-app').addEventListener('click', () => {
// Check for internet connection before reloading
if (navigator.onLine) {
window.ipc.send('app:restart');
return;
} else {
alert('Please check your network and try again.');
};
});
</script>
</body>
</html>

View File

@@ -1,33 +1,37 @@
const { contextBridge, ipcRenderer } = require('electron');
// Expose IPC methods
// Expose protected methods that allow the renderer process to use
const allowedChannels = ["ui:badgeCount", "ui:notif", "ui:settings", "ui:openSettings", "app:restart"];
// Expose ipcRenderer to the renderer process
contextBridge.exposeInMainWorld("ipc", {
send: (channel, data) => {
if (allowedChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
on: (channel, callback) => {
if (allowedChannels.includes(channel)) {
ipcRenderer.on(channel, (event, ...args) => callback(...args));
}
},
});
contextBridge.exposeInMainWorld("badge", {
update: (badgeNumber) => {
ipcRenderer.send('ui:badgeCount', badgeNumber);
}
});
// Helper to dynamically load a script and append it to the DOM
function loadScript(src, callback) {
const script = document.createElement('script');
// Load a script asynchronously
function loadScriptAsync(src) {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = src;
script.onload = () => {
console.log(`Loaded script: ${src}`);
if (callback) callback();
resolve();
};
script.onerror = (error) => {
console.error(`Failed to load script: ${src}`, error);
reject(error);
};
document.body.appendChild(script);
});
}
// Inject CSS into the DOM
@@ -39,22 +43,19 @@ function injectCSS(href) {
console.log(`Injected CSS: ${href}`);
}
document.addEventListener('DOMContentLoaded', () => {
// Inject CSS
injectCSS('ui:///lib/izitoast.min.css');
injectCSS('ui:///rend/extra-themes.css');
injectCSS('ui:///css/fa/6.7.1/css/all.min.css');
document.addEventListener("DOMContentLoaded", async () => {
injectCSS("ui:///lib/izitoast.min.css");
injectCSS("ui:///rend/extra-themes.css");
injectCSS("ui:///css/fa/6.7.1/css/all.min.css");
// Load jQuery first
loadScript('ui:///lib/jquery-3.3.1.min.js', () => {
// Load confetti and iziToast after jQuery (ui libs)
loadScript('ui:///lib/confetti-1.9.3-browser.min.js');
loadScript('ui:///lib/izitoast.min.js', () => {
// Load app specific scripts
loadScript('ui:///rend/register-handles.js');
// Load custom implementations
loadScript('ui:///rend/bsky-ext.js');
loadScript('ui:///rend/specialAnimations.js');
});
});
try {
await loadScriptAsync("ui:///lib/jquery-3.3.1.min.js");
await loadScriptAsync("ui:///lib/confetti-1.9.3-browser.min.js");
await loadScriptAsync("ui:///lib/izitoast.min.js");
await loadScriptAsync("ui:///rend/register-handles.js");
await loadScriptAsync("ui:///rend/bsky-ext.js");
await loadScriptAsync("ui:///rend/specialAnimations.js");
} catch (error) {
console.error("Failed to load one or more scripts.", error);
}
});

File diff suppressed because one or more lines are too long

View File

@@ -36,6 +36,8 @@ document.addEventListener('DOMContentLoaded', () => {
ipcRenderer.on('ui:progtext', (event, other) => {
console.log('Updating progress text:', other);
infotext.innerText = other.title;
if (other.subtitle) {
progtext.innerText = other.subtitle;
};
});
});