From 49eb0ad921e2704e0e538da0863a47037aeb4dd3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 26 Nov 2024 21:39:59 +0100 Subject: [PATCH 01/16] bump to holochain 0.4.0-rc.1 --- .github/workflows/release.yaml | 2 +- kangaroo.config.ts | 20 +++--- package.json | 6 +- src/main/const.ts | 2 +- src/main/holochainManager.ts | 8 ++- yarn.lock | 120 ++++++++++++++++----------------- 6 files changed, 82 insertions(+), 76 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c89e7e8..3242f59 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -56,7 +56,7 @@ jobs: run: | echo ${{ github.repository }} echo "overwriting names for release testing" - curl -f -L --output ./pouch/presence.webhapp /~https://github.com/matthme/presence/releases/download/0.7.3/presence.webhapp + curl -f -L --output ./pouch/presence.webhapp /~https://github.com/holochain-apps/kando/releases/download/v0.11.3/kando.webhapp node ./scripts/overwrite-with-test-name.js - name: Retrieve appId diff --git a/kangaroo.config.ts b/kangaroo.config.ts index 819e0a9..a6212af 100644 --- a/kangaroo.config.ts +++ b/kangaroo.config.ts @@ -9,29 +9,29 @@ export default defineConfig({ fallbackToIndexHtml: true, bins: { holochain: { - version: "0.3.3", + version: "0.4.0-rc.1", sha256: { "x86_64-unknown-linux-gnu": - "889f517e5353287e6656b9516582ae806194eddaae86e2a546afcb8007c6adc1", + "6e111ff588628c8da0b64340a0e2fa9291146c5033b21102ce115fbecf8aa36c", "x86_64-pc-windows-msvc.exe": - "d8702733568791e4e42afaa6bb49b9a992fc0874498fe87b818c64d5e9848e6a", + "4268aac469304cd1b6bb6a90631a3a018e6f08a236088e7a7045a9969ba4458f", "x86_64-apple-darwin": - "b5444f43056abf545176dcea724afe43790d5531e5d1ecde4425d3ecabbcb24c", + "b377612a817310dc4f747662003e68b96b9058d22464d28db8b807cbe7d6704d", "aarch64-apple-darwin": - "93ddcc2beb19e13dd3789b322bba5dcaa9cefd52cd60f1505a764a090673c993", + "23b60ae414b1525a41aabcd213b29922cc4f581f3d748750393357847b10f3fb", }, }, lair: { - version: "0.4.5", + version: "0.5.2", sha256: { "x86_64-unknown-linux-gnu": - "67b5a8d06575fc14c6295fec05cd2dcd338de76a051ceac6dd7b03e921ee1762", + "5fa1b2ece8896208c313c01b531d99d861e156de8f2d2ddc2709a82bc2533550", "x86_64-pc-windows-msvc.exe": - "77cb4e51a9816048520a30293760214483a0a372ab554ad496955167e6009c99", + "42a4a6eaf3cd1cb52bdc6512b392e874467bc6d7f5763b89a303767a9d979ad9", "x86_64-apple-darwin": - "60c81104bbaa37e69749a7f53b079d06414d07418a1514a3c676503ce2861c4a", + "22cadfb73435ce0c97e6581123b4fc3fe9ff0a5ef5b04eed3b4895a84f5cbb79", "aarch64-apple-darwin": - "f6e427557271d13ab32bdd8672f0408b8b248117840adc64c858d55a6ae56583", + "246bb1090e9e875babe056df413f75ad8dd1ba4971f293dd5e94ea05ea364aa0", }, }, }, diff --git a/package.json b/package.json index 96fd55e..605eaa0 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,9 @@ "dependencies": { "@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/utils": "^3.0.0", - "@holochain/client": "0.17.1", - "@holochain/hc-spin-rust-utils": "0.300.1", - "@lightningrodlabs/we-rust-utils": "0.300.2", + "@holochain/client": "0.18.0-rc.0", + "@holochain/hc-spin-rust-utils": "0.400.0-rc.0", + "@lightningrodlabs/we-rust-utils": "0.400.0-rc.0", "@msgpack/msgpack": "^2.8.0", "adm-zip": "0.5.14", "bufferutil": "4.0.8", diff --git a/src/main/const.ts b/src/main/const.ts index a93df08..d5cb896 100644 --- a/src/main/const.ts +++ b/src/main/const.ts @@ -12,7 +12,7 @@ const kangarooConfigString = fs.readFileSync(path.join(RESOURCES_DIRECTORY, 'kan export const KANGAROO_CONFIG: KangarooConfig = JSON.parse(kangarooConfigString); export const DEFAULT_BOOTSTRAP_SERVER = 'https://bootstrap.holo.host'; -export const DEFAULT_SIGNALING_SERVER = 'wss://signal.holo.host'; +export const DEFAULT_SIGNALING_SERVER = 'wss://sbd.holo.host'; const binariesAppendix = KANGAROO_CONFIG.appId.slice(0,10).replace(' ', '-'); diff --git a/src/main/holochainManager.ts b/src/main/holochainManager.ts index 2584dab..53939fa 100644 --- a/src/main/holochainManager.ts +++ b/src/main/holochainManager.ts @@ -73,7 +73,10 @@ export class HolochainManager { lairUrl, bootstrapUrl, signalingUrl, - "*" + "*", + false, + undefined, + undefined, ); console.log("Writing conductor-config.yaml..."); @@ -182,6 +185,9 @@ export class HolochainManager { return; if (!networkSeed) { networkSeed = `${KANGAROO_CONFIG.productName}-${breakingAppVersion(app)}`; + if (!app.isPackaged) { + networkSeed += "-dev"; + } } console.log(`Installing happ...`); const pubKey = await this.adminWebsocket.generateAgentPubKey(); diff --git a/yarn.lock b/yarn.lock index c34159a..12420f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -570,10 +570,10 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== -"@holochain/client@0.17.1": - version "0.17.1" - resolved "https://registry.yarnpkg.com/@holochain/client/-/client-0.17.1.tgz#c3b1e0296e1a226a1b2a68fc106ce48cc9bc1820" - integrity sha512-Jvh6DN+OdktV3KQH+tioRzvPT+LWJFBp1klMFG9vaccphIVvJN1LepJfRB8OyxW5iGAZ/TFCTwF19XSJuM1fQQ== +"@holochain/client@0.18.0-rc.0": + version "0.18.0-rc.0" + resolved "https://registry.yarnpkg.com/@holochain/client/-/client-0.18.0-rc.0.tgz#1ff5e6331387cfd929670148be256a067f7ad431" + integrity sha512-y9dfvrnUL4OeIhW+yHUnsjsBMoWvL1HnvUKGjfoBQDBsqJGpanmysV6ALScNErF5axPVZ30/m0nmQ9NgpFzUGg== dependencies: "@bitgo/blake2b" "^3.2.4" "@holochain/serialization" "^0.1.0-beta-rc.3" @@ -585,35 +585,35 @@ lodash-es "^4.17.21" ws "^8.14.2" -"@holochain/hc-spin-rust-utils-darwin-arm64@0.300.1": - version "0.300.1" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-arm64/-/hc-spin-rust-utils-darwin-arm64-0.300.1.tgz#e183439230a6e98c7c1400d76aa19076d3c55ac7" - integrity sha512-IOt+hTVRByaqpzuZ+pN7tTAqNPXsPxE6oc+Hqjo5D4aWP3oeD2b6bEEDRfBicMuUTp7spIqKgT/4Dj0pQtLvyw== - -"@holochain/hc-spin-rust-utils-darwin-x64@0.300.1": - version "0.300.1" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-x64/-/hc-spin-rust-utils-darwin-x64-0.300.1.tgz#bd2c7fcec4d5f23e0cf6d406dc63f7ccfd22eef0" - integrity sha512-ffxAB9o5XhvwcXi1F6MsURoxhxJbo3HvlBpD0F2VNfyv/zCd15gb8HvcskhcvQFKlCEHigRrilOxHP5Aks8I3w== - -"@holochain/hc-spin-rust-utils-linux-x64-gnu@0.300.1": - version "0.300.1" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-linux-x64-gnu/-/hc-spin-rust-utils-linux-x64-gnu-0.300.1.tgz#410a59bf28974cd7361785bc0631d15186be7a49" - integrity sha512-SKUJdvKIRkqixgaChnkLvBNWgZgFGLI5tNeV/8WMdxCKqD2kLJzUFSIafl1arck9964iSfsCRMG8/5fpfE+sZg== - -"@holochain/hc-spin-rust-utils-win32-x64-msvc@0.300.1": - version "0.300.1" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-win32-x64-msvc/-/hc-spin-rust-utils-win32-x64-msvc-0.300.1.tgz#abdd794bc44a62d2b3c47953eb4277369a5a3ee0" - integrity sha512-S+PcygFnkVbR1/5FF66P7gBju3+PfOd1BLgfDpF6kghSJfb3qSN1h93vPujxeoQcs1qtT3DqMarG2BmyCe9RPA== - -"@holochain/hc-spin-rust-utils@0.300.1": - version "0.300.1" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils/-/hc-spin-rust-utils-0.300.1.tgz#12da10b356c1adb9254305a6c3e774fad2c681ad" - integrity sha512-vMC6cgqJ8gOT7dGunTyYd6frqax+XQO9v4ZB5YL6amws9xu9lL6OqG1igNJfGimAbqCaQTd1bq8Ctr+HF8AYyg== +"@holochain/hc-spin-rust-utils-darwin-arm64@0.400.0-rc.0": + version "0.400.0-rc.0" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-arm64/-/hc-spin-rust-utils-darwin-arm64-0.400.0-rc.0.tgz#5d9468656e86b911eca79287c64ec914db579007" + integrity sha512-EpF+56rM6JsubvNkOfLiMMjz0JXUVH1BmQ6PPeX1vmlYzlrHgbwmGPo+YigUcbsk4PJUpdpOSgRnhLPXsZSvvA== + +"@holochain/hc-spin-rust-utils-darwin-x64@0.400.0-rc.0": + version "0.400.0-rc.0" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-x64/-/hc-spin-rust-utils-darwin-x64-0.400.0-rc.0.tgz#0356bfb4f5b2f2ea3815b79a1ba9526b9a8004a4" + integrity sha512-NQG6fBk1L8LyZ+2i/2Xs7iS5rYHAz8Q6YePQLZVhVIkEVhqlMO4jwNKxGqE5RxT1kv4LJOs+TXLHMtofh6puuQ== + +"@holochain/hc-spin-rust-utils-linux-x64-gnu@0.400.0-rc.0": + version "0.400.0-rc.0" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-linux-x64-gnu/-/hc-spin-rust-utils-linux-x64-gnu-0.400.0-rc.0.tgz#4ee9f2e8ee0db38ff0c4398354aa21785c83ff9b" + integrity sha512-a/HYxQPXEEtgqrNZTeIfXubWGKd0zu/ihP/ZSwcvh+Za5neCpy1dD2YjyrSZd7ClvjLCMH0cO0uNQnTd/sCSoQ== + +"@holochain/hc-spin-rust-utils-win32-x64-msvc@0.400.0-rc.0": + version "0.400.0-rc.0" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-win32-x64-msvc/-/hc-spin-rust-utils-win32-x64-msvc-0.400.0-rc.0.tgz#ec2500f2e19e44349a5e396f5e38a1ed0bfdd2bf" + integrity sha512-UM3fjzXx+mMa3u8gGiZJCslnFu7J6ybnvshCj/Eoh7LL0Ad4obOThq82iYvi/nhO7uWme/KkYu3cLQZ9gz4DTA== + +"@holochain/hc-spin-rust-utils@0.400.0-rc.0": + version "0.400.0-rc.0" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils/-/hc-spin-rust-utils-0.400.0-rc.0.tgz#c6817da0da26e594beb36781dbc338670b77664f" + integrity sha512-lB3YJg4PNDzWkWW1cmrF8aLUNLVmtQCXg1kq1k8jws/ZR4iCJieuUrQPLVjkeHO5x5ZTRG7Ls2MgcGux61Mrzw== optionalDependencies: - "@holochain/hc-spin-rust-utils-darwin-arm64" "0.300.1" - "@holochain/hc-spin-rust-utils-darwin-x64" "0.300.1" - "@holochain/hc-spin-rust-utils-linux-x64-gnu" "0.300.1" - "@holochain/hc-spin-rust-utils-win32-x64-msvc" "0.300.1" + "@holochain/hc-spin-rust-utils-darwin-arm64" "0.400.0-rc.0" + "@holochain/hc-spin-rust-utils-darwin-x64" "0.400.0-rc.0" + "@holochain/hc-spin-rust-utils-linux-x64-gnu" "0.400.0-rc.0" + "@holochain/hc-spin-rust-utils-win32-x64-msvc" "0.400.0-rc.0" "@holochain/serialization@^0.1.0-beta-rc.3": version "0.1.0-beta-rc.3" @@ -691,35 +691,35 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@lightningrodlabs/we-rust-utils-darwin-arm64@0.300.2": - version "0.300.2" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-arm64/-/we-rust-utils-darwin-arm64-0.300.2.tgz#d2c6915fa0bbc957e18c01ff989d8ba5b38a1596" - integrity sha512-2QSeR3O42xSNQBPHG4y+marCPflmrXIBITK5eWNv9bwWteWdbUWSO9ZoEayzFexz1ZqqGqF4zbM78sj+CmLmNQ== - -"@lightningrodlabs/we-rust-utils-darwin-x64@0.300.2": - version "0.300.2" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-x64/-/we-rust-utils-darwin-x64-0.300.2.tgz#b3e31e0e664bb1f40d5a92ebec4ca658e3363a0f" - integrity sha512-a/UuqTTP1Te2UMAZKszCpgpkoTnB1QSHLBb6+83aV1P/1bX/OHhFSdhVOg3qtkECk3xXZdRC4Z2q/+WORODs6w== - -"@lightningrodlabs/we-rust-utils-linux-x64-gnu@0.300.2": - version "0.300.2" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-linux-x64-gnu/-/we-rust-utils-linux-x64-gnu-0.300.2.tgz#8174093f392efc47e3e5c716f0696312d5fcaae1" - integrity sha512-rhPP1Ua0n4kCO0DtiUl9KfxdLNAgU5HqmYhSt4J2aWcsrG4dGUTx5MHtPjC0xU0c5+ccr0x8iwMmbkEl1PWjPA== - -"@lightningrodlabs/we-rust-utils-win32-x64-msvc@0.300.2": - version "0.300.2" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-win32-x64-msvc/-/we-rust-utils-win32-x64-msvc-0.300.2.tgz#60b635155ddfe88b6d58b0c73d21d3fdff732e6b" - integrity sha512-D4jkfaFylA03jz/cGVXViQkSfXUPys3aaCRR/JbsfpvWEvr0D3TR9DIqF1qU7eWQ7rWDLocpBDSXz+f4/auxNQ== - -"@lightningrodlabs/we-rust-utils@0.300.2": - version "0.300.2" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils/-/we-rust-utils-0.300.2.tgz#6681b1fb372c2991c665563c3ecc53d2d4190585" - integrity sha512-+NSe3MSbKQFiArxRQn66mzRkNi/r4B9SAhwzHAT0k2o4tVRbHQ9SeO4V/aXq0VpE83pAEgaRUo9mAkp9ZSkhhw== +"@lightningrodlabs/we-rust-utils-darwin-arm64@0.400.0-rc.0": + version "0.400.0-rc.0" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-arm64/-/we-rust-utils-darwin-arm64-0.400.0-rc.0.tgz#8a159c4d9893dab9e9c7dd7605e2252c46d1e52f" + integrity sha512-ZXCIqllu1poOA4LDgjV3q4aNsC+QkrzrkNWXeaPQlXLyG7w6LnBRTTcyDpIa4+jOA0r3AYigahGY3Itm+JLdKA== + +"@lightningrodlabs/we-rust-utils-darwin-x64@0.400.0-rc.0": + version "0.400.0-rc.0" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-x64/-/we-rust-utils-darwin-x64-0.400.0-rc.0.tgz#15492a985ae0615c23c7a49087e64feb725f8511" + integrity sha512-FQWoHKKi9mmzyO9bB4rh7q6yhnPvxS5H2Gf3tdlVG4a0YKMmZ8a/t32dYvminh7DzokwcsmEbxE0x13K7SL4iA== + +"@lightningrodlabs/we-rust-utils-linux-x64-gnu@0.400.0-rc.0": + version "0.400.0-rc.0" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-linux-x64-gnu/-/we-rust-utils-linux-x64-gnu-0.400.0-rc.0.tgz#f7736a8c522590db3395f8e504f541f068e41c44" + integrity sha512-BJ0iBqxIM6lmbz1MMQ5gqBXXkarMpIrjxEeMy5IDS+tvAEdP7h+6olVsvumiRBhmB6CLwiBzwu4D0EthgbNxaQ== + +"@lightningrodlabs/we-rust-utils-win32-x64-msvc@0.400.0-rc.0": + version "0.400.0-rc.0" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-win32-x64-msvc/-/we-rust-utils-win32-x64-msvc-0.400.0-rc.0.tgz#4bd15789425305061a8449de6eefea07bb47a192" + integrity sha512-Wc5Jo1C9YG/6EP1TEFDuFHoDkxvQG6X5RtLA120zj35W9Ll0Hwhkxd6wBknCYZQNjKhsuqKwTgKM5bpC97tc7w== + +"@lightningrodlabs/we-rust-utils@0.400.0-rc.0": + version "0.400.0-rc.0" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils/-/we-rust-utils-0.400.0-rc.0.tgz#37d848f3de128755893721e4a36c1df481b4258c" + integrity sha512-16ygk4KQqevHCsg9U2UFY6Qq+xY6fslNTJLNyUNevw8gYJhf5S2M/6SdkbCuYsj+I9a6uDnWv6vwV1EoVVVqIw== optionalDependencies: - "@lightningrodlabs/we-rust-utils-darwin-arm64" "0.300.2" - "@lightningrodlabs/we-rust-utils-darwin-x64" "0.300.2" - "@lightningrodlabs/we-rust-utils-linux-x64-gnu" "0.300.2" - "@lightningrodlabs/we-rust-utils-win32-x64-msvc" "0.300.2" + "@lightningrodlabs/we-rust-utils-darwin-arm64" "0.400.0-rc.0" + "@lightningrodlabs/we-rust-utils-darwin-x64" "0.400.0-rc.0" + "@lightningrodlabs/we-rust-utils-linux-x64-gnu" "0.400.0-rc.0" + "@lightningrodlabs/we-rust-utils-win32-x64-msvc" "0.400.0-rc.0" "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" From 8e0d64d6259a598bb0f8bb644560a56315177c34 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 12 Dec 2024 11:35:42 +0100 Subject: [PATCH 02/16] bump to holochain 0.4.0-rc.2 --- .github/workflows/release.yaml | 2 +- kangaroo.config.ts | 20 +++--- package.json | 8 +-- yarn.lock | 120 ++++++++++++++++----------------- 4 files changed, 75 insertions(+), 75 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 3242f59..cb833c9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -56,7 +56,7 @@ jobs: run: | echo ${{ github.repository }} echo "overwriting names for release testing" - curl -f -L --output ./pouch/presence.webhapp /~https://github.com/holochain-apps/kando/releases/download/v0.11.3/kando.webhapp + curl -f -L --output ./pouch/ziptest.webhapp /~https://github.com/holochain-apps/ziptest/releases/download/ziptest-v0.0.9/ziptest.webhapp node ./scripts/overwrite-with-test-name.js - name: Retrieve appId diff --git a/kangaroo.config.ts b/kangaroo.config.ts index a6212af..b0dcaef 100644 --- a/kangaroo.config.ts +++ b/kangaroo.config.ts @@ -9,29 +9,29 @@ export default defineConfig({ fallbackToIndexHtml: true, bins: { holochain: { - version: "0.4.0-rc.1", + version: "0.4.0-rc.2", sha256: { "x86_64-unknown-linux-gnu": - "6e111ff588628c8da0b64340a0e2fa9291146c5033b21102ce115fbecf8aa36c", + "7110f9b0c9c2b4bbc974543df1b633299c7fa8d3d16f3cde4dc894ac64c0670f", "x86_64-pc-windows-msvc.exe": - "4268aac469304cd1b6bb6a90631a3a018e6f08a236088e7a7045a9969ba4458f", + "959fca4b575c6791196fcd1fb9c6c7a92359191dbd60e95b7800c6e79bb21687", "x86_64-apple-darwin": - "b377612a817310dc4f747662003e68b96b9058d22464d28db8b807cbe7d6704d", + "a62d1b6413f2791ec4df87338d794a7ba29a0890f1a2ceb1ed9eeddb0efc94a7", "aarch64-apple-darwin": - "23b60ae414b1525a41aabcd213b29922cc4f581f3d748750393357847b10f3fb", + "f25bee4cb2615b1970a8ef89c82dcfb867682a3502962343d4842571aafb9bc3", }, }, lair: { - version: "0.5.2", + version: "0.5.3", sha256: { "x86_64-unknown-linux-gnu": - "5fa1b2ece8896208c313c01b531d99d861e156de8f2d2ddc2709a82bc2533550", + "96a28b9b37c73ef46d8b5c56b9d799d558fd2fe77b41c577e2bcb37685a46396", "x86_64-pc-windows-msvc.exe": - "42a4a6eaf3cd1cb52bdc6512b392e874467bc6d7f5763b89a303767a9d979ad9", + "68b6453a19921072aac04dae52a4e94e725e7482005d2f54f907aec680e078de", "x86_64-apple-darwin": - "22cadfb73435ce0c97e6581123b4fc3fe9ff0a5ef5b04eed3b4895a84f5cbb79", + "a53bfb8e501431870b99243cbac24f6103d67f8be094930f174829bb249f34c4", "aarch64-apple-darwin": - "246bb1090e9e875babe056df413f75ad8dd1ba4971f293dd5e94ea05ea364aa0", + "6b15d977408847ac977c2e060c7aab84a69e6e90c79390098dd40a6b75256e50", }, }, }, diff --git a/package.json b/package.json index 605eaa0..d1ddb6e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "org.holochain.kangaroo-electron2", + "name": "org.holochain.kangaroo-electron", "version": "0.1.0", "license": "CAL-1.0", "main": "./out/main/index.js", @@ -23,9 +23,9 @@ "dependencies": { "@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/utils": "^3.0.0", - "@holochain/client": "0.18.0-rc.0", - "@holochain/hc-spin-rust-utils": "0.400.0-rc.0", - "@lightningrodlabs/we-rust-utils": "0.400.0-rc.0", + "@holochain/client": "0.18.0-rc.1", + "@holochain/hc-spin-rust-utils": "0.400.0-rc.1", + "@lightningrodlabs/we-rust-utils": "0.400.0-rc.1", "@msgpack/msgpack": "^2.8.0", "adm-zip": "0.5.14", "bufferutil": "4.0.8", diff --git a/yarn.lock b/yarn.lock index 12420f0..53385a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -570,10 +570,10 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== -"@holochain/client@0.18.0-rc.0": - version "0.18.0-rc.0" - resolved "https://registry.yarnpkg.com/@holochain/client/-/client-0.18.0-rc.0.tgz#1ff5e6331387cfd929670148be256a067f7ad431" - integrity sha512-y9dfvrnUL4OeIhW+yHUnsjsBMoWvL1HnvUKGjfoBQDBsqJGpanmysV6ALScNErF5axPVZ30/m0nmQ9NgpFzUGg== +"@holochain/client@0.18.0-rc.1": + version "0.18.0-rc.1" + resolved "https://registry.yarnpkg.com/@holochain/client/-/client-0.18.0-rc.1.tgz#35f67657858593ef380dfccca200ee366a451407" + integrity sha512-01Xh5cpN0lHdtV41V2RtCUfTFEA9K9GWK5vvMPtdqj52WcSNO6gcrfVERKgSG/su8xJ3VmULPYNQyrEMmBReww== dependencies: "@bitgo/blake2b" "^3.2.4" "@holochain/serialization" "^0.1.0-beta-rc.3" @@ -585,35 +585,35 @@ lodash-es "^4.17.21" ws "^8.14.2" -"@holochain/hc-spin-rust-utils-darwin-arm64@0.400.0-rc.0": - version "0.400.0-rc.0" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-arm64/-/hc-spin-rust-utils-darwin-arm64-0.400.0-rc.0.tgz#5d9468656e86b911eca79287c64ec914db579007" - integrity sha512-EpF+56rM6JsubvNkOfLiMMjz0JXUVH1BmQ6PPeX1vmlYzlrHgbwmGPo+YigUcbsk4PJUpdpOSgRnhLPXsZSvvA== - -"@holochain/hc-spin-rust-utils-darwin-x64@0.400.0-rc.0": - version "0.400.0-rc.0" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-x64/-/hc-spin-rust-utils-darwin-x64-0.400.0-rc.0.tgz#0356bfb4f5b2f2ea3815b79a1ba9526b9a8004a4" - integrity sha512-NQG6fBk1L8LyZ+2i/2Xs7iS5rYHAz8Q6YePQLZVhVIkEVhqlMO4jwNKxGqE5RxT1kv4LJOs+TXLHMtofh6puuQ== - -"@holochain/hc-spin-rust-utils-linux-x64-gnu@0.400.0-rc.0": - version "0.400.0-rc.0" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-linux-x64-gnu/-/hc-spin-rust-utils-linux-x64-gnu-0.400.0-rc.0.tgz#4ee9f2e8ee0db38ff0c4398354aa21785c83ff9b" - integrity sha512-a/HYxQPXEEtgqrNZTeIfXubWGKd0zu/ihP/ZSwcvh+Za5neCpy1dD2YjyrSZd7ClvjLCMH0cO0uNQnTd/sCSoQ== - -"@holochain/hc-spin-rust-utils-win32-x64-msvc@0.400.0-rc.0": - version "0.400.0-rc.0" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-win32-x64-msvc/-/hc-spin-rust-utils-win32-x64-msvc-0.400.0-rc.0.tgz#ec2500f2e19e44349a5e396f5e38a1ed0bfdd2bf" - integrity sha512-UM3fjzXx+mMa3u8gGiZJCslnFu7J6ybnvshCj/Eoh7LL0Ad4obOThq82iYvi/nhO7uWme/KkYu3cLQZ9gz4DTA== - -"@holochain/hc-spin-rust-utils@0.400.0-rc.0": - version "0.400.0-rc.0" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils/-/hc-spin-rust-utils-0.400.0-rc.0.tgz#c6817da0da26e594beb36781dbc338670b77664f" - integrity sha512-lB3YJg4PNDzWkWW1cmrF8aLUNLVmtQCXg1kq1k8jws/ZR4iCJieuUrQPLVjkeHO5x5ZTRG7Ls2MgcGux61Mrzw== +"@holochain/hc-spin-rust-utils-darwin-arm64@0.400.0-rc.1": + version "0.400.0-rc.1" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-arm64/-/hc-spin-rust-utils-darwin-arm64-0.400.0-rc.1.tgz#b8ba066394b297d8d8ffd4f6d5bad2b42ad6575c" + integrity sha512-Q9tB/NSt3EcFDXefx+3XMWiiw5TBH/aec7vTUoZZudXqFP6yLvIhd82mufRrunL7GBzUIH/slg0MfKiSkg1elw== + +"@holochain/hc-spin-rust-utils-darwin-x64@0.400.0-rc.1": + version "0.400.0-rc.1" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-x64/-/hc-spin-rust-utils-darwin-x64-0.400.0-rc.1.tgz#5b06bb1e707a0d49b91564deb36e092ef7ae3eda" + integrity sha512-B0yhrmqOqXzABne1IF/mFJmefuCj2otGyMSgwuv0lIrtu9rhe9y8qyrhMBO5ybICmDc3xgBDuE6tBxof5AReYA== + +"@holochain/hc-spin-rust-utils-linux-x64-gnu@0.400.0-rc.1": + version "0.400.0-rc.1" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-linux-x64-gnu/-/hc-spin-rust-utils-linux-x64-gnu-0.400.0-rc.1.tgz#3d8d49d499d368890b405596fc81909d96372f2a" + integrity sha512-8G3pVBBBKmN0RatnvoLbIXztVNsNchqDv9zlEJ4piepDxRhELnaFh8Dy0u5NGsqbnjFZt/NIkxqdm5F3KKQTuw== + +"@holochain/hc-spin-rust-utils-win32-x64-msvc@0.400.0-rc.1": + version "0.400.0-rc.1" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-win32-x64-msvc/-/hc-spin-rust-utils-win32-x64-msvc-0.400.0-rc.1.tgz#41604f98c41cb329c5a352bec707f195e15a50fe" + integrity sha512-xEBpXWqWSNyYdsKOGUERUQSDPDNa6cE93PI1y7YL2kukmzEAocX4GOPzi+IYh4iUttcrkVpJpeway6fGQfAEjg== + +"@holochain/hc-spin-rust-utils@0.400.0-rc.1": + version "0.400.0-rc.1" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils/-/hc-spin-rust-utils-0.400.0-rc.1.tgz#550e7c30b49e38423820dca46b337d6569b41ea4" + integrity sha512-AJo18PYnoDS+45eBpGRNGiHa9UBhe92PzsboG2I8+Ajk2giwcT6bFvl4TM3QymA22xcjWfRoBBCCP0P+CCEGig== optionalDependencies: - "@holochain/hc-spin-rust-utils-darwin-arm64" "0.400.0-rc.0" - "@holochain/hc-spin-rust-utils-darwin-x64" "0.400.0-rc.0" - "@holochain/hc-spin-rust-utils-linux-x64-gnu" "0.400.0-rc.0" - "@holochain/hc-spin-rust-utils-win32-x64-msvc" "0.400.0-rc.0" + "@holochain/hc-spin-rust-utils-darwin-arm64" "0.400.0-rc.1" + "@holochain/hc-spin-rust-utils-darwin-x64" "0.400.0-rc.1" + "@holochain/hc-spin-rust-utils-linux-x64-gnu" "0.400.0-rc.1" + "@holochain/hc-spin-rust-utils-win32-x64-msvc" "0.400.0-rc.1" "@holochain/serialization@^0.1.0-beta-rc.3": version "0.1.0-beta-rc.3" @@ -691,35 +691,35 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@lightningrodlabs/we-rust-utils-darwin-arm64@0.400.0-rc.0": - version "0.400.0-rc.0" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-arm64/-/we-rust-utils-darwin-arm64-0.400.0-rc.0.tgz#8a159c4d9893dab9e9c7dd7605e2252c46d1e52f" - integrity sha512-ZXCIqllu1poOA4LDgjV3q4aNsC+QkrzrkNWXeaPQlXLyG7w6LnBRTTcyDpIa4+jOA0r3AYigahGY3Itm+JLdKA== - -"@lightningrodlabs/we-rust-utils-darwin-x64@0.400.0-rc.0": - version "0.400.0-rc.0" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-x64/-/we-rust-utils-darwin-x64-0.400.0-rc.0.tgz#15492a985ae0615c23c7a49087e64feb725f8511" - integrity sha512-FQWoHKKi9mmzyO9bB4rh7q6yhnPvxS5H2Gf3tdlVG4a0YKMmZ8a/t32dYvminh7DzokwcsmEbxE0x13K7SL4iA== - -"@lightningrodlabs/we-rust-utils-linux-x64-gnu@0.400.0-rc.0": - version "0.400.0-rc.0" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-linux-x64-gnu/-/we-rust-utils-linux-x64-gnu-0.400.0-rc.0.tgz#f7736a8c522590db3395f8e504f541f068e41c44" - integrity sha512-BJ0iBqxIM6lmbz1MMQ5gqBXXkarMpIrjxEeMy5IDS+tvAEdP7h+6olVsvumiRBhmB6CLwiBzwu4D0EthgbNxaQ== - -"@lightningrodlabs/we-rust-utils-win32-x64-msvc@0.400.0-rc.0": - version "0.400.0-rc.0" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-win32-x64-msvc/-/we-rust-utils-win32-x64-msvc-0.400.0-rc.0.tgz#4bd15789425305061a8449de6eefea07bb47a192" - integrity sha512-Wc5Jo1C9YG/6EP1TEFDuFHoDkxvQG6X5RtLA120zj35W9Ll0Hwhkxd6wBknCYZQNjKhsuqKwTgKM5bpC97tc7w== - -"@lightningrodlabs/we-rust-utils@0.400.0-rc.0": - version "0.400.0-rc.0" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils/-/we-rust-utils-0.400.0-rc.0.tgz#37d848f3de128755893721e4a36c1df481b4258c" - integrity sha512-16ygk4KQqevHCsg9U2UFY6Qq+xY6fslNTJLNyUNevw8gYJhf5S2M/6SdkbCuYsj+I9a6uDnWv6vwV1EoVVVqIw== +"@lightningrodlabs/we-rust-utils-darwin-arm64@0.400.0-rc.1": + version "0.400.0-rc.1" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-arm64/-/we-rust-utils-darwin-arm64-0.400.0-rc.1.tgz#b43ee7dd47dfe7696cab9fd5bda7adf07948c297" + integrity sha512-ZrvfCdorPV+F1X+hdEO/ZdU1dPrHkS3LMbZc31lqMSNvas6+ndmnrWJ62L67RcI+Yh/DNKhYV6i7Ou4Si5p6HA== + +"@lightningrodlabs/we-rust-utils-darwin-x64@0.400.0-rc.1": + version "0.400.0-rc.1" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-x64/-/we-rust-utils-darwin-x64-0.400.0-rc.1.tgz#5ed96082fac2d04be8211c3c8b14d31276b3a5b9" + integrity sha512-lzyBjEeFxrYy8eviVlOg2e1m6nHJCNwnwFtJgg880b/BbMKDPP2hDLm10yIu0SOCdxaLXJRt4nKE16oiQm5hwA== + +"@lightningrodlabs/we-rust-utils-linux-x64-gnu@0.400.0-rc.1": + version "0.400.0-rc.1" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-linux-x64-gnu/-/we-rust-utils-linux-x64-gnu-0.400.0-rc.1.tgz#84388e6a74658dc99766ff1f5478e7a4873e8256" + integrity sha512-AsWFWK75e8k40g1aE5UZdsk62la8KVBzL+SQsfiIg4ss5NimwtHNJfzIs1jwUjTg1Blee3e1nt5igVMuOiscyg== + +"@lightningrodlabs/we-rust-utils-win32-x64-msvc@0.400.0-rc.1": + version "0.400.0-rc.1" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-win32-x64-msvc/-/we-rust-utils-win32-x64-msvc-0.400.0-rc.1.tgz#a4f5abe189ed1228810cc15197637238b434c9e6" + integrity sha512-UvBhvLVLiDwojgh8knJ8GOoRAJTz0D6aWfmoAQ0tC9cU90WMcN+8ZMC/nLqwuqqpxQEJ55Z34+Hfm6r7LKh0nQ== + +"@lightningrodlabs/we-rust-utils@0.400.0-rc.1": + version "0.400.0-rc.1" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils/-/we-rust-utils-0.400.0-rc.1.tgz#24bbef3e372ac1bfbe1b802ca55454458462f918" + integrity sha512-W0/gLf5Eg9tePOPRMpjw4sKHEcq8P39ucOlMQrDawPRD0rhdAXr5OAGMNMlvT4fAIOgcwyEyoAwDRu/vdTOqkg== optionalDependencies: - "@lightningrodlabs/we-rust-utils-darwin-arm64" "0.400.0-rc.0" - "@lightningrodlabs/we-rust-utils-darwin-x64" "0.400.0-rc.0" - "@lightningrodlabs/we-rust-utils-linux-x64-gnu" "0.400.0-rc.0" - "@lightningrodlabs/we-rust-utils-win32-x64-msvc" "0.400.0-rc.0" + "@lightningrodlabs/we-rust-utils-darwin-arm64" "0.400.0-rc.1" + "@lightningrodlabs/we-rust-utils-darwin-x64" "0.400.0-rc.1" + "@lightningrodlabs/we-rust-utils-linux-x64-gnu" "0.400.0-rc.1" + "@lightningrodlabs/we-rust-utils-win32-x64-msvc" "0.400.0-rc.1" "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" From c9d9b983cbab8effa149592ae0616f86249b385a Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 12 Dec 2024 13:10:40 +0100 Subject: [PATCH 03/16] add cli options --- README.md | 26 ++++++++++ package.json | 3 +- src/main/cli.ts | 98 ++++++++++++++++++++++++++++++++++++ src/main/filesystem.ts | 4 +- src/main/holochainManager.ts | 26 ++++------ src/main/index.ts | 65 +++++++++++++++++++++--- yarn.lock | 5 ++ 7 files changed, 201 insertions(+), 26 deletions(-) create mode 100644 src/main/cli.ts diff --git a/README.md b/README.md index 0aacece..f2260e6 100644 --- a/README.md +++ b/README.md @@ -100,3 +100,29 @@ If you want to code sign your app with an EV certificate, you can follow [this g Access to things like camera and microphone on macOS require special permissions to be set in the .plist file. For this, uncomment the corresponding permissions in `./templates/electron-builder-template.yml` as needed. +## Run your App from the command line + +If you want to customize some runtime parameters you can run your app via the terminal and pass additional options: + +``` +Options: + -V, --version output the version number + -p, --profile Runs Holochain Kangaroo Electron (Test) with a custom profile with its own dedicated data store. + -n, --network-seed If this is the first time running kangaroo with the given profile, this installs the happ with the + provided network seed. + --holochain-path Runs Holochain Kangaroo Electron (Test) with the holochain binary at the provided path. Use with caution + since this may potentially corrupt your databases if the binary you use is not compatible with existing + databases. + --lair-path Runs the Holochain Kangaroo Electron (Test) with the lair binary at the provided path. Use with caution + since this may potentially corrupt your databases if the binary you use is not compatible with existing + databases. + --holochain-rust-log RUST_LOG value to pass to the holochain binary + --holochain-wasm-log WASM_LOG value to pass to the holochain binary + --lair-rust-log RUST_LOG value to pass to the lair keystore binary + -b, --bootstrap-url URL of the bootstrap server to use (not persisted across restarts). + -s, --signaling-url URL of the signaling server to use (not persisted across restarts). + --ice-urls Comma separated string of ICE server URLs to use. Is ignored if an external holochain binary is being used + (not persisted across restarts). + --print-holochain-logs Print holochain logs directly to the terminal (they will be still written to the logfile as well) + -h, --help display help for command +``` diff --git a/package.json b/package.json index d1ddb6e..e444c31 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "org.holochain.kangaroo-electron", + "name": "org.holochain.kangaroo-electron.test.local", "version": "0.1.0", "license": "CAL-1.0", "main": "./out/main/index.js", @@ -29,6 +29,7 @@ "@msgpack/msgpack": "^2.8.0", "adm-zip": "0.5.14", "bufferutil": "4.0.8", + "commander": "12.1.0", "electron-context-menu": "3.6.1", "get-port": "7.0.0", "nanoid": "5.0.4", diff --git a/src/main/cli.ts b/src/main/cli.ts new file mode 100644 index 0000000..42bc53d --- /dev/null +++ b/src/main/cli.ts @@ -0,0 +1,98 @@ +import { KANGAROO_CONFIG } from './const'; +import { breakingAppVersion } from './filesystem'; +import { app } from 'electron'; + +export interface CliOpts { + profile?: string; + networkSeed?: string | undefined; + holochainPath?: string | undefined; + lairPath?: string | undefined; + holochainRustLog?: string | undefined; + holochainWasmLog?: string | undefined; + lairRustLog?: string | undefined; + bootstrapUrl?: string; + signalingUrl?: string; + iceUrls?: string; + printHolochainLogs?: boolean; +} + +export interface RunOptions { + profile: string | undefined; + networkSeed: string; + bootstrapUrl: string | undefined; + signalingUrl: string | undefined; + iceUrls: string[] | undefined; + customHolochainBinary: string | undefined; + customLairBinary: string | undefined; + holochainRustLog: string | undefined; + holochainWasmLog: string | undefined; + lairRustLog: string | undefined; + printHolochainLogs: boolean; +} + +export function validateArgs(args: CliOpts): RunOptions { + // validate --profile argument + const allowedProfilePattern = /^[0-9a-zA-Z-]+$/; + if (args.profile && !allowedProfilePattern.test(args.profile)) { + throw new Error( + `The --profile argument may only contain digits (0-9), letters (a-z,A-Z) and dashes (-) but got '${args.profile}'`, + ); + } + if (args.networkSeed && typeof args.networkSeed !== 'string') { + throw new Error('The --network-seed argument must be of type string.'); + } + if (args.bootstrapUrl && typeof args.bootstrapUrl !== 'string') { + throw new Error('The --bootstrap-url argument must be of type string.'); + } + if (args.signalingUrl && typeof args.signalingUrl !== 'string') { + throw new Error('The --signaling-url argument must be of type string.'); + } + console.log("ICE URLS arg: ", args.iceUrls); + console.log("ICE URLS arg type: ", typeof args.iceUrls); + if (args.iceUrls && typeof args.iceUrls !== 'string') { + throw new Error('The --ice-urls argument must be of type string.'); + } + if (args.holochainPath && typeof args.holochainPath !== 'string') { + throw new Error('The --holochain-path argument must be of type string.'); + } + if (args.lairPath && typeof args.lairPath !== 'string') { + throw new Error('The --lair-path argument must be of type string.'); + } + if (args.holochainRustLog && typeof args.holochainRustLog !== 'string') { + throw new Error('The --holochain-rust-log argument must be of type string.'); + } + if (args.holochainWasmLog && typeof args.holochainWasmLog !== 'string') { + throw new Error('The --holochain-wasm-log argument must be of type string.'); + } + if (args.lairRustLog && typeof args.lairRustLog !== 'string') { + throw new Error('The --lair-rust-log argument must be of type string.'); + } + + const profile = args.profile ? args.profile : undefined; + // If provided take the one provided, otherwise check whether it's applet dev mode + const networkSeed = args.networkSeed + ? args.networkSeed + : defaultAppNetworkSeed(); + + return { + profile, + networkSeed, + bootstrapUrl: args.bootstrapUrl, + signalingUrl: args.signalingUrl, + iceUrls: args.iceUrls ? args.iceUrls.split(',') : undefined, + customHolochainBinary: args.holochainPath ? args.holochainPath : undefined, + customLairBinary: args.lairPath ? args.lairPath : undefined, + holochainRustLog: args.holochainRustLog ? args.holochainRustLog : undefined, + holochainWasmLog: args.holochainWasmLog ? args.holochainWasmLog : undefined, + lairRustLog: args.lairRustLog ? args.lairRustLog : undefined, + printHolochainLogs: args.printHolochainLogs ? true : false, + }; +} + +function defaultAppNetworkSeed() { + let networkSeed = `${KANGAROO_CONFIG.productName}-${breakingAppVersion(app)}`; + if (!app.isPackaged) { + networkSeed += "-dev"; + } + return networkSeed; +} \ No newline at end of file diff --git a/src/main/filesystem.ts b/src/main/filesystem.ts index 14a353a..8f3aae1 100644 --- a/src/main/filesystem.ts +++ b/src/main/filesystem.ts @@ -54,7 +54,9 @@ export class KangarooFileSystem { createDirIfNotExists(configDir); createDirIfNotExists(dataDir); - console.log('Got logsDir, configDir and dataDir: ', logsDir, configDir, dataDir); + console.log('dataDir: ', dataDir); + console.log('logsDir:', logsDir); + console.log('configDir: ', configDir); const kangarooFs = new KangarooFileSystem(dataDir, configDir, logsDir); diff --git a/src/main/holochainManager.ts b/src/main/holochainManager.ts index 53939fa..88ab0c3 100644 --- a/src/main/holochainManager.ts +++ b/src/main/holochainManager.ts @@ -9,11 +9,11 @@ import { AppAuthenticationToken, AppInfo, } from "@holochain/client"; -import { breakingAppVersion, KangarooFileSystem } from "./filesystem"; -import { HAPP_APP_ID, HAPP_PATH, KANGAROO_CONFIG } from "./const"; -import { app } from "electron"; +import { KangarooFileSystem } from "./filesystem"; +import { HAPP_APP_ID, HAPP_PATH } from "./const"; -const rustUtils = require("@lightningrodlabs/we-rust-utils"); +import { defaultConductorConfig } from "@lightningrodlabs/we-rust-utils"; +import { app } from "electron"; export type AdminPort = number; export type AppPort = number; @@ -60,6 +60,7 @@ export class HolochainManager { lairUrl: string, bootstrapUrl: string, signalingUrl: string, + iceUrls?: string[], rustLog?: string, wasmLog?: string ): Promise { @@ -67,15 +68,15 @@ export class HolochainManager { ? parseInt(process.env.ADMIN_PORT, 10) : await getPort(); - const conductorConfig = rustUtils.defaultConductorConfig( + const conductorConfig = defaultConductorConfig( adminPort, rootDir, lairUrl, bootstrapUrl, signalingUrl, - "*", + "moss-admin-main", false, - undefined, + iceUrls, undefined, ); @@ -150,7 +151,7 @@ export class HolochainManager { } else { const attachAppInterfaceResponse = await adminWebsocket.attachAppInterface({ - allowed_origins: "*", + allowed_origins: app.isPackaged ? 'webhapp://webhappwindow' : '*', }); console.log( "Attached app interface port: ", @@ -175,7 +176,7 @@ export class HolochainManager { }); } - async installHappIfNecessary(networkSeed?: string) { + async installHappIfNecessary(networkSeed) { const installedApps = await this.adminWebsocket.listApps({}); if ( installedApps @@ -183,18 +184,11 @@ export class HolochainManager { .includes(HAPP_APP_ID) ) return; - if (!networkSeed) { - networkSeed = `${KANGAROO_CONFIG.productName}-${breakingAppVersion(app)}`; - if (!app.isPackaged) { - networkSeed += "-dev"; - } - } console.log(`Installing happ...`); const pubKey = await this.adminWebsocket.generateAgentPubKey(); const appInfo = await this.adminWebsocket.installApp({ agent_key: pubKey, installed_app_id: HAPP_APP_ID, - membrane_proofs: {}, path: HAPP_PATH, network_seed: networkSeed, }); diff --git a/src/main/index.ts b/src/main/index.ts index de59e9e..d3a04b9 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -20,6 +20,7 @@ import { getNonceExpiration, randomNonce, } from "@holochain/client"; +import { Command } from 'commander'; import { KangarooFileSystem } from "./filesystem"; import { KangarooEmitter } from "./eventEmitter"; import { setupLogs } from "./logs"; @@ -36,9 +37,56 @@ import { } from "./const"; import { initializeLairKeystore, launchLairKeystore } from "./lairKeystore"; import { kangarooMenu } from "./menu"; +import { validateArgs } from "./cli"; // Read CLI options +const kangarooCli = new Command(); + +kangarooCli + .name(KANGAROO_CONFIG.productName) + .description(`Run ${KANGAROO_CONFIG.productName} via the command line`) + .version(KANGAROO_CONFIG.version) + .option( + '-p, --profile ', + `Runs ${KANGAROO_CONFIG.productName} with a custom profile with its own dedicated data store.`, + ) + .option( + '-n, --network-seed ', + 'If this is the first time running kangaroo with the given profile, this installs the happ with the provided network seed.', + ) + .option( + '--holochain-path ', + `Runs ${KANGAROO_CONFIG.productName} with the holochain binary at the provided path. Use with caution since this may potentially corrupt your databases if the binary you use is not compatible with existing databases.`, + ) + .option( + '--lair-path ', + `Runs the ${KANGAROO_CONFIG.productName} with the lair binary at the provided path. Use with caution since this may potentially corrupt your databases if the binary you use is not compatible with existing databases.`, + ) + .option('--holochain-rust-log ', 'RUST_LOG value to pass to the holochain binary') + .option('--holochain-wasm-log ', 'WASM_LOG value to pass to the holochain binary') + .option('--lair-rust-log ', 'RUST_LOG value to pass to the lair keystore binary') + .option( + '-b, --bootstrap-url ', + 'URL of the bootstrap server to use (not persisted across restarts).', + ) + .option( + '-s, --signaling-url ', + 'URL of the signaling server to use (not persisted across restarts).', + ) + .option( + '--ice-urls ', + 'Comma separated string of ICE server URLs to use. Is ignored if an external holochain binary is being used (not persisted across restarts).', + ) + .option( + '--print-holochain-logs', + 'Print holochain logs directly to the terminal (they will be still written to the logfile as well)', + ); + +kangarooCli.parse(); + +const RUN_OPTIONS = validateArgs(kangarooCli.opts()); + // Read and validate the config file to check that the content does not contain // default values @@ -63,11 +111,11 @@ contextMenu({ ], }); -const KANGAROO_FILESYSTEM = KangarooFileSystem.connect(app); +const KANGAROO_FILESYSTEM = KangarooFileSystem.connect(app, RUN_OPTIONS.profile); const KANGAROO_EMITTER = new KangarooEmitter(); -setupLogs(KANGAROO_EMITTER, KANGAROO_FILESYSTEM, true); +setupLogs(KANGAROO_EMITTER, KANGAROO_FILESYSTEM, RUN_OPTIONS.printHolochainLogs); protocol.registerSchemesAsPrivileged([ { @@ -138,7 +186,7 @@ app.whenReady().then(async () => { console.log("initializing lair keystore...") await initializeLairKeystore( - LAIR_BINARY, + RUN_OPTIONS.customLairBinary ? RUN_OPTIONS.customLairBinary : LAIR_BINARY, KANGAROO_FILESYSTEM.keystoreDir, KANGAROO_EMITTER, LAIR_PASSWORD @@ -154,7 +202,7 @@ app.whenReady().then(async () => { let lairUrl; [LAIR_HANDLE, lairUrl] = await launchLairKeystore( - LAIR_BINARY, + RUN_OPTIONS.customLairBinary ? RUN_OPTIONS.customLairBinary : LAIR_BINARY, KANGAROO_FILESYSTEM.keystoreDir, KANGAROO_EMITTER, LAIR_PASSWORD @@ -171,18 +219,19 @@ app.whenReady().then(async () => { HOLOCHAIN_MANAGER = await HolochainManager.launch( KANGAROO_EMITTER, KANGAROO_FILESYSTEM, - HOLOCHAIN_BINARY, + RUN_OPTIONS.customHolochainBinary ? RUN_OPTIONS.customHolochainBinary : HOLOCHAIN_BINARY, LAIR_PASSWORD, KANGAROO_CONFIG.bins.holochain.version, KANGAROO_FILESYSTEM.conductorDir, KANGAROO_FILESYSTEM.conductorConfigPath, lairUrl, - DEFAULT_BOOTSTRAP_SERVER, - DEFAULT_SIGNALING_SERVER + RUN_OPTIONS.bootstrapUrl ? RUN_OPTIONS.bootstrapUrl : DEFAULT_BOOTSTRAP_SERVER, + RUN_OPTIONS.signalingUrl ? RUN_OPTIONS.signalingUrl : DEFAULT_SIGNALING_SERVER, + RUN_OPTIONS.iceUrls ? RUN_OPTIONS.iceUrls : undefined, ); // Install happ if necessary - await HOLOCHAIN_MANAGER.installHappIfNecessary(); + await HOLOCHAIN_MANAGER.installHappIfNecessary(RUN_OPTIONS.networkSeed); console.log("Happ installed."); diff --git a/yarn.lock b/yarn.lock index 53385a1..6384b72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1889,6 +1889,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" From 96d8a5895b220e70206c0fd8bb9b9a74f56d2716 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 12 Dec 2024 13:14:19 +0100 Subject: [PATCH 04/16] remove modified package.json name --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e444c31..178047e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "org.holochain.kangaroo-electron.test.local", + "name": "org.holochain.kangaroo-electron", "version": "0.1.0", "license": "CAL-1.0", "main": "./out/main/index.js", From 395ec30b3f932a84aeb946b9dccaeba8e5fa6a87 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 12 Dec 2024 13:21:55 +0100 Subject: [PATCH 05/16] fix release workflow --- .github/workflows/release.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index cb833c9..e764964 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v2 - name: Setup for macOS code signing - if: matrix.platform == 'macos-12' || matrix.platform == 'macos-latest' + if: (matrix.platform == 'macos-12' || matrix.platform == 'macos-latest') && steps.shouldMacOSCodeSign.outputs.MACOS_CODE_SIGNING == 'true' uses: matthme/import-codesign-certs@5565bb656f60c98c8fc515f3444dd8db73545dc2 with: p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} @@ -31,13 +31,6 @@ jobs: with: node-version: 20 - - name: Retrieve version - run: | - echo "Retrieved App version: $(node -p -e "require('./package.json').version")" - echo "APP_VERSION=$(node -p -e "require('./package.json').version")" >> $GITHUB_OUTPUT - id: version - shell: bash - - name: install Rust uses: dtolnay/rust-toolchain@1.75.0 @@ -59,6 +52,13 @@ jobs: curl -f -L --output ./pouch/ziptest.webhapp /~https://github.com/holochain-apps/ziptest/releases/download/ziptest-v0.0.9/ziptest.webhapp node ./scripts/overwrite-with-test-name.js + - name: Retrieve version + run: | + echo "Retrieved App version: $(node -p -e "require('./package.json').version")" + echo "APP_VERSION=$(node -p -e "require('./package.json').version")" >> $GITHUB_OUTPUT + id: version + shell: bash + - name: Retrieve appId run: | echo "APP_ID=$(node ./scripts/read-app-id.js)" >> $GITHUB_OUTPUT From c8a3fe97e62223d8fd07af21cc8fcd017e8c967b Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 17 Dec 2024 15:09:43 +0100 Subject: [PATCH 06/16] switch to URL type for bootstrap and signaling url, address cleanup comments --- src/main/cli.ts | 23 +++++++++++++---------- src/main/holochainManager.ts | 2 +- src/main/index.ts | 4 ++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/cli.ts b/src/main/cli.ts index 42bc53d..4c45aaa 100644 --- a/src/main/cli.ts +++ b/src/main/cli.ts @@ -4,12 +4,12 @@ import { app } from 'electron'; export interface CliOpts { profile?: string; - networkSeed?: string | undefined; - holochainPath?: string | undefined; - lairPath?: string | undefined; - holochainRustLog?: string | undefined; - holochainWasmLog?: string | undefined; - lairRustLog?: string | undefined; + networkSeed?: string; + holochainPath?: string; + lairPath?: string; + holochainRustLog?: string; + holochainWasmLog?: string; + lairRustLog?: string; bootstrapUrl?: string; signalingUrl?: string; iceUrls?: string; @@ -19,8 +19,8 @@ export interface CliOpts { export interface RunOptions { profile: string | undefined; networkSeed: string; - bootstrapUrl: string | undefined; - signalingUrl: string | undefined; + bootstrapUrl: URL | undefined; + signalingUrl: URL | undefined; iceUrls: string[] | undefined; customHolochainBinary: string | undefined; customLairBinary: string | undefined; @@ -74,11 +74,14 @@ export function validateArgs(args: CliOpts): RunOptions { ? args.networkSeed : defaultAppNetworkSeed(); + const bootstrapUrl = args.bootstrapUrl ? new URL(args.bootstrapUrl) : undefined; + const signalingUrl = args.signalingUrl ? new URL(args.signalingUrl) : undefined; + return { profile, networkSeed, - bootstrapUrl: args.bootstrapUrl, - signalingUrl: args.signalingUrl, + bootstrapUrl, + signalingUrl, iceUrls: args.iceUrls ? args.iceUrls.split(',') : undefined, customHolochainBinary: args.holochainPath ? args.holochainPath : undefined, customLairBinary: args.lairPath ? args.lairPath : undefined, diff --git a/src/main/holochainManager.ts b/src/main/holochainManager.ts index 88ab0c3..98ccbe0 100644 --- a/src/main/holochainManager.ts +++ b/src/main/holochainManager.ts @@ -138,7 +138,7 @@ export class HolochainManager { const adminWebsocket = await AdminWebsocket.connect({ url: new URL(`ws://127.0.0.1:${adminPort}`), wsClientOptions: { - origin: "moss-admin-main", + origin: "*", }, }); console.log("Connected to admin websocket."); diff --git a/src/main/index.ts b/src/main/index.ts index d3a04b9..ce7cc4f 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -225,8 +225,8 @@ app.whenReady().then(async () => { KANGAROO_FILESYSTEM.conductorDir, KANGAROO_FILESYSTEM.conductorConfigPath, lairUrl, - RUN_OPTIONS.bootstrapUrl ? RUN_OPTIONS.bootstrapUrl : DEFAULT_BOOTSTRAP_SERVER, - RUN_OPTIONS.signalingUrl ? RUN_OPTIONS.signalingUrl : DEFAULT_SIGNALING_SERVER, + RUN_OPTIONS.bootstrapUrl ? RUN_OPTIONS.bootstrapUrl.toString() : DEFAULT_BOOTSTRAP_SERVER, + RUN_OPTIONS.signalingUrl ? RUN_OPTIONS.signalingUrl.toString() : DEFAULT_SIGNALING_SERVER, RUN_OPTIONS.iceUrls ? RUN_OPTIONS.iceUrls : undefined, ); From bace6059049a6f98a985047f1487b5ef69219cc7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 17 Dec 2024 15:35:23 +0100 Subject: [PATCH 07/16] add holochain versions note to readme --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0aacece..88c26e7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,12 @@ This repository let's you easily convert your Holochain app into a standalone, e **Note:** Support for non-breaking updates to happ coordinator zomes is currently not built into the kangaroo. -**Holochain Version**: Kangaroo Electron currently uses holochain 0.3.3. +# Holochain Versions + +Depending on which Holochain minor version you want to use you should use the corresponding branch of this repository. + +* Holochain 0.3.x (stable): [main-0.3v branch](/~https://github.com/holochain/kangaroo-electron/tree/main-0.3) +* Holochain 0.4.x: [main branch](/~https://github.com/holochain/kangaroo-electron/tree/main) # Instructions From d44af1e3c26ec4201673817921d4d434ec739b4f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 17 Dec 2024 15:36:22 +0100 Subject: [PATCH 08/16] fix typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 88c26e7..6bf2800 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ This repository let's you easily convert your Holochain app into a standalone, e Depending on which Holochain minor version you want to use you should use the corresponding branch of this repository. -* Holochain 0.3.x (stable): [main-0.3v branch](/~https://github.com/holochain/kangaroo-electron/tree/main-0.3) -* Holochain 0.4.x: [main branch](/~https://github.com/holochain/kangaroo-electron/tree/main) +* Holochain 0.3.x (stable): [main-0.3](/~https://github.com/holochain/kangaroo-electron/tree/main-0.3) +* Holochain 0.4.x: [main](/~https://github.com/holochain/kangaroo-electron/tree/main) # Instructions From 6fbd90d5409fd09f376680a5f7f0b0bd1dfd3d69 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 17 Dec 2024 17:15:01 +0100 Subject: [PATCH 09/16] fix remaining moss reference, rename to holochainPath and lairPath --- src/main/cli.ts | 8 ++++---- src/main/holochainManager.ts | 4 ++-- src/main/index.ts | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/cli.ts b/src/main/cli.ts index 4c45aaa..49c6889 100644 --- a/src/main/cli.ts +++ b/src/main/cli.ts @@ -22,8 +22,8 @@ export interface RunOptions { bootstrapUrl: URL | undefined; signalingUrl: URL | undefined; iceUrls: string[] | undefined; - customHolochainBinary: string | undefined; - customLairBinary: string | undefined; + holochainPath: string | undefined; + lairPath: string | undefined; holochainRustLog: string | undefined; holochainWasmLog: string | undefined; lairRustLog: string | undefined; @@ -83,8 +83,8 @@ export function validateArgs(args: CliOpts): RunOptions { bootstrapUrl, signalingUrl, iceUrls: args.iceUrls ? args.iceUrls.split(',') : undefined, - customHolochainBinary: args.holochainPath ? args.holochainPath : undefined, - customLairBinary: args.lairPath ? args.lairPath : undefined, + holochainPath: args.holochainPath ? args.holochainPath : undefined, + lairPath: args.lairPath ? args.lairPath : undefined, holochainRustLog: args.holochainRustLog ? args.holochainRustLog : undefined, holochainWasmLog: args.holochainWasmLog ? args.holochainWasmLog : undefined, lairRustLog: args.lairRustLog ? args.lairRustLog : undefined, diff --git a/src/main/holochainManager.ts b/src/main/holochainManager.ts index 98ccbe0..fa4be8f 100644 --- a/src/main/holochainManager.ts +++ b/src/main/holochainManager.ts @@ -74,7 +74,7 @@ export class HolochainManager { lairUrl, bootstrapUrl, signalingUrl, - "moss-admin-main", + "kangaroo", false, iceUrls, undefined, @@ -138,7 +138,7 @@ export class HolochainManager { const adminWebsocket = await AdminWebsocket.connect({ url: new URL(`ws://127.0.0.1:${adminPort}`), wsClientOptions: { - origin: "*", + origin: "kangaroo", }, }); console.log("Connected to admin websocket."); diff --git a/src/main/index.ts b/src/main/index.ts index ce7cc4f..9480a5c 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -186,7 +186,7 @@ app.whenReady().then(async () => { console.log("initializing lair keystore...") await initializeLairKeystore( - RUN_OPTIONS.customLairBinary ? RUN_OPTIONS.customLairBinary : LAIR_BINARY, + RUN_OPTIONS.lairPath ? RUN_OPTIONS.lairPath : LAIR_BINARY, KANGAROO_FILESYSTEM.keystoreDir, KANGAROO_EMITTER, LAIR_PASSWORD @@ -202,7 +202,7 @@ app.whenReady().then(async () => { let lairUrl; [LAIR_HANDLE, lairUrl] = await launchLairKeystore( - RUN_OPTIONS.customLairBinary ? RUN_OPTIONS.customLairBinary : LAIR_BINARY, + RUN_OPTIONS.lairPath ? RUN_OPTIONS.lairPath : LAIR_BINARY, KANGAROO_FILESYSTEM.keystoreDir, KANGAROO_EMITTER, LAIR_PASSWORD @@ -219,7 +219,7 @@ app.whenReady().then(async () => { HOLOCHAIN_MANAGER = await HolochainManager.launch( KANGAROO_EMITTER, KANGAROO_FILESYSTEM, - RUN_OPTIONS.customHolochainBinary ? RUN_OPTIONS.customHolochainBinary : HOLOCHAIN_BINARY, + RUN_OPTIONS.holochainPath ? RUN_OPTIONS.holochainPath : HOLOCHAIN_BINARY, LAIR_PASSWORD, KANGAROO_CONFIG.bins.holochain.version, KANGAROO_FILESYSTEM.conductorDir, From 4c23c9007b3c5701b38b87909644033ad46a1c94 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 17 Dec 2024 17:27:32 +0100 Subject: [PATCH 10/16] add prettierrc.yaml and reformat all files --- .github/workflows/release.yaml | 1 - .prettierrc.yaml | 3 + README.md | 19 +-- electron.vite.config.ts | 16 +-- kangaroo.config.ts | 40 +++--- package.json | 2 +- scripts/create-icons.js | 33 ++--- scripts/extend-deb-postinst.mjs | 2 +- scripts/fetch-binaries.js | 13 +- scripts/overwrite-with-test-name.js | 14 +-- scripts/read-app-id.js | 2 +- scripts/read-macos-code-signing.js | 2 +- scripts/read-windows-code-signing.js | 2 +- scripts/unpack-pouch.js | 28 ++--- scripts/write-builder-config.js | 39 ++---- src/main/cli.ts | 14 +-- src/main/const.ts | 21 ++-- src/main/defineConfig.ts | 2 +- src/main/eventEmitter.ts | 2 +- src/main/filesystem.ts | 6 +- src/main/holochainManager.ts | 105 +++++++--------- src/main/index.ts | 100 ++++++--------- src/main/lairKeystore.ts | 4 +- src/main/logs.ts | 19 +-- src/main/types.ts | 61 +++++---- src/main/windows.ts | 158 ++++++++++-------------- src/preload/happ.ts | 2 +- src/renderer/indexNotFound.html | 5 +- src/renderer/indexNotFound2.html | 2 +- src/renderer/splashscreen.html | 35 +++--- templates/electron-builder-template.yml | 8 +- 31 files changed, 336 insertions(+), 424 deletions(-) create mode 100644 .prettierrc.yaml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index e764964..b3c7a9e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -141,7 +141,6 @@ jobs: gh release upload "v${{ steps.version.outputs.APP_VERSION }}" "latest-linux.yml" --clobber gh release upload "v${{ steps.version.outputs.APP_VERSION }}" "dist/${{ steps.appId.outputs.APP_ID }}_${{ steps.version.outputs.APP_VERSION }}_amd64.deb" --clobber - # Windows #--------------------------------------------------------------------------------------- - name: build, sign and upload the app (Windows) diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 0000000..c2fd2a8 --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,3 @@ +singleQuote: true +semi: true +printWidth: 100 diff --git a/README.md b/README.md index b0289fd..9567628 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,15 @@ This repository let's you easily convert your Holochain app into a standalone, e Depending on which Holochain minor version you want to use you should use the corresponding branch of this repository. -* Holochain 0.3.x (stable): [main-0.3](/~https://github.com/holochain/kangaroo-electron/tree/main-0.3) -* Holochain 0.4.x: [main](/~https://github.com/holochain/kangaroo-electron/tree/main) +- Holochain 0.3.x (stable): [main-0.3](/~https://github.com/holochain/kangaroo-electron/tree/main-0.3) +- Holochain 0.4.x: [main](/~https://github.com/holochain/kangaroo-electron/tree/main) # Instructions ## Setup and Testing Locally 1. Either use this repository as a template (by clicking on the green "Use this template" button) or fork it. -Using it as a template allows you to start with a clean git history and the contributors of this repository won't show up as contributors to your new repository. **Forking has the advantage of being able to relatively easily pull in updates from this parent repository at a later point in time.** If you fork it, it may be smart to work off a different branch than the main branch in your forked repository in order to be able to keep the main branch in sync with this parent repository and selectively merge into your working branch as needed. + Using it as a template allows you to start with a clean git history and the contributors of this repository won't show up as contributors to your new repository. **Forking has the advantage of being able to relatively easily pull in updates from this parent repository at a later point in time.** If you fork it, it may be smart to work off a different branch than the main branch in your forked repository in order to be able to keep the main branch in sync with this parent repository and selectively merge into your working branch as needed. 2. In your local copy of the repository, run @@ -29,9 +29,10 @@ yarn setup 3. In the `kangaroo.config.ts` file, replace the `appId` and `productName` fields with names appropriate for your own app. 4. Paste the `.webhapp` file of your holochain app into the `pouch` folder. -**Note**: The kangaroo expects a 1024x1024 pixel `icon.png` at the root level of your webhapp's UI assets. + **Note**: The kangaroo expects a 1024x1024 pixel `icon.png` at the root level of your webhapp's UI assets. 5. To test it, run + ``` yarn dev ``` @@ -39,6 +40,7 @@ yarn dev ## Build the Distributable ### Build locally + To build the app locally for your platform, run the build command for your respecive platform: ``` @@ -50,6 +52,7 @@ yarn build:mac # or yarn build:windows ``` + ### Build on CI for all platforms The general workflow goes as follows: @@ -59,6 +62,7 @@ The general workflow goes as follows: 2. Merge the main branch into the release branch and push it to github to trigger the release workflow. If you do this for the first time you will need to create the `release` branch first: + ``` git checkout -b release git merge main @@ -66,13 +70,13 @@ git push --set-upstream origin release ``` For subsequent releases after that you can run + ``` git checkout release git merge main git push ``` - ## Code Signing ### macOS @@ -81,30 +85,29 @@ To use code signing on macOS for your release in CI you will have to 1. Set the `macOSCodeSigning` field to `true` in `kangaroo.config.ts` 2. Add the following secrets to your github repository with the appropriate values: + - `APPLE_DEV_IDENTITY` - `APPLE_ID_EMAIL` - `APPLE_ID_PASSWORD` - `APPLE_TEAM_ID` - ### Windows If you want to code sign your app with an EV certificate, you can follow [this guide](https://melatonin.dev/blog/how-to-code-sign-windows-installers-with-an-ev-cert-on-github-actions/) to get your EV certificate hosted on Azure Key Vault and then 1. Set the `windowsEVCodeSigning` field to `true` in `kangaroo.config.ts` 2. Add all the necessary secrets to the repository: + - `AZURE_KEY_VAULT_URI` - `AZURE_CERT_NAME` - `AZURE_TENANT_ID` - `AZURE_CLIENT_ID` - `AZURE_CLIENT_SECRET` - ## Permissions on macOS Access to things like camera and microphone on macOS require special permissions to be set in the .plist file. For this, uncomment the corresponding permissions in `./templates/electron-builder-template.yml` as needed. - ## Run your App from the command line If you want to customize some runtime parameters you can run your app via the terminal and pass additional options: diff --git a/electron.vite.config.ts b/electron.vite.config.ts index 1e4d794..65c3f98 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -1,16 +1,16 @@ -import { defineConfig, externalizeDepsPlugin } from "electron-vite"; -import { resolve } from "path"; +import { defineConfig, externalizeDepsPlugin } from 'electron-vite'; +import { resolve } from 'path'; export default defineConfig({ main: { - plugins: [externalizeDepsPlugin({ exclude: ["@holochain/client", "get-port", "nanoid"] })], + plugins: [externalizeDepsPlugin({ exclude: ['@holochain/client', 'get-port', 'nanoid'] })], }, preload: { build: { rollupOptions: { input: { - happ: resolve(__dirname, "src/preload/happ.ts"), - splashscreen: resolve(__dirname, "src/preload/splashscreen.ts"), + happ: resolve(__dirname, 'src/preload/happ.ts'), + splashscreen: resolve(__dirname, 'src/preload/splashscreen.ts'), }, }, }, @@ -19,9 +19,9 @@ export default defineConfig({ build: { rollupOptions: { input: { - indexNotFound: resolve(__dirname, "src/renderer/indexNotFound.html"), - indexNotFound2: resolve(__dirname, "src/renderer/indexNotFound2.html"), - splashscreen: resolve(__dirname, "src/renderer/splashscreen.html"), + indexNotFound: resolve(__dirname, 'src/renderer/indexNotFound.html'), + indexNotFound2: resolve(__dirname, 'src/renderer/indexNotFound2.html'), + splashscreen: resolve(__dirname, 'src/renderer/splashscreen.html'), }, }, }, diff --git a/kangaroo.config.ts b/kangaroo.config.ts index b0dcaef..34bf44d 100644 --- a/kangaroo.config.ts +++ b/kangaroo.config.ts @@ -1,37 +1,33 @@ -import { defineConfig } from "./src/main/defineConfig"; +import { defineConfig } from './src/main/defineConfig'; export default defineConfig({ - appId: "org.holochain.kangaroo-electron", - productName: "Holochain Kangaroo Electron", - version: "0.1.0", + appId: 'org.holochain.kangaroo-electron', + productName: 'Holochain Kangaroo Electron', + version: '0.1.0', macOSCodeSigning: false, windowsEVCodeSigning: false, fallbackToIndexHtml: true, bins: { holochain: { - version: "0.4.0-rc.2", + version: '0.4.0-rc.2', sha256: { - "x86_64-unknown-linux-gnu": - "7110f9b0c9c2b4bbc974543df1b633299c7fa8d3d16f3cde4dc894ac64c0670f", - "x86_64-pc-windows-msvc.exe": - "959fca4b575c6791196fcd1fb9c6c7a92359191dbd60e95b7800c6e79bb21687", - "x86_64-apple-darwin": - "a62d1b6413f2791ec4df87338d794a7ba29a0890f1a2ceb1ed9eeddb0efc94a7", - "aarch64-apple-darwin": - "f25bee4cb2615b1970a8ef89c82dcfb867682a3502962343d4842571aafb9bc3", + 'x86_64-unknown-linux-gnu': + '7110f9b0c9c2b4bbc974543df1b633299c7fa8d3d16f3cde4dc894ac64c0670f', + 'x86_64-pc-windows-msvc.exe': + '959fca4b575c6791196fcd1fb9c6c7a92359191dbd60e95b7800c6e79bb21687', + 'x86_64-apple-darwin': 'a62d1b6413f2791ec4df87338d794a7ba29a0890f1a2ceb1ed9eeddb0efc94a7', + 'aarch64-apple-darwin': 'f25bee4cb2615b1970a8ef89c82dcfb867682a3502962343d4842571aafb9bc3', }, }, lair: { - version: "0.5.3", + version: '0.5.3', sha256: { - "x86_64-unknown-linux-gnu": - "96a28b9b37c73ef46d8b5c56b9d799d558fd2fe77b41c577e2bcb37685a46396", - "x86_64-pc-windows-msvc.exe": - "68b6453a19921072aac04dae52a4e94e725e7482005d2f54f907aec680e078de", - "x86_64-apple-darwin": - "a53bfb8e501431870b99243cbac24f6103d67f8be094930f174829bb249f34c4", - "aarch64-apple-darwin": - "6b15d977408847ac977c2e060c7aab84a69e6e90c79390098dd40a6b75256e50", + 'x86_64-unknown-linux-gnu': + '96a28b9b37c73ef46d8b5c56b9d799d558fd2fe77b41c577e2bcb37685a46396', + 'x86_64-pc-windows-msvc.exe': + '68b6453a19921072aac04dae52a4e94e725e7482005d2f54f907aec680e078de', + 'x86_64-apple-darwin': 'a53bfb8e501431870b99243cbac24f6103d67f8be094930f174829bb249f34c4', + 'aarch64-apple-darwin': '6b15d977408847ac977c2e060c7aab84a69e6e90c79390098dd40a6b75256e50', }, }, }, diff --git a/package.json b/package.json index 178047e..ab58fd2 100644 --- a/package.json +++ b/package.json @@ -58,4 +58,4 @@ "typescript": "^5.2.2", "vite": "^4.4.9" } -} \ No newline at end of file +} diff --git a/scripts/create-icons.js b/scripts/create-icons.js index f26c9eb..3680ae7 100644 --- a/scripts/create-icons.js +++ b/scripts/create-icons.js @@ -1,22 +1,21 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -const fs = require("fs"); -const path = require("path"); -const png2icons = require("png2icons"); +const fs = require('fs'); +const path = require('path'); +const png2icons = require('png2icons'); generateIcons(); function generateIcons() { - const uiDir = path.join("resources", "ui"); + const uiDir = path.join('resources', 'ui'); const buildDir = 'build'; - const pngPath = path.join(uiDir, "icon.png"); - const icoPath = path.join(uiDir, "icon.ico"); - const icnsPath = path.join(uiDir, "icon.icns"); + const pngPath = path.join(uiDir, 'icon.png'); + const icoPath = path.join(uiDir, 'icon.ico'); + const icnsPath = path.join(uiDir, 'icon.icns'); - - const pngOutPath = path.join(buildDir, "icon.png"); - const icoOutPath = path.join(buildDir, "icon.ico"); - const icnsOutPath = path.join(buildDir, "icon.icns"); + const pngOutPath = path.join(buildDir, 'icon.png'); + const icoOutPath = path.join(buildDir, 'icon.ico'); + const icnsOutPath = path.join(buildDir, 'icon.icns'); if (!fs.existsSync(pngPath)) { console.warn("WARNING: No icon.png found in your webhapp's UI assets."); @@ -28,19 +27,13 @@ function generateIcons() { const pngBuffer = fs.readFileSync(pngPath); if (!fs.existsSync(icoPath)) { - console.log("Generating icon.ico"); - const icoIcon = png2icons.createICO( - pngBuffer, - png2icons.BICUBIC2, - 0, - false, - true - ); + console.log('Generating icon.ico'); + const icoIcon = png2icons.createICO(pngBuffer, png2icons.BICUBIC2, 0, false, true); fs.writeFileSync(icoOutPath, icoIcon); } if (!fs.existsSync(icnsPath)) { - console.log("Generating icon.icns"); + console.log('Generating icon.icns'); const icnsIcon = png2icons.createICNS(pngBuffer, png2icons.BILINEAR, 0); fs.writeFileSync(icnsOutPath, icnsIcon); } diff --git a/scripts/extend-deb-postinst.mjs b/scripts/extend-deb-postinst.mjs index 673baf6..e37ad98 100644 --- a/scripts/extend-deb-postinst.mjs +++ b/scripts/extend-deb-postinst.mjs @@ -73,7 +73,7 @@ profile ${appId} \\"/opt/${productName}/${appId}\\" flags=(unconfined) { fi # SUID chrome-sandbox for Electron 5+ -`, +` ); fs.writeFileSync(posinstPath, postinstScriptModified); diff --git a/scripts/fetch-binaries.js b/scripts/fetch-binaries.js index 1c67a58..efb7730 100644 --- a/scripts/fetch-binaries.js +++ b/scripts/fetch-binaries.js @@ -36,12 +36,11 @@ switch (process.platform) { throw new Error(`Got unexpected OS platform: ${process.platform}`); } -const binariesAppendix = kangarooConfig.appId.slice(0,10).replace(' ', '-'); +const binariesAppendix = kangarooConfig.appId.slice(0, 10).replace(' ', '-'); - -const holochainBinaryFilename = `holochain-v${kangarooConfig.bins.holochain.version}-${binariesAppendix}${ - process.platform === 'win32' ? '.exe' : '' -}`; +const holochainBinaryFilename = `holochain-v${ + kangarooConfig.bins.holochain.version +}-${binariesAppendix}${process.platform === 'win32' ? '.exe' : ''}`; const lairBinaryFilename = `lair-keystore-v${kangarooConfig.bins.lair.version}-${binariesAppendix}${ process.platform === 'win32' ? '.exe' : '' @@ -62,7 +61,7 @@ function downloadFile(url, targetPath, expectedSha256Hex, chmod = false) { const sha256Hex = hasher.digest('hex'); if (sha256Hex !== expectedSha256Hex) throw new Error( - `sha256 does not match the expected sha256. Got ${sha256Hex} but expected ${expectedSha256Hex}`, + `sha256 does not match the expected sha256. Got ${sha256Hex} but expected ${expectedSha256Hex}` ); console.log('Download successful. sha256 of file (hex): ', sha256Hex); @@ -82,7 +81,7 @@ function downloadHolochainBinary() { holochainBinaryUrl, destinationPath, kangarooConfig.bins.holochain.sha256[targetEnding], - true, + true ); } diff --git a/scripts/overwrite-with-test-name.js b/scripts/overwrite-with-test-name.js index 390eb5c..0313d0d 100644 --- a/scripts/overwrite-with-test-name.js +++ b/scripts/overwrite-with-test-name.js @@ -4,18 +4,18 @@ * releases in the official kangaroo repo */ -const path = require("path"); -const fs = require("fs"); +const path = require('path'); +const fs = require('fs'); -let kangarooConfigString = fs.readFileSync("kangaroo.config.ts", "utf-8"); +let kangarooConfigString = fs.readFileSync('kangaroo.config.ts', 'utf-8'); kangarooConfigString = kangarooConfigString.replace( - "org.holochain.kangaroo-electron", - "org.holochain.kangaroo-electron-test" + 'org.holochain.kangaroo-electron', + 'org.holochain.kangaroo-electron-test' ); kangarooConfigString = kangarooConfigString.replace( - "Holochain Kangaroo Electron", - "Holochain Kangaroo Electron (Test)" + 'Holochain Kangaroo Electron', + 'Holochain Kangaroo Electron (Test)' ); fs.writeFileSync('kangaroo.config.ts', kangarooConfigString, 'utf-8'); diff --git a/scripts/read-app-id.js b/scripts/read-app-id.js index 05ba220..96ff7c7 100644 --- a/scripts/read-app-id.js +++ b/scripts/read-app-id.js @@ -6,4 +6,4 @@ tsNode.register(); const kangarooConfig = require(path.join(process.cwd(), 'kangaroo.config.ts')).default; -console.log(kangarooConfig.appId); \ No newline at end of file +console.log(kangarooConfig.appId); diff --git a/scripts/read-macos-code-signing.js b/scripts/read-macos-code-signing.js index 12df872..08e370e 100644 --- a/scripts/read-macos-code-signing.js +++ b/scripts/read-macos-code-signing.js @@ -6,4 +6,4 @@ tsNode.register(); const kangarooConfig = require(path.join(process.cwd(), 'kangaroo.config.ts')).default; -console.log(kangarooConfig.macOSCodeSigning); \ No newline at end of file +console.log(kangarooConfig.macOSCodeSigning); diff --git a/scripts/read-windows-code-signing.js b/scripts/read-windows-code-signing.js index 54c52ca..b6536fb 100644 --- a/scripts/read-windows-code-signing.js +++ b/scripts/read-windows-code-signing.js @@ -6,4 +6,4 @@ tsNode.register(); const kangarooConfig = require(path.join(process.cwd(), 'kangaroo.config.ts')).default; -console.log(kangarooConfig.windowsEVCodeSigning); \ No newline at end of file +console.log(kangarooConfig.windowsEVCodeSigning); diff --git a/scripts/unpack-pouch.js b/scripts/unpack-pouch.js index 919b8a7..f3df470 100644 --- a/scripts/unpack-pouch.js +++ b/scripts/unpack-pouch.js @@ -1,25 +1,19 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -const rustUtils = require("@holochain/hc-spin-rust-utils"); -const path = require("path"); -const fs = require("fs"); +const rustUtils = require('@holochain/hc-spin-rust-utils'); +const path = require('path'); +const fs = require('fs'); -const webhappDir = fs.readdirSync(path.join(process.cwd(), "pouch")); -const webhappFilename = webhappDir.find((file) => file.endsWith(".webhapp")); -if (!webhappFilename) throw new Error("No webhapp file found in pouch folder."); -const webhappPath = path.join(process.cwd(), "pouch", webhappFilename); +const webhappDir = fs.readdirSync(path.join(process.cwd(), 'pouch')); +const webhappFilename = webhappDir.find((file) => file.endsWith('.webhapp')); +if (!webhappFilename) throw new Error('No webhapp file found in pouch folder.'); +const webhappPath = path.join(process.cwd(), 'pouch', webhappFilename); -const resourcesDir = path.join(process.cwd(), "resources"); -const uiDir = path.join(resourcesDir, "ui"); +const resourcesDir = path.join(process.cwd(), 'resources'); +const uiDir = path.join(resourcesDir, 'ui'); // remove existing UI directory if (fs.existsSync(uiDir)) { - fs.rmSync(uiDir, { recursive: true}); + fs.rmSync(uiDir, { recursive: true }); } fs.mkdirSync(uiDir, { recursive: true }); - -rustUtils.saveHappOrWebhapp( - webhappPath, - 'kangaroo', - uiDir, - resourcesDir -); +rustUtils.saveHappOrWebhapp(webhappPath, 'kangaroo', uiDir, resourcesDir); diff --git a/scripts/write-builder-config.js b/scripts/write-builder-config.js index 10252dd..796db09 100644 --- a/scripts/write-builder-config.js +++ b/scripts/write-builder-config.js @@ -1,23 +1,20 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -const jsYaml = require("js-yaml"); -const fs = require("fs"); -const path = require("path"); -const tsNode = require("ts-node"); +const jsYaml = require('js-yaml'); +const fs = require('fs'); +const path = require('path'); +const tsNode = require('ts-node'); tsNode.register(); -const kangarooConfig = require(path.join( - process.cwd(), - "kangaroo.config.ts" -)).default; +const kangarooConfig = require(path.join(process.cwd(), 'kangaroo.config.ts')).default; if (!process.env.KANGAROO_DEV) { // CHECK THAT NO DEFAULT VALUES ANYMORE - if (kangarooConfig.appId === "org.holochain.kangaroo-electron") + if (kangarooConfig.appId === 'org.holochain.kangaroo-electron') throw new Error( "The appId field in 'kangaroo.config.ts' is still using the default value. Change it to the appId of your app." ); - if (kangarooConfig.productName === "Holochain Kangaroo Electron") + if (kangarooConfig.productName === 'Holochain Kangaroo Electron') throw new Error( "The productName field in 'kangaroo.config.ts' is still using the default value. Change it to the productName of your app." ); @@ -25,35 +22,25 @@ if (!process.env.KANGAROO_DEV) { // Store config to json file fs.writeFileSync( - path.join("resources", "kangaroo.config.json"), + path.join('resources', 'kangaroo.config.json'), JSON.stringify(kangarooConfig, undefined, 2), - "utf-8" + 'utf-8' ); // Overwrite package.json values -const packageJsonString = fs.readFileSync("package.json", "utf-8"); +const packageJsonString = fs.readFileSync('package.json', 'utf-8'); const packageJSON = JSON.parse(packageJsonString); packageJSON.name = kangarooConfig.appId; packageJSON.version = kangarooConfig.version; -fs.writeFileSync( - "package.json", - JSON.stringify(packageJSON, undefined, 2), - "utf-8" -); +fs.writeFileSync('package.json', JSON.stringify(packageJSON, undefined, 2), 'utf-8'); const eletronBuilderYml = jsYaml.load( - fs.readFileSync( - path.join(process.cwd(), "templates", "electron-builder-template.yml") - ) + fs.readFileSync(path.join(process.cwd(), 'templates', 'electron-builder-template.yml')) ); eletronBuilderYml.appId = kangarooConfig.appId; eletronBuilderYml.productName = kangarooConfig.productName; eletronBuilderYml.win.executableName = kangarooConfig.appId; -fs.writeFileSync( - "electron-builder.yml", - jsYaml.dump(eletronBuilderYml), - "utf-8" -); +fs.writeFileSync('electron-builder.yml', jsYaml.dump(eletronBuilderYml), 'utf-8'); diff --git a/src/main/cli.ts b/src/main/cli.ts index 49c6889..722287a 100644 --- a/src/main/cli.ts +++ b/src/main/cli.ts @@ -35,7 +35,7 @@ export function validateArgs(args: CliOpts): RunOptions { const allowedProfilePattern = /^[0-9a-zA-Z-]+$/; if (args.profile && !allowedProfilePattern.test(args.profile)) { throw new Error( - `The --profile argument may only contain digits (0-9), letters (a-z,A-Z) and dashes (-) but got '${args.profile}'`, + `The --profile argument may only contain digits (0-9), letters (a-z,A-Z) and dashes (-) but got '${args.profile}'` ); } if (args.networkSeed && typeof args.networkSeed !== 'string') { @@ -47,8 +47,8 @@ export function validateArgs(args: CliOpts): RunOptions { if (args.signalingUrl && typeof args.signalingUrl !== 'string') { throw new Error('The --signaling-url argument must be of type string.'); } - console.log("ICE URLS arg: ", args.iceUrls); - console.log("ICE URLS arg type: ", typeof args.iceUrls); + console.log('ICE URLS arg: ', args.iceUrls); + console.log('ICE URLS arg type: ', typeof args.iceUrls); if (args.iceUrls && typeof args.iceUrls !== 'string') { throw new Error('The --ice-urls argument must be of type string.'); } @@ -70,9 +70,7 @@ export function validateArgs(args: CliOpts): RunOptions { const profile = args.profile ? args.profile : undefined; // If provided take the one provided, otherwise check whether it's applet dev mode - const networkSeed = args.networkSeed - ? args.networkSeed - : defaultAppNetworkSeed(); + const networkSeed = args.networkSeed ? args.networkSeed : defaultAppNetworkSeed(); const bootstrapUrl = args.bootstrapUrl ? new URL(args.bootstrapUrl) : undefined; const signalingUrl = args.signalingUrl ? new URL(args.signalingUrl) : undefined; @@ -95,7 +93,7 @@ export function validateArgs(args: CliOpts): RunOptions { function defaultAppNetworkSeed() { let networkSeed = `${KANGAROO_CONFIG.productName}-${breakingAppVersion(app)}`; if (!app.isPackaged) { - networkSeed += "-dev"; + networkSeed += '-dev'; } return networkSeed; -} \ No newline at end of file +} diff --git a/src/main/const.ts b/src/main/const.ts index d5cb896..a375fb8 100644 --- a/src/main/const.ts +++ b/src/main/const.ts @@ -1,32 +1,37 @@ -import { app } from "electron"; +import { app } from 'electron'; import path from 'path'; import fs from 'fs'; import { KangarooConfig } from './types'; - const RESOURCES_DIRECTORY = app.isPackaged ? path.join(app.getAppPath(), '../app.asar.unpacked/resources') : path.join(app.getAppPath(), './resources'); -const kangarooConfigString = fs.readFileSync(path.join(RESOURCES_DIRECTORY, 'kangaroo.config.json'), 'utf-8'); +const kangarooConfigString = fs.readFileSync( + path.join(RESOURCES_DIRECTORY, 'kangaroo.config.json'), + 'utf-8' +); export const KANGAROO_CONFIG: KangarooConfig = JSON.parse(kangarooConfigString); export const DEFAULT_BOOTSTRAP_SERVER = 'https://bootstrap.holo.host'; export const DEFAULT_SIGNALING_SERVER = 'wss://sbd.holo.host'; -const binariesAppendix = KANGAROO_CONFIG.appId.slice(0,10).replace(' ', '-'); - +const binariesAppendix = KANGAROO_CONFIG.appId.slice(0, 10).replace(' ', '-'); const BINARIES_DIRECTORY = path.join(RESOURCES_DIRECTORY, 'bins'); export const HOLOCHAIN_BINARY = path.join( BINARIES_DIRECTORY, - `holochain-v${KANGAROO_CONFIG.bins.holochain.version}-${binariesAppendix}${process.platform === 'win32' ? '.exe' : ''}`, + `holochain-v${KANGAROO_CONFIG.bins.holochain.version}-${binariesAppendix}${ + process.platform === 'win32' ? '.exe' : '' + }` ); export const LAIR_BINARY = path.join( BINARIES_DIRECTORY, - `lair-keystore-v${KANGAROO_CONFIG.bins.lair.version}-${binariesAppendix}${process.platform === 'win32' ? '.exe' : ''}`, + `lair-keystore-v${KANGAROO_CONFIG.bins.lair.version}-${binariesAppendix}${ + process.platform === 'win32' ? '.exe' : '' + }` ); export const HAPP_PATH = path.join(RESOURCES_DIRECTORY, 'kangaroo.happ'); @@ -38,4 +43,4 @@ export const ICON_PATH = path.join(RESOURCES_DIRECTORY, 'ui', 'icon.png'); export const isMac = process.platform === 'darwin'; export const isWindows = process.platform === 'win32'; -export const isLinux = process.platform === 'linux'; \ No newline at end of file +export const isLinux = process.platform === 'linux'; diff --git a/src/main/defineConfig.ts b/src/main/defineConfig.ts index 5388bd7..1789a5b 100644 --- a/src/main/defineConfig.ts +++ b/src/main/defineConfig.ts @@ -1,4 +1,4 @@ -import { KangarooConfig } from "./types"; +import { KangarooConfig } from './types'; export function defineConfig(config: KangarooConfig) { return config; diff --git a/src/main/eventEmitter.ts b/src/main/eventEmitter.ts index d8dc303..504d504 100644 --- a/src/main/eventEmitter.ts +++ b/src/main/eventEmitter.ts @@ -41,7 +41,7 @@ export declare interface WeEmitter { | WASM_LOG | HAPP_INSTALLED | string, // arbitrary string, e.g. a one-time event with a unique id - listener: (event: HolochainData | string | Error) => void, + listener: (event: HolochainData | string | Error) => void ): this; } diff --git a/src/main/filesystem.ts b/src/main/filesystem.ts index 8f3aae1..8ead9dc 100644 --- a/src/main/filesystem.ts +++ b/src/main/filesystem.ts @@ -4,7 +4,6 @@ import semver from 'semver'; export type Profile = string; - export class KangarooFileSystem { public appDataDir: string; public appConfigDir: string; @@ -78,7 +77,6 @@ function createDirIfNotExists(path: fs.PathLike) { } } - export function breakingAppVersion(app: Electron.App): string { const version = app.getVersion(); if (!semver.valid(version)) { @@ -86,7 +84,9 @@ export function breakingAppVersion(app: Electron.App): string { } const prerelease = semver.prerelease(version); if (prerelease) { - return `${semver.major(version)}.${semver.minor(version)}.${semver.patch(version)}-${prerelease[0]}`; + return `${semver.major(version)}.${semver.minor(version)}.${semver.patch(version)}-${ + prerelease[0] + }`; } switch (semver.major(version)) { case 0: diff --git a/src/main/holochainManager.ts b/src/main/holochainManager.ts index fa4be8f..9134e8a 100644 --- a/src/main/holochainManager.ts +++ b/src/main/holochainManager.ts @@ -1,19 +1,15 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import getPort from "get-port"; -import fs from "fs"; -import * as childProcess from "child_process"; -import { HolochainVersion, KangarooEmitter } from "./eventEmitter"; -import split from "split"; -import { - AdminWebsocket, - AppAuthenticationToken, - AppInfo, -} from "@holochain/client"; -import { KangarooFileSystem } from "./filesystem"; -import { HAPP_APP_ID, HAPP_PATH } from "./const"; +import getPort from 'get-port'; +import fs from 'fs'; +import * as childProcess from 'child_process'; +import { HolochainVersion, KangarooEmitter } from './eventEmitter'; +import split from 'split'; +import { AdminWebsocket, AppAuthenticationToken, AppInfo } from '@holochain/client'; +import { KangarooFileSystem } from './filesystem'; +import { HAPP_APP_ID, HAPP_PATH } from './const'; -import { defaultConductorConfig } from "@lightningrodlabs/we-rust-utils"; -import { app } from "electron"; +import { defaultConductorConfig } from '@lightningrodlabs/we-rust-utils'; +import { app } from 'electron'; export type AdminPort = number; export type AppPort = number; @@ -74,44 +70,40 @@ export class HolochainManager { lairUrl, bootstrapUrl, signalingUrl, - "kangaroo", + 'kangaroo', false, iceUrls, - undefined, + undefined ); - console.log("Writing conductor-config.yaml..."); + console.log('Writing conductor-config.yaml...'); fs.writeFileSync(configPath, conductorConfig); - const conductorHandle = childProcess.spawn( - binary, - ["-c", configPath, "-p"], - { - env: { - RUST_LOG: rustLog - ? rustLog - : "warn," + - // this thrashes on startup - "wasmer_compiler_cranelift=error," + - // this gives a bunch of warnings about how long db accesses are taking, tmi - "holochain_sqlite::db::access=error," + - // this gives a lot of "search_and_discover_peer_connect: no peers found, retrying after delay" messages on INFO - "kitsune_p2p::spawn::actor::discover=error", - WASM_LOG: wasmLog ? wasmLog : "warn", - NO_COLOR: "1", - }, - } - ); + const conductorHandle = childProcess.spawn(binary, ['-c', configPath, '-p'], { + env: { + RUST_LOG: rustLog + ? rustLog + : 'warn,' + + // this thrashes on startup + 'wasmer_compiler_cranelift=error,' + + // this gives a bunch of warnings about how long db accesses are taking, tmi + 'holochain_sqlite::db::access=error,' + + // this gives a lot of "search_and_discover_peer_connect: no peers found, retrying after delay" messages on INFO + 'kitsune_p2p::spawn::actor::discover=error', + WASM_LOG: wasmLog ? wasmLog : 'warn', + NO_COLOR: '1', + }, + }); conductorHandle.stdin.write(password); conductorHandle.stdin.end(); - conductorHandle.stdout.pipe(split()).on("data", async (line: string) => { + conductorHandle.stdout.pipe(split()).on('data', async (line: string) => { kangarooEmitter.emitHolochainLog({ version, data: line, }); }); - conductorHandle.stderr.pipe(split()).on("data", (line: string) => { + conductorHandle.stderr.pipe(split()).on('data', (line: string) => { kangarooEmitter.emitHolochainError({ version, data: line, @@ -119,44 +111,38 @@ export class HolochainManager { }); return new Promise((resolve, reject) => { - conductorHandle.stderr.pipe(split()).on("data", async (line: string) => { - if (line.includes("holochain had a problem and crashed")) { + conductorHandle.stderr.pipe(split()).on('data', async (line: string) => { + if (line.includes('holochain had a problem and crashed')) { reject( `Holochain failed to start up and crashed. Check the logs for details (Help > Open Logs).` ); } }); - conductorHandle.stdout.pipe(split()).on("data", async (line: string) => { - if ( - line.includes("could not be parsed, because it is not valid YAML") - ) { + conductorHandle.stdout.pipe(split()).on('data', async (line: string) => { + if (line.includes('could not be parsed, because it is not valid YAML')) { reject( `Holochain failed to start up and crashed. Check the logs for details (Help > Open Logs).` ); } - if (line.includes("Conductor ready.")) { + if (line.includes('Conductor ready.')) { const adminWebsocket = await AdminWebsocket.connect({ url: new URL(`ws://127.0.0.1:${adminPort}`), wsClientOptions: { - origin: "kangaroo", + origin: 'kangaroo', }, }); - console.log("Connected to admin websocket."); + console.log('Connected to admin websocket.'); const installedApps = await adminWebsocket.listApps({}); const appInterfaces = await adminWebsocket.listAppInterfaces(); - console.log("Got appInterfaces: ", appInterfaces); + console.log('Got appInterfaces: ', appInterfaces); let appPort; if (appInterfaces.length > 0) { appPort = appInterfaces[0].port; } else { - const attachAppInterfaceResponse = - await adminWebsocket.attachAppInterface({ - allowed_origins: app.isPackaged ? 'webhapp://webhappwindow' : '*', - }); - console.log( - "Attached app interface port: ", - attachAppInterfaceResponse - ); + const attachAppInterfaceResponse = await adminWebsocket.attachAppInterface({ + allowed_origins: app.isPackaged ? 'webhapp://webhappwindow' : '*', + }); + console.log('Attached app interface port: ', attachAppInterfaceResponse); appPort = attachAppInterfaceResponse.port; } resolve( @@ -178,12 +164,7 @@ export class HolochainManager { async installHappIfNecessary(networkSeed) { const installedApps = await this.adminWebsocket.listApps({}); - if ( - installedApps - .map((appInfo) => appInfo.installed_app_id) - .includes(HAPP_APP_ID) - ) - return; + if (installedApps.map((appInfo) => appInfo.installed_app_id).includes(HAPP_APP_ID)) return; console.log(`Installing happ...`); const pubKey = await this.adminWebsocket.generateAgentPubKey(); const appInfo = await this.adminWebsocket.installApp({ diff --git a/src/main/index.ts b/src/main/index.ts index 9480a5c..7855572 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,31 +1,20 @@ -import { - app, - BrowserWindow, - ipcMain, - IpcMainInvokeEvent, - Menu, - protocol, -} from "electron"; -import childProcess from "child_process"; -import { - ZomeCallNapi, - ZomeCallSigner, - ZomeCallUnsignedNapi, -} from "@holochain/hc-spin-rust-utils"; +import { app, BrowserWindow, ipcMain, IpcMainInvokeEvent, Menu, protocol } from 'electron'; +import childProcess from 'child_process'; +import { ZomeCallNapi, ZomeCallSigner, ZomeCallUnsignedNapi } from '@holochain/hc-spin-rust-utils'; import contextMenu from 'electron-context-menu'; -import { encode } from "@msgpack/msgpack"; +import { encode } from '@msgpack/msgpack'; import { CallZomeRequest, CallZomeRequestSigned, getNonceExpiration, randomNonce, -} from "@holochain/client"; +} from '@holochain/client'; import { Command } from 'commander'; -import { KangarooFileSystem } from "./filesystem"; -import { KangarooEmitter } from "./eventEmitter"; -import { setupLogs } from "./logs"; -import { HolochainManager } from "./holochainManager"; -import { createHappWindow, createSplashWindow } from "./windows"; +import { KangarooFileSystem } from './filesystem'; +import { KangarooEmitter } from './eventEmitter'; +import { setupLogs } from './logs'; +import { HolochainManager } from './holochainManager'; +import { createHappWindow, createSplashWindow } from './windows'; import { DEFAULT_BOOTSTRAP_SERVER, DEFAULT_SIGNALING_SERVER, @@ -34,10 +23,10 @@ import { KANGAROO_CONFIG, LAIR_BINARY, UI_DIRECTORY, -} from "./const"; -import { initializeLairKeystore, launchLairKeystore } from "./lairKeystore"; -import { kangarooMenu } from "./menu"; -import { validateArgs } from "./cli"; +} from './const'; +import { initializeLairKeystore, launchLairKeystore } from './lairKeystore'; +import { kangarooMenu } from './menu'; +import { validateArgs } from './cli'; // Read CLI options @@ -49,38 +38,38 @@ kangarooCli .version(KANGAROO_CONFIG.version) .option( '-p, --profile ', - `Runs ${KANGAROO_CONFIG.productName} with a custom profile with its own dedicated data store.`, + `Runs ${KANGAROO_CONFIG.productName} with a custom profile with its own dedicated data store.` ) .option( '-n, --network-seed ', - 'If this is the first time running kangaroo with the given profile, this installs the happ with the provided network seed.', + 'If this is the first time running kangaroo with the given profile, this installs the happ with the provided network seed.' ) .option( '--holochain-path ', - `Runs ${KANGAROO_CONFIG.productName} with the holochain binary at the provided path. Use with caution since this may potentially corrupt your databases if the binary you use is not compatible with existing databases.`, + `Runs ${KANGAROO_CONFIG.productName} with the holochain binary at the provided path. Use with caution since this may potentially corrupt your databases if the binary you use is not compatible with existing databases.` ) .option( '--lair-path ', - `Runs the ${KANGAROO_CONFIG.productName} with the lair binary at the provided path. Use with caution since this may potentially corrupt your databases if the binary you use is not compatible with existing databases.`, + `Runs the ${KANGAROO_CONFIG.productName} with the lair binary at the provided path. Use with caution since this may potentially corrupt your databases if the binary you use is not compatible with existing databases.` ) .option('--holochain-rust-log ', 'RUST_LOG value to pass to the holochain binary') .option('--holochain-wasm-log ', 'WASM_LOG value to pass to the holochain binary') .option('--lair-rust-log ', 'RUST_LOG value to pass to the lair keystore binary') .option( '-b, --bootstrap-url ', - 'URL of the bootstrap server to use (not persisted across restarts).', + 'URL of the bootstrap server to use (not persisted across restarts).' ) .option( '-s, --signaling-url ', - 'URL of the signaling server to use (not persisted across restarts).', + 'URL of the signaling server to use (not persisted across restarts).' ) .option( '--ice-urls ', - 'Comma separated string of ICE server URLs to use. Is ignored if an external holochain binary is being used (not persisted across restarts).', + 'Comma separated string of ICE server URLs to use. Is ignored if an external holochain binary is being used (not persisted across restarts).' ) .option( '--print-holochain-logs', - 'Print holochain logs directly to the terminal (they will be still written to the logfile as well)', + 'Print holochain logs directly to the terminal (they will be still written to the logfile as well)' ); kangarooCli.parse(); @@ -90,7 +79,7 @@ const RUN_OPTIONS = validateArgs(kangarooCli.opts()); // Read and validate the config file to check that the content does not contain // default values -const LAIR_PASSWORD = "password"; +const LAIR_PASSWORD = 'password'; // Check whether lair is initialized or not and if not, decide based on the config // file whether or not to show the splashscreen or use a default password @@ -107,7 +96,7 @@ contextMenu({ { label: 'Reload', click: () => (browserWindow as BrowserWindow).reload(), - } + }, ], }); @@ -119,16 +108,13 @@ setupLogs(KANGAROO_EMITTER, KANGAROO_FILESYSTEM, RUN_OPTIONS.printHolochainLogs) protocol.registerSchemesAsPrivileged([ { - scheme: "webhapp", + scheme: 'webhapp', privileges: { standard: true, secure: true, stream: true }, }, ]); -const handleSignZomeCall = async ( - _e: IpcMainInvokeEvent, - request: CallZomeRequest -) => { - if (!ZOME_CALL_SIGNER) throw new Error("Zome call signer undefined."); +const handleSignZomeCall = async (_e: IpcMainInvokeEvent, request: CallZomeRequest) => { + if (!ZOME_CALL_SIGNER) throw new Error('Zome call signer undefined.'); // console.log("Got zome call request: ", request); const zomeCallUnsignedNapi: ZomeCallUnsignedNapi = { provenance: Array.from(request.provenance), @@ -173,31 +159,28 @@ Menu.setApplicationMenu(kangarooMenu(KANGAROO_FILESYSTEM)); app.whenReady().then(async () => { SPLASH_SCREEN_WINDOW = createSplashWindow(); - ipcMain.handle("sign-zome-call", handleSignZomeCall); + ipcMain.handle('sign-zome-call', handleSignZomeCall); ipcMain.handle('exit', () => { app.exit(0); }); if (!KANGAROO_FILESYSTEM.keystoreInitialized()) { if (SPLASH_SCREEN_WINDOW) SPLASH_SCREEN_WINDOW.webContents.send( - "loading-progress-update", - "Initializing lair keystore..." + 'loading-progress-update', + 'Initializing lair keystore...' ); - console.log("initializing lair keystore...") + console.log('initializing lair keystore...'); await initializeLairKeystore( RUN_OPTIONS.lairPath ? RUN_OPTIONS.lairPath : LAIR_BINARY, KANGAROO_FILESYSTEM.keystoreDir, KANGAROO_EMITTER, LAIR_PASSWORD ); - console.log("lair keystore initialized.") + console.log('lair keystore initialized.'); } if (SPLASH_SCREEN_WINDOW) - SPLASH_SCREEN_WINDOW.webContents.send( - "loading-progress-update", - "Starting lair keystore..." - ); + SPLASH_SCREEN_WINDOW.webContents.send('loading-progress-update', 'Starting lair keystore...'); let lairUrl; @@ -211,10 +194,7 @@ app.whenReady().then(async () => { ZOME_CALL_SIGNER = await ZomeCallSigner.connect(lairUrl, LAIR_PASSWORD); if (SPLASH_SCREEN_WINDOW) - SPLASH_SCREEN_WINDOW.webContents.send( - "loading-progress-update", - "Starting Holochain..." - ); + SPLASH_SCREEN_WINDOW.webContents.send('loading-progress-update', 'Starting Holochain...'); HOLOCHAIN_MANAGER = await HolochainManager.launch( KANGAROO_EMITTER, @@ -227,23 +207,23 @@ app.whenReady().then(async () => { lairUrl, RUN_OPTIONS.bootstrapUrl ? RUN_OPTIONS.bootstrapUrl.toString() : DEFAULT_BOOTSTRAP_SERVER, RUN_OPTIONS.signalingUrl ? RUN_OPTIONS.signalingUrl.toString() : DEFAULT_SIGNALING_SERVER, - RUN_OPTIONS.iceUrls ? RUN_OPTIONS.iceUrls : undefined, + RUN_OPTIONS.iceUrls ? RUN_OPTIONS.iceUrls : undefined ); // Install happ if necessary await HOLOCHAIN_MANAGER.installHappIfNecessary(RUN_OPTIONS.networkSeed); - console.log("Happ installed."); + console.log('Happ installed.'); const appToken = await HOLOCHAIN_MANAGER.getAppToken(); - console.log("Starting main window..."); + console.log('Starting main window...'); SPLASH_SCREEN_WINDOW.close(); MAIN_WINDOW = await createHappWindow( { - type: "path", + type: 'path', path: UI_DIRECTORY, }, HAPP_APP_ID, @@ -258,14 +238,14 @@ app.whenReady().then(async () => { // Quit when all windows are closed, except on macOS. There, it's common // for applications and their menu bar to stay active until the user quits // explicitly with Cmd + Q. -app.on("window-all-closed", () => { +app.on('window-all-closed', () => { app.quit(); // if (process.platform !== 'darwin') { // app.quit() // } }); -app.on("quit", () => { +app.on('quit', () => { if (LAIR_HANDLE) { LAIR_HANDLE.kill(); } diff --git a/src/main/lairKeystore.ts b/src/main/lairKeystore.ts index b024236..1e73137 100644 --- a/src/main/lairKeystore.ts +++ b/src/main/lairKeystore.ts @@ -10,7 +10,7 @@ export async function initializeLairKeystore( lairBinary: string, keystoreDir: string, kangarooEmitter: KangarooEmitter, - password: string, + password: string ): Promise { const lairHandle = childProcess.spawn(lairBinary, ['init', '-p'], { cwd: keystoreDir }); lairHandle.stdin.write(password); @@ -35,7 +35,7 @@ export async function launchLairKeystore( keystoreDir: string, kangarooEmitter: KangarooEmitter, password: string, - rustLog?: string, + rustLog?: string ): Promise<[childProcess.ChildProcessWithoutNullStreams, string]> { // On Unix systems, there is a limit to the path length of a domain socket. Create a symlink to the lair directory from the tempdir // instead and overwrite the connectionUrl in the lair-keystore-config.yaml diff --git a/src/main/logs.ts b/src/main/logs.ts index 41c9fe9..e25b905 100644 --- a/src/main/logs.ts +++ b/src/main/logs.ts @@ -12,7 +12,7 @@ import { WASM_LOG, KANGAROO_ERROR, KANGAROO_LOG, - KangarooEmitter + KangarooEmitter, } from './eventEmitter'; import { KANGAROO_CONFIG } from './const'; @@ -26,9 +26,12 @@ const HOLOCHAIN_LOGGERS: Record = {}; export function setupLogs( kangarooEmitter: KangarooEmitter, kangarooFs: KangarooFileSystem, - holochainLogsToTerminal: boolean, + holochainLogsToTerminal: boolean ) { - const logFilePath = path.join(kangarooFs.appLogsDir, `${KANGAROO_CONFIG.productName.replace(' ', '_')}.log`); + const logFilePath = path.join( + kangarooFs.appLogsDir, + `${KANGAROO_CONFIG.productName.replace(' ', '_')}.log` + ); if (fs.existsSync(logFilePath)) { const stats = fs.statSync(logFilePath); // If existing logfile is larger than 1GB, delete it @@ -81,7 +84,7 @@ export function setupLogs( function logHolochain( holochainData: HolochainData, logFileTransport: winston.transports.FileTransportInstance, - printToTerminal: boolean, + printToTerminal: boolean ) { const holochainVersion = (holochainData as HolochainData).version; const line = (holochainData as HolochainData).data; @@ -101,7 +104,7 @@ function logHolochain( function createHolochainLogger( holochainVersion: HolochainVersion, - logFileTransport: winston.transports.FileTransportInstance, + logFileTransport: winston.transports.FileTransportInstance ): winston.Logger { return createLogger({ transports: [logFileTransport], @@ -114,13 +117,13 @@ function createHolochainLogger( level, message, }); - }), + }) ), }); } function createLairLogger( - logFileTransport: winston.transports.FileTransportInstance, + logFileTransport: winston.transports.FileTransportInstance ): winston.Logger { return createLogger({ transports: [logFileTransport], @@ -133,7 +136,7 @@ function createLairLogger( level, message, }); - }), + }) ), }); } diff --git a/src/main/types.ts b/src/main/types.ts index 7bea9c8..02e3fff 100644 --- a/src/main/types.ts +++ b/src/main/types.ts @@ -1,5 +1,3 @@ - - export type KangarooConfig = { /** * App ID. A unique id that will be used by the OS and that defines @@ -9,11 +7,11 @@ export type KangarooConfig = { * * Will also be used as the package name in package.json. */ - appId: string, + appId: string; /** * The name of the app as displayed in places such as the Window bar. */ - productName: string, + productName: string; /** * This version will overwrite the version in package.json. * **IMPORTANT** Breaking version semver changes here will lead to @@ -26,23 +24,23 @@ export type KangarooConfig = { * 0.13.0-alpha.0 -> 0.13.0-beta.0: Breaking change; * 0.13.0-alpha.0 -> 0.13.0-alpha.1: *No* breaking change; */ - version: string, + version: string; /** * Whether to attempt macOS code signing in CI. Requires the corresponding * secrets to be available in the github repository. */ - macOSCodeSigning: boolean, + macOSCodeSigning: boolean; /** * Whether to attempt Windows code signing with an EV certificate in CI. * Assumes that the relevant secrets are available in the repository * in the format of this guide: https://melatonin.dev/blog/how-to-code-sign-windows-installers-with-an-ev-cert-on-github-actions/ */ - windowsEVCodeSigning: boolean, + windowsEVCodeSigning: boolean; /** * Fall back to serving the index.html if a resources is not found. Often required for router-based * frameworks like svelte-kit or vue-router */ - fallbackToIndexHtml: boolean, + fallbackToIndexHtml: boolean; // /** // * Whether or not the app should have the user set up a password. // */ @@ -60,31 +58,32 @@ export type KangarooConfig = { * network seed will automatically be generated and be based on the * productName and the breaking semver version of your app. */ - networkSeed?: string, - devConfig?: { - happPath: string, - uiPort: string, - } | { - webhappPath: string - }, + networkSeed?: string; + devConfig?: + | { + happPath: string; + uiPort: string; + } + | { + webhappPath: string; + }; author?: { - name?: string, - url?: string, - email?: string, - }, + name?: string; + url?: string; + email?: string; + }; bins: { - holochain: VersionAndSha256, - lair: VersionAndSha256 - } -} - + holochain: VersionAndSha256; + lair: VersionAndSha256; + }; +}; type VersionAndSha256 = { - version: string, + version: string; sha256: { - "x86_64-unknown-linux-gnu": string, - "x86_64-pc-windows-msvc.exe": string, - "x86_64-apple-darwin": string, - "aarch64-apple-darwin": string - } -}; \ No newline at end of file + 'x86_64-unknown-linux-gnu': string; + 'x86_64-pc-windows-msvc.exe': string; + 'x86_64-apple-darwin': string; + 'aarch64-apple-darwin': string; + }; +}; diff --git a/src/main/windows.ts b/src/main/windows.ts index 935f31b..e8f7664 100644 --- a/src/main/windows.ts +++ b/src/main/windows.ts @@ -1,25 +1,18 @@ -import path from "path"; -import fs from "fs"; -import url from "url"; -import { AppAuthenticationToken, InstalledAppId } from "@holochain/client"; -import { - BrowserWindow, - NativeImage, - nativeImage, - net, - session, - shell, -} from "electron"; -import { is } from "@electron-toolkit/utils"; -import { ICON_PATH, KANGAROO_CONFIG } from "./const"; +import path from 'path'; +import fs from 'fs'; +import url from 'url'; +import { AppAuthenticationToken, InstalledAppId } from '@holochain/client'; +import { BrowserWindow, NativeImage, nativeImage, net, session, shell } from 'electron'; +import { is } from '@electron-toolkit/utils'; +import { ICON_PATH, KANGAROO_CONFIG } from './const'; export type UISource = | { - type: "path"; + type: 'path'; path: string; } | { - type: "port"; + type: 'port'; port: number; }; @@ -31,31 +24,31 @@ export const createHappWindow = async ( openDevtools: boolean ): Promise => { // TODO create mapping between installed-app-id's and window ids - if (!appPort) throw new Error("App port not defined."); + if (!appPort) throw new Error('App port not defined.'); - if (uiSource.type === "path") { + if (uiSource.type === 'path') { const ses = session.defaultSession; - ses.protocol.handle("webhapp", async (request) => { - const uriWithoutProtocol = request.url.slice("webhapp://".length); - const filePathComponents = uriWithoutProtocol.split("/").slice(1); + ses.protocol.handle('webhapp', async (request) => { + const uriWithoutProtocol = request.url.slice('webhapp://'.length); + const filePathComponents = uriWithoutProtocol.split('/').slice(1); const relativeFilePath = path.join(...filePathComponents); const absoluteFilePath = path.join(uiSource.path, relativeFilePath); - const fallbackToIndexHtml = KANGAROO_CONFIG.fallbackToIndexHtml ? !fs.existsSync(absoluteFilePath) : false; + const fallbackToIndexHtml = KANGAROO_CONFIG.fallbackToIndexHtml + ? !fs.existsSync(absoluteFilePath) + : false; - if (!relativeFilePath.endsWith("index.html") && !fallbackToIndexHtml) { - return net.fetch( - url.pathToFileURL(absoluteFilePath).toString() - ); + if (!relativeFilePath.endsWith('index.html') && !fallbackToIndexHtml) { + return net.fetch(url.pathToFileURL(absoluteFilePath).toString()); } else { const indexHtmlResponse = await net.fetch(url.pathToFileURL(absoluteFilePath).toString()); const content = await indexHtmlResponse.text(); let modifiedContent = content.replace( - "", + '', `` ); // remove title attribute to be able to set title to app id later - modifiedContent = modifiedContent.replace(/.*?<\/title>/i, ""); + modifiedContent = modifiedContent.replace(/<title>.*?<\/title>/i, ''); return new Response(modifiedContent, indexHtmlResponse); } }); @@ -63,29 +56,27 @@ export const createHappWindow = async ( let icon: NativeImage | undefined; - if (uiSource.type === "path") { + if (uiSource.type === 'path') { if (fs.existsSync(ICON_PATH)) { icon = nativeImage.createFromPath(ICON_PATH); } } else { try { - const iconResponse = await net.fetch( - `http://localhost:${uiSource.port}/icon.png` - ); + const iconResponse = await net.fetch(`http://localhost:${uiSource.port}/icon.png`); if (iconResponse.status === 404) { console.warn( - "No icon.png found. It is recommended to put an icon.png file (1024x1024 pixel) in the root of your UI assets directory." + 'No icon.png found. It is recommended to put an icon.png file (1024x1024 pixel) in the root of your UI assets directory.' ); } else { const buffer = await iconResponse.arrayBuffer(); icon = nativeImage.createFromBuffer(Buffer.from(buffer)); } } catch (e) { - console.error("Failed to get icon.png: ", e); + console.error('Failed to get icon.png: ', e); } } - console.log("Instantiating browser window"); + console.log('Instantiating browser window'); const happWindow = new BrowserWindow({ width: 1200, @@ -94,54 +85,47 @@ export const createHappWindow = async ( icon, title: KANGAROO_CONFIG.productName, webPreferences: { - preload: path.resolve(__dirname, "../preload/happ.js"), + preload: path.resolve(__dirname, '../preload/happ.js'), }, }); - console.log("setLinkOpenHandlers"); + console.log('setLinkOpenHandlers'); setLinkOpenHandlers(happWindow); - happWindow.on("page-title-updated", (evt) => { + happWindow.on('page-title-updated', (evt) => { evt.preventDefault(); }); if (openDevtools) happWindow.webContents.openDevTools(); - if (uiSource.type === "port") { + if (uiSource.type === 'port') { try { // Check whether dev server is responsive and index.html exists await net.fetch(`http://localhost:${uiSource.port}/index.html`); } catch (e) { - console.error( - `No index.html file found at http://localhost:${uiSource.port}/index.html`, - e - ); - if (is.dev && process.env["ELECTRON_RENDERER_URL"]) { - happWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]); + console.error(`No index.html file found at http://localhost:${uiSource.port}/index.html`, e); + if (is.dev && process.env['ELECTRON_RENDERER_URL']) { + happWindow.loadURL(process.env['ELECTRON_RENDERER_URL']); } else { - happWindow.loadFile( - path.join(__dirname, "../renderer/indexNotFound.html") - ); + happWindow.loadFile(path.join(__dirname, '../renderer/indexNotFound.html')); } happWindow.show(); return happWindow; } await happWindow.loadURL(`http://localhost:${uiSource.port}`); - } else if (uiSource.type === "path") { + } else if (uiSource.type === 'path') { try { - console.log("loading URL"); + console.log('loading URL'); await happWindow.loadURL(`webhapp://webhappwindow/index.html`); - console.log("URL loaded"); + console.log('URL loaded'); } catch (e) { - console.error("[ERROR] Failed to fetch index.html"); + console.error('[ERROR] Failed to fetch index.html'); - if (is.dev && process.env["ELECTRON_RENDERER_URL"]) { - happWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]); + if (is.dev && process.env['ELECTRON_RENDERER_URL']) { + happWindow.loadURL(process.env['ELECTRON_RENDERER_URL']); } else { - happWindow.loadFile( - path.join(__dirname, "../renderer/indexNotFound2.html") - ); + happWindow.loadFile(path.join(__dirname, '../renderer/indexNotFound2.html')); } happWindow.show(); return happWindow; @@ -158,36 +142,30 @@ export const createHappWindow = async ( export function setLinkOpenHandlers(browserWindow: BrowserWindow): void { // links should open in the system default application // instead of the webview - browserWindow.webContents.on("will-navigate", (e) => { - if ( - e.url.startsWith("http://localhost") || - e.url.startsWith("http://127.0.0.1") - ) { + browserWindow.webContents.on('will-navigate', (e) => { + if (e.url.startsWith('http://localhost') || e.url.startsWith('http://127.0.0.1')) { // ignore dev server reload return; } if ( - e.url.startsWith("http://") || - e.url.startsWith("https://") || - e.url.startsWith("mailto://") + e.url.startsWith('http://') || + e.url.startsWith('https://') || + e.url.startsWith('mailto://') ) { e.preventDefault(); shell.openExternal(e.url); } }); - browserWindow.webContents.on("will-frame-navigate", (e) => { - if ( - e.url.startsWith("http://localhost") || - e.url.startsWith("http://127.0.0.1") - ) { + browserWindow.webContents.on('will-frame-navigate', (e) => { + if (e.url.startsWith('http://localhost') || e.url.startsWith('http://127.0.0.1')) { // ignore dev server reload return; } if ( - e.url.startsWith("http://") || - e.url.startsWith("https://") || - e.url.startsWith("mailto://") + e.url.startsWith('http://') || + e.url.startsWith('https://') || + e.url.startsWith('mailto://') ) { e.preventDefault(); shell.openExternal(e.url); @@ -197,13 +175,10 @@ export function setLinkOpenHandlers(browserWindow: BrowserWindow): void { // Links with target=_blank should open in the system default browser and // happ windows are not allowed to spawn new electron windows browserWindow.webContents.setWindowOpenHandler((details) => { - if ( - details.url.startsWith("http://") || - details.url.startsWith("https://") - ) { + if (details.url.startsWith('http://') || details.url.startsWith('https://')) { shell.openExternal(details.url); } - return { action: "deny" }; + return { action: 'deny' }; }); } @@ -215,31 +190,24 @@ export const createSplashWindow = (): BrowserWindow => { resizable: false, frame: false, show: false, - backgroundColor: "#fbf9f7", + backgroundColor: '#fbf9f7', webPreferences: { - preload: path.join(__dirname, "../preload/splashscreen.js"), + preload: path.join(__dirname, '../preload/splashscreen.js'), }, }); // and load the splashscreen.html of the app. - if (is.dev && process.env["ELECTRON_RENDERER_URL"]) { - splashWindow.loadURL( - `${process.env["ELECTRON_RENDERER_URL"]}/splashscreen.html` - ); + if (is.dev && process.env['ELECTRON_RENDERER_URL']) { + splashWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/splashscreen.html`); } else { - splashWindow.loadFile( - path.join(__dirname, "../renderer/splashscreen.html") - ); + splashWindow.loadFile(path.join(__dirname, '../renderer/splashscreen.html')); } - splashWindow.once("ready-to-show", () => { - splashWindow.webContents.send( - "name-and-version", - { - productName: KANGAROO_CONFIG.productName, - version: KANGAROO_CONFIG.version, - } - ); + splashWindow.once('ready-to-show', () => { + splashWindow.webContents.send('name-and-version', { + productName: KANGAROO_CONFIG.productName, + version: KANGAROO_CONFIG.version, + }); splashWindow.show(); }); diff --git a/src/preload/happ.ts b/src/preload/happ.ts index 24b11d9..3555c14 100644 --- a/src/preload/happ.ts +++ b/src/preload/happ.ts @@ -6,4 +6,4 @@ import { CallZomeRequestUnsigned } from '@holochain/client'; contextBridge.exposeInMainWorld('__HC_ZOME_CALL_SIGNER__', { signZomeCall: (zomeCall: CallZomeRequestUnsigned) => ipcRenderer.invoke('sign-zome-call', zomeCall), -}); \ No newline at end of file +}); diff --git a/src/renderer/indexNotFound.html b/src/renderer/indexNotFound.html index 6bf7e10..82715a9 100644 --- a/src/renderer/indexNotFound.html +++ b/src/renderer/indexNotFound.html @@ -1,4 +1,4 @@ -<!doctype html> +<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> @@ -13,7 +13,8 @@ <div class="container"> <h1>index.html not found.</h1> <div style="margin-bottom: 100px"> - Is your dev server running at the port specified with the <span class="code">devConfig</span> section of the kangaroo config file? + Is your dev server running at the port specified with the + <span class="code">devConfig</span> section of the kangaroo config file? </div> </div> </body> diff --git a/src/renderer/indexNotFound2.html b/src/renderer/indexNotFound2.html index a29a99d..db3f785 100644 --- a/src/renderer/indexNotFound2.html +++ b/src/renderer/indexNotFound2.html @@ -1,4 +1,4 @@ -<!doctype html> +<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> diff --git a/src/renderer/splashscreen.html b/src/renderer/splashscreen.html index 1619cc1..d0e95b8 100644 --- a/src/renderer/splashscreen.html +++ b/src/renderer/splashscreen.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <meta charset="utf-8"> + <meta charset="utf-8" /> <link rel="stylesheet" type="text/css" href="index.css" /> </head> <body> @@ -11,36 +11,39 @@ <div id="productName" class="splash-product-name"></div> <div id="version" class="splash-version"></div> </div> - <div class="splash-loading-message" id="activity"> - Setting up Holochain... - </div> - <div class="splash-license"> - Licensed under the Cryptographic Autonomy License v1.0 - </div> + <div class="splash-loading-message" id="activity">Setting up Holochain...</div> + <div class="splash-license">Licensed under the Cryptographic Autonomy License v1.0</div> </div> - <img style="position: absolute; bottom: 5px; right: 10px; width: 300px;" src="img/powered_by_holochain.png" /> - <img tabindex="0" id="close-btn" style="cursor: pointer; position: absolute; top: 5px; right: 5px; width: 35px;" src="img/close.svg" /> - + <img + style="position: absolute; bottom: 5px; right: 10px; width: 300px" + src="img/powered_by_holochain.png" + /> + <img + tabindex="0" + id="close-btn" + style="cursor: pointer; position: absolute; top: 5px; right: 5px; width: 35px" + src="img/close.svg" + /> </div> <script> window.electronAPI.onNameAndVersion((event, msg) => { - console.log("got name and version: ", msg); + console.log('got name and version: ', msg); document.getElementById('productName').innerHTML = msg.productName; document.getElementById('version').innerHTML = `version ${msg.version}`; - }) + }); window.electronAPI.onProgressUpdate((event, msg) => { console.log('status', msg); document.getElementById('activity').innerHTML = msg; - }) + }); const closeBtn = document.getElementById('close-btn'); closeBtn.addEventListener('click', () => { window.electronAPI.exit(); - }) + }); closeBtn.addEventListener('keypress', (e) => { - if (e.key === "Enter" || e.key === " ") { + if (e.key === 'Enter' || e.key === ' ') { window.electronAPI.exit(); } - }) + }); </script> </body> </html> diff --git a/templates/electron-builder-template.yml b/templates/electron-builder-template.yml index 94ae534..7aefebb 100644 --- a/templates/electron-builder-template.yml +++ b/templates/electron-builder-template.yml @@ -19,10 +19,10 @@ mac: entitlementsInherit: build/entitlements.mac.plist # Uncomment selectively for your application's purposes # extendInfo: - # - NSCameraUsageDescription: Application requests access to the device's camera. - # - NSMicrophoneUsageDescription: Application requests access to the device's microphone. - # - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. - # - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. + # - NSCameraUsageDescription: Application requests access to the device's camera. + # - NSMicrophoneUsageDescription: Application requests access to the device's microphone. + # - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. + # - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. notarize: false dmg: artifactName: ${name}-${version}.${ext} From 3a54b57a7f6cfcb37058fa2fd301984a8139132d Mon Sep 17 00:00:00 2001 From: Matthias <tuttiacc@hotmail.com> Date: Tue, 17 Dec 2024 17:37:52 +0100 Subject: [PATCH 11/16] fix bug of enabling app if memproof provisioning deferred --- src/main/holochainManager.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/holochainManager.ts b/src/main/holochainManager.ts index 9134e8a..dec9dac 100644 --- a/src/main/holochainManager.ts +++ b/src/main/holochainManager.ts @@ -173,18 +173,18 @@ export class HolochainManager { path: HAPP_PATH, network_seed: networkSeed, }); - try { - await this.adminWebsocket.enableApp({ - installed_app_id: appInfo.installed_app_id, - }); - const installedApps = await this.adminWebsocket.listApps({}); - this.installedApps = installedApps; - this.kangarooEmitter.emitHappInstalled(); - } catch (e) { - throw new Error( - `Failed to enable appstore: ${e}.\nIf you encounter this in dev mode your local bootstrap server may not be running or at a different port than the one specified.` - ); + if (appInfo.status !== 'awaiting_memproofs') { + try { + await this.adminWebsocket.enableApp({ + installed_app_id: appInfo.installed_app_id, + }); + } catch (e) { + throw new Error(`Failed to enable happ: ${e}.`); + } } + const installedAppsNew = await this.adminWebsocket.listApps({}); + this.installedApps = installedAppsNew; + this.kangarooEmitter.emitHappInstalled(); } async getAppToken(): Promise<AppAuthenticationToken> { From 224f1fe03aa2c6925cda157dcbfb76eeaa674224 Mon Sep 17 00:00:00 2001 From: Matthias <tuttiacc@hotmail.com> Date: Tue, 17 Dec 2024 18:11:34 +0100 Subject: [PATCH 12/16] add auto updater logic --- README.md | 27 +++++++++++++++++++++++-- kangaroo.config.ts | 1 + package.json | 2 ++ src/main/cli.ts | 2 +- src/main/filesystem.ts | 9 +++++++-- src/main/index.ts | 46 ++++++++++++++++++++++++++++++++++++++++-- src/main/types.ts | 5 +++++ yarn.lock | 39 ++++++++++++++++++++++++++++++++++- 8 files changed, 123 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9567628..bfafd1b 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,12 @@ yarn setup 3. In the `kangaroo.config.ts` file, replace the `appId` and `productName` fields with names appropriate for your own app. -4. Paste the `.webhapp` file of your holochain app into the `pouch` folder. +4. Choose a version number in the `version` field of `kangaroo.config.ts`. And **Read** the section [Versioning](#Versioning) below to understand the implications. + +5. Paste the `.webhapp` file of your holochain app into the `pouch` folder. **Note**: The kangaroo expects a 1024x1024 pixel `icon.png` at the root level of your webhapp's UI assets. -5. To test it, run +6. To test it, run ``` yarn dev @@ -77,6 +79,27 @@ git merge main git push ``` +## Automatic Updates + +By default, the kangaroo is set up to check github releases for semver compatible releases by their tag name whenever the app starts up and will prompt to install and restart if one is available. This can be disabled by setting `autoUpdates` to `false` in `kangaroo.config.ts`. + +> [!NOTE] +> Note that once your app is deployed, this setting can only be turned on again for newer releases and users will have to manually install new versions. + +## Versioning + +To allow for subsequent incompatible releases of your app (for example due to switching to a new Holochain version or introducing a breaking change in the integrity zomes of your .happ) without having to change the app's name or identifier, the kangaroo is set up to use semver to support incompatible versions of your app running fully independently from each other and store their data in dedicated locations on disk. + +Examples: + +- version 0.0.2 and 0.0.3 of your app will store their data in independent locations on disk and version 0.0.3 will not have access to any data created/obtained in version 0.0.2 +- version 0.3.4 will reuse the same Holochain conductor and data as version 0.3.2 +- versions 0.3.0-alpha and 0.3.0-beta will _not_ share data +- versions 0.3.0-alpha.0 and 0.3.0-alpha.1 _will_ share data + +> [!NOTE] +> It is your responsibility to make sure that if you mark two versions of your app as semver compatible they actually are compatible (e.g. that you don't try to run a new incompatible version of Holochain on existing databases). + ## Code Signing ### macOS diff --git a/kangaroo.config.ts b/kangaroo.config.ts index 34bf44d..3b37bde 100644 --- a/kangaroo.config.ts +++ b/kangaroo.config.ts @@ -7,6 +7,7 @@ export default defineConfig({ macOSCodeSigning: false, windowsEVCodeSigning: false, fallbackToIndexHtml: true, + autoUpdates: true, bins: { holochain: { version: '0.4.0-rc.2', diff --git a/package.json b/package.json index ab58fd2..720039c 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@holochain/client": "0.18.0-rc.1", "@holochain/hc-spin-rust-utils": "0.400.0-rc.1", "@lightningrodlabs/we-rust-utils": "0.400.0-rc.1", + "@matthme/electron-updater": "6.3.0-alpha.1", "@msgpack/msgpack": "^2.8.0", "adm-zip": "0.5.14", "bufferutil": "4.0.8", @@ -33,6 +34,7 @@ "electron-context-menu": "3.6.1", "get-port": "7.0.0", "nanoid": "5.0.4", + "semver": "^7.6.2", "split": "1.0.1", "utf-8-validate": "^6.0.3", "winston": "3.11.0" diff --git a/src/main/cli.ts b/src/main/cli.ts index 722287a..e901de0 100644 --- a/src/main/cli.ts +++ b/src/main/cli.ts @@ -91,7 +91,7 @@ export function validateArgs(args: CliOpts): RunOptions { } function defaultAppNetworkSeed() { - let networkSeed = `${KANGAROO_CONFIG.productName}-${breakingAppVersion(app)}`; + let networkSeed = `${KANGAROO_CONFIG.productName}-${breakingAppVersion()}`; if (!app.isPackaged) { networkSeed += '-dev'; } diff --git a/src/main/filesystem.ts b/src/main/filesystem.ts index 8ead9dc..8380249 100644 --- a/src/main/filesystem.ts +++ b/src/main/filesystem.ts @@ -1,6 +1,7 @@ import path from 'path'; import fs from 'fs'; import semver from 'semver'; +import { app } from 'electron'; export type Profile = string; @@ -26,7 +27,7 @@ export class KangarooFileSystem { static connect(app: Electron.App, profile?: Profile, tempDir?: string) { profile = profile ? profile : 'default'; - const versionString = breakingAppVersion(app); + const versionString = breakingAppVersion(); const defaultLogsPath = app.getPath('logs'); console.log('defaultLogsPath: ', defaultLogsPath); @@ -77,8 +78,12 @@ function createDirIfNotExists(path: fs.PathLike) { } } -export function breakingAppVersion(app: Electron.App): string { +export function breakingAppVersion(): string { const version = app.getVersion(); + return breakingVersion(version); +} + +export function breakingVersion(version: string): string { if (!semver.valid(version)) { throw new Error('App has an invalid version number.'); } diff --git a/src/main/index.ts b/src/main/index.ts index 7855572..b35df66 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, ipcMain, IpcMainInvokeEvent, Menu, protocol } from 'electron'; +import { app, BrowserWindow, dialog, ipcMain, IpcMainInvokeEvent, Menu, protocol } from 'electron'; import childProcess from 'child_process'; import { ZomeCallNapi, ZomeCallSigner, ZomeCallUnsignedNapi } from '@holochain/hc-spin-rust-utils'; import contextMenu from 'electron-context-menu'; @@ -10,7 +10,9 @@ import { randomNonce, } from '@holochain/client'; import { Command } from 'commander'; -import { KangarooFileSystem } from './filesystem'; +import semver from "semver"; + +import { breakingVersion, KangarooFileSystem } from './filesystem'; import { KangarooEmitter } from './eventEmitter'; import { setupLogs } from './logs'; import { HolochainManager } from './holochainManager'; @@ -27,6 +29,7 @@ import { import { initializeLairKeystore, launchLairKeystore } from './lairKeystore'; import { kangarooMenu } from './menu'; import { validateArgs } from './cli'; +import { autoUpdater, UpdateCheckResult } from '@matthme/electron-updater'; // Read CLI options @@ -163,6 +166,45 @@ app.whenReady().then(async () => { ipcMain.handle('exit', () => { app.exit(0); }); + + // Check for updates + if (app.isPackaged && KANGAROO_CONFIG.autoUpdates) { + autoUpdater.allowPrerelease = true; + autoUpdater.autoDownload = false; + + let updateCheckResult: UpdateCheckResult | null | undefined; + + try { + updateCheckResult = await autoUpdater.checkForUpdates(); + } catch (e) { + console.warn('Failed to check for updates: ', e); + } + + console.log('updateCheckResult: ', updateCheckResult); + + // We only install semver compatible updates + const appVersion = app.getVersion(); + if ( + updateCheckResult && + breakingVersion(updateCheckResult.updateInfo.version) === breakingVersion(appVersion) && + semver.gt(updateCheckResult.updateInfo.version, appVersion) + ) { + const userDecision = await dialog.showMessageBox({ + title: 'Update Available', + type: 'question', + buttons: ['Deny', 'Install and Restart'], + defaultId: 0, + cancelId: 0, + message: `A new compatible version of ${KANGAROO_CONFIG.productName} is available (${updateCheckResult.updateInfo.version}). Do you want to install it?`, + }); + if (userDecision.response === 1) { + // downloading means that with the next start of the application it's automatically going to be installed + autoUpdater.on('update-downloaded', () => autoUpdater.quitAndInstall()); + await autoUpdater.downloadUpdate(); + } + } + } + if (!KANGAROO_FILESYSTEM.keystoreInitialized()) { if (SPLASH_SCREEN_WINDOW) SPLASH_SCREEN_WINDOW.webContents.send( diff --git a/src/main/types.ts b/src/main/types.ts index 02e3fff..40e1f57 100644 --- a/src/main/types.ts +++ b/src/main/types.ts @@ -41,6 +41,11 @@ export type KangarooConfig = { * frameworks like svelte-kit or vue-router */ fallbackToIndexHtml: boolean; + /** + * Whether the app should check for available, semver compatible releases on github on startup + * and prompt to install and restart if a new release is available. + */ + autoUpdates: boolean; // /** // * Whether or not the app should have the user set up a password. // */ diff --git a/yarn.lock b/yarn.lock index 6384b72..4727535 100644 --- a/yarn.lock +++ b/yarn.lock @@ -738,6 +738,20 @@ lodash "^4.17.15" tmp-promise "^3.0.2" +"@matthme/electron-updater@6.3.0-alpha.1": + version "6.3.0-alpha.1" + resolved "https://registry.yarnpkg.com/@matthme/electron-updater/-/electron-updater-6.3.0-alpha.1.tgz#9bdf1200bba45a1d91f897523fb6e69efb53c6f3" + integrity sha512-k6oaZzT3XWE6hY1IchR5kZ0eEb9sVp9K3+BVtG88rA8aqvI9OJJrGZlCFStO4AXmLgZ/U/MUbWih4eHMS9eDcQ== + dependencies: + builder-util-runtime "9.2.5-alpha.2" + fs-extra "^10.1.0" + js-yaml "^4.1.0" + lazy-val "^1.0.5" + lodash.escaperegexp "^4.1.2" + lodash.isequal "^4.5.0" + semver "^7.3.8" + tiny-typed-emitter "^2.1.0" + "@msgpack/msgpack@^2.8.0": version "2.8.0" resolved "https://registry.yarnpkg.com/@msgpack/msgpack/-/msgpack-2.8.0.tgz#4210deb771ee3912964f14a15ddfb5ff877e70b9" @@ -1697,6 +1711,14 @@ builder-util-runtime@9.2.4: debug "^4.3.4" sax "^1.2.4" +builder-util-runtime@9.2.5-alpha.2: + version "9.2.5-alpha.2" + resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.2.5-alpha.2.tgz#b0a1737996717d7ae0b71e5efdf0bfbd1dd2c21e" + integrity sha512-/Ln2ddejGj2HNMJ+X66mKHRcOvmRzUO/dSi8t4hSV64J7IA+DE+mqDb+zogIE2gin7p7YwcGiOkKny4nwPPPXg== + dependencies: + debug "^4.3.4" + sax "^1.2.4" + builder-util@24.13.1: version "24.13.1" resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-24.13.1.tgz#4a4c4f9466b016b85c6990a0ea15aa14edec6816" @@ -3469,6 +3491,16 @@ lodash-es@^4.17.21: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash.escaperegexp@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" + integrity sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -4247,7 +4279,7 @@ semver@^6.2.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.2, semver@^7.3.4, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: +semver@^7.3.2, semver@^7.3.4, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.2: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== @@ -4590,6 +4622,11 @@ through@2: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +tiny-typed-emitter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz#b3b027fdd389ff81a152c8e847ee2f5be9fad7b5" + integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA== + tmp-promise@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.3.tgz#60a1a1cc98c988674fcbfd23b6e3367bdeac4ce7" From b80eb74fbb8de0f3951ff5e831d127190ac0b3cf Mon Sep 17 00:00:00 2001 From: matthme <36768177+matthme@users.noreply.github.com> Date: Fri, 3 Jan 2025 10:46:04 +0100 Subject: [PATCH 13/16] feat: Password logic (#22) * implemented no-password and password-required options * added password-optional logic * fix bundling of html pages, add additional log line * remove unused CSS * moved styles to shared styles * replace uuid with nanoid --- electron.vite.config.ts | 5 +- kangaroo.config.ts | 1 + package.json | 2 +- src/main/filesystem.ts | 16 + src/main/index.ts | 167 +++++------ src/main/launch.ts | 118 ++++++++ src/main/types.ts | 35 +++ src/main/windows.ts | 29 +- src/preload/splashscreen.ts | 6 +- src/renderer/enterPassword.html | 129 +++++++++ src/renderer/index.css | 63 +++- .../{splashscreen.html => loading.html} | 1 + src/renderer/setupPassword.html | 192 ++++++++++++ src/renderer/setupPasswordOptional.html | 274 ++++++++++++++++++ yarn.lock | 31 +- 15 files changed, 945 insertions(+), 124 deletions(-) create mode 100644 src/main/launch.ts create mode 100644 src/renderer/enterPassword.html rename src/renderer/{splashscreen.html => loading.html} (98%) create mode 100644 src/renderer/setupPassword.html create mode 100644 src/renderer/setupPasswordOptional.html diff --git a/electron.vite.config.ts b/electron.vite.config.ts index 65c3f98..de99f0c 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -21,7 +21,10 @@ export default defineConfig({ input: { indexNotFound: resolve(__dirname, 'src/renderer/indexNotFound.html'), indexNotFound2: resolve(__dirname, 'src/renderer/indexNotFound2.html'), - splashscreen: resolve(__dirname, 'src/renderer/splashscreen.html'), + loading: resolve(__dirname, 'src/renderer/loading.html'), + setupPassword: resolve(__dirname, 'src/renderer/setupPassword.html'), + setupPasswordOptional: resolve(__dirname, 'src/renderer/setupPasswordOptional.html'), + enterPassword: resolve(__dirname, 'src/renderer/enterPassword.html'), }, }, }, diff --git a/kangaroo.config.ts b/kangaroo.config.ts index 3b37bde..92bdf0d 100644 --- a/kangaroo.config.ts +++ b/kangaroo.config.ts @@ -8,6 +8,7 @@ export default defineConfig({ windowsEVCodeSigning: false, fallbackToIndexHtml: true, autoUpdates: true, + passwordMode: 'password-optional', bins: { holochain: { version: '0.4.0-rc.2', diff --git a/package.json b/package.json index 720039c..0595841 100644 --- a/package.json +++ b/package.json @@ -60,4 +60,4 @@ "typescript": "^5.2.2", "vite": "^4.4.9" } -} +} \ No newline at end of file diff --git a/src/main/filesystem.ts b/src/main/filesystem.ts index 8380249..ffcb558 100644 --- a/src/main/filesystem.ts +++ b/src/main/filesystem.ts @@ -1,6 +1,7 @@ import path from 'path'; import fs from 'fs'; import semver from 'semver'; +import { nanoid } from 'nanoid'; import { app } from 'electron'; export type Profile = string; @@ -54,6 +55,7 @@ export class KangarooFileSystem { createDirIfNotExists(configDir); createDirIfNotExists(dataDir); + console.log('userData directory (the one to be deleted for a factory reset): ', app.getPath('userData')); console.log('dataDir: ', dataDir); console.log('logsDir:', logsDir); console.log('configDir: ', configDir); @@ -70,6 +72,20 @@ export class KangarooFileSystem { keystoreInitialized = () => { return fs.existsSync(path.join(this.keystoreDir, 'lair-keystore-config.yaml')); }; + + readOrCreatePassword() { + const pwPath = path.join(this.appDataDir, '.pw'); + if (!fs.existsSync(pwPath)) { + const pw = nanoid(); + fs.writeFileSync(pwPath, pw, 'utf-8'); + } + return fs.readFileSync(pwPath, 'utf-8'); + } + + randomPasswordExists() { + const pwPath = path.join(this.appDataDir, '.pw'); + return fs.existsSync(pwPath); + } } function createDirIfNotExists(path: fs.PathLike) { diff --git a/src/main/index.ts b/src/main/index.ts index b35df66..57e2bf5 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -10,26 +10,19 @@ import { randomNonce, } from '@holochain/client'; import { Command } from 'commander'; -import semver from "semver"; +import semver from 'semver'; import { breakingVersion, KangarooFileSystem } from './filesystem'; import { KangarooEmitter } from './eventEmitter'; import { setupLogs } from './logs'; import { HolochainManager } from './holochainManager'; -import { createHappWindow, createSplashWindow } from './windows'; -import { - DEFAULT_BOOTSTRAP_SERVER, - DEFAULT_SIGNALING_SERVER, - HAPP_APP_ID, - HOLOCHAIN_BINARY, - KANGAROO_CONFIG, - LAIR_BINARY, - UI_DIRECTORY, -} from './const'; -import { initializeLairKeystore, launchLairKeystore } from './lairKeystore'; +import { createSplashWindow } from './windows'; +import { KANGAROO_CONFIG } from './const'; import { kangarooMenu } from './menu'; import { validateArgs } from './cli'; import { autoUpdater, UpdateCheckResult } from '@matthme/electron-updater'; +import { launch } from './launch'; +import { PasswordType, SplashScreenType } from './types'; // Read CLI options @@ -82,8 +75,6 @@ const RUN_OPTIONS = validateArgs(kangarooCli.opts()); // Read and validate the config file to check that the content does not contain // default values -const LAIR_PASSWORD = 'password'; - // Check whether lair is initialized or not and if not, decide based on the config // file whether or not to show the splashscreen or use a default password @@ -161,13 +152,73 @@ let SPLASH_SCREEN_WINDOW: BrowserWindow | undefined; Menu.setApplicationMenu(kangarooMenu(KANGAROO_FILESYSTEM)); app.whenReady().then(async () => { - SPLASH_SCREEN_WINDOW = createSplashWindow(); + /** + * Figure out which splashscreen to show and whether to start holochain immediately. + */ + let splashScreenType: SplashScreenType; + let startImmediately = false; + + if (KANGAROO_CONFIG.passwordMode === 'no-password') { + splashScreenType = SplashScreenType.LoadingOnly; + startImmediately = true; + } else if (KANGAROO_CONFIG.passwordMode === 'password-required') { + if (KANGAROO_FILESYSTEM.keystoreInitialized()) { + splashScreenType = SplashScreenType.EnterPassword; + } else { + splashScreenType = SplashScreenType.PasswordSetup; + } + } else if (KANGAROO_CONFIG.passwordMode === 'password-optional') { + const keystoreInitialized = KANGAROO_FILESYSTEM.keystoreInitialized(); + const randomPwExists = KANGAROO_FILESYSTEM.randomPasswordExists(); + if (keystoreInitialized && randomPwExists) { + splashScreenType = SplashScreenType.LoadingOnly; + startImmediately = true; + } else if (keystoreInitialized && !randomPwExists) { + splashScreenType = SplashScreenType.EnterPassword; + } else { + splashScreenType = SplashScreenType.PasswordSetupOtional; + } + } else { + throw new Error( + `Unexpected setup state.\nKeystore initialized: ${KANGAROO_FILESYSTEM.keystoreInitialized()}.\nPassword mode: ${ + KANGAROO_CONFIG.passwordMode + }\nRandom pw exists: ${KANGAROO_FILESYSTEM.randomPasswordExists()}` + ); + } + + SPLASH_SCREEN_WINDOW = createSplashWindow(splashScreenType); + + /** + * IPC handlers + */ + ipcMain.handle('get-name-and-version', () => ({ + productName: KANGAROO_CONFIG.productName, + version: KANGAROO_CONFIG.version, + })); ipcMain.handle('sign-zome-call', handleSignZomeCall); ipcMain.handle('exit', () => { app.exit(0); }); + // Will be called by the splashscreen UI in the "password-optional" + // or "user-provided" password modes + ipcMain.handle('launch', async (_e, passwordInput: PasswordType): Promise<void> => { + const { lairHandle, holochainManager, mainWindow, zomeCallSigner } = await launch( + KANGAROO_FILESYSTEM, + KANGAROO_EMITTER, + SPLASH_SCREEN_WINDOW, + passwordInput, + RUN_OPTIONS + ); + + LAIR_HANDLE = lairHandle; + HOLOCHAIN_MANAGER = holochainManager; + MAIN_WINDOW = mainWindow; + ZOME_CALL_SIGNER = zomeCallSigner; + }); - // Check for updates + /** + * Checking for app updates + */ if (app.isPackaged && KANGAROO_CONFIG.autoUpdates) { autoUpdater.allowPrerelease = true; autoUpdater.autoDownload = false; @@ -205,76 +256,28 @@ app.whenReady().then(async () => { } } - if (!KANGAROO_FILESYSTEM.keystoreInitialized()) { - if (SPLASH_SCREEN_WINDOW) - SPLASH_SCREEN_WINDOW.webContents.send( - 'loading-progress-update', - 'Initializing lair keystore...' - ); - - console.log('initializing lair keystore...'); - await initializeLairKeystore( - RUN_OPTIONS.lairPath ? RUN_OPTIONS.lairPath : LAIR_BINARY, - KANGAROO_FILESYSTEM.keystoreDir, + /** + * If the conditions are fulfilled we can immediately start holochain here, + * otherwise we start holochain when the corresponding splashscreen UI invokes + * the 'launch' IPC command + */ + if (startImmediately) { + const { lairHandle, holochainManager, mainWindow, zomeCallSigner } = await launch( + KANGAROO_FILESYSTEM, KANGAROO_EMITTER, - LAIR_PASSWORD + SPLASH_SCREEN_WINDOW, + { type: 'random' }, + RUN_OPTIONS ); - console.log('lair keystore initialized.'); - } - if (SPLASH_SCREEN_WINDOW) - SPLASH_SCREEN_WINDOW.webContents.send('loading-progress-update', 'Starting lair keystore...'); - let lairUrl; + LAIR_HANDLE = lairHandle; + HOLOCHAIN_MANAGER = holochainManager; + MAIN_WINDOW = mainWindow; + ZOME_CALL_SIGNER = zomeCallSigner; - [LAIR_HANDLE, lairUrl] = await launchLairKeystore( - RUN_OPTIONS.lairPath ? RUN_OPTIONS.lairPath : LAIR_BINARY, - KANGAROO_FILESYSTEM.keystoreDir, - KANGAROO_EMITTER, - LAIR_PASSWORD - ); - - ZOME_CALL_SIGNER = await ZomeCallSigner.connect(lairUrl, LAIR_PASSWORD); - - if (SPLASH_SCREEN_WINDOW) - SPLASH_SCREEN_WINDOW.webContents.send('loading-progress-update', 'Starting Holochain...'); - - HOLOCHAIN_MANAGER = await HolochainManager.launch( - KANGAROO_EMITTER, - KANGAROO_FILESYSTEM, - RUN_OPTIONS.holochainPath ? RUN_OPTIONS.holochainPath : HOLOCHAIN_BINARY, - LAIR_PASSWORD, - KANGAROO_CONFIG.bins.holochain.version, - KANGAROO_FILESYSTEM.conductorDir, - KANGAROO_FILESYSTEM.conductorConfigPath, - lairUrl, - RUN_OPTIONS.bootstrapUrl ? RUN_OPTIONS.bootstrapUrl.toString() : DEFAULT_BOOTSTRAP_SERVER, - RUN_OPTIONS.signalingUrl ? RUN_OPTIONS.signalingUrl.toString() : DEFAULT_SIGNALING_SERVER, - RUN_OPTIONS.iceUrls ? RUN_OPTIONS.iceUrls : undefined - ); - - // Install happ if necessary - await HOLOCHAIN_MANAGER.installHappIfNecessary(RUN_OPTIONS.networkSeed); - - console.log('Happ installed.'); - - const appToken = await HOLOCHAIN_MANAGER.getAppToken(); - - console.log('Starting main window...'); - - SPLASH_SCREEN_WINDOW.close(); - - MAIN_WINDOW = await createHappWindow( - { - type: 'path', - path: UI_DIRECTORY, - }, - HAPP_APP_ID, - HOLOCHAIN_MANAGER.appPort, - appToken, - false - ); - // This is just here to make it compile for now. - console.log(MAIN_WINDOW); + // Only logged for now to get rid of unused warning + console.log('MAIN_WINDOW: ', MAIN_WINDOW); + } }); // Quit when all windows are closed, except on macOS. There, it's common diff --git a/src/main/launch.ts b/src/main/launch.ts new file mode 100644 index 0000000..bc80d75 --- /dev/null +++ b/src/main/launch.ts @@ -0,0 +1,118 @@ +import * as childProcess from 'child_process'; +import { BrowserWindow } from 'electron'; +import { KangarooEmitter } from './eventEmitter'; +import { KangarooFileSystem } from './filesystem'; +import { PasswordType } from './types'; +import { RunOptions } from './cli'; +import { initializeLairKeystore, launchLairKeystore } from './lairKeystore'; +import { + DEFAULT_BOOTSTRAP_SERVER, + DEFAULT_SIGNALING_SERVER, + HAPP_APP_ID, + HOLOCHAIN_BINARY, + KANGAROO_CONFIG, + LAIR_BINARY, + UI_DIRECTORY, +} from './const'; +import { createHappWindow } from './windows'; +import { ZomeCallSigner } from '@holochain/hc-spin-rust-utils'; +import { HolochainManager } from './holochainManager'; + +export async function launch( + kangarooFs: KangarooFileSystem, + kangarooEmitter: KangarooEmitter, + splashscreenWindow: BrowserWindow | undefined, + passwordInput: PasswordType, + runOptions: RunOptions +): Promise<{ + lairHandle: childProcess.ChildProcessWithoutNullStreams; + holochainManager: HolochainManager; + mainWindow: BrowserWindow; + zomeCallSigner: ZomeCallSigner; +}> { + let password: string; + switch (passwordInput.type) { + case 'random': { + password = kangarooFs.readOrCreatePassword(); + break; + } + case 'user-provided': { + password = passwordInput.password; + break; + } + } + + if (!kangarooFs.keystoreInitialized()) { + if (splashscreenWindow) + splashscreenWindow.webContents.send( + 'loading-progress-update', + 'Initializing lair keystore...' + ); + + console.log('initializing lair keystore...'); + await initializeLairKeystore( + runOptions.lairPath ? runOptions.lairPath : LAIR_BINARY, + kangarooFs.keystoreDir, + kangarooEmitter, + password + ); + console.log('lair keystore initialized.'); + } + if (splashscreenWindow) + splashscreenWindow.webContents.send('loading-progress-update', 'Starting lair keystore...'); + + const [lairHandle, lairUrl] = await launchLairKeystore( + runOptions.lairPath ? runOptions.lairPath : LAIR_BINARY, + kangarooFs.keystoreDir, + kangarooEmitter, + password + ); + + const zomeCallSigner = await ZomeCallSigner.connect(lairUrl, password); + + if (splashscreenWindow) + splashscreenWindow.webContents.send('loading-progress-update', 'Starting Holochain...'); + + const holochainManager = await HolochainManager.launch( + kangarooEmitter, + kangarooFs, + runOptions.holochainPath ? runOptions.holochainPath : HOLOCHAIN_BINARY, + password, + KANGAROO_CONFIG.bins.holochain.version, + kangarooFs.conductorDir, + kangarooFs.conductorConfigPath, + lairUrl, + runOptions.bootstrapUrl ? runOptions.bootstrapUrl.toString() : DEFAULT_BOOTSTRAP_SERVER, + runOptions.signalingUrl ? runOptions.signalingUrl.toString() : DEFAULT_SIGNALING_SERVER, + runOptions.iceUrls ? runOptions.iceUrls : undefined + ); + + // Install happ if necessary + await holochainManager.installHappIfNecessary(runOptions.networkSeed); + + console.log('Happ installed.'); + + const appToken = await holochainManager.getAppToken(); + + console.log('Starting main window...'); + + if (splashscreenWindow) splashscreenWindow.close(); + + const mainWindow = await createHappWindow( + { + type: 'path', + path: UI_DIRECTORY, + }, + HAPP_APP_ID, + holochainManager.appPort, + appToken, + false + ); + + return { + lairHandle, + holochainManager, + mainWindow, + zomeCallSigner, + }; +} diff --git a/src/main/types.ts b/src/main/types.ts index 40e1f57..045f812 100644 --- a/src/main/types.ts +++ b/src/main/types.ts @@ -25,6 +25,23 @@ export type KangarooConfig = { * 0.13.0-alpha.0 -> 0.13.0-alpha.1: *No* breaking change; */ version: string; + /** + * Which password mode to use. Available modes are: + * + * - "no-password": Users do not have to set up a password and kangaroo + * instead generates a random password under the hood + * to encrypt the conductor database and private keys. + * + * - "password-optional": Users can choose once at setup time whether to use + * a password or not. Cannot be changed later and the + * password cannot be reset. + * + * - "password-required": Users have to set up a password when they start the + * app for the first time. This password cannot be reset + * and if users forget it they lose access to their data + * and private keys. + */ + passwordMode: PasswordMode; /** * Whether to attempt macOS code signing in CI. Requires the corresponding * secrets to be available in the github repository. @@ -92,3 +109,21 @@ type VersionAndSha256 = { 'aarch64-apple-darwin': string; }; }; + +export type PasswordMode = 'no-password' | 'password-optional' | 'password-required'; + +export type PasswordType = + | { + type: 'user-provided'; + password: string; + } + | { + type: 'random'; + }; + +export enum SplashScreenType { + LoadingOnly, + EnterPassword, + PasswordSetup, + PasswordSetupOtional, +} diff --git a/src/main/windows.ts b/src/main/windows.ts index e8f7664..65a7b64 100644 --- a/src/main/windows.ts +++ b/src/main/windows.ts @@ -5,6 +5,7 @@ import { AppAuthenticationToken, InstalledAppId } from '@holochain/client'; import { BrowserWindow, NativeImage, nativeImage, net, session, shell } from 'electron'; import { is } from '@electron-toolkit/utils'; import { ICON_PATH, KANGAROO_CONFIG } from './const'; +import { SplashScreenType } from './types'; export type UISource = | { @@ -131,6 +132,7 @@ export const createHappWindow = async ( return happWindow; } } else { + // eslint-disable-next-line @typescript-eslint/no-explicit-any throw new Error(`Unsupported uiSource type: ${(uiSource as any).type}`); } @@ -182,7 +184,27 @@ export function setLinkOpenHandlers(browserWindow: BrowserWindow): void { }); } -export const createSplashWindow = (): BrowserWindow => { +export const createSplashWindow = (type: SplashScreenType): BrowserWindow => { + let htmlFile: string; + switch (type) { + case SplashScreenType.EnterPassword: { + htmlFile = 'enterPassword.html'; + break; + } + case SplashScreenType.LoadingOnly: { + htmlFile = 'loading.html'; + break; + } + case SplashScreenType.PasswordSetup: { + htmlFile = 'setupPassword.html'; + break; + } + case SplashScreenType.PasswordSetupOtional: { + htmlFile = 'setupPasswordOptional.html'; + break; + } + } + const splashWindow = new BrowserWindow({ height: 450, width: 800, @@ -196,11 +218,10 @@ export const createSplashWindow = (): BrowserWindow => { }, }); - // and load the splashscreen.html of the app. if (is.dev && process.env['ELECTRON_RENDERER_URL']) { - splashWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/splashscreen.html`); + splashWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/${htmlFile}`); } else { - splashWindow.loadFile(path.join(__dirname, '../renderer/splashscreen.html')); + splashWindow.loadFile(path.join(__dirname, `../renderer/${htmlFile}`)); } splashWindow.once('ready-to-show', () => { diff --git a/src/preload/splashscreen.ts b/src/preload/splashscreen.ts index ff881d1..5f878f6 100644 --- a/src/preload/splashscreen.ts +++ b/src/preload/splashscreen.ts @@ -1,12 +1,14 @@ // See the Electron documentation for details on how to use preload scripts: // https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts import { contextBridge, ipcRenderer } from 'electron'; +import { PasswordType } from '../main/types'; contextBridge.exposeInMainWorld('electronAPI', { onProgressUpdate: (callback) => ipcRenderer.on('loading-progress-update', callback), onNameAndVersion: (callback) => ipcRenderer.on('name-and-version', callback), - lairSetupRequired: () => ipcRenderer.invoke('lair-setup-required'), - launch: (password: string) => ipcRenderer.invoke('launch', password), getProfile: () => ipcRenderer.invoke('get-profile'), + getNameAndVersion: () => ipcRenderer.invoke('get-name-and-version'), + lairSetupRequired: () => ipcRenderer.invoke('lair-setup-required'), + launch: (passwordInput: PasswordType) => ipcRenderer.invoke('launch', passwordInput), exit: () => ipcRenderer.invoke('exit'), }); diff --git a/src/renderer/enterPassword.html b/src/renderer/enterPassword.html new file mode 100644 index 0000000..cc440f1 --- /dev/null +++ b/src/renderer/enterPassword.html @@ -0,0 +1,129 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <link rel="stylesheet" type="text/css" href="index.css" /> + </head> + <body> + <div id="app" class="splash-wrapper"> + <div class="splash-content-wrapper"> + <div> + <div id="productName" class="splash-product-name"></div> + <div id="version" class="splash-version"></div> + </div> + <div class="content column"> + <div class="column items-center" id="password-creation-container"> + <!-- Choose password --> + <div class="column items-center" id="enter-password-div"> + <h2>Enter password</h2> + <input + class="pw-input" + type="password" + id="enter-password-input" + placeholder="password" + /> + <div class="warning" id="warning-1"></div> + <button style="margin-top: 5px" id="launch-btn" disabled>Launch</button> + </div> + </div> + + <!-- Loading message --> + <div class="splash-loading-message hidden" id="activity">Loading...</div> + </div> + <div class="splash-license">Licensed under the Cryptographic Autonomy License v1.0</div> + </div> + <img + style="position: absolute; bottom: 5px; right: 10px; width: 300px" + src="img/powered_by_holochain.png" + /> + <img + tabindex="0" + id="close-btn" + title="close" + style="cursor: pointer; position: absolute; top: 5px; right: 5px; width: 35px" + src="img/close.svg" + /> + </div> + <script> + // TODO add event listener for holochain fatal panic case + + let password = ''; + + (async () => { + const { productName, version } = await window.electronAPI.getNameAndVersion(); + document.getElementById('productName').innerHTML = productName; + document.getElementById('version').innerHTML = `version ${version}`; + })(); + + const activitEl = document.getElementById('activity'); + window.electronAPI.onProgressUpdate((event, msg) => { + console.log('status', msg); + activitEl.innerHTML = msg; + }); + + const closeBtn = document.getElementById('close-btn'); + closeBtn.addEventListener('click', () => { + window.electronAPI.exit(); + }); + closeBtn.addEventListener('keypress', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + window.electronAPI.exit(); + } + }); + + const enterPwDiv = document.getElementById('enter-password-div'); + + const warningEl = document.getElementById('warning-1'); + + const enterPwInput = document.getElementById('enter-password-input'); + + enterPwInput.focus(); + + const handleLaunch = async () => { + enterPwDiv.classList.add('hidden'); + activitEl.classList.remove('hidden'); + try { + await window.electronAPI.launch({ type: 'user-provided', password }); + } catch (e) { + console.error('Failed to launch: ', e); + activitEl.innerHTML = ''; + activitEl.classList.add('hidden'); + enterPwDiv.classList.remove('hidden'); + if (e.toString().includes('Wrong password.')) { + password = ''; + enterPwInput.value = ''; + warningEl.innerHTML = 'Wrong Password.'; + setTimeout(() => { + enterPwInput.focus(); + }); + } else { + // TODO add logic to offer exporting log files + warningEl.innerHTML = `ERROR: Failed to launch Holochain.`; + } + } + }; + + enterPwInput.addEventListener('input', (e) => { + password = enterPwInput.value; + if (!password) { + launchBtn.disabled = true; + } else { + launchBtn.disabled = false; + } + warningEl.innerHTML = ''; + }); + + enterPwDiv.addEventListener('keypress', async (e) => { + if (e.key === 'Enter') { + await handleLaunch(password); + } + }); + + // Add event listener to "Launch" button + const launchBtn = document.getElementById('launch-btn'); + launchBtn.addEventListener('click', async () => { + await handleLaunch(); + }); + </script> + </body> +</html> diff --git a/src/renderer/index.css b/src/renderer/index.css index c9c63e6..767e87f 100644 --- a/src/renderer/index.css +++ b/src/renderer/index.css @@ -11,7 +11,34 @@ body { margin: 0; padding: 0; /* to match the main window */ - background-color: #f7f5f3; + font-family: 'gilroyextrabold', Helvetica, sans-serif; + /* background: linear-gradient(90deg, #0edad3, #4622e3); */ +} + +.flex { + display: flex; +} + +.column { + display: flex; + flex-direction: column; +} + +.row { + display: flex; + flex-direction: row; +} + +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + +.hidden { + display: none; } .splash-wrapper { @@ -20,11 +47,6 @@ body { } .splash-image-wrapper { - background-color: #fff; - /* background-image: url('img/iuliu-illes-MkMvM2T0gVE-unsplash.jpg'); */ - background-repeat: no-repeat; - background-size: cover; - background-position: center; width: 320px; height: 450px; padding: 30px; @@ -86,4 +108,33 @@ body { position: absolute; bottom: 3px; left: 5px; +} + +.pw-input { + height: 30px; + width: 200px; + border-radius: 5px; + font-size: 16px; +} + +button { + height: 26px; + min-width: 80px; + cursor: pointer; +} + +.warning { + color: rgb(193, 0, 0); + font-size: 14px; + min-height: 16px; +} + +.red { + color: rgb(193, 0, 0); +} + +.previous-step-btn { + position: fixed; + top: 6px; + left: 6px; } \ No newline at end of file diff --git a/src/renderer/splashscreen.html b/src/renderer/loading.html similarity index 98% rename from src/renderer/splashscreen.html rename to src/renderer/loading.html index d0e95b8..f4b63f9 100644 --- a/src/renderer/splashscreen.html +++ b/src/renderer/loading.html @@ -21,6 +21,7 @@ <img tabindex="0" id="close-btn" + title="close" style="cursor: pointer; position: absolute; top: 5px; right: 5px; width: 35px" src="img/close.svg" /> diff --git a/src/renderer/setupPassword.html b/src/renderer/setupPassword.html new file mode 100644 index 0000000..40172be --- /dev/null +++ b/src/renderer/setupPassword.html @@ -0,0 +1,192 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <link rel="stylesheet" type="text/css" href="index.css" /> + </head> + <body> + <div id="app" class="splash-wrapper"> + <div class="splash-content-wrapper"> + <div> + <div id="productName" class="splash-product-name"></div> + <div id="version" class="splash-version"></div> + </div> + <div class="content column"> + <div class="column items-center" id="password-creation-container"> + <!-- Choose password --> + <div class="column items-center" id="choose-password-div"> + <h2>Choose a password</h2> + <div style="text-align: center; margin-bottom: 20px"> + This password will be used to encrypt your data and private keys on your device.<br /> + <b + >It cannot be reset and is not backed up by any central authority.<br /><u + >If you forget it you lose access to your data</u + ></b + > + </div> + <input + class="pw-input" + type="password" + id="choose-password-input" + placeholder="password" + /> + <div class="warning" id="warning-1"></div> + <button style="margin-top: 5px" id="continue-btn" disabled>Continue</button> + </div> + + <!-- Confirm password --> + <div class="column items-center hidden" id="confirm-password-div"> + <h2>Confirm password</h2> + <button class="previous-step-btn" id="previous-step-btn">< previous step</button> + <input + class="pw-input" + type="password" + id="confirm-password-input" + placeholder="password" + /> + <div class="warning" id="warning-2"></div> + <div class="row" style="max-width: 400px; align-items: flex-start;" id="understood-div"> + <input type="checkbox" id="understood-checkbox"/> + <span style="margin-left: 5px;">I understood that I cannot reset this password because there is no central authority storing it for me and that <b>I will lose access to my data if I forget it</b>.</span> + </div> + <button style="margin-top: 5px" id="launch-btn" disabled>Launch</button> + </div> + </div> + + <!-- Loading message --> + <div class="splash-loading-message hidden" id="activity">Setting up Holochain...</div> + </div> + <div class="splash-license">Licensed under the Cryptographic Autonomy License v1.0</div> + </div> + <img + style="position: absolute; bottom: 5px; right: 10px; width: 300px" + src="img/powered_by_holochain.png" + /> + <img + tabindex="0" + id="close-btn" + title="close" + style="cursor: pointer; position: absolute; top: 5px; right: 5px; width: 35px" + src="img/close.svg" + /> + </div> + <script> + // TODO add event listener for holochain fatal panic case + + let password = ''; + let confirmedPassword = ''; + + (async () => { + const { productName, version } = await window.electronAPI.getNameAndVersion(); + document.getElementById('productName').innerHTML = productName; + document.getElementById('version').innerHTML = `version ${version}`; + })(); + const activitEl = document.getElementById('activity'); + window.electronAPI.onProgressUpdate((event, msg) => { + console.log('status', msg); + activitEl.innerHTML = msg; + }); + const closeBtn = document.getElementById('close-btn'); + closeBtn.addEventListener('click', () => { + window.electronAPI.exit(); + }); + closeBtn.addEventListener('keypress', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + window.electronAPI.exit(); + } + }); + + const choosePwDiv = document.getElementById('choose-password-div'); + const confirmPwDiv = document.getElementById('confirm-password-div'); + const continueBtn = document.getElementById('continue-btn'); + const choosePwInput = document.getElementById('choose-password-input'); + const confirmPwInput = document.getElementById('confirm-password-input'); + const warning1El = document.getElementById('warning-1'); + const warning2El = document.getElementById('warning-2'); + const launchBtn = document.getElementById('launch-btn'); + const previousStepBtn = document.getElementById('previous-step-btn'); + const understoodDiv = document.getElementById('understood-div'); + const understoodCheckbox = document.getElementById('understood-checkbox'); + + const handleLaunch = async () => { + if (password !== confirmedPassword) { + warning2El.innerHTML = "Passwords don't match!"; + confirmPwInput.focus(); + } else if (!understoodCheckbox.checked) { + understoodDiv.classList.add('red'); + } else { + confirmPwDiv.classList.add('hidden'); + activitEl.classList.remove('hidden'); + try { + await window.electronAPI.launch({ type: "user-provided", password }); + } catch (e) { + console.error('Failed to launch: ', e); + activitEl.innerHTML = ''; + password = ''; + choosePwInput.value = ''; + confirmedPassword = ''; + confirmPwInput.value = ''; + activitEl.classList.add('hidden'); + choosePwDiv.classList.remove('hidden'); + warning1El.innerHTML = `ERROR: Failed to launch Holochain.`; + setTimeout(() => choosePwInput.focus()); + } + } + }; + + continueBtn.addEventListener('click', () => { + choosePwDiv.classList.add('hidden'); + confirmPwDiv.classList.remove('hidden'); + confirmPwInput.focus(); + }); + + choosePwInput.addEventListener('input', (e) => { + password = choosePwInput.value; + if (!password) { + continueBtn.disabled = true; + } else { + continueBtn.disabled = false; + } + }); + + choosePwInput.addEventListener('keypress', async (e) => { + if (e.key === 'Enter') { + choosePwDiv.classList.add('hidden'); + confirmPwDiv.classList.remove('hidden'); + confirmPwInput.focus(); + } + }); + + confirmPwInput.addEventListener('input', (e) => { + confirmedPassword = confirmPwInput.value; + warning2El.innerHTML = ''; + if (!confirmedPassword) { + launchBtn.disabled = true; + } else { + launchBtn.disabled = false; + } + }); + + previousStepBtn.addEventListener('click', () => { + password = ''; + confirmedPassword = ''; + choosePwInput.value = ''; + confirmPwInput.value = ''; + warning2El.innerHTML = ''; + choosePwDiv.classList.remove('hidden'); + confirmPwDiv.classList.add('hidden'); + understoodDiv.classList.remove('red'); + understoodCheckbox.checked = false; + choosePwInput.focus(); + }); + + launchBtn.addEventListener('click', handleLaunch); + + confirmPwInput.addEventListener('keypress', async (e) => { + if (e.key === 'Enter') { + await handleLaunch(); + } + }); + </script> + </body> +</html> diff --git a/src/renderer/setupPasswordOptional.html b/src/renderer/setupPasswordOptional.html new file mode 100644 index 0000000..906f02f --- /dev/null +++ b/src/renderer/setupPasswordOptional.html @@ -0,0 +1,274 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <link rel="stylesheet" type="text/css" href="index.css" /> + </head> + <body> + <div id="app" class="splash-wrapper"> + <div class="splash-content-wrapper"> + <div> + <div id="productName" class="splash-product-name"></div> + <div id="version" class="splash-version"></div> + </div> + <div class="content column"> + <div class="column items-center" id="password-creation-container"> + <!-- Choose setup method --> + <div class="column items-center" id="choose-setup-div"> + <h2>Setup</h2> + <div + style="max-width: 700px; text-align: center; line-height: 1.5" + id="choose-setup-sentence" + ></div> + <div style="max-width: 500px; text-align: center; line-height: 1.5"> + The password will be used to encrypt your data locally on your device. + </div> + <div + style=" + max-width: 500px; + text-align: center; + line-height: 1.5; + font-weight: bold; + margin-bottom: 20px; + " + > + A password cannot be added, changed or removed later. + </div> + <button style="margin-bottom: 2px" id="with-password-btn">Setup With Password</button> + <button style="margin-top: 5px" id="without-password-btn"> + Setup Without Password + </button> + <div class="warning" id="warning-1" style="margin-top: 5px"></div> + </div> + + <!-- Choose password --> + <div class="column items-center hidden" id="choose-password-div"> + <button class="previous-step-btn" id="previous-step-btn-0">< previous step</button> + <h2>Choose a password</h2> + <div style="text-align: center; margin-bottom: 20px"> + This password will be used to encrypt your data and private keys on your device.<br /> + <b + >It cannot be reset and is not backed up by any central authority.<br /><u + >If you forget it you lose access to your data</u + ></b + > + </div> + <input + class="pw-input" + type="password" + id="choose-password-input" + placeholder="password" + /> + <div class="warning" id="warning-1"></div> + <button style="margin-top: 5px" id="continue-btn" disabled>Continue</button> + </div> + + <!-- Confirm password --> + <div class="column items-center hidden" id="confirm-password-div"> + <h2>Confirm password</h2> + <button class="previous-step-btn" id="previous-step-btn">< previous step</button> + <input + class="pw-input" + type="password" + id="confirm-password-input" + placeholder="password" + /> + <div class="warning" id="warning-2"></div> + <div + class="row" + style="max-width: 400px; align-items: flex-start" + id="understood-div" + > + <input type="checkbox" id="understood-checkbox" /> + <span style="margin-left: 5px" + >I understood that I cannot reset this password because there is no central + authority storing it for me and that + <b>I will lose access to my data if I forget it</b>.</span + > + </div> + <button style="margin-top: 5px" id="launch-btn" disabled>Launch</button> + </div> + </div> + + <!-- Loading message --> + <div class="splash-loading-message hidden" id="activity">Setting up Holochain...</div> + </div> + <div class="splash-license">Licensed under the Cryptographic Autonomy License v1.0</div> + </div> + <img + style="position: absolute; bottom: 5px; right: 10px; width: 300px" + src="img/powered_by_holochain.png" + /> + <img + tabindex="0" + id="close-btn" + title="close" + style="cursor: pointer; position: absolute; top: 5px; right: 5px; width: 35px" + src="img/close.svg" + /> + </div> + <script> + // TODO add event listener for holochain fatal panic case + + let password = ''; + let confirmedPassword = ''; + + (async () => { + const { productName, version } = await window.electronAPI.getNameAndVersion(); + document.getElementById('productName').innerHTML = productName; + document.getElementById('version').innerHTML = `version ${version}`; + document.getElementById( + 'choose-setup-sentence' + ).innerHTML = `Choose whether you want to set up ${productName} with or without a password.`; + })(); + + const activitEl = document.getElementById('activity'); + window.electronAPI.onProgressUpdate((event, msg) => { + console.log('status', msg); + activitEl.innerHTML = msg; + }); + const closeBtn = document.getElementById('close-btn'); + closeBtn.addEventListener('click', () => { + window.electronAPI.exit(); + }); + closeBtn.addEventListener('keypress', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + window.electronAPI.exit(); + } + }); + + const chooseSetupDiv = document.getElementById('choose-setup-div'); + const withPwBtn = document.getElementById('with-password-btn'); + const withoutPwBtn = document.getElementById('without-password-btn'); + const warning0El = document.getElementById('warning-0'); + + const choosePwDiv = document.getElementById('choose-password-div'); + const choosePwInput = document.getElementById('choose-password-input'); + const continueBtn = document.getElementById('continue-btn'); + const warning1El = document.getElementById('warning-1'); + const previousStepBtn0 = document.getElementById('previous-step-btn-0'); + + const confirmPwDiv = document.getElementById('confirm-password-div'); + const confirmPwInput = document.getElementById('confirm-password-input'); + const launchBtn = document.getElementById('launch-btn'); + const warning2El = document.getElementById('warning-2'); + const previousStepBtn = document.getElementById('previous-step-btn'); + const understoodDiv = document.getElementById('understood-div'); + const understoodCheckbox = document.getElementById('understood-checkbox'); + + const handleLaunch = async () => { + if (password !== confirmedPassword) { + warning2El.innerHTML = "Passwords don't match!"; + confirmPwInput.focus(); + } else if (!understoodCheckbox.checked) { + understoodDiv.classList.add('red'); + } else { + confirmPwDiv.classList.add('hidden'); + activitEl.classList.remove('hidden'); + try { + await window.electronAPI.launch({ type: "user-provided", password }); + } catch (e) { + console.error('Failed to launch: ', e); + activitEl.innerHTML = ''; + password = ''; + choosePwInput.value = ''; + confirmedPassword = ''; + confirmPwInput.value = ''; + activitEl.classList.add('hidden'); + confirmPwDiv.classList.remove('hidden'); + warning1El.innerHTML = `ERROR: Failed to launch Holochain.`; + setTimeout(() => choosePwInput.focus()); + } + } + }; + + withPwBtn.addEventListener('click', () => { + chooseSetupDiv.classList.add('hidden'); + choosePwDiv.classList.remove('hidden'); + }); + + previousStepBtn0.addEventListener('click', () => { + password = ''; + confirmedPassword = ''; + choosePwInput.value = ''; + confirmPwInput.value = ''; + choosePwDiv.classList.add('hidden'); + chooseSetupDiv.classList.remove('hidden'); + }); + + withoutPwBtn.addEventListener('click', async () => { + try { + chooseSetupDiv.classList.add('hidden'); + activitEl.classList.remove('hidden'); + await window.electronAPI.launch({ type: 'random' }); + } catch (e) { + console.error('Failed to launch: ', e); + activitEl.innerHTML = ''; + password = ''; + choosePwInput.value = ''; + confirmedPassword = ''; + confirmPwInput.value = ''; + activitEl.classList.add('hidden'); + chooseSetupDiv.classList.remove('hidden'); + warning1El.innerHTML = `ERROR: Failed to launch Holochain.`; + setTimeout(() => choosePwInput.focus()); + confirmPwInput.focus(); + } + }); + + continueBtn.addEventListener('click', () => { + choosePwDiv.classList.add('hidden'); + confirmPwDiv.classList.remove('hidden'); + confirmPwInput.focus(); + }); + + choosePwInput.addEventListener('input', (e) => { + password = choosePwInput.value; + if (!password) { + continueBtn.disabled = true; + } else { + continueBtn.disabled = false; + } + }); + + choosePwInput.addEventListener('keypress', async (e) => { + if (e.key === 'Enter') { + choosePwDiv.classList.add('hidden'); + confirmPwDiv.classList.remove('hidden'); + confirmPwInput.focus(); + } + }); + + confirmPwInput.addEventListener('input', (e) => { + confirmedPassword = confirmPwInput.value; + warning2El.innerHTML = ''; + if (!confirmedPassword) { + launchBtn.disabled = true; + } else { + launchBtn.disabled = false; + } + }); + + previousStepBtn.addEventListener('click', () => { + password = ''; + confirmedPassword = ''; + choosePwInput.value = ''; + confirmPwInput.value = ''; + warning2El.innerHTML = ''; + choosePwDiv.classList.remove('hidden'); + confirmPwDiv.classList.add('hidden'); + understoodDiv.classList.remove('red'); + understoodCheckbox.checked = false; + choosePwInput.focus(); + }); + + launchBtn.addEventListener('click', handleLaunch); + + confirmPwInput.addEventListener('keypress', async (e) => { + if (e.key === 'Enter') { + await handleLaunch(); + } + }); + </script> + </body> +</html> diff --git a/yarn.lock b/yarn.lock index 4727535..276a3b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4453,16 +4453,7 @@ stat-mode@^1.0.0: resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-1.0.0.tgz#68b55cb61ea639ff57136f36b216a291800d1465" integrity sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4515,14 +4506,7 @@ string_decoder@^1.1.1, string_decoder@^1.3.0: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -4958,16 +4942,7 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== From be753f055e4b35b9bd03a7092352a4775b0798bf Mon Sep 17 00:00:00 2001 From: matthme <36768177+matthme@users.noreply.github.com> Date: Fri, 3 Jan 2025 16:28:05 +0100 Subject: [PATCH 14/16] bump kangaroo to holochain 0.4.0 (#24) --- kangaroo.config.ts | 10 ++-- package.json | 4 +- src/main/holochainManager.ts | 2 +- yarn.lock | 112 +++++++++++++++++------------------ 4 files changed, 64 insertions(+), 64 deletions(-) diff --git a/kangaroo.config.ts b/kangaroo.config.ts index 92bdf0d..a862791 100644 --- a/kangaroo.config.ts +++ b/kangaroo.config.ts @@ -11,14 +11,14 @@ export default defineConfig({ passwordMode: 'password-optional', bins: { holochain: { - version: '0.4.0-rc.2', + version: '0.4.0', sha256: { 'x86_64-unknown-linux-gnu': - '7110f9b0c9c2b4bbc974543df1b633299c7fa8d3d16f3cde4dc894ac64c0670f', + 'f2e5d5c5c90a0c5eb85641bd8ab207396ddbbc304aaa51982dfde24037a0d0a9', 'x86_64-pc-windows-msvc.exe': - '959fca4b575c6791196fcd1fb9c6c7a92359191dbd60e95b7800c6e79bb21687', - 'x86_64-apple-darwin': 'a62d1b6413f2791ec4df87338d794a7ba29a0890f1a2ceb1ed9eeddb0efc94a7', - 'aarch64-apple-darwin': 'f25bee4cb2615b1970a8ef89c82dcfb867682a3502962343d4842571aafb9bc3', + '9b893527d1f4c1e69fa3c9fbd605987065087ca15ebc72bbe598edef9ab5b27a', + 'x86_64-apple-darwin': '9d8e4996dd86441ec859faf9fa90c31bdfaddd49d5079bf67492d9c93d17c503', + 'aarch64-apple-darwin': '1d206d09ddf90c85b781457514df3c87d8c7e38a6dab4e53f01a8f089acfa3d1', }, }, lair: { diff --git a/package.json b/package.json index 0595841..76aedd1 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,8 @@ "@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/utils": "^3.0.0", "@holochain/client": "0.18.0-rc.1", - "@holochain/hc-spin-rust-utils": "0.400.0-rc.1", - "@lightningrodlabs/we-rust-utils": "0.400.0-rc.1", + "@holochain/hc-spin-rust-utils": "0.400.0", + "@lightningrodlabs/we-rust-utils": "0.400.0", "@matthme/electron-updater": "6.3.0-alpha.1", "@msgpack/msgpack": "^2.8.0", "adm-zip": "0.5.14", diff --git a/src/main/holochainManager.ts b/src/main/holochainManager.ts index dec9dac..2dd6258 100644 --- a/src/main/holochainManager.ts +++ b/src/main/holochainManager.ts @@ -162,7 +162,7 @@ export class HolochainManager { }); } - async installHappIfNecessary(networkSeed) { + async installHappIfNecessary(networkSeed: string) { const installedApps = await this.adminWebsocket.listApps({}); if (installedApps.map((appInfo) => appInfo.installed_app_id).includes(HAPP_APP_ID)) return; console.log(`Installing happ...`); diff --git a/yarn.lock b/yarn.lock index 276a3b7..dde3960 100644 --- a/yarn.lock +++ b/yarn.lock @@ -585,35 +585,35 @@ lodash-es "^4.17.21" ws "^8.14.2" -"@holochain/hc-spin-rust-utils-darwin-arm64@0.400.0-rc.1": - version "0.400.0-rc.1" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-arm64/-/hc-spin-rust-utils-darwin-arm64-0.400.0-rc.1.tgz#b8ba066394b297d8d8ffd4f6d5bad2b42ad6575c" - integrity sha512-Q9tB/NSt3EcFDXefx+3XMWiiw5TBH/aec7vTUoZZudXqFP6yLvIhd82mufRrunL7GBzUIH/slg0MfKiSkg1elw== - -"@holochain/hc-spin-rust-utils-darwin-x64@0.400.0-rc.1": - version "0.400.0-rc.1" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-x64/-/hc-spin-rust-utils-darwin-x64-0.400.0-rc.1.tgz#5b06bb1e707a0d49b91564deb36e092ef7ae3eda" - integrity sha512-B0yhrmqOqXzABne1IF/mFJmefuCj2otGyMSgwuv0lIrtu9rhe9y8qyrhMBO5ybICmDc3xgBDuE6tBxof5AReYA== - -"@holochain/hc-spin-rust-utils-linux-x64-gnu@0.400.0-rc.1": - version "0.400.0-rc.1" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-linux-x64-gnu/-/hc-spin-rust-utils-linux-x64-gnu-0.400.0-rc.1.tgz#3d8d49d499d368890b405596fc81909d96372f2a" - integrity sha512-8G3pVBBBKmN0RatnvoLbIXztVNsNchqDv9zlEJ4piepDxRhELnaFh8Dy0u5NGsqbnjFZt/NIkxqdm5F3KKQTuw== - -"@holochain/hc-spin-rust-utils-win32-x64-msvc@0.400.0-rc.1": - version "0.400.0-rc.1" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-win32-x64-msvc/-/hc-spin-rust-utils-win32-x64-msvc-0.400.0-rc.1.tgz#41604f98c41cb329c5a352bec707f195e15a50fe" - integrity sha512-xEBpXWqWSNyYdsKOGUERUQSDPDNa6cE93PI1y7YL2kukmzEAocX4GOPzi+IYh4iUttcrkVpJpeway6fGQfAEjg== - -"@holochain/hc-spin-rust-utils@0.400.0-rc.1": - version "0.400.0-rc.1" - resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils/-/hc-spin-rust-utils-0.400.0-rc.1.tgz#550e7c30b49e38423820dca46b337d6569b41ea4" - integrity sha512-AJo18PYnoDS+45eBpGRNGiHa9UBhe92PzsboG2I8+Ajk2giwcT6bFvl4TM3QymA22xcjWfRoBBCCP0P+CCEGig== +"@holochain/hc-spin-rust-utils-darwin-arm64@0.400.0": + version "0.400.0" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-arm64/-/hc-spin-rust-utils-darwin-arm64-0.400.0.tgz#7773c68bb0e9d040b0c08b4979fa84d04a2755d8" + integrity sha512-FL/pnutrsj7AfIyml4flM2FpMMjm6KCDfaR+e+xB9d4dyFxAc1h9YcuUDHZkAGBhqCiLJ5FtiIOHqu770XCQIg== + +"@holochain/hc-spin-rust-utils-darwin-x64@0.400.0": + version "0.400.0" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-darwin-x64/-/hc-spin-rust-utils-darwin-x64-0.400.0.tgz#2ae2a28e07844a74e94c41500784ba4bf146346a" + integrity sha512-FThpisR49A/lMFA1yv5IDrCSZQe7/s48xRf85iVNYl1aUM/ftKOcEFzwEQe+cN+nzJLhi8vJzZDAyBVdCKB7Mg== + +"@holochain/hc-spin-rust-utils-linux-x64-gnu@0.400.0": + version "0.400.0" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-linux-x64-gnu/-/hc-spin-rust-utils-linux-x64-gnu-0.400.0.tgz#464239e843d55eaf3bd39e4c957fe0e7cadcb248" + integrity sha512-13d/Wn0/73OdQ+B8Zf8xM3naiZlqIva/8rQvgUQTRQszgMrIuTz64hZ0goAG0rhxR+TzfY3MPUys17KfWIjSBw== + +"@holochain/hc-spin-rust-utils-win32-x64-msvc@0.400.0": + version "0.400.0" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils-win32-x64-msvc/-/hc-spin-rust-utils-win32-x64-msvc-0.400.0.tgz#735b1470e6a675f11ad8588f02b6fa42ca0e4e30" + integrity sha512-5/GxzAEAQyVy9ZXF6Py+jUA3d5RktjhYSWx+FF6OqOkTKmkg5e/XX8srDFWdL5GEi/gW/47NRZVqdjD3LYvjEA== + +"@holochain/hc-spin-rust-utils@0.400.0": + version "0.400.0" + resolved "https://registry.yarnpkg.com/@holochain/hc-spin-rust-utils/-/hc-spin-rust-utils-0.400.0.tgz#6215f2b2ff6d8e083e17d1cc248b0af210e7fc79" + integrity sha512-yNfrqAD3l7rgr2abhuPcb/7/zi4VR4QQCCJMvsE6rwl2D2NtFC0PMiBk34kVCdABQqJyFRgaPoDAA0ll9Yic2Q== optionalDependencies: - "@holochain/hc-spin-rust-utils-darwin-arm64" "0.400.0-rc.1" - "@holochain/hc-spin-rust-utils-darwin-x64" "0.400.0-rc.1" - "@holochain/hc-spin-rust-utils-linux-x64-gnu" "0.400.0-rc.1" - "@holochain/hc-spin-rust-utils-win32-x64-msvc" "0.400.0-rc.1" + "@holochain/hc-spin-rust-utils-darwin-arm64" "0.400.0" + "@holochain/hc-spin-rust-utils-darwin-x64" "0.400.0" + "@holochain/hc-spin-rust-utils-linux-x64-gnu" "0.400.0" + "@holochain/hc-spin-rust-utils-win32-x64-msvc" "0.400.0" "@holochain/serialization@^0.1.0-beta-rc.3": version "0.1.0-beta-rc.3" @@ -691,35 +691,35 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@lightningrodlabs/we-rust-utils-darwin-arm64@0.400.0-rc.1": - version "0.400.0-rc.1" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-arm64/-/we-rust-utils-darwin-arm64-0.400.0-rc.1.tgz#b43ee7dd47dfe7696cab9fd5bda7adf07948c297" - integrity sha512-ZrvfCdorPV+F1X+hdEO/ZdU1dPrHkS3LMbZc31lqMSNvas6+ndmnrWJ62L67RcI+Yh/DNKhYV6i7Ou4Si5p6HA== - -"@lightningrodlabs/we-rust-utils-darwin-x64@0.400.0-rc.1": - version "0.400.0-rc.1" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-x64/-/we-rust-utils-darwin-x64-0.400.0-rc.1.tgz#5ed96082fac2d04be8211c3c8b14d31276b3a5b9" - integrity sha512-lzyBjEeFxrYy8eviVlOg2e1m6nHJCNwnwFtJgg880b/BbMKDPP2hDLm10yIu0SOCdxaLXJRt4nKE16oiQm5hwA== - -"@lightningrodlabs/we-rust-utils-linux-x64-gnu@0.400.0-rc.1": - version "0.400.0-rc.1" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-linux-x64-gnu/-/we-rust-utils-linux-x64-gnu-0.400.0-rc.1.tgz#84388e6a74658dc99766ff1f5478e7a4873e8256" - integrity sha512-AsWFWK75e8k40g1aE5UZdsk62la8KVBzL+SQsfiIg4ss5NimwtHNJfzIs1jwUjTg1Blee3e1nt5igVMuOiscyg== - -"@lightningrodlabs/we-rust-utils-win32-x64-msvc@0.400.0-rc.1": - version "0.400.0-rc.1" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-win32-x64-msvc/-/we-rust-utils-win32-x64-msvc-0.400.0-rc.1.tgz#a4f5abe189ed1228810cc15197637238b434c9e6" - integrity sha512-UvBhvLVLiDwojgh8knJ8GOoRAJTz0D6aWfmoAQ0tC9cU90WMcN+8ZMC/nLqwuqqpxQEJ55Z34+Hfm6r7LKh0nQ== - -"@lightningrodlabs/we-rust-utils@0.400.0-rc.1": - version "0.400.0-rc.1" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils/-/we-rust-utils-0.400.0-rc.1.tgz#24bbef3e372ac1bfbe1b802ca55454458462f918" - integrity sha512-W0/gLf5Eg9tePOPRMpjw4sKHEcq8P39ucOlMQrDawPRD0rhdAXr5OAGMNMlvT4fAIOgcwyEyoAwDRu/vdTOqkg== +"@lightningrodlabs/we-rust-utils-darwin-arm64@0.400.0": + version "0.400.0" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-arm64/-/we-rust-utils-darwin-arm64-0.400.0.tgz#ecaec34ea442155783b72bbd05634c1428273f81" + integrity sha512-uGRp+oZ3ghZTfZZAVKLxb0b/QxM3xRZkiOLcdTx7DkBDOkTKGd85gXkUMk1azGThDc0HbOnuDQlx4LTK3I3EIw== + +"@lightningrodlabs/we-rust-utils-darwin-x64@0.400.0": + version "0.400.0" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-x64/-/we-rust-utils-darwin-x64-0.400.0.tgz#4dd0de818c1fb1c0cd3941369dd26454b1fee569" + integrity sha512-k061/M4rgWE/5GeuNDpdXw0L5KdTkX+KXtLJKBoGgy0FcEYvr4f8v2BETWRMP8d9ZPdw7DOh6lzxcOhx0HWHJw== + +"@lightningrodlabs/we-rust-utils-linux-x64-gnu@0.400.0": + version "0.400.0" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-linux-x64-gnu/-/we-rust-utils-linux-x64-gnu-0.400.0.tgz#f4ad691b0787ec82fa671434a90d0c1a5ba60950" + integrity sha512-mTlECeugVa6dawIcgCCi46U68s+eKwHUfX7XdwOgwDmjeCDp+kFsheXo93McUC4fmj3WYk2BEv94HMVaGb26xg== + +"@lightningrodlabs/we-rust-utils-win32-x64-msvc@0.400.0": + version "0.400.0" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-win32-x64-msvc/-/we-rust-utils-win32-x64-msvc-0.400.0.tgz#7e953b006e58772f36e5b3e8f2f382c11ac6819d" + integrity sha512-46cKe5CIz1nz7Slb1J5HMLt4CVMFsUQcrru2/TLk9c5krbV1DjYK89O8FJyLRnObJGzXThc+OpH8L0GBIV1otg== + +"@lightningrodlabs/we-rust-utils@0.400.0": + version "0.400.0" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils/-/we-rust-utils-0.400.0.tgz#6ead42c3bc9ce9d33efc2c95b73107f99015a1a9" + integrity sha512-vVZElVkTl10d9KU26sQ6Ix2UDgvpBkLyDFrbS9o5HoBSh0IjnR4Bozn01EMmPh5gmTPdEL7HHFwPBhRhdahoLA== optionalDependencies: - "@lightningrodlabs/we-rust-utils-darwin-arm64" "0.400.0-rc.1" - "@lightningrodlabs/we-rust-utils-darwin-x64" "0.400.0-rc.1" - "@lightningrodlabs/we-rust-utils-linux-x64-gnu" "0.400.0-rc.1" - "@lightningrodlabs/we-rust-utils-win32-x64-msvc" "0.400.0-rc.1" + "@lightningrodlabs/we-rust-utils-darwin-arm64" "0.400.0" + "@lightningrodlabs/we-rust-utils-darwin-x64" "0.400.0" + "@lightningrodlabs/we-rust-utils-linux-x64-gnu" "0.400.0" + "@lightningrodlabs/we-rust-utils-win32-x64-msvc" "0.400.0" "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" From f867d678b11ceba500e69a9dfdecf249b2552eb4 Mon Sep 17 00:00:00 2001 From: matthme <36768177+matthme@users.noreply.github.com> Date: Mon, 13 Jan 2025 21:54:07 +0000 Subject: [PATCH 15/16] (feat) systray option (#25) * bump kangaroo to holochain 0.4.0 * add optional systray logic * revert accidentally changed package name --- kangaroo.config.ts | 1 + package.json | 3 +- scripts/create-icons.js | 23 +- src/main/const.ts | 3 + src/main/holochainManager.ts | 4 +- src/main/index.ts | 168 +++++++---- src/main/menu.ts | 2 +- src/main/types.ts | 5 + src/main/windows.ts | 9 +- yarn.lock | 543 +++++++++++++++++++++++++++++++++-- 10 files changed, 675 insertions(+), 86 deletions(-) diff --git a/kangaroo.config.ts b/kangaroo.config.ts index a862791..73a605d 100644 --- a/kangaroo.config.ts +++ b/kangaroo.config.ts @@ -8,6 +8,7 @@ export default defineConfig({ windowsEVCodeSigning: false, fallbackToIndexHtml: true, autoUpdates: true, + systray: true, passwordMode: 'password-optional', bins: { holochain: { diff --git a/package.json b/package.json index 76aedd1..47d1e77 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@electron-toolkit/utils": "^3.0.0", "@holochain/client": "0.18.0-rc.1", "@holochain/hc-spin-rust-utils": "0.400.0", - "@lightningrodlabs/we-rust-utils": "0.400.0", + "@lightningrodlabs/we-rust-utils": "0.400.1", "@matthme/electron-updater": "6.3.0-alpha.1", "@msgpack/msgpack": "^2.8.0", "adm-zip": "0.5.14", @@ -50,6 +50,7 @@ "electron-vite": "^2.3.0", "eslint": "^8.0.1", "eslint-plugin-import": "^2.25.0", + "jimp": "^1.6.0", "js-yaml": "4.1.0", "make-dir-cli": "^3.1.0", "ncp": "^2.0.0", diff --git a/scripts/create-icons.js b/scripts/create-icons.js index 3680ae7..6445bc8 100644 --- a/scripts/create-icons.js +++ b/scripts/create-icons.js @@ -2,10 +2,11 @@ const fs = require('fs'); const path = require('path'); const png2icons = require('png2icons'); +const jimp = require('jimp'); generateIcons(); -function generateIcons() { +async function generateIcons() { const uiDir = path.join('resources', 'ui'); const buildDir = 'build'; @@ -30,11 +31,31 @@ function generateIcons() { console.log('Generating icon.ico'); const icoIcon = png2icons.createICO(pngBuffer, png2icons.BICUBIC2, 0, false, true); fs.writeFileSync(icoOutPath, icoIcon); + } else { + fs.cpSync(icoPath, icoOutPath); } if (!fs.existsSync(icnsPath)) { console.log('Generating icon.icns'); const icnsIcon = png2icons.createICNS(pngBuffer, png2icons.BILINEAR, 0); fs.writeFileSync(icnsOutPath, icnsIcon); + } else { + fs.cpSync(icnsPath, icnsOutPath); } + + // Generate the systray icon + console.log('Generating systray icon'); + const systrayIcon = await jimp.Jimp.fromBuffer(pngBuffer); + systrayIcon.resize({ w: 64, h: 64}); + const iconsDir = path.join('resources', 'icons'); + if (!fs.existsSync(iconsDir)) { + fs.mkdirSync(iconsDir); + } + systrayIcon.write(path.join(iconsDir, '32x32@2.png')); + + // Generate the icon for OS notifications + console.log('Generating notifications icon'); + const icon128x128 = await jimp.Jimp.fromBuffer(pngBuffer); + icon128x128.resize({ w: 128, h: 128}); + icon128x128.write(path.join(iconsDir, '128x128.png')); } diff --git a/src/main/const.ts b/src/main/const.ts index a375fb8..22424fd 100644 --- a/src/main/const.ts +++ b/src/main/const.ts @@ -41,6 +41,9 @@ export const UI_DIRECTORY = path.join(RESOURCES_DIRECTORY, 'ui'); export const ICON_PATH = path.join(RESOURCES_DIRECTORY, 'ui', 'icon.png'); +export const SYSTRAY_ICON_PATH = path.join(RESOURCES_DIRECTORY, 'icons', '32x32@2.png'); +export const NOTIFICATIONS_ICON_PATH = path.join(RESOURCES_DIRECTORY, 'icons', '128x128.png'); + export const isMac = process.platform === 'darwin'; export const isWindows = process.platform === 'win32'; export const isLinux = process.platform === 'linux'; diff --git a/src/main/holochainManager.ts b/src/main/holochainManager.ts index 2dd6258..b22c28d 100644 --- a/src/main/holochainManager.ts +++ b/src/main/holochainManager.ts @@ -28,7 +28,7 @@ export class HolochainManager { constructor( processHandle: childProcess.ChildProcessWithoutNullStreams, kangarooEmitter: KangarooEmitter, - mossFileSystem: KangarooFileSystem, + kangarooFileSystem: KangarooFileSystem, adminPort: AdminPort, appPort: AppPort, adminWebsocket: AdminWebsocket, @@ -40,7 +40,7 @@ export class HolochainManager { this.adminPort = adminPort; this.appPort = appPort; this.adminWebsocket = adminWebsocket; - this.fs = mossFileSystem; + this.fs = kangarooFileSystem; this.installedApps = installedApps; this.version = version; } diff --git a/src/main/index.ts b/src/main/index.ts index 57e2bf5..03d3654 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,4 +1,16 @@ -import { app, BrowserWindow, dialog, ipcMain, IpcMainInvokeEvent, Menu, protocol } from 'electron'; +import { + app, + BrowserWindow, + dialog, + ipcMain, + IpcMainInvokeEvent, + Menu, + nativeImage, + protocol, + Tray, + Notification, + Event +} from 'electron'; import childProcess from 'child_process'; import { ZomeCallNapi, ZomeCallSigner, ZomeCallUnsignedNapi } from '@holochain/hc-spin-rust-utils'; import contextMenu from 'electron-context-menu'; @@ -17,7 +29,7 @@ import { KangarooEmitter } from './eventEmitter'; import { setupLogs } from './logs'; import { HolochainManager } from './holochainManager'; import { createSplashWindow } from './windows'; -import { KANGAROO_CONFIG } from './const'; +import { KANGAROO_CONFIG, NOTIFICATIONS_ICON_PATH, SYSTRAY_ICON_PATH } from './const'; import { kangarooMenu } from './menu'; import { validateArgs } from './cli'; import { autoUpdater, UpdateCheckResult } from '@matthme/electron-updater'; @@ -148,6 +160,7 @@ let LAIR_HANDLE: childProcess.ChildProcessWithoutNullStreams | undefined; // eslint-disable-next-line @typescript-eslint/no-unused-vars let MAIN_WINDOW: BrowserWindow | undefined | null; let SPLASH_SCREEN_WINDOW: BrowserWindow | undefined; +let IS_APP_QUITTING = false; Menu.setApplicationMenu(kangarooMenu(KANGAROO_FILESYSTEM)); @@ -187,6 +200,57 @@ app.whenReady().then(async () => { } SPLASH_SCREEN_WINDOW = createSplashWindow(splashScreenType); + SPLASH_SCREEN_WINDOW.on('closed', () => { + // We need to drop the variable here to be able to distinguish + // in other places whether the splah screen window is still open + // or not. + SPLASH_SCREEN_WINDOW = undefined; + }); + + if (KANGAROO_CONFIG.systray) { + const systray = new Tray(SYSTRAY_ICON_PATH); + systray.setToolTip(KANGAROO_CONFIG.productName); + + const contextMenu = Menu.buildFromTemplate([ + { + label: 'Open', + type: 'normal', + click() { + if (SPLASH_SCREEN_WINDOW) { + SPLASH_SCREEN_WINDOW.show(); + } else if(MAIN_WINDOW) { + MAIN_WINDOW.show(); + } + }, + }, + { + label: 'Restart', + type: 'normal', + click() { + const options: Electron.RelaunchOptions = { + args: process.argv, + }; + // /~https://github.com/electron-userland/electron-builder/issues/1727#issuecomment-769896927 + if (process.env.APPIMAGE) { + console.log('process.execPath: ', process.execPath); + options.args?.unshift('--appimage-extract-and-run'); + options.execPath = process.env.APPIMAGE; + } + app.relaunch(options); + app.quit(); + }, + }, + { + label: 'Quit', + type: 'normal', + click() { + app.quit(); + }, + }, + ]); + + systray.setContextMenu(contextMenu); + } /** * IPC handlers @@ -214,6 +278,10 @@ app.whenReady().then(async () => { HOLOCHAIN_MANAGER = holochainManager; MAIN_WINDOW = mainWindow; ZOME_CALL_SIGNER = zomeCallSigner; + + if (KANGAROO_CONFIG.systray) { + MAIN_WINDOW.on('close', mainWindowCloseHandler); + } }); /** @@ -275,8 +343,9 @@ app.whenReady().then(async () => { MAIN_WINDOW = mainWindow; ZOME_CALL_SIGNER = zomeCallSigner; - // Only logged for now to get rid of unused warning - console.log('MAIN_WINDOW: ', MAIN_WINDOW); + if (KANGAROO_CONFIG.systray) { + MAIN_WINDOW.on('close', mainWindowCloseHandler); + } } }); @@ -290,6 +359,14 @@ app.on('window-all-closed', () => { // } }); +// This is here to distinguish in the 'close' listener of the main window, +// for the case that a systray icon is used, whether the main window should +// indeed be closed (if the app is attempted to be quit via the systray menu) +// or only hidden +app.on('before-quit', () => { + IS_APP_QUITTING = true; +}); + app.on('quit', () => { if (LAIR_HANDLE) { LAIR_HANDLE.kill(); @@ -299,49 +376,40 @@ app.on('quit', () => { } }); -// app.on("activate", () => { -// // On OS X it's common to re-create a window in the app when the -// // dock icon is clicked and there are no other windows open. -// if (BrowserWindow.getAllWindows().length === 0) { -// createMainWindow(); -// } -// }); - -// const contextMenu = Menu.buildFromTemplate([ -// { -// label: 'Open', -// type: 'normal', -// click() { -// if (SPLASH_SCREEN_WINDOW) { -// SPLASH_SCREEN_WINDOW.show(); -// } else if (MAIN_WINDOW) { -// MAIN_WINDOW.show(); -// } -// }, -// }, -// { -// label: 'Restart', -// type: 'normal', -// click() { -// const options: Electron.RelaunchOptions = { -// args: process.argv, -// }; -// // /~https://github.com/electron-userland/electron-builder/issues/1727#issuecomment-769896927 -// if (process.env.APPIMAGE) { -// console.log('process.execPath: ', process.execPath); -// options.args?.unshift('--appimage-extract-and-run'); -// options.execPath = process.env.APPIMAGE; -// } -// app.relaunch(options); -// app.quit(); -// }, -// }, -// { -// label: 'Quit', -// type: 'normal', -// click() { -// app.quit(); -// }, -// }, -// ]); -// }); +/** + * This handler will make sure that the main window only gets hidden instead of + * closed (to maintain the javascript state) if the systray icon option is + * used. + * + * @param e Window close event + */ +const mainWindowCloseHandler = (e: Event) => { + if (!IS_APP_QUITTING && MAIN_WINDOW) { + e.preventDefault(); + MAIN_WINDOW.hide(); + + const notificationIcon = nativeImage.createFromPath(NOTIFICATIONS_ICON_PATH); + new Notification({ + title: `${KANGAROO_CONFIG.productName} keeps running in the background`, + body: `To close ${KANGAROO_CONFIG.productName} and stop synching with peers, quit from the icon in the system tray.`, + icon: notificationIcon, + }) + .on('click', async () => { + if (MAIN_WINDOW) { + MAIN_WINDOW.show(); + const response = await dialog.showMessageBox(MAIN_WINDOW, { + type: 'info', + message: `${KANGAROO_CONFIG.productName} keeps running in the background if you close the Window.\n\nThis is to keep synchronizing data with peers.\n\nDo you want to quit ${KANGAROO_CONFIG.productName} fully?`, + buttons: ['Keep Running', 'Quit'], + defaultId: 0, + cancelId: 1, + }); + if (response.response === 1) { + app.quit(); + } + } + }) + .show(); + } + console.log("Is main window still defined?", MAIN_WINDOW); +}; diff --git a/src/main/menu.ts b/src/main/menu.ts index 66db8b2..96380d7 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -28,7 +28,7 @@ export const kangarooMenu = (kangarooFs: KangarooFileSystem) => { const exportToPathResponse = await dialog.showSaveDialog({ title: 'Export Logs', buttonLabel: 'Export', - defaultPath: `Moss_${app.getVersion()}_logs_${new Date().toISOString()}.zip`, + defaultPath: `${KANGAROO_CONFIG.productName}_${app.getVersion()}_logs_${new Date().toISOString()}.zip`, }); if (exportToPathResponse.filePath) { zip.writeZip(exportToPathResponse.filePath); diff --git a/src/main/types.ts b/src/main/types.ts index 045f812..b7f28b4 100644 --- a/src/main/types.ts +++ b/src/main/types.ts @@ -63,6 +63,11 @@ export type KangarooConfig = { * and prompt to install and restart if a new release is available. */ autoUpdates: boolean; + /** + * Whether or not to use a systray. If true, the app will remain running in the background + * upon closing its window and can be re-opened via its icon in the systray. + */ + systray: boolean; // /** // * Whether or not the app should have the user set up a password. // */ diff --git a/src/main/windows.ts b/src/main/windows.ts index 65a7b64..d935022 100644 --- a/src/main/windows.ts +++ b/src/main/windows.ts @@ -2,7 +2,14 @@ import path from 'path'; import fs from 'fs'; import url from 'url'; import { AppAuthenticationToken, InstalledAppId } from '@holochain/client'; -import { BrowserWindow, NativeImage, nativeImage, net, session, shell } from 'electron'; +import { + BrowserWindow, + NativeImage, + nativeImage, + net, + session, + shell, +} from 'electron'; import { is } from '@electron-toolkit/utils'; import { ICON_PATH, KANGAROO_CONFIG } from './const'; import { SplashScreenType } from './types'; diff --git a/yarn.lock b/yarn.lock index dde3960..364f47e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -651,6 +651,279 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" +"@jimp/core@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/core/-/core-1.6.0.tgz#3ef241bf02f40431bb382aea665e5187a2c05eef" + integrity sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w== + dependencies: + "@jimp/file-ops" "1.6.0" + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + await-to-js "^3.0.0" + exif-parser "^0.1.12" + file-type "^16.0.0" + mime "3" + +"@jimp/diff@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/diff/-/diff-1.6.0.tgz#f8d058bfad64751c5e5c135499d1a784f797c5c8" + integrity sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw== + dependencies: + "@jimp/plugin-resize" "1.6.0" + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + pixelmatch "^5.3.0" + +"@jimp/file-ops@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/file-ops/-/file-ops-1.6.0.tgz#ae9c6aa65b2c9a5a16515a8fdf83b55f51100087" + integrity sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ== + +"@jimp/js-bmp@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/js-bmp/-/js-bmp-1.6.0.tgz#ff7c4306e764745063e249ee926d0dd807924abf" + integrity sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + bmp-ts "^1.0.9" + +"@jimp/js-gif@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/js-gif/-/js-gif-1.6.0.tgz#0efa5d83317a89d6eda936e2ae1df2b7d122a38d" + integrity sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/types" "1.6.0" + gifwrap "^0.10.1" + omggif "^1.0.10" + +"@jimp/js-jpeg@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/js-jpeg/-/js-jpeg-1.6.0.tgz#e47da6758346548079f0ac8ff215d0d9d1ec435e" + integrity sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/types" "1.6.0" + jpeg-js "^0.4.4" + +"@jimp/js-png@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/js-png/-/js-png-1.6.0.tgz#c857adfdbfcb7107a6511c3b2939ffbad0fefedc" + integrity sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/types" "1.6.0" + pngjs "^7.0.0" + +"@jimp/js-tiff@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/js-tiff/-/js-tiff-1.6.0.tgz#f18fa3d59f52fda339acfdcadbe7363bed912e81" + integrity sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/types" "1.6.0" + utif2 "^4.1.0" + +"@jimp/plugin-blit@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-blit/-/plugin-blit-1.6.0.tgz#fed35aefbb5757599a4299a9ff6c06cc3466f46f" + integrity sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA== + dependencies: + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-blur@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-blur/-/plugin-blur-1.6.0.tgz#781b3be9de2744e5eb6ab86ec05ee7d2ce5092e8" + integrity sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/utils" "1.6.0" + +"@jimp/plugin-circle@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-circle/-/plugin-circle-1.6.0.tgz#2314dc7955068cb4a000de4eceb02890eb131c88" + integrity sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw== + dependencies: + "@jimp/types" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-color@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-color/-/plugin-color-1.6.0.tgz#927c83ee932070ad285266840728c21ac39bf27b" + integrity sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + tinycolor2 "^1.6.0" + zod "^3.23.8" + +"@jimp/plugin-contain@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-contain/-/plugin-contain-1.6.0.tgz#d08900ecf85ac564a6f9f3fc0d61cc8d5e43626e" + integrity sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/plugin-blit" "1.6.0" + "@jimp/plugin-resize" "1.6.0" + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-cover@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-cover/-/plugin-cover-1.6.0.tgz#07ffb2f3d6ac53616c66f1131cd66ced17e3ca3e" + integrity sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/plugin-crop" "1.6.0" + "@jimp/plugin-resize" "1.6.0" + "@jimp/types" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-crop@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-crop/-/plugin-crop-1.6.0.tgz#59f2b20869330fd768d1743d845b8ba9ed9bc52a" + integrity sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-displace@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-displace/-/plugin-displace-1.6.0.tgz#41b3257a6c0f64c749c29c1a2e64ba7df31a7a25" + integrity sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q== + dependencies: + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-dither@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-dither/-/plugin-dither-1.6.0.tgz#10c17070dcbec565904f11b7986e90ae20850b6f" + integrity sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ== + dependencies: + "@jimp/types" "1.6.0" + +"@jimp/plugin-fisheye@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-fisheye/-/plugin-fisheye-1.6.0.tgz#2831c0060598b27bf004bf8a70adfeec003d4fcc" + integrity sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA== + dependencies: + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-flip@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-flip/-/plugin-flip-1.6.0.tgz#75c87bdb0f0ca9db44b320cc9671aa201e52b5c3" + integrity sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg== + dependencies: + "@jimp/types" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-hash@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-hash/-/plugin-hash-1.6.0.tgz#8de89dfbbb6be671f9cdb2b59816acf3f07c4298" + integrity sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/js-bmp" "1.6.0" + "@jimp/js-jpeg" "1.6.0" + "@jimp/js-png" "1.6.0" + "@jimp/js-tiff" "1.6.0" + "@jimp/plugin-color" "1.6.0" + "@jimp/plugin-resize" "1.6.0" + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + any-base "^1.1.0" + +"@jimp/plugin-mask@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-mask/-/plugin-mask-1.6.0.tgz#2b5a437e5d9a9906dcabb7a7baf4d5cd7d2361b1" + integrity sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA== + dependencies: + "@jimp/types" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-print@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-print/-/plugin-print-1.6.0.tgz#ccef327f53afb47617aa66ca65435447380faf34" + integrity sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/js-jpeg" "1.6.0" + "@jimp/js-png" "1.6.0" + "@jimp/plugin-blit" "1.6.0" + "@jimp/types" "1.6.0" + parse-bmfont-ascii "^1.0.6" + parse-bmfont-binary "^1.0.6" + parse-bmfont-xml "^1.1.6" + simple-xml-to-json "^1.2.2" + zod "^3.23.8" + +"@jimp/plugin-quantize@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-quantize/-/plugin-quantize-1.6.0.tgz#880095fc0ead41321d94bf54895e366dd7d079d6" + integrity sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg== + dependencies: + image-q "^4.0.0" + zod "^3.23.8" + +"@jimp/plugin-resize@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-resize/-/plugin-resize-1.6.0.tgz#331e8912ed68746846145019bc6e2ea057e6f175" + integrity sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/types" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-rotate@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-rotate/-/plugin-rotate-1.6.0.tgz#de271f39a3ac9e853b02e01d3d44ab086d12e099" + integrity sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/plugin-crop" "1.6.0" + "@jimp/plugin-resize" "1.6.0" + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + zod "^3.23.8" + +"@jimp/plugin-threshold@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/plugin-threshold/-/plugin-threshold-1.6.0.tgz#11479cf59131ea95dcaff6a1403af1964593a3fa" + integrity sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/plugin-color" "1.6.0" + "@jimp/plugin-hash" "1.6.0" + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + zod "^3.23.8" + +"@jimp/types@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/types/-/types-1.6.0.tgz#27022730fd673653e1430e6bd8ac6f6de1596f89" + integrity sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg== + dependencies: + zod "^3.23.8" + +"@jimp/utils@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jimp/utils/-/utils-1.6.0.tgz#e196f3953ea1ebc88f50cf0d490adb24aeffe596" + integrity sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA== + dependencies: + "@jimp/types" "1.6.0" + tinycolor2 "^1.6.0" + "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" @@ -691,35 +964,35 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@lightningrodlabs/we-rust-utils-darwin-arm64@0.400.0": - version "0.400.0" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-arm64/-/we-rust-utils-darwin-arm64-0.400.0.tgz#ecaec34ea442155783b72bbd05634c1428273f81" - integrity sha512-uGRp+oZ3ghZTfZZAVKLxb0b/QxM3xRZkiOLcdTx7DkBDOkTKGd85gXkUMk1azGThDc0HbOnuDQlx4LTK3I3EIw== - -"@lightningrodlabs/we-rust-utils-darwin-x64@0.400.0": - version "0.400.0" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-x64/-/we-rust-utils-darwin-x64-0.400.0.tgz#4dd0de818c1fb1c0cd3941369dd26454b1fee569" - integrity sha512-k061/M4rgWE/5GeuNDpdXw0L5KdTkX+KXtLJKBoGgy0FcEYvr4f8v2BETWRMP8d9ZPdw7DOh6lzxcOhx0HWHJw== - -"@lightningrodlabs/we-rust-utils-linux-x64-gnu@0.400.0": - version "0.400.0" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-linux-x64-gnu/-/we-rust-utils-linux-x64-gnu-0.400.0.tgz#f4ad691b0787ec82fa671434a90d0c1a5ba60950" - integrity sha512-mTlECeugVa6dawIcgCCi46U68s+eKwHUfX7XdwOgwDmjeCDp+kFsheXo93McUC4fmj3WYk2BEv94HMVaGb26xg== - -"@lightningrodlabs/we-rust-utils-win32-x64-msvc@0.400.0": - version "0.400.0" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-win32-x64-msvc/-/we-rust-utils-win32-x64-msvc-0.400.0.tgz#7e953b006e58772f36e5b3e8f2f382c11ac6819d" - integrity sha512-46cKe5CIz1nz7Slb1J5HMLt4CVMFsUQcrru2/TLk9c5krbV1DjYK89O8FJyLRnObJGzXThc+OpH8L0GBIV1otg== - -"@lightningrodlabs/we-rust-utils@0.400.0": - version "0.400.0" - resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils/-/we-rust-utils-0.400.0.tgz#6ead42c3bc9ce9d33efc2c95b73107f99015a1a9" - integrity sha512-vVZElVkTl10d9KU26sQ6Ix2UDgvpBkLyDFrbS9o5HoBSh0IjnR4Bozn01EMmPh5gmTPdEL7HHFwPBhRhdahoLA== +"@lightningrodlabs/we-rust-utils-darwin-arm64@0.400.1": + version "0.400.1" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-arm64/-/we-rust-utils-darwin-arm64-0.400.1.tgz#4c024f18326dee2b7ed8cb9bba4503be579693e4" + integrity sha512-gBmkFmioy8oXN5iQySGzZq8tjfJ2SGs6X9flp3vsbYgX1gtIqFSUTsdxJz+ZjIzxsH2Jvj8Kz++/wGVuT09dPg== + +"@lightningrodlabs/we-rust-utils-darwin-x64@0.400.1": + version "0.400.1" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-darwin-x64/-/we-rust-utils-darwin-x64-0.400.1.tgz#4518eed480e2e6edd94d2e5625706f7aa29e62c1" + integrity sha512-sBagev9/+YKR7wLYMOBUyZZzWMgZDieTnT7fiP5AGM1iwJ2CLMgAIQ0xiaYQFDCQ3rLg7tUdX+2iMxLrtTtQ/w== + +"@lightningrodlabs/we-rust-utils-linux-x64-gnu@0.400.1": + version "0.400.1" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-linux-x64-gnu/-/we-rust-utils-linux-x64-gnu-0.400.1.tgz#9cdeb4b895c0486e30203bdac5de226132cf5587" + integrity sha512-KirgXwKi75mtVGnUzj4aYUN9US0yNM+Az0+vAD8rubPSysHV+47HL1GWLAOHqHwvQ0fT6VWOKB4qSkngJP2b7A== + +"@lightningrodlabs/we-rust-utils-win32-x64-msvc@0.400.1": + version "0.400.1" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils-win32-x64-msvc/-/we-rust-utils-win32-x64-msvc-0.400.1.tgz#2113e12e73f10b5498b184580f96985477bf914c" + integrity sha512-t/p+Nzt+LpIJqo4oM6ofO0Kj51ptWQWzisWX3/5Ch+NDUaKZp3RODzLok+pM1vvoxsL+eyt3MaOLo5oNC8UgUg== + +"@lightningrodlabs/we-rust-utils@0.400.1": + version "0.400.1" + resolved "https://registry.yarnpkg.com/@lightningrodlabs/we-rust-utils/-/we-rust-utils-0.400.1.tgz#d2417b7bdb3abffe4d39710a497b74a6d4e35e99" + integrity sha512-Dv86gqeVHg+RATe5LO3uVdElqU2SgQxD8PMc3Ao+g2CQRK/RBc5ls2CGAxFDoTlTFJgVpqT65I6BSgayCIeU7g== optionalDependencies: - "@lightningrodlabs/we-rust-utils-darwin-arm64" "0.400.0" - "@lightningrodlabs/we-rust-utils-darwin-x64" "0.400.0" - "@lightningrodlabs/we-rust-utils-linux-x64-gnu" "0.400.0" - "@lightningrodlabs/we-rust-utils-win32-x64-msvc" "0.400.0" + "@lightningrodlabs/we-rust-utils-darwin-arm64" "0.400.1" + "@lightningrodlabs/we-rust-utils-darwin-x64" "0.400.1" + "@lightningrodlabs/we-rust-utils-linux-x64-gnu" "0.400.1" + "@lightningrodlabs/we-rust-utils-win32-x64-msvc" "0.400.1" "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" @@ -1020,6 +1293,11 @@ dependencies: defer-to-connect "^2.0.0" +"@tokenizer/token@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276" + integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A== + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -1126,6 +1404,11 @@ dependencies: undici-types "~6.19.2" +"@types/node@16.9.1": + version "16.9.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708" + integrity sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g== + "@types/node@^20.9.0": version "20.16.10" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.10.tgz#0cc3fdd3daf114a4776f54ba19726a01c907ef71" @@ -1435,6 +1718,11 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== +any-base@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" + integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== + app-builder-bin@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-4.0.0.tgz#1df8e654bd1395e4a319d82545c98667d7eed2f0" @@ -1596,6 +1884,11 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" +await-to-js@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/await-to-js/-/await-to-js-3.0.0.tgz#70929994185616f4675a91af6167eb61cc92868f" + integrity sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -1623,6 +1916,11 @@ bluebird@^3.5.5: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== +bmp-ts@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/bmp-ts/-/bmp-ts-1.0.9.tgz#0fd124ba812be9b786b29e5b186ee76d74ff5538" + integrity sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw== + boolean@^3.0.1: version "3.2.0" resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b" @@ -2626,6 +2924,11 @@ events@^3.3.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +exif-parser@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922" + integrity sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw== + ext-list@^2.0.0: version "2.2.2" resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" @@ -2714,6 +3017,15 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-type@^16.0.0: + version "16.5.4" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-16.5.4.tgz#474fb4f704bee427681f98dd390058a172a6c2fd" + integrity sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw== + dependencies: + readable-web-to-node-stream "^3.0.0" + strtok3 "^6.2.4" + token-types "^4.1.1" + filelist@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" @@ -2886,6 +3198,14 @@ get-symbol-description@^1.0.2: es-errors "^1.3.0" get-intrinsic "^1.2.4" +gifwrap@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.10.1.tgz#9ed46a5d51913b482d4221ce9c727080260b681e" + integrity sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw== + dependencies: + image-q "^4.0.0" + omggif "^1.0.10" + glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -3115,6 +3435,13 @@ ignore@^5.2.0, ignore@^5.2.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== +image-q@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/image-q/-/image-q-4.0.0.tgz#31e075be7bae3c1f42a85c469b4732c358981776" + integrity sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw== + dependencies: + "@types/node" "16.9.1" + import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -3357,6 +3684,44 @@ jake@^10.8.5: filelist "^1.0.4" minimatch "^3.1.2" +jimp@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/jimp/-/jimp-1.6.0.tgz#7c7e5133c8dc06706e1ed35e771c685af393bfd2" + integrity sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg== + dependencies: + "@jimp/core" "1.6.0" + "@jimp/diff" "1.6.0" + "@jimp/js-bmp" "1.6.0" + "@jimp/js-gif" "1.6.0" + "@jimp/js-jpeg" "1.6.0" + "@jimp/js-png" "1.6.0" + "@jimp/js-tiff" "1.6.0" + "@jimp/plugin-blit" "1.6.0" + "@jimp/plugin-blur" "1.6.0" + "@jimp/plugin-circle" "1.6.0" + "@jimp/plugin-color" "1.6.0" + "@jimp/plugin-contain" "1.6.0" + "@jimp/plugin-cover" "1.6.0" + "@jimp/plugin-crop" "1.6.0" + "@jimp/plugin-displace" "1.6.0" + "@jimp/plugin-dither" "1.6.0" + "@jimp/plugin-fisheye" "1.6.0" + "@jimp/plugin-flip" "1.6.0" + "@jimp/plugin-hash" "1.6.0" + "@jimp/plugin-mask" "1.6.0" + "@jimp/plugin-print" "1.6.0" + "@jimp/plugin-quantize" "1.6.0" + "@jimp/plugin-resize" "1.6.0" + "@jimp/plugin-rotate" "1.6.0" + "@jimp/plugin-threshold" "1.6.0" + "@jimp/types" "1.6.0" + "@jimp/utils" "1.6.0" + +jpeg-js@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa" + integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg== + js-base64@^3.7.5: version "3.7.7" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79" @@ -3639,6 +4004,11 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" +mime@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + mime@^2.5.2: version "2.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" @@ -3870,6 +4240,11 @@ octokit@4.0.2: "@octokit/request-error" "^6.0.0" "@octokit/types" "^13.0.0" +omggif@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19" + integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw== + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -3920,6 +4295,11 @@ package-json-from-dist@^1.0.0: resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== +pako@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -3927,6 +4307,24 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-bmfont-ascii@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz#11ac3c3ff58f7c2020ab22769079108d4dfa0285" + integrity sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA== + +parse-bmfont-binary@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz#d038b476d3e9dd9db1e11a0b0e53a22792b69006" + integrity sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA== + +parse-bmfont-xml@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz#016b655da7aebe6da38c906aca16bf0415773767" + integrity sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA== + dependencies: + xml-parse-from-string "^1.0.0" + xml2js "^0.5.0" + parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -3970,6 +4368,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +peek-readable@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-4.1.0.tgz#4ece1111bf5c2ad8867c314c81356847e8a62e72" + integrity sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg== + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -3985,6 +4388,13 @@ picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pixelmatch@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.3.0.tgz#5e5321a7abedfb7962d60dbf345deda87cb9560a" + integrity sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q== + dependencies: + pngjs "^6.0.0" + plist@^3.0.4, plist@^3.0.5: version "3.1.0" resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9" @@ -3999,6 +4409,16 @@ png2icons@2.0.1: resolved "https://registry.yarnpkg.com/png2icons/-/png2icons-2.0.1.tgz#09d8f10b71302e98ca178d3324bc4deff9b90124" integrity sha512-GDEQJr8OG4e6JMp7mABtXFSEpgJa1CCpbQiAR+EjhkHJHnUL9zPPtbOrjsMD8gUbikgv3j7x404b0YJsV3aVFA== +pngjs@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821" + integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== + +pngjs@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-7.0.0.tgz#a8b7446020ebbc6ac739db6c5415a65d17090e26" + integrity sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow== + possible-typed-array-names@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" @@ -4104,7 +4524,7 @@ read-pkg@^6.0.0: parse-json "^5.2.0" type-fest "^1.0.1" -readable-stream@^3.4.0: +readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -4124,6 +4544,13 @@ readable-stream@^4.5.2: process "^0.11.10" string_decoder "^1.3.0" +readable-web-to-node-stream@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz#5d52bb5df7b54861fd48d015e93a2cb87b3ee0bb" + integrity sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw== + dependencies: + readable-stream "^3.6.0" + redent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-4.0.0.tgz#0c0ba7caabb24257ab3bb7a4fd95dd1d5c5681f9" @@ -4264,7 +4691,7 @@ sanitize-filename@^1.6.3: dependencies: truncate-utf8-bytes "^1.0.0" -sax@^1.2.4: +sax@>=0.6.0, sax@^1.2.4: version "1.4.1" resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== @@ -4354,6 +4781,11 @@ simple-update-notifier@2.0.0: dependencies: semver "^7.5.3" +simple-xml-to-json@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/simple-xml-to-json/-/simple-xml-to-json-1.2.3.tgz#79c7188ff99ae209a267b70ee0db06b0e4597787" + integrity sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -4537,6 +4969,14 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strtok3@^6.2.4: + version "6.3.0" + resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-6.3.0.tgz#358b80ffe6d5d5620e19a073aa78ce947a90f9a0" + integrity sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw== + dependencies: + "@tokenizer/token" "^0.3.0" + peek-readable "^4.1.0" + sumchecker@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42" @@ -4611,6 +5051,11 @@ tiny-typed-emitter@^2.1.0: resolved "https://registry.yarnpkg.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz#b3b027fdd389ff81a152c8e847ee2f5be9fad7b5" integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA== +tinycolor2@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" + integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== + tmp-promise@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.3.tgz#60a1a1cc98c988674fcbfd23b6e3367bdeac4ce7" @@ -4635,6 +5080,14 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +token-types@^4.1.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/token-types/-/token-types-4.2.1.tgz#0f897f03665846982806e138977dbe72d44df753" + integrity sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ== + dependencies: + "@tokenizer/token" "^0.3.0" + ieee754 "^1.2.1" + trim-newlines@^4.0.2: version "4.1.1" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-4.1.1.tgz#28c88deb50ed10c7ba6dc2474421904a00139125" @@ -4844,6 +5297,13 @@ utf8-byte-length@^1.0.1: resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz#f9f63910d15536ee2b2d5dd4665389715eac5c1e" integrity sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA== +utif2@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/utif2/-/utif2-4.1.0.tgz#e768d37bd619b995d56d9780b5d2b4611a3d932b" + integrity sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w== + dependencies: + pako "^1.0.11" + util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -4970,11 +5430,29 @@ ws@^8.14.2: resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== +xml-parse-from-string@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" + integrity sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g== + +xml2js@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" + integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + xmlbuilder@>=11.0.1, xmlbuilder@^15.1.1: version "15.1.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -5030,3 +5508,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zod@^3.23.8: + version "3.24.1" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.1.tgz#27445c912738c8ad1e9de1bea0359fa44d9d35ee" + integrity sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A== From db27c2e1ffda4e941b8eb33b06721728572e4e86 Mon Sep 17 00:00:00 2001 From: matthme <36768177+matthme@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:48:42 +0000 Subject: [PATCH 16/16] Clarify icon not found warning (#26) * clarify icon not found warning * rephrasing * remove redundant PNG * remove duplicate whitespace * change icon resolution requirement --- scripts/create-icons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/create-icons.js b/scripts/create-icons.js index 6445bc8..4d6430e 100644 --- a/scripts/create-icons.js +++ b/scripts/create-icons.js @@ -19,7 +19,7 @@ async function generateIcons() { const icnsOutPath = path.join(buildDir, 'icon.icns'); if (!fs.existsSync(pngPath)) { - console.warn("WARNING: No icon.png found in your webhapp's UI assets."); + console.warn("WARNING: No icon.png found. If you're using the systray option, an icon.png (256x256 pixel) is required to be provided at the root level of your webhapp's UI assets."); return; }