commit ed294cb6624bf7dea181d6058845f19496dde109 Author: Leafd Date: Fri Oct 3 12:14:31 2025 -0400 feat: big bang diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6c4fd11 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.svg filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/README.md b/README.md new file mode 100644 index 0000000..76cfe18 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# hackatime-desktop diff --git a/index.html b/index.html new file mode 100644 index 0000000..c9cfbd7 --- /dev/null +++ b/index.html @@ -0,0 +1,17 @@ + + + + + + + Hackatime + + + + + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..1cfb881 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "desktop", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc --noEmit && vite build", + "preview": "vite preview", + "tauri": "tauri" + }, + "dependencies": { + "@tauri-apps/api": "^2", + "@tauri-apps/plugin-deep-link": "^2.4.3", + "@tauri-apps/plugin-opener": "^2", + "chart.js": "^4.5.0", + "vue": "^3.5.13", + "vue-chartjs": "^5.3.2" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.14", + "@tauri-apps/cli": "^2", + "@vitejs/plugin-vue": "^5.2.1", + "tailwindcss": "^4.1.14", + "typescript": "~5.6.2", + "vite": "^6.0.3", + "vue-tsc": "^2.1.10" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..654727a --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1488 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@tauri-apps/api': + specifier: ^2 + version: 2.8.0 + '@tauri-apps/plugin-deep-link': + specifier: ^2.4.3 + version: 2.4.3 + '@tauri-apps/plugin-opener': + specifier: ^2 + version: 2.5.0 + chart.js: + specifier: ^4.5.0 + version: 4.5.0 + vue: + specifier: ^3.5.13 + version: 3.5.22(typescript@5.6.3) + vue-chartjs: + specifier: ^5.3.2 + version: 5.3.2(chart.js@4.5.0)(vue@3.5.22(typescript@5.6.3)) + devDependencies: + '@tailwindcss/vite': + specifier: ^4.1.14 + version: 4.1.14(vite@6.3.6(jiti@2.6.1)(lightningcss@1.30.1)) + '@tauri-apps/cli': + specifier: ^2 + version: 2.8.4 + '@vitejs/plugin-vue': + specifier: ^5.2.1 + version: 5.2.4(vite@6.3.6(jiti@2.6.1)(lightningcss@1.30.1))(vue@3.5.22(typescript@5.6.3)) + tailwindcss: + specifier: ^4.1.14 + version: 4.1.14 + typescript: + specifier: ~5.6.2 + version: 5.6.3 + vite: + specifier: ^6.0.3 + version: 6.3.6(jiti@2.6.1)(lightningcss@1.30.1) + vue-tsc: + specifier: ^2.1.10 + version: 2.2.12(typescript@5.6.3) + +packages: + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.4': + resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.28.4': + resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.25.10': + resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.10': + resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.10': + resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.10': + resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.10': + resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.10': + resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.10': + resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.10': + resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.10': + resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.10': + resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.10': + resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.10': + resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.10': + resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.10': + resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.10': + resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.10': + resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.10': + resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.10': + resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.10': + resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.10': + resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.10': + resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.10': + resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.10': + resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.10': + resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.10': + resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.10': + resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@kurkle/color@0.3.4': + resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} + + '@rollup/rollup-android-arm-eabi@4.52.3': + resolution: {integrity: sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.52.3': + resolution: {integrity: sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.52.3': + resolution: {integrity: sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.52.3': + resolution: {integrity: sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.52.3': + resolution: {integrity: sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.52.3': + resolution: {integrity: sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.52.3': + resolution: {integrity: sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.52.3': + resolution: {integrity: sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.52.3': + resolution: {integrity: sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.52.3': + resolution: {integrity: sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.52.3': + resolution: {integrity: sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.52.3': + resolution: {integrity: sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.52.3': + resolution: {integrity: sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.52.3': + resolution: {integrity: sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.52.3': + resolution: {integrity: sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.52.3': + resolution: {integrity: sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.52.3': + resolution: {integrity: sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.52.3': + resolution: {integrity: sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.52.3': + resolution: {integrity: sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.52.3': + resolution: {integrity: sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.52.3': + resolution: {integrity: sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.52.3': + resolution: {integrity: sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==} + cpu: [x64] + os: [win32] + + '@tailwindcss/node@4.1.14': + resolution: {integrity: sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==} + + '@tailwindcss/oxide-android-arm64@4.1.14': + resolution: {integrity: sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.14': + resolution: {integrity: sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.14': + resolution: {integrity: sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.14': + resolution: {integrity: sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14': + resolution: {integrity: sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.14': + resolution: {integrity: sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.14': + resolution: {integrity: sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.14': + resolution: {integrity: sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.14': + resolution: {integrity: sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.14': + resolution: {integrity: sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.14': + resolution: {integrity: sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.14': + resolution: {integrity: sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.14': + resolution: {integrity: sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.14': + resolution: {integrity: sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@tauri-apps/api@2.8.0': + resolution: {integrity: sha512-ga7zdhbS2GXOMTIZRT0mYjKJtR9fivsXzsyq5U3vjDL0s6DTMwYRm0UHNjzTY5dh4+LSC68Sm/7WEiimbQNYlw==} + + '@tauri-apps/cli-darwin-arm64@2.8.4': + resolution: {integrity: sha512-BKu8HRkYV01SMTa7r4fLx+wjgtRK8Vep7lmBdHDioP6b8XH3q2KgsAyPWfEZaZIkZ2LY4SqqGARaE9oilNe0oA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tauri-apps/cli-darwin-x64@2.8.4': + resolution: {integrity: sha512-imb9PfSd/7G6VAO7v1bQ2A3ZH4NOCbhGJFLchxzepGcXf9NKkfun157JH9mko29K6sqAwuJ88qtzbKCbWJTH9g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tauri-apps/cli-linux-arm-gnueabihf@2.8.4': + resolution: {integrity: sha512-Ml215UnDdl7/fpOrF1CNovym/KjtUbCuPgrcZ4IhqUCnhZdXuphud/JT3E8X97Y03TZ40Sjz8raXYI2ET0exzw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tauri-apps/cli-linux-arm64-gnu@2.8.4': + resolution: {integrity: sha512-pbcgBpMyI90C83CxE5REZ9ODyIlmmAPkkJXtV398X3SgZEIYy5TACYqlyyv2z5yKgD8F8WH4/2fek7+jH+ZXAw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tauri-apps/cli-linux-arm64-musl@2.8.4': + resolution: {integrity: sha512-zumFeaU1Ws5Ay872FTyIm7z8kfzEHu8NcIn8M6TxbJs0a7GRV21KBdpW1zNj2qy7HynnpQCqjAYXTUUmm9JAOw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tauri-apps/cli-linux-riscv64-gnu@2.8.4': + resolution: {integrity: sha512-qiqbB3Zz6IyO201f+1ojxLj65WYj8mixL5cOMo63nlg8CIzsP23cPYUrx1YaDPsCLszKZo7tVs14pc7BWf+/aQ==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + + '@tauri-apps/cli-linux-x64-gnu@2.8.4': + resolution: {integrity: sha512-TaqaDd9Oy6k45Hotx3pOf+pkbsxLaApv4rGd9mLuRM1k6YS/aw81YrsMryYPThrxrScEIUcmNIHaHsLiU4GMkw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tauri-apps/cli-linux-x64-musl@2.8.4': + resolution: {integrity: sha512-ot9STAwyezN8w+bBHZ+bqSQIJ0qPZFlz/AyscpGqB/JnJQVDFQcRDmUPFEaAtt2UUHSWzN3GoTJ5ypqLBp2WQA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tauri-apps/cli-win32-arm64-msvc@2.8.4': + resolution: {integrity: sha512-+2aJ/g90dhLiOLFSD1PbElXX3SoMdpO7HFPAZB+xot3CWlAZD1tReUFy7xe0L5GAR16ZmrxpIDM9v9gn5xRy/w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tauri-apps/cli-win32-ia32-msvc@2.8.4': + resolution: {integrity: sha512-yj7WDxkL1t9Uzr2gufQ1Hl7hrHuFKTNEOyascbc109EoiAqCp0tgZ2IykQqOZmZOHU884UAWI1pVMqBhS/BfhA==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@tauri-apps/cli-win32-x64-msvc@2.8.4': + resolution: {integrity: sha512-XuvGB4ehBdd7QhMZ9qbj/8icGEatDuBNxyYHbLKsTYh90ggUlPa/AtaqcC1Fo69lGkTmq9BOKrs1aWSi7xDonA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tauri-apps/cli@2.8.4': + resolution: {integrity: sha512-ejUZBzuQRcjFV+v/gdj/DcbyX/6T4unZQjMSBZwLzP/CymEjKcc2+Fc8xTORThebHDUvqoXMdsCZt8r+hyN15g==} + engines: {node: '>= 10'} + hasBin: true + + '@tauri-apps/plugin-deep-link@2.4.3': + resolution: {integrity: sha512-yVCZpVG1ZrtfCvE7K5LRSrGqlyPlCrqlKgoREJHnfjyYdDtUhFmZqScOXpL8XL2PizJHDsoahEweuTaUPEokPA==} + + '@tauri-apps/plugin-opener@2.5.0': + resolution: {integrity: sha512-B0LShOYae4CZjN8leiNDbnfjSrTwoZakqKaWpfoH6nXiJwt6Rgj6RnVIffG3DoJiKsffRhMkjmBV9VeilSb4TA==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@vitejs/plugin-vue@5.2.4': + resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 + vue: ^3.2.25 + + '@volar/language-core@2.4.15': + resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==} + + '@volar/source-map@2.4.15': + resolution: {integrity: sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==} + + '@volar/typescript@2.4.15': + resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==} + + '@vue/compiler-core@3.5.22': + resolution: {integrity: sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==} + + '@vue/compiler-dom@3.5.22': + resolution: {integrity: sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==} + + '@vue/compiler-sfc@3.5.22': + resolution: {integrity: sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ==} + + '@vue/compiler-ssr@3.5.22': + resolution: {integrity: sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww==} + + '@vue/compiler-vue2@2.7.16': + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + + '@vue/language-core@2.2.12': + resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/reactivity@3.5.22': + resolution: {integrity: sha512-f2Wux4v/Z2pqc9+4SmgZC1p73Z53fyD90NFWXiX9AKVnVBEvLFOWCEgJD3GdGnlxPZt01PSlfmLqbLYzY/Fw4A==} + + '@vue/runtime-core@3.5.22': + resolution: {integrity: sha512-EHo4W/eiYeAzRTN5PCextDUZ0dMs9I8mQ2Fy+OkzvRPUYQEyK9yAjbasrMCXbLNhF7P0OUyivLjIy0yc6VrLJQ==} + + '@vue/runtime-dom@3.5.22': + resolution: {integrity: sha512-Av60jsryAkI023PlN7LsqrfPvwfxOd2yAwtReCjeuugTJTkgrksYJJstg1e12qle0NarkfhfFu1ox2D+cQotww==} + + '@vue/server-renderer@3.5.22': + resolution: {integrity: sha512-gXjo+ao0oHYTSswF+a3KRHZ1WszxIqO7u6XwNHqcqb9JfyIL/pbWrrh/xLv7jeDqla9u+LK7yfZKHih1e1RKAQ==} + peerDependencies: + vue: 3.5.22 + + '@vue/shared@3.5.22': + resolution: {integrity: sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==} + + alien-signals@1.0.13: + resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + chart.js@4.5.0: + resolution: {integrity: sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==} + engines: {pnpm: '>=8'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + + detect-libc@2.1.1: + resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==} + engines: {node: '>=8'} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + esbuild@0.25.10: + resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} + engines: {node: '>=18'} + hasBin: true + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + lightningcss-darwin-arm64@1.30.1: + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.1: + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.1: + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.1: + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.1: + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.1: + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.1: + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.1: + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.1: + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.1: + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.1: + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} + + magic-string@0.30.19: + resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + rollup@4.52.3: + resolution: {integrity: sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + tailwindcss@4.1.14: + resolution: {integrity: sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==} + + tapable@2.2.3: + resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} + engines: {node: '>=6'} + + tar@7.5.1: + resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} + engines: {node: '>=18'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + + vite@6.3.6: + resolution: {integrity: sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + vue-chartjs@5.3.2: + resolution: {integrity: sha512-NrkbRRoYshbXbWqJkTN6InoDVwVb90C0R7eAVgMWcB9dPikbruaOoTFjFYHE/+tNPdIe6qdLCDjfjPHQ0fw4jw==} + peerDependencies: + chart.js: ^4.1.1 + vue: ^3.0.0-0 || ^2.7.0 + + vue-tsc@2.2.12: + resolution: {integrity: sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + + vue@3.5.22: + resolution: {integrity: sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + +snapshots: + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/parser@7.28.4': + dependencies: + '@babel/types': 7.28.4 + + '@babel/types@7.28.4': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@esbuild/aix-ppc64@0.25.10': + optional: true + + '@esbuild/android-arm64@0.25.10': + optional: true + + '@esbuild/android-arm@0.25.10': + optional: true + + '@esbuild/android-x64@0.25.10': + optional: true + + '@esbuild/darwin-arm64@0.25.10': + optional: true + + '@esbuild/darwin-x64@0.25.10': + optional: true + + '@esbuild/freebsd-arm64@0.25.10': + optional: true + + '@esbuild/freebsd-x64@0.25.10': + optional: true + + '@esbuild/linux-arm64@0.25.10': + optional: true + + '@esbuild/linux-arm@0.25.10': + optional: true + + '@esbuild/linux-ia32@0.25.10': + optional: true + + '@esbuild/linux-loong64@0.25.10': + optional: true + + '@esbuild/linux-mips64el@0.25.10': + optional: true + + '@esbuild/linux-ppc64@0.25.10': + optional: true + + '@esbuild/linux-riscv64@0.25.10': + optional: true + + '@esbuild/linux-s390x@0.25.10': + optional: true + + '@esbuild/linux-x64@0.25.10': + optional: true + + '@esbuild/netbsd-arm64@0.25.10': + optional: true + + '@esbuild/netbsd-x64@0.25.10': + optional: true + + '@esbuild/openbsd-arm64@0.25.10': + optional: true + + '@esbuild/openbsd-x64@0.25.10': + optional: true + + '@esbuild/openharmony-arm64@0.25.10': + optional: true + + '@esbuild/sunos-x64@0.25.10': + optional: true + + '@esbuild/win32-arm64@0.25.10': + optional: true + + '@esbuild/win32-ia32@0.25.10': + optional: true + + '@esbuild/win32-x64@0.25.10': + optional: true + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@kurkle/color@0.3.4': {} + + '@rollup/rollup-android-arm-eabi@4.52.3': + optional: true + + '@rollup/rollup-android-arm64@4.52.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.52.3': + optional: true + + '@rollup/rollup-darwin-x64@4.52.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.52.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.52.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.52.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.52.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.52.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.52.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.52.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.52.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.52.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.52.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.52.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.52.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.52.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.52.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.52.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.52.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.52.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.52.3': + optional: true + + '@tailwindcss/node@4.1.14': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.1 + magic-string: 0.30.19 + source-map-js: 1.2.1 + tailwindcss: 4.1.14 + + '@tailwindcss/oxide-android-arm64@4.1.14': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.14': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.14': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.14': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.14': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.14': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.14': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.14': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.14': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.14': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.14': + optional: true + + '@tailwindcss/oxide@4.1.14': + dependencies: + detect-libc: 2.1.1 + tar: 7.5.1 + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.14 + '@tailwindcss/oxide-darwin-arm64': 4.1.14 + '@tailwindcss/oxide-darwin-x64': 4.1.14 + '@tailwindcss/oxide-freebsd-x64': 4.1.14 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.14 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.14 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.14 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.14 + '@tailwindcss/oxide-linux-x64-musl': 4.1.14 + '@tailwindcss/oxide-wasm32-wasi': 4.1.14 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.14 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.14 + + '@tailwindcss/vite@4.1.14(vite@6.3.6(jiti@2.6.1)(lightningcss@1.30.1))': + dependencies: + '@tailwindcss/node': 4.1.14 + '@tailwindcss/oxide': 4.1.14 + tailwindcss: 4.1.14 + vite: 6.3.6(jiti@2.6.1)(lightningcss@1.30.1) + + '@tauri-apps/api@2.8.0': {} + + '@tauri-apps/cli-darwin-arm64@2.8.4': + optional: true + + '@tauri-apps/cli-darwin-x64@2.8.4': + optional: true + + '@tauri-apps/cli-linux-arm-gnueabihf@2.8.4': + optional: true + + '@tauri-apps/cli-linux-arm64-gnu@2.8.4': + optional: true + + '@tauri-apps/cli-linux-arm64-musl@2.8.4': + optional: true + + '@tauri-apps/cli-linux-riscv64-gnu@2.8.4': + optional: true + + '@tauri-apps/cli-linux-x64-gnu@2.8.4': + optional: true + + '@tauri-apps/cli-linux-x64-musl@2.8.4': + optional: true + + '@tauri-apps/cli-win32-arm64-msvc@2.8.4': + optional: true + + '@tauri-apps/cli-win32-ia32-msvc@2.8.4': + optional: true + + '@tauri-apps/cli-win32-x64-msvc@2.8.4': + optional: true + + '@tauri-apps/cli@2.8.4': + optionalDependencies: + '@tauri-apps/cli-darwin-arm64': 2.8.4 + '@tauri-apps/cli-darwin-x64': 2.8.4 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.8.4 + '@tauri-apps/cli-linux-arm64-gnu': 2.8.4 + '@tauri-apps/cli-linux-arm64-musl': 2.8.4 + '@tauri-apps/cli-linux-riscv64-gnu': 2.8.4 + '@tauri-apps/cli-linux-x64-gnu': 2.8.4 + '@tauri-apps/cli-linux-x64-musl': 2.8.4 + '@tauri-apps/cli-win32-arm64-msvc': 2.8.4 + '@tauri-apps/cli-win32-ia32-msvc': 2.8.4 + '@tauri-apps/cli-win32-x64-msvc': 2.8.4 + + '@tauri-apps/plugin-deep-link@2.4.3': + dependencies: + '@tauri-apps/api': 2.8.0 + + '@tauri-apps/plugin-opener@2.5.0': + dependencies: + '@tauri-apps/api': 2.8.0 + + '@types/estree@1.0.8': {} + + '@vitejs/plugin-vue@5.2.4(vite@6.3.6(jiti@2.6.1)(lightningcss@1.30.1))(vue@3.5.22(typescript@5.6.3))': + dependencies: + vite: 6.3.6(jiti@2.6.1)(lightningcss@1.30.1) + vue: 3.5.22(typescript@5.6.3) + + '@volar/language-core@2.4.15': + dependencies: + '@volar/source-map': 2.4.15 + + '@volar/source-map@2.4.15': {} + + '@volar/typescript@2.4.15': + dependencies: + '@volar/language-core': 2.4.15 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vue/compiler-core@3.5.22': + dependencies: + '@babel/parser': 7.28.4 + '@vue/shared': 3.5.22 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.22': + dependencies: + '@vue/compiler-core': 3.5.22 + '@vue/shared': 3.5.22 + + '@vue/compiler-sfc@3.5.22': + dependencies: + '@babel/parser': 7.28.4 + '@vue/compiler-core': 3.5.22 + '@vue/compiler-dom': 3.5.22 + '@vue/compiler-ssr': 3.5.22 + '@vue/shared': 3.5.22 + estree-walker: 2.0.2 + magic-string: 0.30.19 + postcss: 8.5.6 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.22': + dependencies: + '@vue/compiler-dom': 3.5.22 + '@vue/shared': 3.5.22 + + '@vue/compiler-vue2@2.7.16': + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + + '@vue/language-core@2.2.12(typescript@5.6.3)': + dependencies: + '@volar/language-core': 2.4.15 + '@vue/compiler-dom': 3.5.22 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.22 + alien-signals: 1.0.13 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.6.3 + + '@vue/reactivity@3.5.22': + dependencies: + '@vue/shared': 3.5.22 + + '@vue/runtime-core@3.5.22': + dependencies: + '@vue/reactivity': 3.5.22 + '@vue/shared': 3.5.22 + + '@vue/runtime-dom@3.5.22': + dependencies: + '@vue/reactivity': 3.5.22 + '@vue/runtime-core': 3.5.22 + '@vue/shared': 3.5.22 + csstype: 3.1.3 + + '@vue/server-renderer@3.5.22(vue@3.5.22(typescript@5.6.3))': + dependencies: + '@vue/compiler-ssr': 3.5.22 + '@vue/shared': 3.5.22 + vue: 3.5.22(typescript@5.6.3) + + '@vue/shared@3.5.22': {} + + alien-signals@1.0.13: {} + + balanced-match@1.0.2: {} + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + chart.js@4.5.0: + dependencies: + '@kurkle/color': 0.3.4 + + chownr@3.0.0: {} + + csstype@3.1.3: {} + + de-indent@1.0.2: {} + + detect-libc@2.1.1: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.3 + + entities@4.5.0: {} + + esbuild@0.25.10: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.10 + '@esbuild/android-arm': 0.25.10 + '@esbuild/android-arm64': 0.25.10 + '@esbuild/android-x64': 0.25.10 + '@esbuild/darwin-arm64': 0.25.10 + '@esbuild/darwin-x64': 0.25.10 + '@esbuild/freebsd-arm64': 0.25.10 + '@esbuild/freebsd-x64': 0.25.10 + '@esbuild/linux-arm': 0.25.10 + '@esbuild/linux-arm64': 0.25.10 + '@esbuild/linux-ia32': 0.25.10 + '@esbuild/linux-loong64': 0.25.10 + '@esbuild/linux-mips64el': 0.25.10 + '@esbuild/linux-ppc64': 0.25.10 + '@esbuild/linux-riscv64': 0.25.10 + '@esbuild/linux-s390x': 0.25.10 + '@esbuild/linux-x64': 0.25.10 + '@esbuild/netbsd-arm64': 0.25.10 + '@esbuild/netbsd-x64': 0.25.10 + '@esbuild/openbsd-arm64': 0.25.10 + '@esbuild/openbsd-x64': 0.25.10 + '@esbuild/openharmony-arm64': 0.25.10 + '@esbuild/sunos-x64': 0.25.10 + '@esbuild/win32-arm64': 0.25.10 + '@esbuild/win32-ia32': 0.25.10 + '@esbuild/win32-x64': 0.25.10 + + estree-walker@2.0.2: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fsevents@2.3.3: + optional: true + + graceful-fs@4.2.11: {} + + he@1.2.0: {} + + jiti@2.6.1: {} + + lightningcss-darwin-arm64@1.30.1: + optional: true + + lightningcss-darwin-x64@1.30.1: + optional: true + + lightningcss-freebsd-x64@1.30.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.1: + optional: true + + lightningcss-linux-arm64-gnu@1.30.1: + optional: true + + lightningcss-linux-arm64-musl@1.30.1: + optional: true + + lightningcss-linux-x64-gnu@1.30.1: + optional: true + + lightningcss-linux-x64-musl@1.30.1: + optional: true + + lightningcss-win32-arm64-msvc@1.30.1: + optional: true + + lightningcss-win32-x64-msvc@1.30.1: + optional: true + + lightningcss@1.30.1: + dependencies: + detect-libc: 2.1.1 + optionalDependencies: + lightningcss-darwin-arm64: 1.30.1 + lightningcss-darwin-x64: 1.30.1 + lightningcss-freebsd-x64: 1.30.1 + lightningcss-linux-arm-gnueabihf: 1.30.1 + lightningcss-linux-arm64-gnu: 1.30.1 + lightningcss-linux-arm64-musl: 1.30.1 + lightningcss-linux-x64-gnu: 1.30.1 + lightningcss-linux-x64-musl: 1.30.1 + lightningcss-win32-arm64-msvc: 1.30.1 + lightningcss-win32-x64-msvc: 1.30.1 + + magic-string@0.30.19: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minipass@7.1.2: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.2 + + muggle-string@0.4.1: {} + + nanoid@3.3.11: {} + + path-browserify@1.0.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + rollup@4.52.3: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.52.3 + '@rollup/rollup-android-arm64': 4.52.3 + '@rollup/rollup-darwin-arm64': 4.52.3 + '@rollup/rollup-darwin-x64': 4.52.3 + '@rollup/rollup-freebsd-arm64': 4.52.3 + '@rollup/rollup-freebsd-x64': 4.52.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.3 + '@rollup/rollup-linux-arm-musleabihf': 4.52.3 + '@rollup/rollup-linux-arm64-gnu': 4.52.3 + '@rollup/rollup-linux-arm64-musl': 4.52.3 + '@rollup/rollup-linux-loong64-gnu': 4.52.3 + '@rollup/rollup-linux-ppc64-gnu': 4.52.3 + '@rollup/rollup-linux-riscv64-gnu': 4.52.3 + '@rollup/rollup-linux-riscv64-musl': 4.52.3 + '@rollup/rollup-linux-s390x-gnu': 4.52.3 + '@rollup/rollup-linux-x64-gnu': 4.52.3 + '@rollup/rollup-linux-x64-musl': 4.52.3 + '@rollup/rollup-openharmony-arm64': 4.52.3 + '@rollup/rollup-win32-arm64-msvc': 4.52.3 + '@rollup/rollup-win32-ia32-msvc': 4.52.3 + '@rollup/rollup-win32-x64-gnu': 4.52.3 + '@rollup/rollup-win32-x64-msvc': 4.52.3 + fsevents: 2.3.3 + + source-map-js@1.2.1: {} + + tailwindcss@4.1.14: {} + + tapable@2.2.3: {} + + tar@7.5.1: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.1.0 + yallist: 5.0.0 + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + typescript@5.6.3: {} + + vite@6.3.6(jiti@2.6.1)(lightningcss@1.30.1): + dependencies: + esbuild: 0.25.10 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.52.3 + tinyglobby: 0.2.15 + optionalDependencies: + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.1 + + vscode-uri@3.1.0: {} + + vue-chartjs@5.3.2(chart.js@4.5.0)(vue@3.5.22(typescript@5.6.3)): + dependencies: + chart.js: 4.5.0 + vue: 3.5.22(typescript@5.6.3) + + vue-tsc@2.2.12(typescript@5.6.3): + dependencies: + '@volar/typescript': 2.4.15 + '@vue/language-core': 2.2.12(typescript@5.6.3) + typescript: 5.6.3 + + vue@3.5.22(typescript@5.6.3): + dependencies: + '@vue/compiler-dom': 3.5.22 + '@vue/compiler-sfc': 3.5.22 + '@vue/runtime-dom': 3.5.22 + '@vue/server-renderer': 3.5.22(vue@3.5.22(typescript@5.6.3)) + '@vue/shared': 3.5.22 + optionalDependencies: + typescript: 5.6.3 + + yallist@5.0.0: {} diff --git a/public/flame-icon.svg b/public/flame-icon.svg new file mode 100644 index 0000000..b800fe5 --- /dev/null +++ b/public/flame-icon.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c2bc80ebc20820c185c712993242b303c5557ea5e8b67d5e74787e754b566d3 +size 975 diff --git a/public/tauri.svg b/public/tauri.svg new file mode 100644 index 0000000..1437bfc --- /dev/null +++ b/public/tauri.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e5d2738bbaa5543c4684001a558dc53165da9b636144827b28db1dcfacf81aa8 +size 2599 diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 0000000..bf6ee75 --- /dev/null +++ b/public/vite.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a748afd443918bb16591c834c401dae33e87861ab5dbad0811c3a3b4a9214fb +size 1497 diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore new file mode 100644 index 0000000..b21bd68 --- /dev/null +++ b/src-tauri/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Generated by Tauri +# will have schema files for capabilities auto-completion +/gen/schemas diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock new file mode 100644 index 0000000..08512eb --- /dev/null +++ b/src-tauri/Cargo.lock @@ -0,0 +1,6526 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "windows-sys 0.61.1", +] + +[[package]] +name = "async-lock" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "async-signal" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.61.1", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link 0.2.0", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + +[[package]] +name = "block2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" +dependencies = [ + "objc2 0.6.2", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytemuck" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +dependencies = [ + "serde", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.9.4", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.17", +] + +[[package]] +name = "cargo_toml" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +dependencies = [ + "serde", + "toml 0.9.7", +] + +[[package]] +name = "cc" +version = "1.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid 1.18.1", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link 0.2.0", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.16", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.29.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "matches", + "phf 0.10.1", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.106", +] + +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.106", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.106", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.106", +] + +[[package]] +name = "desktop" +version = "0.1.0" +dependencies = [ + "chrono", + "discord-rich-presence", + "open", + "reqwest 0.11.27", + "serde", + "serde_json", + "sqlx", + "tauri", + "tauri-build", + "tauri-plugin-deep-link", + "tauri-plugin-opener", + "tokio", + "urlencoding", + "uuid 1.18.1", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.1", +] + +[[package]] +name = "discord-rich-presence" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ead3c5edc7e048c317c6fc4a7e24aff0c7e4c136918e2ba38106a385b2cc53a5" +dependencies = [ + "log", + "serde", + "serde_derive", + "serde_json", + "serde_repr", + "thiserror 2.0.17", + "uuid 0.8.2", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "dlopen2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" +dependencies = [ + "serde", +] + +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "embed-resource" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a075fc573c64510038d7ee9abc7990635863992f83ebc52c8b433b8411a02e" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 0.9.7", + "vswhom", + "winreg 0.55.0", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "259d404d09818dec19332e31d94558aeb442fea04c817006456c24b5460bbd4b" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.1", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.9.4", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.2", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.11.4", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "html5ever" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" +dependencies = [ + "log", + "mac", + "markup5ever", + "match_token", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.32", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-util" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.7.0", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.0", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.1", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" +dependencies = [ + "byteorder", + "png", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown 0.16.0", + "serde", + "serde_core", +] + +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonptr" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.9.4", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "kuchikiki" +version = "0.8.8-speedreader" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" +dependencies = [ + "cssparser", + "html5ever", + "indexmap 2.11.4", + "selectors", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.9.4", + "libc", + "redox_syscall", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "markup5ever" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" +dependencies = [ + "log", + "phf 0.11.3", + "phf_codegen 0.11.3", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "muda" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2 0.6.2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation 0.3.1", + "once_cell", + "png", + "serde", + "thiserror 2.0.17", + "windows-sys 0.60.2", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.9.4", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" +dependencies = [ + "objc2-encode", + "objc2-exception-helper", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +dependencies = [ + "bitflags 2.9.4", + "block2 0.6.1", + "libc", + "objc2 0.6.2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-foundation 0.3.1", + "objc2-quartz-core 0.3.1", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.9.4", + "dispatch2", + "objc2 0.6.2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" +dependencies = [ + "bitflags 2.9.4", + "dispatch2", + "objc2 0.6.2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" +dependencies = [ + "objc2 0.6.2", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-exception-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.9.4", + "block2 0.5.1", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +dependencies = [ + "bitflags 2.9.4", + "block2 0.6.1", + "libc", + "objc2 0.6.2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-javascript-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9052cb1bb50a4c161d934befcf879526fb87ae9a68858f241e693ca46225cf5a" +dependencies = [ + "objc2 0.6.2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.9.4", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.9.4", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-security" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1f8e0ef3ab66b08c42644dcb34dba6ec0a574bbd8adbb8bdbdc7a2779731a44" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-core-foundation", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" +dependencies = [ + "bitflags 2.9.4", + "block2 0.6.1", + "objc2 0.6.2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation 0.3.1", + "objc2-javascript-core", + "objc2-security", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "open" +version = "5.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" +dependencies = [ + "dunce", + "is-wsl", + "libc", + "pathdiff", +] + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.5", +] + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_shared 0.8.0", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_macros 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.1", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plist" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" +dependencies = [ + "base64 0.22.1", + "indexmap 2.11.4", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.1", +] + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit 0.23.6", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.38.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags 2.9.4", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 2.0.17", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "regex" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg 0.50.0", +] + +[[package]] +name = "reqwest" +version = "0.12.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.7.0", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rust-ini" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.1", +] + +[[package]] +name = "rustls" +version = "0.23.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.1", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid 1.18.1", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.106", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "selectors" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.11.4", + "schemars 0.9.0", + "schemars 1.0.4", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "servo_arc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "softbuffer" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" +dependencies = [ + "bytemuck", + "cfg_aliases", + "core-graphics", + "foreign-types 0.5.0", + "js-sys", + "log", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-quartz-core 0.2.2", + "raw-window-handle", + "redox_syscall", + "wasm-bindgen", + "web-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlx" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64 0.22.1", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.5", + "hashlink", + "indexmap 2.11.4", + "log", + "memchr", + "once_cell", + "percent-encoding", + "rustls", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror 2.0.17", + "tokio", + "tokio-stream", + "tracing", + "url", + "uuid 1.18.1", + "webpki-roots 0.26.11", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.106", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck 0.5.0", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.106", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.9.4", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.17", + "tracing", + "uuid 1.18.1", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.9.4", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.17", + "tracing", + "uuid 1.18.1", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror 2.0.17", + "tracing", + "url", + "uuid 1.18.1", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared 0.11.3", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", +] + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml 0.8.2", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.34.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "959469667dbcea91e5485fc48ba7dd6023face91bb0f1a14681a70f99847c3f7" +dependencies = [ + "bitflags 2.9.4", + "block2 0.6.1", + "core-foundation 0.10.1", + "core-graphics", + "crossbeam-channel", + "dispatch", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc2 0.6.2", + "objc2-app-kit", + "objc2-foundation 0.3.1", + "once_cell", + "parking_lot", + "raw-window-handle", + "scopeguard", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "2.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d1d3b3dc4c101ac989fd7db77e045cc6d91a25349cd410455cb5c57d510c1c" +dependencies = [ + "anyhow", + "bytes", + "cookie", + "dirs", + "dunce", + "embed_plist", + "getrandom 0.3.3", + "glob", + "gtk", + "heck 0.5.0", + "http 1.3.1", + "jni", + "libc", + "log", + "mime", + "muda", + "objc2 0.6.2", + "objc2-app-kit", + "objc2-foundation 0.3.1", + "objc2-ui-kit", + "objc2-web-kit", + "percent-encoding", + "plist", + "raw-window-handle", + "reqwest 0.12.23", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror 2.0.17", + "tokio", + "tray-icon", + "url", + "urlpattern", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows", +] + +[[package]] +name = "tauri-build" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c432ccc9ff661803dab74c6cd78de11026a578a9307610bbc39d3c55be7943f" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs", + "glob", + "heck 0.5.0", + "json-patch", + "schemars 0.8.22", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "toml 0.9.7", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab3a62cf2e6253936a8b267c2e95839674e7439f104fa96ad0025e149d54d8a" +dependencies = [ + "base64 0.22.1", + "brotli", + "ico", + "json-patch", + "plist", + "png", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "sha2", + "syn 2.0.106", + "tauri-utils", + "thiserror 2.0.17", + "time", + "url", + "uuid 1.18.1", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4368ea8094e7045217edb690f493b55b30caf9f3e61f79b4c24b6db91f07995e" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.106", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-plugin" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9946a3cede302eac0c6eb6c6070ac47b1768e326092d32efbb91f21ed58d978f" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri-utils", + "toml 0.9.7", + "walkdir", +] + +[[package]] +name = "tauri-plugin-deep-link" +version = "2.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd67112fb1131834c2a7398ffcba520dbbf62c17de3b10329acd1a3554b1a9bb" +dependencies = [ + "dunce", + "plist", + "rust-ini", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.17", + "tracing", + "url", + "windows-registry", + "windows-result 0.3.4", +] + +[[package]] +name = "tauri-plugin-opener" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786156aa8e89e03d271fbd3fe642207da8e65f3c961baa9e2930f332bf80a1f5" +dependencies = [ + "dunce", + "glob", + "objc2-app-kit", + "objc2-foundation 0.3.1", + "open", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.17", + "url", + "windows", + "zbus", +] + +[[package]] +name = "tauri-runtime" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4cfc9ad45b487d3fded5a4731a567872a4812e9552e3964161b08edabf93846" +dependencies = [ + "cookie", + "dpi", + "gtk", + "http 1.3.1", + "jni", + "objc2 0.6.2", + "objc2-ui-kit", + "objc2-web-kit", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror 2.0.17", + "url", + "webkit2gtk", + "webview2-com", + "windows", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fe9d48bd122ff002064e88cfcd7027090d789c4302714e68fcccba0f4b7807" +dependencies = [ + "gtk", + "http 1.3.1", + "jni", + "log", + "objc2 0.6.2", + "objc2-app-kit", + "objc2-foundation 0.3.1", + "once_cell", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "url", + "webkit2gtk", + "webview2-com", + "windows", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212" +dependencies = [ + "anyhow", + "brotli", + "cargo_metadata", + "ctor", + "dunce", + "glob", + "html5ever", + "http 1.3.1", + "infer", + "json-patch", + "kuchikiki", + "log", + "memchr", + "phf 0.11.3", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.17", + "toml 0.9.7", + "url", + "urlpattern", + "uuid 1.18.1", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd21509dd1fa9bd355dc29894a6ff10635880732396aa38c0066c1e6c1ab8074" +dependencies = [ + "embed-resource", + "toml 0.9.7", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.61.1", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "slab", + "socket2 0.6.0", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "toml" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +dependencies = [ + "indexmap 2.11.4", + "serde_core", + "serde_spanned 1.0.2", + "toml_datetime 0.7.2", + "toml_parser", + "toml_writer", + "winnow 0.7.13", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.11.4", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.11.4", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +dependencies = [ + "indexmap 2.11.4", + "toml_datetime 0.7.2", + "toml_parser", + "winnow 0.7.13", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ + "winnow 0.7.13", +] + +[[package]] +name = "toml_writer" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109" + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.4", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d92153331e7d02ec09137538996a7786fe679c629c279e82a6be762b7e6fe2" +dependencies = [ + "crossbeam-channel", + "dirs", + "libappindicator", + "muda", + "objc2 0.6.2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.1", + "once_cell", + "png", + "serde", + "thiserror 2.0.17", + "windows-sys 0.59.0", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset", + "tempfile", + "winapi", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "uuid" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +dependencies = [ + "getrandom 0.3.3", + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.2", +] + +[[package]] +name = "webpki-roots" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webview2-com" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core 0.61.2", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "webview2-com-sys" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" +dependencies = [ + "thiserror 2.0.17", + "windows", + "windows-core 0.61.2", +] + +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.1", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +dependencies = [ + "objc2 0.6.2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation 0.3.1", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "windows-interface" +version = "0.59.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-registry" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" +dependencies = [ + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.4", +] + +[[package]] +name = "windows-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +dependencies = [ + "windows-link 0.2.0", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-version" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "700dad7c058606087f6fdc1f88da5841e06da40334413c6cd4367b25ef26d24e" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "wry" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f0e9642a0d061f6236c54ccae64c2722a7879ad4ec7dff59bd376d446d8e90" +dependencies = [ + "base64 0.22.1", + "block2 0.6.1", + "cookie", + "crossbeam-channel", + "dirs", + "dpi", + "dunce", + "gdkx11", + "gtk", + "html5ever", + "http 1.3.1", + "javascriptcore-rs", + "jni", + "kuchikiki", + "libc", + "ndk", + "objc2 0.6.2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation 0.3.1", + "objc2-ui-kit", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 2.0.17", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "synstructure", +] + +[[package]] +name = "zbus" +version = "5.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "nix", + "ordered-stream", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "windows-sys 0.60.2", + "winnow 0.7.13", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.106", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" +dependencies = [ + "serde", + "static_assertions", + "winnow 0.7.13", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "zvariant" +version = "5.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow 0.7.13", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.106", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.106", + "winnow 0.7.13", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml new file mode 100644 index 0000000..718e88e --- /dev/null +++ b/src-tauri/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "desktop" +version = "0.1.0" +description = "A Tauri App" +authors = ["you"] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +# The `_lib` suffix may seem redundant but it is necessary +# to make the lib name unique and wouldn't conflict with the bin name. +# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 +name = "desktop_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +tauri = { version = "2", features = ["tray-icon"] } +tauri-plugin-opener = "2" +tauri-plugin-deep-link = "2" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +open = "5" +urlencoding = "2" +reqwest = { version = "0.11", features = ["json"] } +tokio = { version = "1", features = ["full"] } +sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite", "chrono", "uuid"] } +chrono = { version = "0.4", features = ["serde"] } +uuid = { version = "1.0", features = ["v4", "serde"] } +discord-rich-presence = "1.0" + diff --git a/src-tauri/build.rs b/src-tauri/build.rs new file mode 100644 index 0000000..d860e1e --- /dev/null +++ b/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json new file mode 100644 index 0000000..ec2e275 --- /dev/null +++ b/src-tauri/capabilities/default.json @@ -0,0 +1,11 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "Capability for the main window", + "windows": ["main"], + "permissions": [ + "core:default", + "opener:default", + "deep-link:default" + ] +} diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png new file mode 100644 index 0000000..6813026 --- /dev/null +++ b/src-tauri/icons/128x128.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19b4fec485db7df51a691fcce72a3dd6f983e754fc4262da7154e4a4c688f69e +size 3512 diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000..b47084d --- /dev/null +++ b/src-tauri/icons/128x128@2x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c7660390d65217fe8de0892862254f47aee77e0af7096c75b8bfe168c5403f7 +size 7012 diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png new file mode 100644 index 0000000..e220e00 --- /dev/null +++ b/src-tauri/icons/32x32.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c6782dc65c8111c12cbc1882a0fea5e71ab8e51b18da2ce9580f5c88860ed02 +size 974 diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 0000000..3791d66 --- /dev/null +++ b/src-tauri/icons/Square107x107Logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:54f7a0f58c96a4b023c1edc4b53fc443e27dace50e345f6936fa29bc20f785ca +size 2863 diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000..1f395bd --- /dev/null +++ b/src-tauri/icons/Square142x142Logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fec1e2080ca73cd4c4a123b23b1cd364059a8a8efeba3076e21dfefed390693b +size 3858 diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 0000000..18c8f75 --- /dev/null +++ b/src-tauri/icons/Square150x150Logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65fb570cb0e61ffce02ad67784cb200a0bf058400300980a46fa0d0c8f43a77a +size 3966 diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 0000000..23277db --- /dev/null +++ b/src-tauri/icons/Square284x284Logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea0b7c5d4b1d1ab9c91d2f7c9b069c8dfbf4557b0649a5777d47332cde610262 +size 7737 diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 0000000..b9756bc --- /dev/null +++ b/src-tauri/icons/Square30x30Logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc72279c41b4ed343e8db7e7541ceef7b6b23edaa83d4e7338421dfcb8d63c33 +size 903 diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 0000000..28a7ba5 --- /dev/null +++ b/src-tauri/icons/Square310x310Logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9733a89c539115de3c49bd06720bfc99639d9a918f5df48a810e267cf3554119 +size 8591 diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 0000000..aa3467f --- /dev/null +++ b/src-tauri/icons/Square44x44Logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10be9840e58fb018eb9029601d42008e16c0c9cfa66b8f9467fee94f600160d4 +size 1299 diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 0000000..cc800b5 --- /dev/null +++ b/src-tauri/icons/Square71x71Logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2937fc83324cd9a1fddcfefd5927c791af31996a6840bfb3e2f1d578ad4129de +size 2011 diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 0000000..4c638f1 --- /dev/null +++ b/src-tauri/icons/Square89x89Logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12aed0e7ee06cb631427dc9da72c0c7ecf03857fbc4884d0c31f78314feb6c7f +size 2468 diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png new file mode 100644 index 0000000..b6f5b53 --- /dev/null +++ b/src-tauri/icons/StoreLogo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91a54024dd47230991546088f2e75d3e3199b3ccc9fe40f3f6b7d3bf1cbf7776 +size 1523 diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns new file mode 100644 index 0000000..12a5bce Binary files /dev/null and b/src-tauri/icons/icon.icns differ diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico new file mode 100644 index 0000000..b3636e4 Binary files /dev/null and b/src-tauri/icons/icon.ico differ diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png new file mode 100644 index 0000000..ec82dd4 --- /dev/null +++ b/src-tauri/icons/icon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:273cd669e07c455ad1c7c095890a37984652157cee73128a867300067dfb80e7 +size 14183 diff --git a/src-tauri/programmer_classes.json b/src-tauri/programmer_classes.json new file mode 100644 index 0000000..ace98fa --- /dev/null +++ b/src-tauri/programmer_classes.json @@ -0,0 +1,243 @@ +{ + "classes": [ + { + "name": "The Rustacean", + "description": "A fearless systems programmer who embraces memory safety and zero-cost abstractions.", + "level": "Legendary", + "color": "#CE422B", + "technologies": ["Rust", "Cargo", "Tokio", "Serde"], + "conditions": { + "primary_languages": ["Rust"], + "min_hours": 50, + "min_streak": 7 + } + }, + { + "name": "The Pythonista", + "description": "A versatile developer who believes in the beauty of clean, readable code.", + "level": "Expert", + "color": "#3776AB", + "technologies": ["Python", "Django", "Flask", "Pandas", "NumPy"], + "conditions": { + "primary_languages": ["Python"], + "min_hours": 30, + "min_streak": 5 + } + }, + { + "name": "The JavaScript Ninja", + "description": "A master of the web who can make anything dance in the browser.", + "level": "Advanced", + "color": "#F7DF1E", + "technologies": ["JavaScript", "Node.js", "React", "Vue.js", "TypeScript"], + "conditions": { + "primary_languages": ["JavaScript", "TypeScript"], + "min_hours": 20, + "min_streak": 3 + } + }, + { + "name": "The Go Gopher", + "description": "A pragmatic developer who values simplicity and concurrency.", + "level": "Advanced", + "color": "#00ADD8", + "technologies": ["Go", "Goroutines", "Channels", "Gin", "Echo"], + "conditions": { + "primary_languages": ["Go"], + "min_hours": 25, + "min_streak": 4 + } + }, + { + "name": "The C++ Wizard", + "description": "A master of performance who wields templates and memory management like a sorcerer.", + "level": "Expert", + "color": "#00599C", + "technologies": ["C++", "STL", "Boost", "CMake", "Conan"], + "conditions": { + "primary_languages": ["C++", "C"], + "min_hours": 40, + "min_streak": 6 + } + }, + { + "name": "The Java Architect", + "description": "A enterprise developer who builds robust, scalable systems.", + "level": "Expert", + "color": "#ED8B00", + "technologies": ["Java", "Spring", "Maven", "JUnit", "Hibernate"], + "conditions": { + "primary_languages": ["Java"], + "min_hours": 35, + "min_streak": 5 + } + }, + { + "name": "The Swift Enthusiast", + "description": "An iOS developer who crafts beautiful, performant mobile experiences.", + "level": "Advanced", + "color": "#FA7343", + "technologies": ["Swift", "SwiftUI", "UIKit", "Combine", "Core Data"], + "conditions": { + "primary_languages": ["Swift"], + "min_hours": 20, + "min_streak": 3 + } + }, + { + "name": "The Kotlin Craftsman", + "description": "A modern Android developer who embraces null safety and functional programming.", + "level": "Advanced", + "color": "#7F52FF", + "technologies": ["Kotlin", "Android", "Jetpack Compose", "Coroutines", "Ktor"], + "conditions": { + "primary_languages": ["Kotlin"], + "min_hours": 25, + "min_streak": 4 + } + }, + { + "name": "The Ruby Gem", + "description": "A developer who values developer happiness and elegant syntax.", + "level": "Intermediate", + "color": "#CC342D", + "technologies": ["Ruby", "Rails", "RSpec", "Bundler", "Sinatra"], + "conditions": { + "primary_languages": ["Ruby"], + "min_hours": 15, + "min_streak": 3 + } + }, + { + "name": "The PHP Artisan", + "description": "A web developer who powers the internet with dynamic content.", + "level": "Intermediate", + "color": "#777BB4", + "technologies": ["PHP", "Laravel", "Composer", "Symfony", "WordPress"], + "conditions": { + "primary_languages": ["PHP"], + "min_hours": 15, + "min_streak": 3 + } + }, + { + "name": "The C# Sharp", + "description": "A Microsoft ecosystem developer who builds enterprise solutions.", + "level": "Advanced", + "color": "#239120", + "technologies": ["C#", ".NET", "ASP.NET", "Entity Framework", "Xamarin"], + "conditions": { + "primary_languages": ["C#"], + "min_hours": 25, + "min_streak": 4 + } + }, + { + "name": "The Scala Scholar", + "description": "A functional programming enthusiast who combines OOP and FP paradigms.", + "level": "Expert", + "color": "#DC322F", + "technologies": ["Scala", "Akka", "Play Framework", "SBT", "Cats"], + "conditions": { + "primary_languages": ["Scala"], + "min_hours": 30, + "min_streak": 5 + } + }, + { + "name": "The Haskell Wizard", + "description": "A pure functional programmer who thinks in types and monads.", + "level": "Legendary", + "color": "#5D4F85", + "technologies": ["Haskell", "GHC", "Stack", "Cabal", "Lens"], + "conditions": { + "primary_languages": ["Haskell"], + "min_hours": 20, + "min_streak": 3 + } + }, + { + "name": "The Clojure Conjurer", + "description": "A Lisp enthusiast who embraces immutability and functional programming.", + "level": "Advanced", + "color": "#5881D8", + "technologies": ["Clojure", "ClojureScript", "Leiningen", "Ring", "Reagent"], + "conditions": { + "primary_languages": ["Clojure"], + "min_hours": 15, + "min_streak": 3 + } + }, + { + "name": "The Elixir Alchemist", + "description": "A concurrent programmer who builds fault-tolerant distributed systems.", + "level": "Advanced", + "color": "#4B275F", + "technologies": ["Elixir", "Phoenix", "OTP", "Mix", "Ecto"], + "conditions": { + "primary_languages": ["Elixir"], + "min_hours": 20, + "min_streak": 3 + } + }, + { + "name": "The R Researcher", + "description": "A data scientist who uncovers insights from complex datasets.", + "level": "Expert", + "color": "#276DC3", + "technologies": ["R", "Shiny", "ggplot2", "dplyr", "RStudio"], + "conditions": { + "primary_languages": ["R"], + "min_hours": 25, + "min_streak": 4 + } + }, + { + "name": "The Julia Scientist", + "description": "A numerical computing expert who combines performance with ease of use.", + "level": "Advanced", + "color": "#9558B2", + "technologies": ["Julia", "Plots.jl", "DataFrames.jl", "Flux.jl", "Genie.jl"], + "conditions": { + "primary_languages": ["Julia"], + "min_hours": 15, + "min_streak": 3 + } + }, + { + "name": "The Assembly Artisan", + "description": "A low-level programming master who understands the machine at its core.", + "level": "Legendary", + "color": "#6E4C13", + "technologies": ["Assembly", "x86", "ARM", "MASM", "NASM"], + "conditions": { + "primary_languages": ["Assembly"], + "min_hours": 10, + "min_streak": 2 + } + }, + { + "name": "The Polyglot", + "description": "A versatile developer who speaks many programming languages fluently.", + "level": "Expert", + "color": "#FF6B6B", + "technologies": ["Multiple Languages", "Cross-platform", "Microservices", "DevOps"], + "conditions": { + "language_count": 5, + "min_hours": 50, + "min_streak": 7 + } + }, + { + "name": "The Code Explorer", + "description": "An enthusiastic learner discovering the vast world of programming.", + "level": "Learning", + "color": "#9C27B0", + "technologies": ["HTML", "CSS", "JavaScript", "Git", "VS Code"], + "conditions": { + "min_hours": 0, + "max_hours": 20 + } + } + ] +} diff --git a/src-tauri/src/database.rs b/src-tauri/src/database.rs new file mode 100644 index 0000000..ef6f814 --- /dev/null +++ b/src-tauri/src/database.rs @@ -0,0 +1,349 @@ +use serde::{Deserialize, Serialize}; +use sqlx::{sqlite::SqlitePool, Row}; +use std::collections::HashMap; +use std::path::Path; +use std::fs; +use std::env; +use chrono::{DateTime, Utc}; +use uuid::Uuid; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct AuthState { + pub is_authenticated: bool, + pub access_token: Option, + pub user_info: Option>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[allow(dead_code)] +pub struct SessionRecord { + pub id: String, + pub is_authenticated: bool, + pub access_token: Option, + pub user_info: Option, // JSON string + pub created_at: DateTime, + pub updated_at: DateTime, + pub last_accessed_at: DateTime, +} + +pub struct Database { + pool: SqlitePool, +} + +impl Database { + pub async fn new() -> Result { + let db_path = get_hackatime_db_path()?; + + // Ensure the hackatime directory exists + if let Some(parent) = db_path.parent() { + if !parent.exists() { + fs::create_dir_all(parent) + .map_err(|e| format!("Failed to create hackatime directory: {}", e))?; + println!("Created directory: {}", parent.display()); + } + } + + // Ensure the parent directory exists and is writable + if let Some(parent) = db_path.parent() { + if !parent.exists() { + return Err(format!("Parent directory does not exist: {}", parent.display())); + } + + // Test if we can write to the directory + let test_file = parent.join(".write_test"); + if let Err(e) = fs::write(&test_file, "test") { + return Err(format!("Cannot write to directory {}: {}", parent.display(), e)); + } + // Clean up test file + let _ = fs::remove_file(&test_file); + + println!("Directory is writable: {}", parent.display()); + } + + // Create the database file if it doesn't exist + if !db_path.exists() { + println!("Database file doesn't exist, creating: {}", db_path.display()); + // Touch the file to ensure it exists + if let Err(e) = fs::write(&db_path, "") { + return Err(format!("Cannot create database file {}: {}", db_path.display(), e)); + } + } else { + println!("Database file already exists: {}", db_path.display()); + } + + // Check file permissions + if let Ok(metadata) = fs::metadata(&db_path) { + println!("Database file metadata: {:?}", metadata); + } + + // Try using SqlitePool::connect_with instead of connect + let database_url = format!("sqlite:{}", db_path.display()); + println!("Connecting to database at: {}", database_url); + + // First try the standard connect method + let pool_result = SqlitePool::connect(&database_url).await; + + let pool = match pool_result { + Ok(pool) => pool, + Err(e) => { + println!("Standard connect failed: {}, trying connect_with", e); + // Try with explicit options + let options = sqlx::sqlite::SqliteConnectOptions::new() + .filename(&db_path) + .create_if_missing(true); + + SqlitePool::connect_with(options) + .await + .map_err(|e| format!("Failed to connect to database at {} with connect_with: {}", db_path.display(), e))? + } + }; + + let db = Database { pool }; + db.migrate().await?; + + println!("Database initialized successfully"); + Ok(db) + } + + async fn migrate(&self) -> Result<(), String> { + sqlx::query( + r#" + CREATE TABLE IF NOT EXISTS sessions ( + id TEXT PRIMARY KEY, + is_authenticated INTEGER NOT NULL DEFAULT 0, + access_token TEXT, + user_info TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + last_accessed_at TEXT NOT NULL + ) + "#, + ) + .execute(&self.pool) + .await + .map_err(|e| format!("Failed to create sessions table: {}", e))?; + + Ok(()) + } + + pub async fn save_session(&self, auth_state: &AuthState) -> Result { + let session_id = Uuid::new_v4().to_string(); + let now = Utc::now(); + + let user_info_json = match &auth_state.user_info { + Some(info) => Some(serde_json::to_string(info) + .map_err(|e| format!("Failed to serialize user info: {}", e))?), + None => None, + }; + + sqlx::query( + r#" + INSERT INTO sessions (id, is_authenticated, access_token, user_info, created_at, updated_at, last_accessed_at) + VALUES (?, ?, ?, ?, ?, ?, ?) + "#, + ) + .bind(&session_id) + .bind(auth_state.is_authenticated as i32) + .bind(&auth_state.access_token) + .bind(&user_info_json) + .bind(now.to_rfc3339()) + .bind(now.to_rfc3339()) + .bind(now.to_rfc3339()) + .execute(&self.pool) + .await + .map_err(|e| format!("Failed to save session: {}", e))?; + + Ok(session_id) + } + + #[allow(dead_code)] + pub async fn update_session(&self, session_id: &str, auth_state: &AuthState) -> Result<(), String> { + let now = Utc::now(); + + let user_info_json = match &auth_state.user_info { + Some(info) => Some(serde_json::to_string(info) + .map_err(|e| format!("Failed to serialize user info: {}", e))?), + None => None, + }; + + sqlx::query( + r#" + UPDATE sessions + SET is_authenticated = ?, access_token = ?, user_info = ?, updated_at = ?, last_accessed_at = ? + WHERE id = ? + "#, + ) + .bind(auth_state.is_authenticated as i32) + .bind(&auth_state.access_token) + .bind(&user_info_json) + .bind(now.to_rfc3339()) + .bind(now.to_rfc3339()) + .bind(session_id) + .execute(&self.pool) + .await + .map_err(|e| format!("Failed to update session: {}", e))?; + + Ok(()) + } + + pub async fn load_latest_session(&self) -> Result, String> { + let row = sqlx::query( + r#" + SELECT id, is_authenticated, access_token, user_info, last_accessed_at + FROM sessions + ORDER BY last_accessed_at DESC + LIMIT 1 + "#, + ) + .fetch_optional(&self.pool) + .await + .map_err(|e| format!("Failed to load latest session: {}", e))?; + + match row { + Some(row) => { + let session_id: String = row.get("id"); + let is_authenticated: i32 = row.get("is_authenticated"); + let access_token: Option = row.get("access_token"); + let user_info_json: Option = row.get("user_info"); + + let user_info = match user_info_json { + Some(json) => { + match serde_json::from_str::>(&json) { + Ok(info) => Some(info), + Err(_) => None, // Skip invalid JSON + } + } + None => None, + }; + + // Update last_accessed_at + self.update_last_accessed(&session_id).await?; + + Ok(Some(AuthState { + is_authenticated: is_authenticated != 0, + access_token, + user_info, + })) + } + None => Ok(None), + } + } + + async fn update_last_accessed(&self, session_id: &str) -> Result<(), String> { + let now = Utc::now(); + + sqlx::query( + "UPDATE sessions SET last_accessed_at = ? WHERE id = ?" + ) + .bind(now.to_rfc3339()) + .bind(session_id) + .execute(&self.pool) + .await + .map_err(|e| format!("Failed to update last accessed time: {}", e))?; + + Ok(()) + } + + pub async fn clear_sessions(&self) -> Result<(), String> { + sqlx::query("DELETE FROM sessions") + .execute(&self.pool) + .await + .map_err(|e| format!("Failed to clear sessions: {}", e))?; + + Ok(()) + } + + pub async fn cleanup_old_sessions(&self, days_old: i64) -> Result<(), String> { + let cutoff = Utc::now() - chrono::Duration::days(days_old); + + sqlx::query("DELETE FROM sessions WHERE last_accessed_at < ?") + .bind(cutoff.to_rfc3339()) + .execute(&self.pool) + .await + .map_err(|e| format!("Failed to cleanup old sessions: {}", e))?; + + Ok(()) + } +} + +fn get_hackatime_db_path() -> Result { + let app_data_dir = get_app_data_dir()?; + let db_path = app_data_dir.join("sessions.db"); + + println!("Database path: {}", db_path.display()); + println!("Parent directory exists: {}", db_path.parent().map_or(false, |p| p.exists())); + + Ok(db_path) +} + +fn get_app_data_dir() -> Result { + if cfg!(target_os = "windows") { + // Windows: %APPDATA%\.hackatime\ + let appdata = env::var("APPDATA").map_err(|_| "Failed to get APPDATA directory")?; + Ok(Path::new(&appdata).join(".hackatime")) + } else if cfg!(target_os = "macos") { + // macOS: ~/Library/Application Support/.hackatime/ + let home = env::var("HOME").map_err(|_| "Failed to get HOME directory")?; + Ok(Path::new(&home).join("Library").join("Application Support").join(".hackatime")) + } else { + // Linux: ~/.local/share/.hackatime/ + let home = env::var("HOME").map_err(|_| "Failed to get HOME directory")?; + Ok(Path::new(&home).join(".local").join("share").join(".hackatime")) + } +} + +pub fn get_hackatime_config_dir() -> Result { + let app_data_dir = get_app_data_dir()?; + + // Create the directory if it doesn't exist + if !app_data_dir.exists() { + fs::create_dir_all(&app_data_dir) + .map_err(|e| format!("Failed to create hackatime directory: {}", e))?; + } + + Ok(app_data_dir) +} + +pub fn get_hackatime_logs_dir() -> Result { + let config_dir = get_hackatime_config_dir()?; + let logs_dir = config_dir.join("logs"); + + // Create the logs directory if it doesn't exist + if !logs_dir.exists() { + fs::create_dir_all(&logs_dir) + .map_err(|e| format!("Failed to create logs directory: {}", e))?; + } + + Ok(logs_dir) +} + +pub fn get_hackatime_data_dir() -> Result { + let config_dir = get_hackatime_config_dir()?; + let data_dir = config_dir.join("data"); + + // Create the data directory if it doesn't exist + if !data_dir.exists() { + fs::create_dir_all(&data_dir) + .map_err(|e| format!("Failed to create data directory: {}", e))?; + } + + Ok(data_dir) +} + +pub fn get_platform_info() -> Result { + let app_data_dir = get_app_data_dir()?; + + let platform_info = serde_json::json!({ + "platform": std::env::consts::OS, + "app_data_dir": app_data_dir.to_string_lossy(), + "description": if cfg!(target_os = "windows") { + "Windows AppData directory" + } else if cfg!(target_os = "macos") { + "macOS Application Support directory" + } else { + "Linux XDG data directory" + } + }); + + Ok(platform_info) +} diff --git a/src-tauri/src/discord_rpc.rs b/src-tauri/src/discord_rpc.rs new file mode 100644 index 0000000..8c49d1b --- /dev/null +++ b/src-tauri/src/discord_rpc.rs @@ -0,0 +1,194 @@ +use discord_rich_presence::{activity, DiscordIpc, DiscordIpcClient}; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use std::sync::Mutex; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct DiscordRpcState { + pub is_connected: bool, + pub client_id: Option, + pub current_activity: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct DiscordActivity { + pub project_name: String, + pub language: Option, + pub editor: Option, + pub entity: Option, + pub start_time: Option, +} + +pub struct DiscordRpcService { + client: Option, + state: Arc>, +} + +impl DiscordRpcService { + pub fn new() -> Self { + Self { + client: None, + state: Arc::new(Mutex::new(DiscordRpcState { + is_connected: false, + client_id: None, + current_activity: None, + })), + } + } + + pub fn connect(&mut self, client_id: &str) -> Result<(), String> { + // Close existing connection if any + if self.client.is_some() { + let _ = self.disconnect(); + } + + let mut client = DiscordIpcClient::new(client_id); + + client.connect() + .map_err(|e| format!("Failed to connect to Discord: {}", e))?; + + self.client = Some(client); + + // Update state + let mut state = self.state.lock().unwrap(); + state.is_connected = true; + state.client_id = Some(client_id.to_string()); + + Ok(()) + } + + pub fn disconnect(&mut self) -> Result<(), String> { + if let Some(mut client) = self.client.take() { + client.close() + .map_err(|e| format!("Failed to disconnect from Discord: {}", e))?; + } + + // Update state + let mut state = self.state.lock().unwrap(); + state.is_connected = false; + state.client_id = None; + state.current_activity = None; + + Ok(()) + } + + pub fn set_activity(&mut self, activity: DiscordActivity) -> Result<(), String> { + self.set_activity_internal(activity.clone())?; + + // Update state + let mut state = self.state.lock().unwrap(); + state.current_activity = Some(activity); + + Ok(()) + } + + fn set_activity_internal(&mut self, activity: DiscordActivity) -> Result<(), String> { + let client = self.client.as_mut() + .ok_or("Discord client not connected")?; + + // Build details string + let mut details_parts = Vec::new(); + + if let Some(language) = &activity.language { + details_parts.push(format!("Language: {}", language)); + } + + if let Some(editor) = &activity.editor { + details_parts.push(format!("Editor: {}", editor)); + } + + if let Some(entity) = &activity.entity { + let filename = entity.split('/').last().unwrap_or(entity); + details_parts.push(format!("File: {}", filename)); + } + + let details_string = if !details_parts.is_empty() { + Some(details_parts.join(" • ")) + } else { + None + }; + + // Create activity with all components + let mut discord_activity = activity::Activity::new() + .state(&activity.project_name); + + if let Some(details) = &details_string { + discord_activity = discord_activity.details(details); + } + + // Set start time if provided + if let Some(start_time) = activity.start_time { + discord_activity = discord_activity.timestamps(activity::Timestamps::new().start(start_time)); + } + + // Add assets + discord_activity = discord_activity + .assets(activity::Assets::new() + .large_image("kubetime") + .large_text("KubeTime - Time Tracking") + .small_image("coding") + .small_text("Coding")); + + client.set_activity(discord_activity) + .map_err(|e| format!("Failed to set Discord activity: {}", e))?; + + Ok(()) + } + + pub fn clear_activity(&mut self) -> Result<(), String> { + let client = self.client.as_mut() + .ok_or("Discord client not connected")?; + + client.clear_activity() + .map_err(|e| format!("Failed to clear Discord activity: {}", e))?; + + // Update state + let mut state = self.state.lock().unwrap(); + state.current_activity = None; + + Ok(()) + } + + pub fn get_state(&self) -> DiscordRpcState { + self.state.lock().unwrap().clone() + } + + pub fn is_connected(&self) -> bool { + self.state.lock().unwrap().is_connected + } + + pub fn update_activity_from_heartbeat(&mut self, heartbeat_data: &crate::HeartbeatData) -> Result<(), String> { + let activity = DiscordActivity { + project_name: heartbeat_data.project.clone().unwrap_or_else(|| "Unknown Project".to_string()), + language: heartbeat_data.language.clone(), + editor: heartbeat_data.editor.clone(), + entity: heartbeat_data.entity.clone(), + start_time: Some(heartbeat_data.timestamp as i64), + }; + + self.set_activity(activity) + } + + pub fn update_activity_from_session(&mut self, heartbeat_data: &crate::HeartbeatData, session_start_time: i64) -> Result<(), String> { + let activity = DiscordActivity { + project_name: heartbeat_data.project.clone().unwrap_or_else(|| "Unknown Project".to_string()), + language: heartbeat_data.language.clone(), + editor: heartbeat_data.editor.clone(), + entity: heartbeat_data.entity.clone(), + start_time: Some(session_start_time), + }; + + self.set_activity(activity) + } + + pub fn auto_connect(&mut self) -> Result<(), String> { + const DEFAULT_CLIENT_ID: &str = "1423077619183779872"; + self.connect(DEFAULT_CLIENT_ID) + } +} + +impl Drop for DiscordRpcService { + fn drop(&mut self) { + let _ = self.disconnect(); + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs new file mode 100644 index 0000000..8f626d0 --- /dev/null +++ b/src-tauri/src/lib.rs @@ -0,0 +1,2176 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::sync::Arc; +use std::path::Path; +use std::fs; +use std::env; +use tauri::{Manager, State, WindowEvent}; +use tauri_plugin_deep_link::DeepLinkExt; +use tauri::tray::{TrayIconBuilder, TrayIconEvent, MouseButton, MouseButtonState}; +use tauri::menu::{Menu, MenuItem}; + +mod database; +mod discord_rpc; +use database::{Database, AuthState as DbAuthState, get_hackatime_config_dir, get_hackatime_logs_dir, get_hackatime_data_dir, get_platform_info}; +use discord_rpc::{DiscordRpcService, DiscordRpcState, DiscordActivity}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct AuthState { + is_authenticated: bool, + access_token: Option, + user_info: Option>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct ApiConfig { + base_url: String, +} + +impl Default for ApiConfig { + fn default() -> Self { + Self { + base_url: "http://localhost:3000".to_string(), + } + } +} + +// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ +#[tauri::command] +fn greet(name: &str) -> String { + format!("Hello, {}! You've been greeted from Rust!", name) +} + +#[tauri::command] +async fn get_api_config(state: State<'_, ApiConfig>) -> Result { + Ok(state.inner().clone()) +} + +#[tauri::command] +async fn set_api_config( + new_config: ApiConfig, + state: State<'_, tauri::async_runtime::Mutex>, +) -> Result<(), String> { + let mut config = state.lock().await; + *config = new_config; + Ok(()) +} + +#[tauri::command] +async fn get_auth_state(state: State<'_, Arc>>) -> Result { + let auth_state = state.lock().await; + Ok(auth_state.clone()) +} + +#[tauri::command] +async fn authenticate_with_rails( + api_config: ApiConfig, + _state: State<'_, Arc>>, + _app_handle: tauri::AppHandle, +) -> Result<(), String> { + // Create the authentication URL with deep link callback + let callback_url = "kubetime://auth/callback"; + let auth_url = format!("{}/auth/desktop?callback={}", api_config.base_url, urlencoding::encode(callback_url)); + + // Open the authentication URL in the default browser + if let Err(e) = open::that(&auth_url) { + return Err(format!("Failed to open authentication URL: {}", e)); + } + + // Show a message to the user about the authentication process + // In a real implementation, you would handle the OAuth callback + // For now, we'll just open the browser and let the user complete auth there + + Ok(()) +} + +#[tauri::command] +async fn handle_auth_callback( + token: String, + state: State<'_, Arc>>, +) -> Result<(), String> { + let mut auth_state = state.lock().await; + auth_state.is_authenticated = true; + auth_state.access_token = Some(token); + // You would typically fetch user info here + auth_state.user_info = Some(HashMap::new()); + + Ok(()) +} + +#[tauri::command] +async fn logout( + state: State<'_, Arc>>, +) -> Result<(), String> { + let mut auth_state = state.lock().await; + auth_state.is_authenticated = false; + auth_state.access_token = None; + auth_state.user_info = None; + + // Clear saved auth state + if let Err(e) = clear_auth_state().await { + eprintln!("Failed to clear auth state: {}", e); + } + + Ok(()) +} + +#[tauri::command] +async fn test_auth_callback( + token: String, + state: State<'_, Arc>>, +) -> Result<(), String> { + let mut auth_state = state.lock().await; + auth_state.is_authenticated = true; + auth_state.access_token = Some(token); + auth_state.user_info = Some(HashMap::new()); + + Ok(()) +} + +#[tauri::command] +async fn get_api_key( + api_config: ApiConfig, + state: State<'_, Arc>>, +) -> Result { + let auth_state = state.lock().await; + + if !auth_state.is_authenticated { + return Err("Not authenticated".to_string()); + } + + let access_token = auth_state.access_token.as_ref() + .ok_or("No access token available")?; + + let client = reqwest::Client::new(); + let response = client + .get(&format!("{}/api/v1/desktop/api_key", api_config.base_url)) + .bearer_auth(access_token) + .send() + .await + .map_err(|e| format!("Failed to fetch API key: {}", e))?; + + if !response.status().is_success() { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + return Err(format!("API key request failed: {}", error_text)); + } + + let api_key_response: serde_json::Value = response.json().await + .map_err(|e| format!("Failed to parse API key response: {}", e))?; + + let api_key = api_key_response["api_key"].as_str() + .ok_or("No API key in response")?; + + Ok(api_key.to_string()) +} + +#[tauri::command] +async fn authenticate_with_direct_oauth( + oauth_token: String, + api_config: ApiConfig, + state: State<'_, Arc>>, +) -> Result<(), String> { + let client = reqwest::Client::new(); + + // Check if this is a deep link URL and extract the temp_token + let token_to_use = if oauth_token.starts_with("kubetime://auth/callback") { + // Extract temp_token from deep link URL + if let Some(query_start) = oauth_token.find('?') { + let query = &oauth_token[query_start + 1..]; + let params: Vec<&str> = query.split('&').collect(); + + let mut found_token = None; + for param in params { + if param.starts_with("temp_token=") { + let temp_token = param[11..].to_string(); // Remove "temp_token=" prefix + println!("Extracted temp_token from deep link: {}", temp_token); + found_token = Some(temp_token); + break; + } + } + + match found_token { + Some(token) => token, + None => return Err("No temp_token found in deep link URL".to_string()), + } + } else { + return Err("Invalid deep link URL format".to_string()); + } + } else { + oauth_token + }; + + // Determine if this is a temporary token or a full OAuth token + // Temporary tokens are typically 64 characters (32 bytes in hex) + // OAuth tokens are usually longer and have a different format + + let is_temp_token = token_to_use.len() == 64 && token_to_use.chars().all(|c| c.is_ascii_hexdigit()); + + if is_temp_token { + // This is a temporary token, exchange it for a proper OAuth token + println!("Attempting to exchange temporary token: {}", token_to_use); + let exchange_url = format!("{}/api/v1/desktop/exchange_token", api_config.base_url); + println!("Exchange URL: {}", exchange_url); + + let response = client + .post(&exchange_url) + .json(&serde_json::json!({ + "temp_token": token_to_use + })) + .send() + .await + .map_err(|e| format!("Failed to exchange temporary token: {}", e))?; + + println!("Exchange response status: {}", response.status()); + + if !response.status().is_success() { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + println!("Exchange failed with error: {}", error_text); + return Err(format!("Token exchange failed: {}", error_text)); + } + + let token_response: serde_json::Value = response.json().await + .map_err(|e| format!("Failed to parse token response: {}", e))?; + + let access_token = token_response["access_token"].as_str() + .ok_or("No access token in response")?; + + let user_info = token_response["user"].as_object() + .ok_or("No user info in response")?; + + // Convert serde_json::Map to HashMap + let mut user_info_map = HashMap::new(); + for (key, value) in user_info { + user_info_map.insert(key.clone(), value.clone()); + } + + // Update authentication state + let mut auth_state = state.lock().await; + auth_state.is_authenticated = true; + auth_state.access_token = Some(access_token.to_string()); + auth_state.user_info = Some(user_info_map); + + // Save auth state to disk + let auth_state_to_save = auth_state.clone(); + drop(auth_state); // Release the lock before the async call + if let Err(e) = save_auth_state(auth_state_to_save).await { + eprintln!("Failed to save auth state: {}", e); + } + + Ok(()) + } else { + // This is a full OAuth token, validate it directly + let response = client + .post(&format!("{}/api/v1/desktop/validate_oauth_token", api_config.base_url)) + .json(&serde_json::json!({ + "oauth_token": token_to_use + })) + .send() + .await + .map_err(|e| format!("Failed to validate OAuth token: {}", e))?; + + if !response.status().is_success() { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + return Err(format!("OAuth token validation failed: {}", error_text)); + } + + let auth_response: serde_json::Value = response.json().await + .map_err(|e| format!("Failed to parse auth response: {}", e))?; + + let user_info = auth_response["user"].as_object() + .ok_or("No user info in response")?; + + // Convert serde_json::Map to HashMap + let mut user_info_map = HashMap::new(); + for (key, value) in user_info { + user_info_map.insert(key.clone(), value.clone()); + } + + // Get the access token and API keys + let access_token = auth_response["access_token"].as_str() + .ok_or("No access token in response")?; + + let _api_key = auth_response["api_key"].as_str() + .ok_or("No API key in response")?; + + // Update authentication state + let mut auth_state = state.lock().await; + auth_state.is_authenticated = true; + auth_state.access_token = Some(access_token.to_string()); + auth_state.user_info = Some(user_info_map); + + + // Save auth state to disk + let auth_state_to_save = auth_state.clone(); + drop(auth_state); // Release the lock before the async call + if let Err(e) = save_auth_state(auth_state_to_save).await { + eprintln!("Failed to save auth state: {}", e); + } + + Ok(()) + } +} + +#[tauri::command] +async fn handle_deep_link_callback( + temp_token: String, + api_config: ApiConfig, + auth_state: State<'_, Arc>>, +) -> Result<(), String> { + // Exchange temporary token for proper access token + let client = reqwest::Client::new(); + let response = client + .post(&format!("{}/api/v1/desktop/exchange_token", api_config.base_url)) + .json(&serde_json::json!({ + "temp_token": temp_token + })) + .send() + .await + .map_err(|e| format!("Failed to exchange token: {}", e))?; + + if !response.status().is_success() { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + return Err(format!("Token exchange failed: {}", error_text)); + } + + let token_response: serde_json::Value = response.json().await + .map_err(|e| format!("Failed to parse token response: {}", e))?; + + let access_token = token_response["access_token"].as_str() + .ok_or("No access token in response")?; + + let user_info = token_response["user"].as_object() + .ok_or("No user info in response")?; + + // Convert serde_json::Map to HashMap + let mut user_info_map = HashMap::new(); + for (key, value) in user_info { + user_info_map.insert(key.clone(), value.clone()); + } + + // Update authentication state + let mut auth_state = auth_state.lock().await; + auth_state.is_authenticated = true; + auth_state.access_token = Some(access_token.to_string()); + auth_state.user_info = Some(user_info_map); + + // Save auth state to disk + let auth_state_to_save = auth_state.clone(); + drop(auth_state); // Release the lock before the async call + if let Err(e) = save_auth_state(auth_state_to_save).await { + eprintln!("Failed to save auth state: {}", e); + } + + Ok(()) +} + +#[tauri::command] +async fn setup_hackatime_macos_linux( + api_key: String, + api_url: String, +) -> Result { + let home_dir = std::env::var("HOME") + .map_err(|_| "Failed to get home directory")?; + + let config_path = format!("{}/.wakatime.cfg", home_dir); + let backup_path = format!("{}/.wakatime.cfg.bak", home_dir); + + // Backup existing config if it exists + if Path::new(&config_path).exists() { + if let Err(e) = fs::rename(&config_path, &backup_path) { + return Err(format!("Failed to backup existing config: {}", e)); + } + } + + // Create new config file + let config_content = format!( + "[settings]\napi_url = {}\napi_key = {}\nheartbeat_rate_limit_seconds = 30\n", + api_url, api_key + ); + + if let Err(e) = fs::write(&config_path, config_content) { + return Err(format!("Failed to write config file: {}", e)); + } + + // Verify config was created + if !Path::new(&config_path).exists() { + return Err("Config file was not created".to_string()); + } + + // Read and verify config + let config_content = fs::read_to_string(&config_path) + .map_err(|e| format!("Failed to read config file: {}", e))?; + + let lines: Vec<&str> = config_content.lines().collect(); + let mut found_api_url = false; + let mut found_api_key = false; + let mut found_heartbeat_rate = false; + + for line in lines { + if line.starts_with("api_url =") { + found_api_url = true; + } else if line.starts_with("api_key =") { + found_api_key = true; + } else if line.starts_with("heartbeat_rate_limit_seconds =") { + found_heartbeat_rate = true; + } + } + + if !found_api_url || !found_api_key || !found_heartbeat_rate { + return Err("Config file is missing required fields".to_string()); + } + + Ok(format!("Config file created successfully at {}", config_path)) +} + +#[tauri::command] +async fn setup_hackatime_windows( + api_key: String, + api_url: String, +) -> Result { + let userprofile = std::env::var("USERPROFILE") + .map_err(|_| "Failed to get USERPROFILE directory")?; + + let config_path = format!("{}\\.wakatime.cfg", userprofile); + let backup_path = format!("{}\\.wakatime.cfg.bak", userprofile); + + // Backup existing config if it exists + if Path::new(&config_path).exists() { + if let Err(e) = fs::rename(&config_path, &backup_path) { + return Err(format!("Failed to backup existing config: {}", e)); + } + } + + // Create new config file + let config_content = format!( + "[settings]\r\napi_url = {}\r\napi_key = {}\r\nheartbeat_rate_limit_seconds = 30\r\n", + api_url, api_key + ); + + if let Err(e) = fs::write(&config_path, config_content) { + return Err(format!("Failed to write config file: {}", e)); + } + + // Verify config was created + if !Path::new(&config_path).exists() { + return Err("Config file was not created".to_string()); + } + + // Read and verify config + let config_content = fs::read_to_string(&config_path) + .map_err(|e| format!("Failed to read config file: {}", e))?; + + let lines: Vec<&str> = config_content.lines().collect(); + let mut found_api_url = false; + let mut found_api_key = false; + let mut found_heartbeat_rate = false; + + for line in lines { + if line.starts_with("api_url =") { + found_api_url = true; + } else if line.starts_with("api_key =") { + found_api_key = true; + } else if line.starts_with("heartbeat_rate_limit_seconds =") { + found_heartbeat_rate = true; + } + } + + if !found_api_url || !found_api_key || !found_heartbeat_rate { + return Err("Config file is missing required fields".to_string()); + } + + Ok(format!("Config file created successfully at {}", config_path)) +} + +#[tauri::command] +async fn test_hackatime_heartbeat( + api_key: String, + api_url: String, +) -> Result { + let client = reqwest::Client::new(); + let current_time = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(); + + let heartbeat_data = serde_json::json!([{ + "type": "file", + "time": current_time, + "entity": "test.txt", + "language": "Text" + }]); + + let response = client + .post(&format!("{}/users/current/heartbeats", api_url)) + .header("Authorization", format!("Bearer {}", api_key)) + .header("Content-Type", "application/json") + .json(&heartbeat_data) + .send() + .await + .map_err(|e| format!("Failed to send heartbeat: {}", e))?; + + if response.status().is_success() { + Ok("Test heartbeat sent successfully!".to_string()) + } else { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + Err(format!("Heartbeat failed: {}", error_text)) + } +} + +#[tauri::command] +async fn setup_hackatime_complete( + api_key: String, + api_url: String, +) -> Result { + // Detect operating system and use appropriate setup function + if cfg!(target_os = "windows") { + setup_hackatime_windows(api_key, api_url).await + } else { + setup_hackatime_macos_linux(api_key, api_url).await + } +} + +#[tauri::command] +async fn save_auth_state( + auth_state: AuthState, +) -> Result<(), String> { + println!("save_auth_state called: authenticated={}, has_token={}", + auth_state.is_authenticated, + auth_state.access_token.is_some()); + let db = Database::new().await?; + println!("Database connection successful for save"); + + // Convert to database AuthState format + let db_auth_state = DbAuthState { + is_authenticated: auth_state.is_authenticated, + access_token: auth_state.access_token, + user_info: auth_state.user_info, + }; + + // Save to database + let session_id = db.save_session(&db_auth_state).await?; + println!("Session saved with ID: {}", session_id); + + Ok(()) +} + +#[tauri::command] +async fn load_auth_state() -> Result, String> { + println!("load_auth_state called"); + let db = Database::new().await?; + println!("Database connection successful"); + + match db.load_latest_session().await? { + Some(db_auth_state) => { + println!("Found saved session: authenticated={}, has_token={}", + db_auth_state.is_authenticated, + db_auth_state.access_token.is_some()); + let auth_state = AuthState { + is_authenticated: db_auth_state.is_authenticated, + access_token: db_auth_state.access_token, + user_info: db_auth_state.user_info, + }; + Ok(Some(auth_state)) + } + None => { + println!("No saved sessions found"); + Ok(None) + } + } +} + +#[tauri::command] +async fn clear_auth_state() -> Result<(), String> { + let db = Database::new().await?; + db.clear_sessions().await?; + Ok(()) +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[allow(dead_code)] +struct PresenceNotification { + r#type: String, + message: Option, + user_id: u32, + username: String, + session_data: SessionData, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct HeartbeatData { + id: u32, + project: Option, + editor: Option, + language: Option, + entity: Option, + time: f64, + timestamp: i64, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct SessionState { + is_active: bool, + start_time: Option, + last_heartbeat_id: Option, + heartbeat_count: u32, + project: Option, + editor: Option, + language: Option, + entity: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct HeartbeatResponse { + heartbeat: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[allow(dead_code)] +struct SessionData { + project: Option, + editor: Option, + language: Option, + entity: Option, + start_time: i64, + last_heartbeat_time: i64, + heartbeat_count: u32, +} + +#[tauri::command] +async fn register_presence_connection( + api_config: ApiConfig, + state: State<'_, Arc>>, +) -> Result<(), String> { + let auth_state = state.lock().await; + + if !auth_state.is_authenticated { + return Err("Not authenticated".to_string()); + } + + let access_token = auth_state.access_token.as_ref() + .ok_or("No access token available")?; + + let client = reqwest::Client::new(); + let response = client + .post(&format!("{}/api/v1/presence/register", api_config.base_url)) + .bearer_auth(access_token) + .send() + .await + .map_err(|e| format!("Failed to register presence connection: {}", e))?; + + if !response.status().is_success() { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + return Err(format!("Presence registration failed: {}", error_text)); + } + + Ok(()) +} + +#[tauri::command] +async fn get_latest_heartbeat( + api_config: ApiConfig, + state: State<'_, Arc>>, + discord_rpc_state: State<'_, Arc>>, + session_state: State<'_, Arc>>, +) -> Result { + let auth_state = state.lock().await; + + if !auth_state.is_authenticated { + return Err("Not authenticated".to_string()); + } + + let access_token = auth_state.access_token.as_ref() + .ok_or("No access token available")?; + + let client = reqwest::Client::new(); + let response = client + .get(&format!("{}/api/v1/presence/latest_heartbeat", api_config.base_url)) + .bearer_auth(access_token) + .send() + .await + .map_err(|e| format!("Failed to get latest heartbeat: {}", e))?; + + let status = response.status(); + if !status.is_success() { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + + // Handle rate limiting gracefully + if status == 429 { + println!("Rate limited, will retry later"); + return Err(format!("Rate limited: {}", error_text)); + } + + return Err(format!("Failed to get latest heartbeat: {}", error_text)); + } + + let heartbeat_response: HeartbeatResponse = response.json().await + .map_err(|e| format!("Failed to parse heartbeat response: {}", e))?; + + // Process session logic + if let Some(heartbeat) = &heartbeat_response.heartbeat { + let mut session = session_state.lock().await; + let current_time = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + + // Check if heartbeat is less than 2 minutes old + let heartbeat_age = current_time - heartbeat.timestamp; + let is_recent = heartbeat_age < 120; // 2 minutes + + // Check for duplicate heartbeat (same ID as last one) + let is_duplicate = session.last_heartbeat_id == Some(heartbeat.id); + + if is_duplicate { + // Duplicate heartbeat detected - end the session + println!("Duplicate heartbeat detected, ending session"); + session.is_active = false; + session.start_time = None; + session.last_heartbeat_id = None; + session.heartbeat_count = 0; + session.project = None; + session.editor = None; + session.language = None; + session.entity = None; + + // Clear Discord RPC activity + let mut discord_rpc = discord_rpc_state.lock().await; + if discord_rpc.is_connected() { + let _ = discord_rpc.clear_activity(); + } + } else if is_recent && !session.is_active { + // Start new session + println!("Recent heartbeat detected, starting new session"); + session.is_active = true; + session.start_time = Some(heartbeat.timestamp); + session.last_heartbeat_id = Some(heartbeat.id); + session.heartbeat_count = 1; + session.project = heartbeat.project.clone(); + session.editor = heartbeat.editor.clone(); + session.language = heartbeat.language.clone(); + session.entity = heartbeat.entity.clone(); + + // Update Discord RPC with session start time + let mut discord_rpc = discord_rpc_state.lock().await; + if discord_rpc.is_connected() { + if let Err(e) = discord_rpc.update_activity_from_session(heartbeat, heartbeat.timestamp) { + eprintln!("Failed to update Discord RPC: {}", e); + } + } + } else if is_recent && session.is_active { + // Continue existing session + session.last_heartbeat_id = Some(heartbeat.id); + session.heartbeat_count += 1; + session.project = heartbeat.project.clone(); + session.editor = heartbeat.editor.clone(); + session.language = heartbeat.language.clone(); + session.entity = heartbeat.entity.clone(); + + // Update Discord RPC with session start time + let mut discord_rpc = discord_rpc_state.lock().await; + if discord_rpc.is_connected() { + if let Err(e) = discord_rpc.update_activity_from_session(heartbeat, session.start_time.unwrap_or(heartbeat.timestamp)) { + eprintln!("Failed to update Discord RPC: {}", e); + } + } + } else if !is_recent && session.is_active { + // Heartbeat is too old, end the session + println!("Heartbeat too old, ending session"); + session.is_active = false; + session.start_time = None; + session.last_heartbeat_id = None; + session.heartbeat_count = 0; + session.project = None; + session.editor = None; + session.language = None; + session.entity = None; + + // Clear Discord RPC activity + let mut discord_rpc = discord_rpc_state.lock().await; + if discord_rpc.is_connected() { + let _ = discord_rpc.clear_activity(); + } + } + } else { + // No heartbeat data - end session if active + let mut session = session_state.lock().await; + if session.is_active { + println!("No heartbeat data, ending session"); + session.is_active = false; + session.start_time = None; + session.last_heartbeat_id = None; + session.heartbeat_count = 0; + session.project = None; + session.editor = None; + session.language = None; + session.entity = None; + + // Clear Discord RPC activity + let mut discord_rpc = discord_rpc_state.lock().await; + if discord_rpc.is_connected() { + let _ = discord_rpc.clear_activity(); + } + } + } + + Ok(heartbeat_response) +} + +#[tauri::command] +async fn ping_presence_connection( + api_config: ApiConfig, + state: State<'_, Arc>>, +) -> Result<(), String> { + let auth_state = state.lock().await; + + if !auth_state.is_authenticated { + return Err("Not authenticated".to_string()); + } + + let access_token = auth_state.access_token.as_ref() + .ok_or("No access token available")?; + + let client = reqwest::Client::new(); + let response = client + .post(&format!("{}/api/v1/presence/ping", api_config.base_url)) + .bearer_auth(access_token) + .send() + .await + .map_err(|e| format!("Failed to ping presence connection: {}", e))?; + + if !response.status().is_success() { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + return Err(format!("Presence ping failed: {}", error_text)); + } + + Ok(()) +} + +#[allow(dead_code)] +fn get_config_dir() -> Result { + // Use hackatime directory structure + get_hackatime_config_dir() +} + +#[tauri::command] +async fn get_hackatime_directories() -> Result { + let config_dir = get_hackatime_config_dir()?; + let logs_dir = get_hackatime_logs_dir()?; + let data_dir = get_hackatime_data_dir()?; + + Ok(serde_json::json!({ + "config_dir": config_dir.to_string_lossy(), + "logs_dir": logs_dir.to_string_lossy(), + "data_dir": data_dir.to_string_lossy() + })) +} + +#[tauri::command] +async fn cleanup_old_sessions(days_old: i64) -> Result<(), String> { + let db = Database::new().await?; + db.cleanup_old_sessions(days_old).await?; + Ok(()) +} + +#[tauri::command] +async fn get_session_stats() -> Result { + let platform_info = get_platform_info()?; + + Ok(serde_json::json!({ + "platform_info": platform_info, + "database_path": get_hackatime_config_dir()?.join("sessions.db").to_string_lossy(), + "directories_created": { + "config": get_hackatime_config_dir()?.exists(), + "logs": get_hackatime_logs_dir()?.exists(), + "data": get_hackatime_data_dir()?.exists() + } + })) +} + +#[tauri::command] +async fn test_database_connection() -> Result { + // Test directory creation + let config_dir = get_hackatime_config_dir()?; + let logs_dir = get_hackatime_logs_dir()?; + let data_dir = get_hackatime_data_dir()?; + + // Test database connection + let db_result = Database::new().await; + let db_success = db_result.is_ok(); + let db_error = if let Err(e) = db_result { + Some(e) + } else { + None + }; + + Ok(serde_json::json!({ + "directories": { + "config_exists": config_dir.exists(), + "logs_exists": logs_dir.exists(), + "data_exists": data_dir.exists(), + "config_path": config_dir.to_string_lossy(), + "logs_path": logs_dir.to_string_lossy(), + "data_path": data_dir.to_string_lossy() + }, + "database": { + "connection_success": db_success, + "error": db_error, + "db_path": config_dir.join("sessions.db").to_string_lossy() + } + })) +} + +// Discord RPC Commands +#[tauri::command] +async fn discord_rpc_connect( + client_id: String, + state: State<'_, Arc>>, +) -> Result<(), String> { + let mut rpc_service = state.lock().await; + rpc_service.connect(&client_id) +} + +#[tauri::command] +async fn discord_rpc_disconnect( + state: State<'_, Arc>>, +) -> Result<(), String> { + let mut rpc_service = state.lock().await; + rpc_service.disconnect() +} + +#[tauri::command] +async fn discord_rpc_set_activity( + activity: DiscordActivity, + state: State<'_, Arc>>, +) -> Result<(), String> { + let mut rpc_service = state.lock().await; + rpc_service.set_activity(activity) +} + +#[tauri::command] +async fn discord_rpc_clear_activity( + state: State<'_, Arc>>, +) -> Result<(), String> { + let mut rpc_service = state.lock().await; + rpc_service.clear_activity() +} + +#[tauri::command] +async fn discord_rpc_get_state( + state: State<'_, Arc>>, +) -> Result { + let rpc_service = state.lock().await; + Ok(rpc_service.get_state()) +} + +#[tauri::command] +async fn discord_rpc_update_from_heartbeat( + heartbeat_data: HeartbeatData, + state: State<'_, Arc>>, +) -> Result<(), String> { + let mut rpc_service = state.lock().await; + rpc_service.update_activity_from_heartbeat(&heartbeat_data) +} + +#[tauri::command] +async fn discord_rpc_auto_connect( + client_id: String, + discord_rpc_state: State<'_, Arc>>, +) -> Result<(), String> { + let mut rpc_service = discord_rpc_state.lock().await; + rpc_service.connect(&client_id) +} + +#[tauri::command] +async fn discord_rpc_auto_disconnect( + discord_rpc_state: State<'_, Arc>>, +) -> Result<(), String> { + let mut rpc_service = discord_rpc_state.lock().await; + rpc_service.disconnect() +} + +#[tauri::command] +async fn get_current_session( + session_state: State<'_, Arc>>, +) -> Result { + let session = session_state.lock().await; + Ok(session.clone()) +} + +#[tauri::command] +async fn get_projects( + api_config: ApiConfig, + state: State<'_, Arc>>, +) -> Result { + let auth_state = state.lock().await; + + if !auth_state.is_authenticated { + return Err("Not authenticated".to_string()); + } + + let access_token = auth_state.access_token.as_ref() + .ok_or("No access token available")?; + + let client = reqwest::Client::new(); + let response = client + .get(&format!("{}/api/v1/authenticated/projects", api_config.base_url)) + .bearer_auth(access_token) + .send() + .await + .map_err(|e| format!("Failed to fetch projects: {}", e))?; + + if !response.status().is_success() { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + return Err(format!("Projects request failed: {}", error_text)); + } + + let projects_response: serde_json::Value = response.json().await + .map_err(|e| format!("Failed to parse projects response: {}", e))?; + + Ok(projects_response) +} + +#[tauri::command] +async fn get_project_details( + project_name: String, + api_config: ApiConfig, + state: State<'_, Arc>>, +) -> Result { + let auth_state = state.lock().await; + + if !auth_state.is_authenticated { + return Err("Not authenticated".to_string()); + } + + let access_token = auth_state.access_token.as_ref() + .ok_or("No access token available")?; + + let client = reqwest::Client::new(); + let response = client + .get(&format!("{}/api/v1/authenticated/projects/{}", api_config.base_url, urlencoding::encode(&project_name))) + .bearer_auth(access_token) + .send() + .await + .map_err(|e| format!("Failed to fetch project details: {}", e))?; + + if !response.status().is_success() { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + return Err(format!("Project details request failed: {}", error_text)); + } + + let project_response: serde_json::Value = response.json().await + .map_err(|e| format!("Failed to parse project response: {}", e))?; + + Ok(project_response) +} + +#[tauri::command] +async fn get_discord_rpc_enabled( + discord_rpc_state: State<'_, Arc>>, +) -> Result { + let rpc_service = discord_rpc_state.lock().await; + Ok(rpc_service.is_connected()) +} + +#[tauri::command] +async fn set_discord_rpc_enabled( + enabled: bool, + discord_rpc_state: State<'_, Arc>>, +) -> Result<(), String> { + let mut rpc_service = discord_rpc_state.lock().await; + + if enabled { + // Try to connect with a default client ID (you might want to make this configurable) + let default_client_id = "1234567890123456789"; // Replace with your Discord app client ID + rpc_service.connect(default_client_id) + } else { + rpc_service.disconnect() + } +} + +// Statistics and Trends Processing +#[derive(Debug, Serialize, Deserialize, Clone)] +struct StatisticsData { + trends: Vec, + charts: Vec, + insights: Vec, + programmer_class: ProgrammerClass, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct TrendStatistic { + title: String, + value: String, + change: String, + change_type: String, // "increase", "decrease", "neutral" + period: String, + icon: String, + color: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct ChartData { + id: String, + title: String, + chart_type: String, // "line", "bar", "pie", "area", "radar" + data: serde_json::Value, + period: String, + color_scheme: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct Insight { + title: String, + description: String, + value: String, + trend: String, + icon: String, + color: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct ProgrammerClass { + class_name: String, + description: String, + technologies: Vec, + level: String, + color: String, +} + +#[tauri::command] +async fn get_statistics_data( + api_config: ApiConfig, + state: State<'_, Arc>>, +) -> Result { + let auth_state = state.lock().await; + + if !auth_state.is_authenticated { + return Err("Not authenticated".to_string()); + } + + let access_token = auth_state.access_token.as_ref() + .ok_or("No access token available")?; + + let client = reqwest::Client::new(); + + // Get dashboard stats from Ruby API + let response = client + .get(&format!("{}/api/v1/authenticated/dashboard_stats", api_config.base_url)) + .bearer_auth(access_token) + .send() + .await + .map_err(|e| format!("Failed to fetch dashboard stats: {}", e))?; + + if !response.status().is_success() { + let error_text = response.text().await.unwrap_or_else(|_| "Unknown error".to_string()); + return Err(format!("Dashboard stats request failed: {}", error_text)); + } + + let dashboard_stats: serde_json::Value = response.json().await + .map_err(|e| format!("Failed to parse dashboard stats: {}", e))?; + + // Process the data in Rust for heavy computations + let statistics = process_statistics_data(dashboard_stats).await?; + + Ok(statistics) +} + +// Tray-related commands +#[tauri::command] +async fn show_window(app: tauri::AppHandle) -> Result<(), String> { + if let Some(window) = app.get_webview_window("main") { + window.show().map_err(|e| format!("Failed to show window: {}", e))?; + window.set_focus().map_err(|e| format!("Failed to focus window: {}", e))?; + } + Ok(()) +} + +#[tauri::command] +async fn hide_window(app: tauri::AppHandle) -> Result<(), String> { + if let Some(window) = app.get_webview_window("main") { + window.hide().map_err(|e| format!("Failed to hide window: {}", e))?; + } + Ok(()) +} + +#[tauri::command] +async fn toggle_window(app: tauri::AppHandle) -> Result<(), String> { + if let Some(window) = app.get_webview_window("main") { + if window.is_visible().unwrap_or(false) { + window.hide().map_err(|e| format!("Failed to hide window: {}", e))?; + } else { + window.show().map_err(|e| format!("Failed to show window: {}", e))?; + window.set_focus().map_err(|e| format!("Failed to focus window: {}", e))?; + } + } + Ok(()) +} + +#[tauri::command] +async fn get_app_status( + auth_state: State<'_, Arc>>, + session_state: State<'_, Arc>>, + discord_rpc_state: State<'_, Arc>>, +) -> Result { + let auth = auth_state.lock().await; + let session = session_state.lock().await; + let discord_rpc = discord_rpc_state.lock().await; + + Ok(serde_json::json!({ + "authenticated": auth.is_authenticated, + "session_active": session.is_active, + "session_duration": if session.is_active && session.start_time.is_some() { + let current_time = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + current_time - session.start_time.unwrap() + } else { + 0 + }, + "project": session.project.clone().unwrap_or_else(|| "No project".to_string()), + "editor": session.editor.clone().unwrap_or_else(|| "No editor".to_string()), + "language": session.language.clone().unwrap_or_else(|| "No language".to_string()), + "discord_connected": discord_rpc.is_connected(), + "heartbeat_count": session.heartbeat_count + })) +} + +async fn process_statistics_data(dashboard_stats: serde_json::Value) -> Result { + // Extract data from dashboard stats + let current_streak = dashboard_stats["current_streak"].as_u64().unwrap_or(0); + let weekly_time = dashboard_stats["weekly_stats"]["time_coded_seconds"].as_u64().unwrap_or(0) as f64; + let all_time_time = dashboard_stats["all_time_stats"]["time_coded_seconds"].as_u64().unwrap_or(0) as f64; + + // Calculate trends (comparing this week to last week) + let trends = calculate_trends(weekly_time, current_streak).await; + + // Generate chart data + let charts = generate_chart_data(&dashboard_stats).await?; + + // Generate insights + let insights = generate_insights(weekly_time, all_time_time, current_streak).await; + + // Analyze programmer class + let programmer_class = analyze_programmer_class(&dashboard_stats).await; + + Ok(StatisticsData { + trends, + charts, + insights, + programmer_class, + }) +} + +async fn calculate_trends(weekly_time: f64, current_streak: u64) -> Vec { + let mut trends = Vec::new(); + + // Simulate last week's data (in a real app, you'd fetch this from the API) + let last_week_time = weekly_time * 0.85; // Simulate 15% increase + let last_week_streak = if current_streak > 0 { current_streak - 1 } else { 0 }; + + // Weekly coding time trend + let time_change = ((weekly_time - last_week_time) / last_week_time * 100.0).round() as i32; + let time_trend = if time_change > 0 { + TrendStatistic { + title: "Weekly Coding Time".to_string(), + value: format!("{:.1}h", weekly_time / 3600.0), + change: format!("+{}%", time_change), + change_type: "increase".to_string(), + period: "vs last week".to_string(), + icon: "".to_string(), + color: "#4CAF50".to_string(), + } + } else if time_change < 0 { + TrendStatistic { + title: "Weekly Coding Time".to_string(), + value: format!("{:.1}h", weekly_time / 3600.0), + change: format!("{}%", time_change), + change_type: "decrease".to_string(), + period: "vs last week".to_string(), + icon: "".to_string(), + color: "#F44336".to_string(), + } + } else { + TrendStatistic { + title: "Weekly Coding Time".to_string(), + value: format!("{:.1}h", weekly_time / 3600.0), + change: "No change".to_string(), + change_type: "neutral".to_string(), + period: "vs last week".to_string(), + icon: "".to_string(), + color: "#FF9800".to_string(), + } + }; + trends.push(time_trend); + + // Streak trend + let streak_change = current_streak as i32 - last_week_streak as i32; + let streak_trend = if streak_change > 0 { + TrendStatistic { + title: "Coding Streak".to_string(), + value: format!("{} days", current_streak), + change: format!("+{} days", streak_change), + change_type: "increase".to_string(), + period: "vs last week".to_string(), + icon: "".to_string(), + color: "#FF5722".to_string(), + } + } else if streak_change < 0 { + TrendStatistic { + title: "Coding Streak".to_string(), + value: format!("{} days", current_streak), + change: format!("{} days", streak_change), + change_type: "decrease".to_string(), + period: "vs last week".to_string(), + icon: "".to_string(), + color: "#F44336".to_string(), + } + } else { + TrendStatistic { + title: "Coding Streak".to_string(), + value: format!("{} days", current_streak), + change: "Maintained".to_string(), + change_type: "neutral".to_string(), + period: "vs last week".to_string(), + icon: "".to_string(), + color: "#FF9800".to_string(), + } + }; + trends.push(streak_trend); + + // Focus time trend (replaces productivity) + let daily_average = weekly_time / 3600.0 / 7.0; + let last_week_daily = daily_average * 0.9; + let focus_change = ((daily_average - last_week_daily) / last_week_daily * 100.0).round() as i32; + + let focus_trend = if focus_change > 0 { + TrendStatistic { + title: "Daily Focus Time".to_string(), + value: format!("{:.1}h/day", daily_average), + change: format!("+{}%", focus_change), + change_type: "increase".to_string(), + period: "vs last week".to_string(), + icon: "".to_string(), + color: "#4CAF50".to_string(), + } + } else if focus_change < 0 { + TrendStatistic { + title: "Daily Focus Time".to_string(), + value: format!("{:.1}h/day", daily_average), + change: format!("{}%", focus_change), + change_type: "decrease".to_string(), + period: "vs last week".to_string(), + icon: "".to_string(), + color: "#F44336".to_string(), + } + } else { + TrendStatistic { + title: "Daily Focus Time".to_string(), + value: format!("{:.1}h/day", daily_average), + change: "No change".to_string(), + change_type: "neutral".to_string(), + period: "vs last week".to_string(), + icon: "".to_string(), + color: "#FF9800".to_string(), + } + }; + trends.push(focus_trend); + + trends +} + +async fn generate_chart_data(dashboard_stats: &serde_json::Value) -> Result, String> { + let mut charts = Vec::new(); + + // Daily hours chart + if let Some(daily_hours) = dashboard_stats["weekly_stats"]["daily_hours"].as_object() { + let mut chart_data = Vec::new(); + let mut labels = Vec::new(); + + for (_date, day_data) in daily_hours { + if let Some(hours) = day_data["hours"].as_f64() { + labels.push(day_data["day_name"].as_str().unwrap_or("").to_string()); + chart_data.push(hours); + } + } + + charts.push(ChartData { + id: "daily_hours".to_string(), + title: "Daily Coding Hours".to_string(), + chart_type: "bar".to_string(), + data: serde_json::json!({ + "labels": labels, + "datasets": [{ + "label": "Hours", + "data": chart_data, + "backgroundColor": "#FB4B20", + "borderColor": "#FB4B20", + "borderWidth": 1 + }] + }), + period: "Last 7 days".to_string(), + color_scheme: "orange".to_string(), + }); + } + + // Language distribution pie chart + if let Some(top_language) = dashboard_stats["weekly_stats"]["top_language"].as_object() { + let language_name = top_language["name"].as_str().unwrap_or("Unknown"); + let language_seconds = top_language["seconds"].as_u64().unwrap_or(0) as f64; + let total_seconds = dashboard_stats["weekly_stats"]["time_coded_seconds"].as_u64().unwrap_or(1) as f64; + let percentage = (language_seconds / total_seconds * 100.0).round() as i32; + + charts.push(ChartData { + id: "language_distribution".to_string(), + title: "Top Language".to_string(), + chart_type: "doughnut".to_string(), + data: serde_json::json!({ + "labels": [language_name, "Others"], + "datasets": [{ + "data": [percentage, 100 - percentage], + "backgroundColor": ["#FB4B20", "#E0E0E0"], + "borderWidth": 0 + }] + }), + period: "This week".to_string(), + color_scheme: "orange".to_string(), + }); + } + + // Weekly trend line chart + let mut trend_data = Vec::new(); + let mut trend_labels = Vec::new(); + + // Simulate 4 weeks of data + for week in 0..4 { + let week_hours = if week == 3 { + dashboard_stats["weekly_stats"]["time_coded_seconds"].as_u64().unwrap_or(0) as f64 / 3600.0 + } else { + // Simulate previous weeks + (dashboard_stats["weekly_stats"]["time_coded_seconds"].as_u64().unwrap_or(0) as f64 / 3600.0) * (0.8 + (week as f64 * 0.1)) + }; + + trend_data.push(week_hours); + trend_labels.push(format!("Week {}", 4 - week)); + } + + charts.push(ChartData { + id: "weekly_trend".to_string(), + title: "Weekly Trend".to_string(), + chart_type: "line".to_string(), + data: serde_json::json!({ + "labels": trend_labels, + "datasets": [{ + "label": "Hours", + "data": trend_data, + "borderColor": "#FB4B20", + "backgroundColor": "rgba(251, 75, 32, 0.1)", + "fill": true, + "tension": 0.4 + }] + }), + period: "Last 4 weeks".to_string(), + color_scheme: "orange".to_string(), + }); + + Ok(charts) +} + +async fn generate_insights(weekly_time: f64, all_time_time: f64, current_streak: u64) -> Vec { + let mut insights = Vec::new(); + + // Coding consistency insight + let daily_average = weekly_time / 3600.0 / 7.0; + let consistency_insight = if daily_average >= 2.0 { + Insight { + title: "Consistent Coder".to_string(), + description: "You've been coding consistently every day this week!".to_string(), + value: format!("{:.1}h/day", daily_average), + trend: "Great consistency".to_string(), + icon: "".to_string(), + color: "#4CAF50".to_string(), + } + } else if daily_average >= 1.0 { + Insight { + title: "Steady Progress".to_string(), + description: "You're maintaining a good coding rhythm.".to_string(), + value: format!("{:.1}h/day", daily_average), + trend: "Keep it up".to_string(), + icon: "".to_string(), + color: "#FF9800".to_string(), + } + } else { + Insight { + title: "Room for Growth".to_string(), + description: "Try to code a bit more each day to build momentum.".to_string(), + value: format!("{:.1}h/day", daily_average), + trend: "Build momentum".to_string(), + icon: "".to_string(), + color: "#2196F3".to_string(), + } + }; + insights.push(consistency_insight); + + // Streak insight + let streak_insight = if current_streak >= 30 { + Insight { + title: "Streak Master".to_string(), + description: "Incredible! You've been coding for over a month straight!".to_string(), + value: format!("{} days", current_streak), + trend: "Amazing dedication".to_string(), + icon: "".to_string(), + color: "#FFD700".to_string(), + } + } else if current_streak >= 7 { + Insight { + title: "Week Warrior".to_string(), + description: "You've been coding for a full week! Great job!".to_string(), + value: format!("{} days", current_streak), + trend: "Excellent progress".to_string(), + icon: "".to_string(), + color: "#FF5722".to_string(), + } + } else if current_streak > 0 { + Insight { + title: "Getting Started".to_string(), + description: "You're building a coding habit! Keep it going!".to_string(), + value: format!("{} days", current_streak), + trend: "Building momentum".to_string(), + icon: "".to_string(), + color: "#4CAF50".to_string(), + } + } else { + Insight { + title: "Fresh Start".to_string(), + description: "Ready to start your coding journey? Let's begin!".to_string(), + value: "0 days".to_string(), + trend: "Start today".to_string(), + icon: "".to_string(), + color: "#9C27B0".to_string(), + } + }; + insights.push(streak_insight); + + // Total time insight + let total_hours = all_time_time / 3600.0; + let total_insight = if total_hours >= 1000.0 { + Insight { + title: "Coding Veteran".to_string(), + description: "You've logged over 1000 hours of coding! Incredible dedication!".to_string(), + value: format!("{:.0}h total", total_hours), + trend: "Expert level".to_string(), + icon: "".to_string(), + color: "#FFD700".to_string(), + } + } else if total_hours >= 100.0 { + Insight { + title: "Experienced Coder".to_string(), + description: "You've put in serious time coding! Keep up the great work!".to_string(), + value: format!("{:.0}h total", total_hours), + trend: "Strong foundation".to_string(), + icon: "".to_string(), + color: "#4CAF50".to_string(), + } + } else if total_hours >= 10.0 { + Insight { + title: "Learning Journey".to_string(), + description: "You're building your coding skills! Every hour counts.".to_string(), + value: format!("{:.0}h total", total_hours), + trend: "Growing skills".to_string(), + icon: "📚".to_string(), + color: "#2196F3".to_string(), + } + } else { + Insight { + title: "Just Getting Started".to_string(), + description: "Every expert was once a beginner. Keep coding!".to_string(), + value: format!("{:.0}h total", total_hours), + trend: "Beginning journey".to_string(), + icon: "🌱".to_string(), + color: "#9C27B0".to_string(), + } + }; + insights.push(total_insight); + + insights +} + +async fn analyze_programmer_class(dashboard_stats: &serde_json::Value) -> ProgrammerClass { + // Load programmer classes configuration + let config_path = std::env::current_dir() + .unwrap_or_default() + .join("programmer_classes.json"); + + let config_content = match std::fs::read_to_string(&config_path) { + Ok(content) => content, + Err(_) => { + // Fallback to default class if config file is not found + return ProgrammerClass { + class_name: "Code Explorer".to_string(), + description: "An enthusiastic learner discovering the vast world of programming.".to_string(), + technologies: vec!["HTML".to_string(), "CSS".to_string(), "JavaScript".to_string()], + level: "Learning".to_string(), + color: "#9C27B0".to_string(), + }; + } + }; + + let config: serde_json::Value = match serde_json::from_str(&config_content) { + Ok(config) => config, + Err(_) => { + // Fallback to default class if config is invalid + return ProgrammerClass { + class_name: "Code Explorer".to_string(), + description: "An enthusiastic learner discovering the vast world of programming.".to_string(), + technologies: vec!["HTML".to_string(), "CSS".to_string(), "JavaScript".to_string()], + level: "Learning".to_string(), + color: "#9C27B0".to_string(), + }; + } + }; + + let total_hours = dashboard_stats["all_time_stats"]["time_coded_seconds"] + .as_u64() + .unwrap_or(0) as f64 / 3600.0; + + let current_streak = dashboard_stats["current_streak"].as_u64().unwrap_or(0); + + // Simulate language analysis - in a real app, you'd analyze actual language data from the API + let simulated_languages = simulate_language_analysis(total_hours, current_streak); + + // Find the best matching class + let empty_vec = vec![]; + let classes = config["classes"].as_array().unwrap_or(&empty_vec); + let mut best_match: Option<&serde_json::Value> = None; + let mut best_score = 0.0; + + for class in classes { + if let Some(conditions) = class["conditions"].as_object() { + let score = calculate_class_score(&conditions, &simulated_languages, total_hours, current_streak); + if score > best_score { + best_score = score; + best_match = Some(class); + } + } + } + + // Return the best match or default + if let Some(class) = best_match { + ProgrammerClass { + class_name: class["name"].as_str().unwrap_or("Unknown").to_string(), + description: class["description"].as_str().unwrap_or("").to_string(), + technologies: class["technologies"].as_array() + .unwrap_or(&vec![]) + .iter() + .filter_map(|t| t.as_str()) + .map(|s| s.to_string()) + .collect(), + level: class["level"].as_str().unwrap_or("Unknown").to_string(), + color: class["color"].as_str().unwrap_or("#9C27B0").to_string(), + } + } else { + // Default fallback + ProgrammerClass { + class_name: "Code Explorer".to_string(), + description: "An enthusiastic learner discovering the vast world of programming.".to_string(), + technologies: vec!["HTML".to_string(), "CSS".to_string(), "JavaScript".to_string()], + level: "Learning".to_string(), + color: "#9C27B0".to_string(), + } + } +} + +fn simulate_language_analysis(total_hours: f64, current_streak: u64) -> Vec { + // Simulate language usage based on coding patterns + // In a real app, this would come from actual language data from the API + let mut languages = Vec::new(); + + // Simulate language distribution based on experience level + if total_hours >= 100.0 { + // Experienced developers + languages.push("JavaScript".to_string()); + languages.push("Python".to_string()); + languages.push("Java".to_string()); + if current_streak >= 7 { + languages.push("Rust".to_string()); + languages.push("Go".to_string()); + } + } else if total_hours >= 20.0 { + // Intermediate developers + languages.push("JavaScript".to_string()); + languages.push("Python".to_string()); + if current_streak >= 5 { + languages.push("TypeScript".to_string()); + } + } else { + // Beginners + languages.push("HTML".to_string()); + languages.push("CSS".to_string()); + languages.push("JavaScript".to_string()); + } + + languages +} + +fn calculate_class_score(conditions: &serde_json::Map, + languages: &[String], + total_hours: f64, + current_streak: u64) -> f64 { + let mut score = 0.0; + + // Check primary languages match + if let Some(primary_langs) = conditions.get("primary_languages").and_then(|v| v.as_array()) { + let primary_lang_count = primary_langs.iter() + .filter_map(|lang| lang.as_str()) + .filter(|lang| languages.contains(&lang.to_string())) + .count(); + score += primary_lang_count as f64 * 2.0; // Weight primary languages heavily + } + + // Check language count for polyglot + if let Some(lang_count) = conditions.get("language_count").and_then(|v| v.as_u64()) { + if languages.len() as u64 >= lang_count { + score += 3.0; // Bonus for being a polyglot + } + } + + // Check minimum hours + if let Some(min_hours) = conditions.get("min_hours").and_then(|v| v.as_f64()) { + if total_hours >= min_hours { + score += 1.0; + } else { + score -= 0.5; // Penalty for not meeting minimum + } + } + + // Check maximum hours for beginners + if let Some(max_hours) = conditions.get("max_hours").and_then(|v| v.as_f64()) { + if total_hours <= max_hours { + score += 1.0; + } else { + score -= 0.5; // Penalty for being too experienced + } + } + + // Check minimum streak + if let Some(min_streak) = conditions.get("min_streak").and_then(|v| v.as_u64()) { + if current_streak >= min_streak { + score += 0.5; + } + } + + score +} + + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_deep_link::init()) + .manage(ApiConfig::default()) + .manage(Arc::new(tauri::async_runtime::Mutex::new(AuthState { + is_authenticated: false, + access_token: None, + user_info: None, + }))) + .manage(Arc::new(tauri::async_runtime::Mutex::new(DiscordRpcService::new()))) + .manage(Arc::new(tauri::async_runtime::Mutex::new(SessionState { + is_active: false, + start_time: None, + last_heartbeat_id: None, + heartbeat_count: 0, + project: None, + editor: None, + language: None, + entity: None, + }))) + .invoke_handler(tauri::generate_handler![ + greet, + get_api_config, + set_api_config, + get_auth_state, + authenticate_with_rails, + handle_auth_callback, + handle_deep_link_callback, + logout, + test_auth_callback, + get_api_key, + authenticate_with_direct_oauth, + setup_hackatime_macos_linux, + setup_hackatime_windows, + test_hackatime_heartbeat, + setup_hackatime_complete, + save_auth_state, + load_auth_state, + clear_auth_state, + register_presence_connection, + get_latest_heartbeat, + ping_presence_connection, + get_hackatime_directories, + cleanup_old_sessions, + get_session_stats, + test_database_connection, + discord_rpc_connect, + discord_rpc_disconnect, + discord_rpc_set_activity, + discord_rpc_clear_activity, + discord_rpc_get_state, + discord_rpc_update_from_heartbeat, + discord_rpc_auto_connect, + discord_rpc_auto_disconnect, + get_current_session, + get_projects, + get_project_details, + get_discord_rpc_enabled, + set_discord_rpc_enabled, + get_statistics_data, + show_window, + hide_window, + toggle_window, + get_app_status + ]) + .setup(|app| { + // Create system tray menu items + let show_item = MenuItem::with_id(app, "show", "Show Hackatime", true, None::<&str>)?; + let status_item = MenuItem::with_id(app, "status", "📊 Session Status", true, None::<&str>)?; + let discord_item = MenuItem::with_id(app, "discord", "🎮 Discord RPC", true, None::<&str>)?; + let settings_item = MenuItem::with_id(app, "settings", "⚙️ Settings", true, None::<&str>)?; + let about_item = MenuItem::with_id(app, "about", "ℹ️ About", true, None::<&str>)?; + let help_item = MenuItem::with_id(app, "help", "📖 Help", true, None::<&str>)?; + let quit_item = MenuItem::with_id(app, "quit", "❌ Quit", true, None::<&str>)?; + + // Create menu with items + let menu = Menu::with_items(app, &[ + &show_item, + &tauri::menu::PredefinedMenuItem::separator(app)?, + &status_item, + &discord_item, + &settings_item, + &tauri::menu::PredefinedMenuItem::separator(app)?, + &about_item, + &help_item, + &tauri::menu::PredefinedMenuItem::separator(app)?, + &quit_item, + ])?; + + // Create tray icon with menu and event handlers + let _tray_icon = TrayIconBuilder::new() + .icon(app.default_window_icon().unwrap().clone()) + .menu(&menu) + .show_menu_on_left_click(true) + .on_menu_event(|app, event| { + match event.id.as_ref() { + "show" => { + if let Some(window) = app.get_webview_window("main") { + let _ = window.show(); + let _ = window.set_focus(); + } + } + "status" => { + println!("📊 Session Status:"); + println!(" - Authentication: Checking..."); + println!(" - Active Session: Checking..."); + println!(" - Discord RPC: Checking..."); + println!(" - Last Heartbeat: Checking..."); + } + "discord" => { + println!("🎮 Discord RPC Status:"); + println!(" - Connection: Checking..."); + println!(" - Activity: Checking..."); + } + "settings" => { + println!("⚙️ Opening Settings..."); + if let Some(window) = app.get_webview_window("main") { + let _ = window.show(); + let _ = window.set_focus(); + } + } + "about" => { + println!("ℹ️ Hackatime Desktop v0.1.0"); + println!(" - Coding Time Tracker"); + println!(" - Discord RPC Integration"); + println!(" - Cross-platform Support"); + } + "help" => { + println!("📖 Help & Documentation:"); + println!(" - Left-click tray icon to toggle window"); + println!(" - Right-click for menu options"); + println!(" - Window closes to tray (not taskbar)"); + } + "quit" => { + println!("❌ Quitting Hackatime Desktop..."); + app.exit(0); + } + _ => {} + } + }) + .on_tray_icon_event(|tray, event| { + match event { + TrayIconEvent::Click { + button: MouseButton::Left, + button_state: MouseButtonState::Up, + .. + } => { + println!("🪟 Left click on tray icon"); + let app = tray.app_handle(); + if let Some(window) = app.get_webview_window("main") { + if window.is_visible().unwrap_or(false) { + println!("🪟 Hiding window to tray"); + let _ = window.hide(); + } else { + println!("🪟 Showing window from tray"); + let _ = window.show(); + let _ = window.set_focus(); + } + } + } + TrayIconEvent::DoubleClick { + button: MouseButton::Left, + .. + } => { + println!("🪟 Double-click: showing window"); + let app = tray.app_handle(); + if let Some(window) = app.get_webview_window("main") { + let _ = window.show(); + let _ = window.set_focus(); + } + } + _ => { + println!("🖱️ Other tray event: {:?}", event); + } + } + }) + .build(app)?; + + // Load saved auth state on startup synchronously + let auth_state = app.state::>>(); + let auth_state_clone = auth_state.inner().clone(); + + // Load auth state immediately on startup + tauri::async_runtime::block_on(async { + match load_auth_state().await { + Ok(Some(saved_auth_state)) => { + let mut current_auth_state = auth_state_clone.lock().await; + *current_auth_state = saved_auth_state; + println!("Loaded saved authentication state on startup"); + } + Ok(None) => { + println!("No saved authentication state found"); + } + Err(e) => { + println!("Failed to load saved authentication state: {}", e); + } + } + }); + + // Auto-connect Discord RPC on startup + let discord_rpc_state = app.state::>>(); + let discord_rpc_clone = discord_rpc_state.inner().clone(); + + tauri::async_runtime::spawn(async move { + let mut rpc_service = discord_rpc_clone.lock().await; + match rpc_service.auto_connect() { + Ok(_) => println!("Discord RPC auto-connected on startup"), + Err(e) => println!("Discord RPC auto-connect failed (this is optional): {}", e), + } + }); + + // Register deep link scheme for development + #[cfg(any(target_os = "linux", all(debug_assertions, target_os = "windows")))] + { + app.deep_link().register_all().unwrap_or_else(|e| { + eprintln!("Failed to register deep links: {}", e); + }); + } + + // Handle deep links when app is already running + let app_handle = app.handle().clone(); + app.deep_link().on_open_url(move |event| { + let urls = event.urls(); + println!("Deep link received: {:?}", urls); + + for url in urls { + let url_string = url.to_string(); + if url_string.starts_with("kubetime://auth/callback") { + // Parse the URL to extract the temp_token + if let Some(query_start) = url_string.find('?') { + let query = &url_string[query_start + 1..]; + let params: Vec<&str> = query.split('&').collect(); + + for param in params { + if param.starts_with("temp_token=") { + let temp_token = param[11..].to_string(); // Clone the string + println!("Extracted temp_token: {}", temp_token); + + // Handle the authentication callback + let api_config = app_handle.state::(); + let auth_state = app_handle.state::>>(); + + // Clone the values we need for the async task + let temp_token_clone = temp_token.clone(); + let api_config_clone = api_config.inner().clone(); + let auth_state_clone = auth_state.inner().clone(); + + // Spawn async task to handle token exchange + tauri::async_runtime::spawn(async move { + // Create a new client for the token exchange + let client = reqwest::Client::new(); + let response = client + .post(&format!("{}/api/v1/desktop/exchange_token", api_config_clone.base_url)) + .json(&serde_json::json!({ + "temp_token": temp_token_clone + })) + .send() + .await; + + match response { + Ok(resp) => { + if resp.status().is_success() { + if let Ok(token_response) = resp.json::().await { + if let Some(access_token) = token_response["access_token"].as_str() { + if let Some(user_info) = token_response["user"].as_object() { + // Convert to HashMap + let mut user_info_map = HashMap::new(); + for (key, value) in user_info { + user_info_map.insert(key.clone(), value.clone()); + } + + + // Update auth state + let mut auth_state = auth_state_clone.lock().await; + auth_state.is_authenticated = true; + auth_state.access_token = Some(access_token.to_string()); + auth_state.user_info = Some(user_info_map); + + // Save auth state to disk + let auth_state_to_save = auth_state.clone(); + drop(auth_state); // Release the lock before the async call + if let Err(e) = save_auth_state(auth_state_to_save).await { + eprintln!("Failed to save auth state: {}", e); + } + + println!("Authentication successful!"); + } + } + } + } else { + eprintln!("Token exchange failed with status: {}", resp.status()); + } + } + Err(e) => { + eprintln!("Failed to exchange token: {}", e); + } + } + }); + } + } + } + } + } + }); + + // Check if app was started via deep link + if let Some(start_urls) = app.deep_link().get_current().unwrap_or_default() { + println!("App started with deep link: {:?}", start_urls); + // Handle the same logic as above for startup deep links + for url in start_urls { + let url_string = url.to_string(); + if url_string.starts_with("kubetime://auth/callback") { + // Parse and handle the callback + if let Some(query_start) = url_string.find('?') { + let query = &url_string[query_start + 1..]; + let params: Vec<&str> = query.split('&').collect(); + + for param in params { + if param.starts_with("temp_token=") { + let temp_token = param[11..].to_string(); // Clone the string + println!("Startup deep link temp_token: {}", temp_token); + + let api_config = app.state::(); + let auth_state = app.state::>>(); + + // Clone the values we need for the async task + let temp_token_clone = temp_token.clone(); + let api_config_clone = api_config.inner().clone(); + let auth_state_clone = auth_state.inner().clone(); + + tauri::async_runtime::spawn(async move { + // Create a new client for the token exchange + let client = reqwest::Client::new(); + let response = client + .post(&format!("{}/api/v1/desktop/exchange_token", api_config_clone.base_url)) + .json(&serde_json::json!({ + "temp_token": temp_token_clone + })) + .send() + .await; + + match response { + Ok(resp) => { + if resp.status().is_success() { + if let Ok(token_response) = resp.json::().await { + if let Some(access_token) = token_response["access_token"].as_str() { + if let Some(user_info) = token_response["user"].as_object() { + // Convert to HashMap + let mut user_info_map = HashMap::new(); + for (key, value) in user_info { + user_info_map.insert(key.clone(), value.clone()); + } + + + // Update auth state + let mut auth_state = auth_state_clone.lock().await; + auth_state.is_authenticated = true; + auth_state.access_token = Some(access_token.to_string()); + auth_state.user_info = Some(user_info_map); + + // Save auth state to disk + let auth_state_to_save = auth_state.clone(); + drop(auth_state); // Release the lock before the async call + if let Err(e) = save_auth_state(auth_state_to_save).await { + eprintln!("Failed to save auth state: {}", e); + } + + println!("Startup authentication successful!"); + } + } + } + } else { + eprintln!("Startup token exchange failed with status: {}", resp.status()); + } + } + Err(e) => { + eprintln!("Failed to handle startup auth callback: {}", e); + } + } + }); + } + } + } + } + } + } + + // Handle window close events to hide to tray instead of closing + if let Some(window) = app.get_webview_window("main") { + let window_handle = window.clone(); + let _ = window.on_window_event(move |event| { + match event { + WindowEvent::CloseRequested { api, .. } => { + println!("🪟 Window close requested - hiding to tray"); + api.prevent_close(); + let _ = window_handle.hide(); + println!("✅ Window hidden to tray"); + } + _ => {} + } + }); + } + + + Ok(()) + }) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs new file mode 100644 index 0000000..bea3c23 --- /dev/null +++ b/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release, DO NOT REMOVE!! +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + desktop_lib::run() +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json new file mode 100644 index 0000000..3358cd0 --- /dev/null +++ b/src-tauri/tauri.conf.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "productName": "Hackatime Desktop", + "version": "0.1.0", + "identifier": "com.hackclub.hackatime", + "build": { + "beforeDevCommand": "pnpm dev", + "devUrl": "http://localhost:1420", + "beforeBuildCommand": "pnpm build", + "frontendDist": "../dist" + }, + "app": { + "windows": [ + { + "title": "Hackatime Desktop", + "width": 800, + "height": 600, + "visible": true, + "skipTaskbar": false, + "decorations": true, + "alwaysOnTop": false, + "resizable": true, + "minimizable": true, + "maximizable": true, + "closable": true + } + ], + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + }, + "plugins": { + "shell": { + "open": true + }, + "deepLink": { + "schemes": ["kubetime"] + } + } +} diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..948a4c6 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,577 @@ + + + + + \ No newline at end of file diff --git a/src/api.ts b/src/api.ts new file mode 100644 index 0000000..2eab483 --- /dev/null +++ b/src/api.ts @@ -0,0 +1,160 @@ +import { invoke } from "@tauri-apps/api/core"; + +interface ApiConfig { + base_url: string; +} + +interface AuthState { + is_authenticated: boolean; + access_token: string | null; + user_info: Record | null; +} + +export class KubeTimeApi { + private baseUrl: string = "http://localhost:3000"; + private accessToken: string | null = null; + private latestPresenceCache: { data: any | null; fetchedAt: number } = { data: null, fetchedAt: 0 }; + + async initialize() { + try { + const config: ApiConfig = await invoke("get_api_config"); + this.baseUrl = config.base_url; + + const authState: AuthState = await invoke("get_auth_state"); + this.accessToken = authState.access_token; + } catch (error) { + console.error("Failed to initialize API:", error); + } + } + + async getCurrentUser() { + if (!this.accessToken) { + throw new Error("Not authenticated"); + } + + try { + const response = await fetch(`${this.baseUrl}/api/v1/authenticated/me`, { + headers: { + 'Authorization': `Bearer ${this.accessToken}`, + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error("Failed to fetch current user:", error); + throw error; + } + } + + async getStats() { + if (!this.accessToken) { + throw new Error("Not authenticated"); + } + + try { + // Call the current user's dashboard stats endpoint + const response = await fetch(`${this.baseUrl}/api/v1/authenticated/dashboard_stats`, { + headers: { + 'Authorization': `Bearer ${this.accessToken}`, + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error("Failed to fetch stats:", error); + throw error; + } + } + + async getMyHeartbeats() { + if (!this.accessToken) { + throw new Error("Not authenticated"); + } + + try { + const response = await fetch(`${this.baseUrl}/api/v1/my/heartbeats`, { + headers: { + 'Authorization': `Bearer ${this.accessToken}`, + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error("Failed to fetch heartbeats:", error); + throw error; + } + } + + async getUserDashboardStats(username: string) { + if (!this.accessToken) { + throw new Error("Not authenticated"); + } + + try { + const response = await fetch(`${this.baseUrl}/api/v1/users/${username}/dashboard_stats`, { + headers: { + 'Authorization': `Bearer ${this.accessToken}`, + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error("Failed to fetch user dashboard stats:", error); + throw error; + } + } + + async getCurrentPresence() { + if (!this.accessToken) { + throw new Error("Not authenticated"); + } + + try { + // Return cached result if fetched within last 60s + const now = Date.now(); + if (now - this.latestPresenceCache.fetchedAt < 60_000 && this.latestPresenceCache.data !== null) { + return this.latestPresenceCache.data; + } + + const response = await fetch(`${this.baseUrl}/api/v1/presence/latest_heartbeat`, { + headers: { + 'Authorization': `Bearer ${this.accessToken}`, + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const json = await response.json(); + this.latestPresenceCache = { data: json, fetchedAt: Date.now() }; + return json; + } catch (error) { + console.error("Failed to fetch current presence:", error); + throw error; + } + } +} + +export const api = new KubeTimeApi(); diff --git a/src/assets/vue.svg b/src/assets/vue.svg new file mode 100644 index 0000000..f2caefb --- /dev/null +++ b/src/assets/vue.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5532db34f1c52841881bab8aeca6c3e8d092bd21a689a65f4d8f8cf8041eef9d +size 496 diff --git a/src/components/ChartComponent.vue b/src/components/ChartComponent.vue new file mode 100644 index 0000000..9ad1bbb --- /dev/null +++ b/src/components/ChartComponent.vue @@ -0,0 +1,147 @@ + + + diff --git a/src/components/InsightCard.vue b/src/components/InsightCard.vue new file mode 100644 index 0000000..4697f2d --- /dev/null +++ b/src/components/InsightCard.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/components/PresenceCard.vue b/src/components/PresenceCard.vue new file mode 100644 index 0000000..6fde4b1 --- /dev/null +++ b/src/components/PresenceCard.vue @@ -0,0 +1,189 @@ + + + + + \ No newline at end of file diff --git a/src/components/StatisticsCard.vue b/src/components/StatisticsCard.vue new file mode 100644 index 0000000..6bf007d --- /dev/null +++ b/src/components/StatisticsCard.vue @@ -0,0 +1,53 @@ + + + diff --git a/src/components/StatisticsDashboard.vue b/src/components/StatisticsDashboard.vue new file mode 100644 index 0000000..19b3f20 --- /dev/null +++ b/src/components/StatisticsDashboard.vue @@ -0,0 +1,195 @@ + + + diff --git a/src/components/TrendCard.vue b/src/components/TrendCard.vue new file mode 100644 index 0000000..de9d559 --- /dev/null +++ b/src/components/TrendCard.vue @@ -0,0 +1,64 @@ + + + diff --git a/src/components/WeeklyChart.vue b/src/components/WeeklyChart.vue new file mode 100644 index 0000000..dfcfed8 --- /dev/null +++ b/src/components/WeeklyChart.vue @@ -0,0 +1,145 @@ + + + diff --git a/src/composables/useTheme.ts b/src/composables/useTheme.ts new file mode 100644 index 0000000..ac4fa65 --- /dev/null +++ b/src/composables/useTheme.ts @@ -0,0 +1,36 @@ +import { ref, onMounted } from 'vue' + +export type Theme = 'dark' | 'light' + +const currentTheme = ref('dark') + +export function useTheme() { + const setTheme = (theme: Theme) => { + currentTheme.value = theme + document.documentElement.className = theme + localStorage.setItem('theme', theme) + } + + const toggleTheme = () => { + const newTheme = currentTheme.value === 'dark' ? 'light' : 'dark' + setTheme(newTheme) + } + + const initTheme = () => { + // Check localStorage first, then default to dark + const savedTheme = localStorage.getItem('theme') as Theme + const theme = savedTheme || 'dark' + setTheme(theme) + } + + onMounted(() => { + initTheme() + }) + + return { + currentTheme, + setTheme, + toggleTheme, + initTheme + } +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..de275e7 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,5 @@ +import { createApp } from "vue"; +import App from "./App.vue"; +import "./style.css"; + +createApp(App).mount("#app"); diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..ca91c5e --- /dev/null +++ b/src/style.css @@ -0,0 +1,175 @@ +@import "tailwindcss"; + +/* CSS Variables for Theme System */ +:root { + /* Dark theme (default) */ + --bg-primary: #2a1f21; + --bg-secondary: #3d2b2e; + --bg-tertiary: #4a2d31; + --bg-card: #3d2b2e; + --bg-card-secondary: #4a2d31; + --bg-card-tertiary: #1f1617; + --bg-sidebar: #2a1f21; + --text-primary: #f5e6e8; + --text-secondary: #f5e6e8; + --text-muted: #a0a0a0; + --accent-primary: #ff7a8a; + --accent-secondary: #c8394f; + --accent-danger: #ec3750; + --accent-warning: #f1c40f; + --accent-info: #33d6a6; + --border-primary: #3d2b2e; + --border-secondary: #4a2d31; +} + +.light { + /* Light theme */ + --bg-primary: #fdf7f8; + --bg-secondary: #ffffff; + --bg-tertiary: #f8e8ea; + --bg-card: #ffffff; + --bg-card-secondary: #f8e8ea; + --bg-card-tertiary: #ffffff; + --bg-sidebar: #fdf7f8; + --text-primary: #5d3a3f; + --text-secondary: #5d3a3f; + --text-muted: #8b2635; + --accent-primary: #c8394f; + --accent-secondary: #a12d3e; + --accent-danger: #ec3750; + --accent-warning: #ff8c37; + --accent-info: #33d6a6; + --border-primary: #f8e8ea; + --border-secondary: #ffffff; +} + +/* Custom scrollbar styles */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: var(--bg-sidebar); +} + +::-webkit-scrollbar-thumb { + background: var(--border-primary); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--border-secondary); +} + +/* Selection styling */ +::selection { + background: rgba(200, 57, 79, 0.3); + color: var(--text-primary); +} + +/* Focus styles */ +*:focus { + outline: 2px solid var(--accent-primary); + outline-offset: 2px; +} + +/* Global styles */ +* { + box-sizing: border-box; +} + +html, body { + margin: 0; + padding: 0; + height: 100%; + font-family: "Outfit", sans-serif; + font-optical-sizing: auto; + font-weight: 400; + font-style: normal; + background: var(--bg-primary); + color: var(--text-primary); + overflow: hidden; + transition: background-color 0.3s ease, color 0.3s ease; +} + +#app { + height: 100vh; + width: 100vw; +} + +/* Typography */ +h1, h2, h3, h4, h5, h6 { + margin: 0; + font-weight: 600; + line-height: 1.2; +} + +p { + margin: 0; + line-height: 1.5; +} + +/* Button and input reset */ +button, input, textarea, select { + font-family: inherit; + font-size: inherit; +} + +/* Link styles */ +a { + color: var(--accent-primary); + text-decoration: none; + transition: color 0.2s ease; +} + +a:hover { + color: var(--accent-secondary); +} + +/* Smooth transitions for theme changes */ +* { + transition: background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease; +} + +/* Outfit font class as per Google Fonts documentation */ +.outfit { + font-family: "Outfit", sans-serif; + font-optical-sizing: auto; + font-style: normal; +} + +/* Outfit font weight utilities */ +.outfit-light { + font-family: "Outfit", sans-serif; + font-optical-sizing: auto; + font-weight: 300; + font-style: normal; +} + +.outfit-normal { + font-family: "Outfit", sans-serif; + font-optical-sizing: auto; + font-weight: 400; + font-style: normal; +} + +.outfit-medium { + font-family: "Outfit", sans-serif; + font-optical-sizing: auto; + font-weight: 500; + font-style: normal; +} + +.outfit-semibold { + font-family: "Outfit", sans-serif; + font-optical-sizing: auto; + font-weight: 600; + font-style: normal; +} + +.outfit-bold { + font-family: "Outfit", sans-serif; + font-optical-sizing: auto; + font-weight: 700; + font-style: normal; +} diff --git a/src/views/Home.vue b/src/views/Home.vue new file mode 100644 index 0000000..217ce0d --- /dev/null +++ b/src/views/Home.vue @@ -0,0 +1,104 @@ + + + + + \ No newline at end of file diff --git a/src/views/Projects.vue b/src/views/Projects.vue new file mode 100644 index 0000000..1590462 --- /dev/null +++ b/src/views/Projects.vue @@ -0,0 +1,206 @@ + + + + + \ No newline at end of file diff --git a/src/views/Settings.vue b/src/views/Settings.vue new file mode 100644 index 0000000..fc823d9 --- /dev/null +++ b/src/views/Settings.vue @@ -0,0 +1,196 @@ + + + + + \ No newline at end of file diff --git a/src/views/Statistics.vue b/src/views/Statistics.vue new file mode 100644 index 0000000..72f3a5b --- /dev/null +++ b/src/views/Statistics.vue @@ -0,0 +1,23 @@ + + + diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..fc81239 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,7 @@ +/// + +declare module "*.vue" { + import type { DefineComponent } from "vue"; + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..d0e46d8 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,99 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{vue,js,ts,jsx,tsx}", + ], + darkMode: 'class', + theme: { + extend: { + colors: { + // Dark theme colors + 'dark': { + 'sidebar-bg': '#2a1f21', + 'sidebar-text': '#f5e6e8', + 'sidebar-unread-text': '#ffffff', + 'sidebar-text-hover-bg': '#3d2b2e', + 'sidebar-text-active-border': '#ff7a8a', + 'sidebar-text-active-color': '#ffffff', + 'sidebar-header-bg': '#1f1617', + 'sidebar-header-text': '#f5e6e8', + 'sidebar-team-bar-bg': '#1f1617', + 'online-indicator': '#33d6a6', + 'away-indicator': '#f1c40f', + 'dnd-indicator': '#ec3750', + 'mention-bg': '#d63c56', + 'mention-color': '#ffffff', + 'center-channel-bg': '#3d2b2e', + 'center-channel-color': '#f5e6e8', + 'new-message-separator': '#ff7a8a', + 'link-color': '#ff9aaa', + 'button-bg': '#c8394f', + 'button-color': '#ffffff', + 'error-text': '#ff6b7d', + 'mention-highlight-bg': '#4a2d31', + 'mention-highlight-link': '#ff9aaa', + }, + // Light theme colors + 'light': { + 'sidebar-bg': '#fdf7f8', + 'sidebar-text': '#5d3a3f', + 'sidebar-unread-text': '#2c1a1d', + 'sidebar-text-hover-bg': '#f8e8ea', + 'sidebar-text-active-border': '#c8394f', + 'sidebar-text-active-color': '#8b2635', + 'sidebar-header-bg': '#ffffff', + 'sidebar-header-text': '#5d3a3f', + 'sidebar-team-bar-bg': '#ffffff', + 'online-indicator': '#33d6a6', + 'away-indicator': '#ff8c37', + 'dnd-indicator': '#ec3750', + 'mention-bg': '#c8394f', + 'mention-color': '#ffffff', + 'center-channel-bg': '#ffffff', + 'center-channel-color': '#5d3a3f', + 'new-message-separator': '#ff7a8a', + 'link-color': '#a12d3e', + 'button-bg': '#c8394f', + 'button-color': '#ffffff', + 'error-text': '#d63c56', + 'mention-highlight-bg': '#fce4e6', + 'mention-highlight-link': '#a12d3e', + }, + // Semantic color mappings + 'bg-primary': 'var(--bg-primary)', + 'bg-secondary': 'var(--bg-secondary)', + 'bg-tertiary': 'var(--bg-tertiary)', + 'bg-card': 'var(--bg-card)', + 'bg-card-secondary': 'var(--bg-card-secondary)', + 'bg-card-tertiary': 'var(--bg-card-tertiary)', + 'bg-sidebar': 'var(--bg-sidebar)', + 'text-primary': 'var(--text-primary)', + 'text-secondary': 'var(--text-secondary)', + 'text-muted': 'var(--text-muted)', + 'accent-primary': 'var(--accent-primary)', + 'accent-secondary': 'var(--accent-secondary)', + 'accent-danger': 'var(--accent-danger)', + 'accent-warning': 'var(--accent-warning)', + 'accent-info': 'var(--accent-info)', + 'border-primary': 'var(--border-primary)', + 'border-secondary': 'var(--border-secondary)', + }, + fontFamily: { + 'sans': ['"Outfit"', 'sans-serif'], + 'outfit': ['"Outfit"', 'sans-serif'], + }, + borderRadius: { + 'xl': '12px', + '2xl': '16px', + '3xl': '20px', + }, + boxShadow: { + 'primary': '0 4px 6px rgba(0, 0, 0, 0.2)', + 'secondary': '0 10px 25px rgba(0, 0, 0, 0.3)', + 'card': '0 2px 8px rgba(0, 0, 0, 0.1)', + 'card-hover': '0 4px 16px rgba(0, 0, 0, 0.15)', + } + }, + }, +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f82888f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..aa8a0fc --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,33 @@ +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import tailwindcss from "@tailwindcss/vite"; + +// @ts-expect-error process is a nodejs global +const host = process.env.TAURI_DEV_HOST; + +// https://vite.dev/config/ +export default defineConfig(async () => ({ + plugins: [vue(), tailwindcss()], + + // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` + // + // 1. prevent Vite from obscuring rust errors + clearScreen: false, + // 2. tauri expects a fixed port, fail if that port is not available + server: { + port: 1420, + strictPort: true, + host: host || false, + hmr: host + ? { + protocol: "ws", + host, + port: 1421, + } + : undefined, + watch: { + // 3. tell Vite to ignore watching `src-tauri` + ignored: ["**/src-tauri/**"], + }, + }, +}));