initial version (alpha)
9
.editorconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
1
.env
Normal file
|
@ -0,0 +1 @@
|
|||
MAIN_VITE_ELECTRON_RENDERER_URL='http://localhost:5173/'
|
4
.eslintignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
node_modules
|
||||
dist
|
||||
out
|
||||
.gitignore
|
38
.eslintrc.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
commonjs: true,
|
||||
es6: true,
|
||||
node: true
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2021
|
||||
},
|
||||
plugins: ['@typescript-eslint'],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:@typescript-eslint/eslint-recommended',
|
||||
'plugin:prettier/recommended'
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/ban-ts-comment': ['error', { 'ts-ignore': 'allow-with-description' }],
|
||||
'@typescript-eslint/explicit-function-return-type': 'error',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-empty-function': ['error', { allow: ['arrowFunctions'] }],
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-function-return-type': 'off'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
node_modules
|
||||
dist
|
||||
out
|
||||
*.log*
|
||||
.DS_Store
|
||||
pnpm-lock.yaml
|
4
.npmrc
Normal file
|
@ -0,0 +1,4 @@
|
|||
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/
|
||||
|
||||
# Needed for correct packaging
|
||||
shamefully-hoist=true
|
6
.prettierignore
Normal file
|
@ -0,0 +1,6 @@
|
|||
out
|
||||
dist
|
||||
pnpm-lock.yaml
|
||||
LICENSE.md
|
||||
tsconfig.json
|
||||
tsconfig.*.json
|
17
.prettierrc
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": [
|
||||
"prettier-plugin-svelte"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
"options": {
|
||||
"parser": "svelte"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
3
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"recommendations": ["dbaeumer.vscode-eslint"]
|
||||
}
|
39
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug Main Process",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
|
||||
},
|
||||
"runtimeArgs": ["--sourcemap"],
|
||||
"env": {
|
||||
"REMOTE_DEBUGGING_PORT": "9222"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Debug Renderer Process",
|
||||
"port": 9222,
|
||||
"request": "attach",
|
||||
"type": "chrome",
|
||||
"webRoot": "${workspaceFolder}/src/renderer",
|
||||
"timeout": 60000,
|
||||
"presentation": {
|
||||
"hidden": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Debug All",
|
||||
"configurations": ["Debug Main Process", "Debug Renderer Process"],
|
||||
"presentation": {
|
||||
"order": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
11
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
}
|
0
.zed/debug.json
Normal file
0
README.md
Normal file
12
build/entitlements.mac.plist
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
BIN
build/icon.icns
Normal file
BIN
build/icon.ico
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
build/icon.png
Normal file
After Width: | Height: | Size: 35 KiB |
971
bun.lock
Normal file
|
@ -0,0 +1,971 @@
|
|||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "eve-lite",
|
||||
"dependencies": {
|
||||
"@electron-toolkit/preload": "^1.0.3",
|
||||
"@electron-toolkit/utils": "^1.0.2",
|
||||
"@svelte-put/qr": "^2.1.0",
|
||||
"electron-serve": "^1.1.0",
|
||||
"electron-updater": "^5.3.0",
|
||||
"electron-window-state": "^5.0.3",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-toolkit/tsconfig": "^1.0.1",
|
||||
"@electron/notarize": "^1.2.3",
|
||||
"@types/node": "^18.15.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"concurrently": "^8.0.1",
|
||||
"electron": "^37.4.0",
|
||||
"electron-builder": "^23.6.0",
|
||||
"electron-vite": "^1.0.21",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-svelte": "^3.4.0",
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^4.2.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"7zip-bin": ["7zip-bin@5.1.1", "", {}, "sha512-sAP4LldeWNz0lNzmTird3uWfFDWWTeg6V/MsmyyLR9X1idwKBWIgt/ZvinqQldJm3LecKEs1emkbquO6PCiLVQ=="],
|
||||
|
||||
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
||||
|
||||
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
|
||||
|
||||
"@babel/compat-data": ["@babel/compat-data@7.28.0", "", {}, "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw=="],
|
||||
|
||||
"@babel/core": ["@babel/core@7.28.3", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.3", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ=="],
|
||||
|
||||
"@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="],
|
||||
|
||||
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
|
||||
|
||||
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
|
||||
|
||||
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
|
||||
|
||||
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
|
||||
|
||||
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
|
||||
|
||||
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
|
||||
|
||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
|
||||
|
||||
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
|
||||
|
||||
"@babel/helpers": ["@babel/helpers@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw=="],
|
||||
|
||||
"@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="],
|
||||
|
||||
"@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="],
|
||||
|
||||
"@babel/runtime": ["@babel/runtime@7.28.3", "", {}, "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA=="],
|
||||
|
||||
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
|
||||
|
||||
"@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="],
|
||||
|
||||
"@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
||||
|
||||
"@develar/schema-utils": ["@develar/schema-utils@2.6.5", "", { "dependencies": { "ajv": "^6.12.0", "ajv-keywords": "^3.4.1" } }, "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig=="],
|
||||
|
||||
"@electron-toolkit/preload": ["@electron-toolkit/preload@1.0.3", "", { "peerDependencies": { "electron": ">=13.0.0" } }, "sha512-3V/BS5Rg+Yd8lJyPA6kvHJe7zznPx9A5QrJ7AZlmnEkVWadiGSLrD87xyEaDlzgWKFuLJsyE9E4E0uNIJLWSvQ=="],
|
||||
|
||||
"@electron-toolkit/tsconfig": ["@electron-toolkit/tsconfig@1.0.1", "", { "peerDependencies": { "@types/node": "*" } }, "sha512-M0Mol3odspvtCuheyujLNAW7bXq7KFNYVMRtpjFa4ZfES4MuklXBC7Nli/omvc+PRKlrklgAGx3l4VakjNo8jg=="],
|
||||
|
||||
"@electron-toolkit/utils": ["@electron-toolkit/utils@1.0.2", "", { "dependencies": { "jszip": "^3.7.1" }, "peerDependencies": { "electron": ">=13.0.0" } }, "sha512-EHqVijVPdjBJBivxJH5E/Gu6Dzd5GfoUH0Ilbtx+EQarwaeJLPLxRM5DzD54uuhs1b8TGDI7uMYmcJW2CKrijg=="],
|
||||
|
||||
"@electron/get": ["@electron/get@2.0.3", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ=="],
|
||||
|
||||
"@electron/notarize": ["@electron/notarize@1.2.4", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.1" } }, "sha512-W5GQhJEosFNafewnS28d3bpQ37/s91CDWqxVchHfmv2dQSTWpOzNlUVQwYzC1ay5bChRV/A9BTL68yj0Pa+TSg=="],
|
||||
|
||||
"@electron/universal": ["@electron/universal@1.2.1", "", { "dependencies": { "@malept/cross-spawn-promise": "^1.1.0", "asar": "^3.1.0", "debug": "^4.3.1", "dir-compare": "^2.4.0", "fs-extra": "^9.0.1", "minimatch": "^3.0.4", "plist": "^3.0.4" } }, "sha512-7323HyMh7KBAl/nPDppdLsC87G6RwRU02dy5FPeGB1eS7rUePh55+WNWiDPLhFQqqVPHzh77M69uhmoT8XnwMQ=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
|
||||
|
||||
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
|
||||
|
||||
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
|
||||
|
||||
"@eslint/eslintrc": ["@eslint/eslintrc@2.1.4", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ=="],
|
||||
|
||||
"@eslint/js": ["@eslint/js@8.57.1", "", {}, "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q=="],
|
||||
|
||||
"@humanwhocodes/config-array": ["@humanwhocodes/config-array@0.13.0", "", { "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" } }, "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw=="],
|
||||
|
||||
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
|
||||
|
||||
"@humanwhocodes/object-schema": ["@humanwhocodes/object-schema@2.0.3", "", {}, "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
|
||||
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
|
||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="],
|
||||
|
||||
"@malept/cross-spawn-promise": ["@malept/cross-spawn-promise@1.1.1", "", { "dependencies": { "cross-spawn": "^7.0.1" } }, "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ=="],
|
||||
|
||||
"@malept/flatpak-bundler": ["@malept/flatpak-bundler@0.4.0", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.0", "lodash": "^4.17.15", "tmp-promise": "^3.0.2" } }, "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q=="],
|
||||
|
||||
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||
|
||||
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
||||
|
||||
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
||||
|
||||
"@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="],
|
||||
|
||||
"@svelte-put/qr": ["@svelte-put/qr@2.1.0", "", { "dependencies": { "headless-qr": "^1.0.3" }, "peerDependencies": { "svelte": "^5.1.0" } }, "sha512-7HzQjoNZI9k6J4R6tnMi0ZGtRQKIFmZqzeo2GtkKZkumtPYByuqjGcB/ApFkxfg+J5mARKezWzKiq9EDJ6htRg=="],
|
||||
|
||||
"@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.5", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ=="],
|
||||
|
||||
"@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="],
|
||||
|
||||
"@tootallnate/once": ["@tootallnate/once@2.0.0", "", {}, "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A=="],
|
||||
|
||||
"@types/cacheable-request": ["@types/cacheable-request@6.0.3", "", { "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "^3.1.4", "@types/node": "*", "@types/responselike": "^1.0.0" } }, "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw=="],
|
||||
|
||||
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||
|
||||
"@types/fs-extra": ["@types/fs-extra@9.0.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA=="],
|
||||
|
||||
"@types/glob": ["@types/glob@7.2.0", "", { "dependencies": { "@types/minimatch": "*", "@types/node": "*" } }, "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA=="],
|
||||
|
||||
"@types/http-cache-semantics": ["@types/http-cache-semantics@4.0.4", "", {}, "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA=="],
|
||||
|
||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||
|
||||
"@types/keyv": ["@types/keyv@3.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg=="],
|
||||
|
||||
"@types/minimatch": ["@types/minimatch@5.1.2", "", {}, "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA=="],
|
||||
|
||||
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||
|
||||
"@types/node": ["@types/node@18.19.123", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg=="],
|
||||
|
||||
"@types/plist": ["@types/plist@3.0.5", "", { "dependencies": { "@types/node": "*", "xmlbuilder": ">=11.0.1" } }, "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA=="],
|
||||
|
||||
"@types/responselike": ["@types/responselike@1.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw=="],
|
||||
|
||||
"@types/semver": ["@types/semver@7.7.0", "", {}, "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA=="],
|
||||
|
||||
"@types/verror": ["@types/verror@1.10.11", "", {}, "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg=="],
|
||||
|
||||
"@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="],
|
||||
|
||||
"@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="],
|
||||
|
||||
"@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="],
|
||||
|
||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@5.62.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/type-utils": "5.62.0", "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, "peerDependencies": { "@typescript-eslint/parser": "^5.0.0", "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag=="],
|
||||
|
||||
"@typescript-eslint/parser": ["@typescript-eslint/parser@5.62.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", "@typescript-eslint/typescript-estree": "5.62.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA=="],
|
||||
|
||||
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@5.62.0", "", { "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0" } }, "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w=="],
|
||||
|
||||
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@5.62.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "5.62.0", "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, "peerDependencies": { "eslint": "*" } }, "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew=="],
|
||||
|
||||
"@typescript-eslint/types": ["@typescript-eslint/types@5.62.0", "", {}, "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@5.62.0", "", { "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", "semver": "^7.3.7", "tsutils": "^3.21.0" } }, "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA=="],
|
||||
|
||||
"@typescript-eslint/utils": ["@typescript-eslint/utils@5.62.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ=="],
|
||||
|
||||
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@5.62.0", "", { "dependencies": { "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" } }, "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw=="],
|
||||
|
||||
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
||||
|
||||
"@xmldom/xmldom": ["@xmldom/xmldom@0.8.11", "", {}, "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw=="],
|
||||
|
||||
"acorn": ["acorn@8.15.0", "", { "bin": "bin/acorn" }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||
|
||||
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
|
||||
|
||||
"agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
||||
|
||||
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||
|
||||
"ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"app-builder-bin": ["app-builder-bin@4.0.0", "", {}, "sha512-xwdG0FJPQMe0M0UA4Tz0zEB8rBJTRA5a476ZawAqiBkMv16GRK5xpXThOjMaEOFnZ6zabejjG4J3da0SXG63KA=="],
|
||||
|
||||
"app-builder-lib": ["app-builder-lib@23.6.0", "", { "dependencies": { "7zip-bin": "~5.1.1", "@develar/schema-utils": "~2.6.5", "@electron/universal": "1.2.1", "@malept/flatpak-bundler": "^0.4.0", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", "builder-util": "23.6.0", "builder-util-runtime": "9.1.1", "chromium-pickle-js": "^0.2.0", "debug": "^4.3.4", "ejs": "^3.1.7", "electron-osx-sign": "^0.6.0", "electron-publish": "23.6.0", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "is-ci": "^3.0.0", "isbinaryfile": "^4.0.10", "js-yaml": "^4.1.0", "lazy-val": "^1.0.5", "minimatch": "^3.1.2", "read-config-file": "6.2.0", "sanitize-filename": "^1.6.3", "semver": "^7.3.7", "tar": "^6.1.11", "temp-file": "^3.4.0" } }, "sha512-dQYDuqm/rmy8GSCE6Xl/3ShJg6Ab4bZJMT8KaTKGzT436gl1DN4REP3FCWfXoh75qGTJ+u+WsdnnpO9Jl8nyMA=="],
|
||||
|
||||
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||
|
||||
"aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
|
||||
|
||||
"array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="],
|
||||
|
||||
"asar": ["asar@3.2.0", "", { "dependencies": { "chromium-pickle-js": "^0.2.0", "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "optionalDependencies": { "@types/glob": "^7.1.1" }, "bin": "bin/asar.js" }, "sha512-COdw2ZQvKdFGFxXwX3oYh2/sOsJWJegrdJCGxnN4MZ7IULgRBp9P6665aqj9z1v9VwP4oP1hRBojRDQ//IGgAg=="],
|
||||
|
||||
"assert-plus": ["assert-plus@1.0.0", "", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="],
|
||||
|
||||
"astral-regex": ["astral-regex@2.0.0", "", {}, "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="],
|
||||
|
||||
"async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="],
|
||||
|
||||
"async-exit-hook": ["async-exit-hook@2.0.1", "", {}, "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="],
|
||||
|
||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
||||
|
||||
"at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="],
|
||||
|
||||
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||
|
||||
"bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="],
|
||||
|
||||
"bluebird-lst": ["bluebird-lst@1.0.9", "", { "dependencies": { "bluebird": "^3.5.5" } }, "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw=="],
|
||||
|
||||
"boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
||||
|
||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||
|
||||
"browserslist": ["browserslist@4.25.3", "", { "dependencies": { "caniuse-lite": "^1.0.30001735", "electron-to-chromium": "^1.5.204", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": "cli.js" }, "sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ=="],
|
||||
|
||||
"buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
|
||||
|
||||
"buffer-alloc": ["buffer-alloc@1.2.0", "", { "dependencies": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" } }, "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow=="],
|
||||
|
||||
"buffer-alloc-unsafe": ["buffer-alloc-unsafe@1.1.0", "", {}, "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="],
|
||||
|
||||
"buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
|
||||
|
||||
"buffer-equal": ["buffer-equal@1.0.0", "", {}, "sha512-tcBWO2Dl4e7Asr9hTGcpVrCe+F7DubpmqWCTbj4FHLmjqO2hIaC383acQubWtRJhdceqs5uBHs6Es+Sk//RKiQ=="],
|
||||
|
||||
"buffer-fill": ["buffer-fill@1.0.0", "", {}, "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ=="],
|
||||
|
||||
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
||||
|
||||
"builder-util": ["builder-util@23.6.0", "", { "dependencies": { "7zip-bin": "~5.1.1", "@types/debug": "^4.1.6", "@types/fs-extra": "^9.0.11", "app-builder-bin": "4.0.0", "bluebird-lst": "^1.0.9", "builder-util-runtime": "9.1.1", "chalk": "^4.1.1", "cross-spawn": "^7.0.3", "debug": "^4.3.4", "fs-extra": "^10.0.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-ci": "^3.0.0", "js-yaml": "^4.1.0", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.4.0" } }, "sha512-QiQHweYsh8o+U/KNCZFSvISRnvRctb8m/2rB2I1JdByzvNKxPeFLlHFRPQRXab6aYeXc18j9LpsDLJ3sGQmWTQ=="],
|
||||
|
||||
"builder-util-runtime": ["builder-util-runtime@9.1.1", "", { "dependencies": { "debug": "^4.3.4", "sax": "^1.2.4" } }, "sha512-azRhYLEoDvRDR8Dhis4JatELC/jUvYjm4cVSj7n9dauGTOM2eeNn9KS0z6YA6oDsjI1xphjNbY6PZZeHPzzqaw=="],
|
||||
|
||||
"cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
|
||||
|
||||
"cacheable-lookup": ["cacheable-lookup@5.0.4", "", {}, "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="],
|
||||
|
||||
"cacheable-request": ["cacheable-request@7.0.4", "", { "dependencies": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", "normalize-url": "^6.0.1", "responselike": "^2.0.0" } }, "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg=="],
|
||||
|
||||
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
||||
|
||||
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
|
||||
|
||||
"caniuse-lite": ["caniuse-lite@1.0.30001737", "", {}, "sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw=="],
|
||||
|
||||
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||
|
||||
"chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
|
||||
|
||||
"chromium-pickle-js": ["chromium-pickle-js@0.2.0", "", {}, "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw=="],
|
||||
|
||||
"ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],
|
||||
|
||||
"cli-truncate": ["cli-truncate@2.1.0", "", { "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" } }, "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg=="],
|
||||
|
||||
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
||||
|
||||
"clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="],
|
||||
|
||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"colors": ["colors@1.0.3", "", {}, "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw=="],
|
||||
|
||||
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
|
||||
|
||||
"commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="],
|
||||
|
||||
"compare-version": ["compare-version@0.1.2", "", {}, "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A=="],
|
||||
|
||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||
|
||||
"concurrently": ["concurrently@8.2.2", "", { "dependencies": { "chalk": "^4.1.2", "date-fns": "^2.30.0", "lodash": "^4.17.21", "rxjs": "^7.8.1", "shell-quote": "^1.8.1", "spawn-command": "0.0.2", "supports-color": "^8.1.1", "tree-kill": "^1.2.2", "yargs": "^17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg=="],
|
||||
|
||||
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||
|
||||
"core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
|
||||
|
||||
"crc": ["crc@3.8.0", "", { "dependencies": { "buffer": "^5.1.0" } }, "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"date-fns": ["date-fns@2.30.0", "", { "dependencies": { "@babel/runtime": "^7.21.0" } }, "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw=="],
|
||||
|
||||
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||
|
||||
"decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
|
||||
|
||||
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
|
||||
|
||||
"defer-to-connect": ["defer-to-connect@2.0.1", "", {}, "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="],
|
||||
|
||||
"define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="],
|
||||
|
||||
"define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
|
||||
|
||||
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
|
||||
|
||||
"detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="],
|
||||
|
||||
"dir-compare": ["dir-compare@2.4.0", "", { "dependencies": { "buffer-equal": "1.0.0", "colors": "1.0.3", "commander": "2.9.0", "minimatch": "3.0.4" }, "bin": { "dircompare": "src/cli/dircompare.js" } }, "sha512-l9hmu8x/rjVC9Z2zmGzkhOEowZvW7pmYws5CWHutg8u1JgvsKWMx7Q/UODeu4djLZ4FgW5besw5yvMQnBHzuCA=="],
|
||||
|
||||
"dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
|
||||
|
||||
"dmg-builder": ["dmg-builder@23.6.0", "", { "dependencies": { "app-builder-lib": "23.6.0", "builder-util": "23.6.0", "builder-util-runtime": "9.1.1", "fs-extra": "^10.0.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" } }, "sha512-jFZvY1JohyHarIAlTbfQOk+HnceGjjAdFjVn3n8xlDWKsYNqbO4muca6qXEZTfGXeQMG7TYim6CeS5XKSfSsGA=="],
|
||||
|
||||
"dmg-license": ["dmg-license@1.0.11", "", { "dependencies": { "@types/plist": "^3.0.1", "@types/verror": "^1.10.3", "ajv": "^6.10.0", "crc": "^3.8.0", "iconv-corefoundation": "^1.1.7", "plist": "^3.0.4", "smart-buffer": "^4.0.2", "verror": "^1.10.0" }, "os": "darwin", "bin": "bin/dmg-license.js" }, "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q=="],
|
||||
|
||||
"doctrine": ["doctrine@3.0.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w=="],
|
||||
|
||||
"dotenv": ["dotenv@9.0.2", "", {}, "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg=="],
|
||||
|
||||
"dotenv-expand": ["dotenv-expand@5.1.0", "", {}, "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="],
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": "bin/cli.js" }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||
|
||||
"electron": ["electron@37.4.0", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^22.7.7", "extract-zip": "^2.0.1" }, "bin": "cli.js" }, "sha512-HhsSdWowE5ODOeWNc/323Ug2C52mq/TqNBG+4uMeOA3G2dMXNc/nfyi0RYu1rJEgiaJLEjtHveeZZaYRYFsFCQ=="],
|
||||
|
||||
"electron-builder": ["electron-builder@23.6.0", "", { "dependencies": { "@types/yargs": "^17.0.1", "app-builder-lib": "23.6.0", "builder-util": "23.6.0", "builder-util-runtime": "9.1.1", "chalk": "^4.1.1", "dmg-builder": "23.6.0", "fs-extra": "^10.0.0", "is-ci": "^3.0.0", "lazy-val": "^1.0.5", "read-config-file": "6.2.0", "simple-update-notifier": "^1.0.7", "yargs": "^17.5.1" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-y8D4zO+HXGCNxFBV/JlyhFnoQ0Y0K7/sFH+XwIbj47pqaW8S6PGYQbjoObolKBR1ddQFPt4rwp4CnwMJrW3HAw=="],
|
||||
|
||||
"electron-osx-sign": ["electron-osx-sign@0.6.0", "", { "dependencies": { "bluebird": "^3.5.0", "compare-version": "^0.1.2", "debug": "^2.6.8", "isbinaryfile": "^3.0.2", "minimist": "^1.2.0", "plist": "^3.0.1" }, "bin": { "electron-osx-flat": "bin/electron-osx-flat.js", "electron-osx-sign": "bin/electron-osx-sign.js" } }, "sha512-+hiIEb2Xxk6eDKJ2FFlpofCnemCbjbT5jz+BKGpVBrRNT3kWTGs4DfNX6IzGwgi33hUcXF+kFs9JW+r6Wc1LRg=="],
|
||||
|
||||
"electron-publish": ["electron-publish@23.6.0", "", { "dependencies": { "@types/fs-extra": "^9.0.11", "builder-util": "23.6.0", "builder-util-runtime": "9.1.1", "chalk": "^4.1.1", "fs-extra": "^10.0.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, "sha512-jPj3y+eIZQJF/+t5SLvsI5eS4mazCbNYqatv5JihbqOstIM13k0d1Z3vAWntvtt13Itl61SO6seicWdioOU5dg=="],
|
||||
|
||||
"electron-serve": ["electron-serve@1.3.0", "", {}, "sha512-OEC/48ZBJxR6XNSZtCl4cKPyQ1lvsu8yp8GdCplMWwGS1eEyMcEmzML5BRs/io/RLDnpgyf+7rSL+X6ICifRIg=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.211", "", {}, "sha512-IGBvimJkotaLzFnwIVgW9/UD/AOJ2tByUmeOrtqBfACSbAw5b1G0XpvdaieKyc7ULmbwXVx+4e4Be8pOPBrYkw=="],
|
||||
|
||||
"electron-updater": ["electron-updater@5.3.0", "", { "dependencies": { "@types/semver": "^7.3.6", "builder-util-runtime": "9.1.1", "fs-extra": "^10.0.0", "js-yaml": "^4.1.0", "lazy-val": "^1.0.5", "lodash.escaperegexp": "^4.1.2", "lodash.isequal": "^4.5.0", "semver": "^7.3.5", "typed-emitter": "^2.1.0" } }, "sha512-iKEr7yQBcvnQUPnSDYGSWC9t0eF2YbZWeYYYZzYxdl+HiRejXFENjYMnYjoOm2zxyD6Cr2JTHZhp9pqxiXuCOw=="],
|
||||
|
||||
"electron-vite": ["electron-vite@1.0.29", "", { "dependencies": { "@babel/core": "^7.22.8", "@babel/plugin-transform-arrow-functions": "^7.22.5", "cac": "^6.7.14", "esbuild": "^0.18.11", "magic-string": "^0.30.1", "picocolors": "^1.0.0" }, "peerDependencies": { "@swc/core": "^1.0.0", "vite": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["@swc/core"], "bin": "bin/electron-vite.js" }, "sha512-BDTmVTLIri8W4Lz1tn5RAV1slSTinBBb6G77+qKcjkF0vEwdiUp2ntSU6FDqwP9pmy1t96U1CZqIYIStF8H6Jw=="],
|
||||
|
||||
"electron-window-state": ["electron-window-state@5.0.3", "", { "dependencies": { "jsonfile": "^4.0.0", "mkdirp": "^0.5.1" } }, "sha512-1mNTwCfkolXl3kMf50yW3vE2lZj0y92P/HYWFBrb+v2S/pCka5mdwN3cagKm458A7NjndSwijynXgcLWRodsVg=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
|
||||
|
||||
"env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="],
|
||||
|
||||
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
||||
|
||||
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||
|
||||
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
||||
|
||||
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
|
||||
|
||||
"es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="],
|
||||
|
||||
"esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": "bin/esbuild" }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
|
||||
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||
|
||||
"eslint": ["eslint@8.57.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", "@eslint/js": "8.57.1", "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": "bin/eslint.js" }, "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA=="],
|
||||
|
||||
"eslint-config-prettier": ["eslint-config-prettier@8.10.2", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": "bin/cli.js" }, "sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A=="],
|
||||
|
||||
"eslint-plugin-prettier": ["eslint-plugin-prettier@4.2.5", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0" }, "peerDependencies": { "eslint": ">=7.28.0", "prettier": ">=2.0.0" } }, "sha512-9Ni+xgemM2IWLq6aXEpP2+V/V30GeA/46Ar629vcMqVPodFFWC9skHu/D1phvuqtS8bJCFnNf01/qcmqYEwNfg=="],
|
||||
|
||||
"eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="],
|
||||
|
||||
"eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
||||
|
||||
"esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
|
||||
|
||||
"espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="],
|
||||
|
||||
"esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
|
||||
|
||||
"esrap": ["esrap@2.1.0", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA=="],
|
||||
|
||||
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
|
||||
|
||||
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
|
||||
|
||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||
|
||||
"extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": "cli.js" }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="],
|
||||
|
||||
"extsprintf": ["extsprintf@1.4.1", "", {}, "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
|
||||
|
||||
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
||||
|
||||
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
||||
|
||||
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
|
||||
|
||||
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
|
||||
|
||||
"fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="],
|
||||
|
||||
"file-entry-cache": ["file-entry-cache@6.0.1", "", { "dependencies": { "flat-cache": "^3.0.4" } }, "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="],
|
||||
|
||||
"filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="],
|
||||
|
||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||
|
||||
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
||||
|
||||
"flat-cache": ["flat-cache@3.2.0", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" } }, "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw=="],
|
||||
|
||||
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
|
||||
|
||||
"form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
|
||||
|
||||
"fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="],
|
||||
|
||||
"fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="],
|
||||
|
||||
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||
|
||||
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
|
||||
|
||||
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
||||
|
||||
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
||||
|
||||
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||
|
||||
"get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
|
||||
|
||||
"glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
|
||||
|
||||
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
||||
|
||||
"global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="],
|
||||
|
||||
"globals": ["globals@13.24.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ=="],
|
||||
|
||||
"globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
|
||||
|
||||
"globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="],
|
||||
|
||||
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
||||
|
||||
"got": ["got@11.8.6", "", { "dependencies": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", "@types/cacheable-request": "^6.0.1", "@types/responselike": "^1.0.0", "cacheable-lookup": "^5.0.3", "cacheable-request": "^7.0.2", "decompress-response": "^6.0.0", "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", "p-cancelable": "^2.0.0", "responselike": "^2.0.0" } }, "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
|
||||
"graceful-readlink": ["graceful-readlink@1.0.1", "", {}, "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w=="],
|
||||
|
||||
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
|
||||
|
||||
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
||||
|
||||
"has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="],
|
||||
|
||||
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
||||
|
||||
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
|
||||
|
||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||
|
||||
"headless-qr": ["headless-qr@1.0.3", "", {}, "sha512-HHVwf1i++Ho2vFstHxAdfP0OjB7Di44nGXbh3VXciuzwkuFb1oeFDCrfOLjFgHip/Kbc/wq2GOaSTiKQ81K/Yg=="],
|
||||
|
||||
"hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="],
|
||||
|
||||
"http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="],
|
||||
|
||||
"http-proxy-agent": ["http-proxy-agent@5.0.0", "", { "dependencies": { "@tootallnate/once": "2", "agent-base": "6", "debug": "4" } }, "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w=="],
|
||||
|
||||
"http2-wrapper": ["http2-wrapper@1.0.3", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.0.0" } }, "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg=="],
|
||||
|
||||
"https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
|
||||
|
||||
"iconv-corefoundation": ["iconv-corefoundation@1.1.7", "", { "dependencies": { "cli-truncate": "^2.1.0", "node-addon-api": "^1.6.3" }, "os": "darwin" }, "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ=="],
|
||||
|
||||
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||
|
||||
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
||||
|
||||
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||
|
||||
"immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="],
|
||||
|
||||
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
|
||||
|
||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||
|
||||
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
|
||||
|
||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"is-ci": ["is-ci@3.0.1", "", { "dependencies": { "ci-info": "^3.2.0" }, "bin": "bin.js" }, "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
|
||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
|
||||
"is-path-inside": ["is-path-inside@3.0.3", "", {}, "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="],
|
||||
|
||||
"is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
|
||||
|
||||
"isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
|
||||
|
||||
"isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": "bin/cli.js" }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="],
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
|
||||
|
||||
"jsesc": ["jsesc@3.1.0", "", { "bin": "bin/jsesc" }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
||||
|
||||
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
|
||||
|
||||
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
||||
|
||||
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
|
||||
|
||||
"json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="],
|
||||
|
||||
"json5": ["json5@2.2.3", "", { "bin": "lib/cli.js" }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||
|
||||
"jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
|
||||
|
||||
"jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="],
|
||||
|
||||
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
||||
|
||||
"lazy-val": ["lazy-val@1.0.5", "", {}, "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q=="],
|
||||
|
||||
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
||||
|
||||
"lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="],
|
||||
|
||||
"locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
|
||||
|
||||
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
||||
|
||||
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||
|
||||
"lodash.escaperegexp": ["lodash.escaperegexp@4.1.2", "", {}, "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw=="],
|
||||
|
||||
"lodash.isequal": ["lodash.isequal@4.5.0", "", {}, "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="],
|
||||
|
||||
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
|
||||
|
||||
"lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="],
|
||||
|
||||
"lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.18", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ=="],
|
||||
|
||||
"matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="],
|
||||
|
||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||
|
||||
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
||||
|
||||
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
||||
|
||||
"mime": ["mime@2.6.0", "", { "bin": "cli.js" }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="],
|
||||
|
||||
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||
|
||||
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||
|
||||
"mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
|
||||
|
||||
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
||||
|
||||
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||
|
||||
"minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
|
||||
|
||||
"minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
|
||||
|
||||
"mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": "bin/cmd.js" }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": "bin/nanoid.cjs" }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
|
||||
|
||||
"natural-compare-lite": ["natural-compare-lite@1.4.0", "", {}, "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g=="],
|
||||
|
||||
"node-addon-api": ["node-addon-api@1.7.2", "", {}, "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
|
||||
|
||||
"normalize-url": ["normalize-url@6.1.0", "", {}, "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="],
|
||||
|
||||
"object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
|
||||
|
||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||
|
||||
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||
|
||||
"p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="],
|
||||
|
||||
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
||||
|
||||
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
||||
|
||||
"pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
|
||||
|
||||
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
|
||||
|
||||
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
|
||||
|
||||
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
|
||||
|
||||
"pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="],
|
||||
|
||||
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||
|
||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||
|
||||
"prettier": ["prettier@3.6.2", "", { "bin": "bin/prettier.cjs" }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
|
||||
|
||||
"prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="],
|
||||
|
||||
"prettier-plugin-svelte": ["prettier-plugin-svelte@3.4.0", "", { "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" } }, "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ=="],
|
||||
|
||||
"process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
|
||||
|
||||
"progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="],
|
||||
|
||||
"pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||
|
||||
"quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="],
|
||||
|
||||
"read-config-file": ["read-config-file@6.2.0", "", { "dependencies": { "dotenv": "^9.0.2", "dotenv-expand": "^5.1.0", "js-yaml": "^4.1.0", "json5": "^2.2.0", "lazy-val": "^1.0.4" } }, "sha512-gx7Pgr5I56JtYz+WuqEbQHj/xWo+5Vwua2jhb1VwM4Wid5PqYmZ4i00ZB0YEGIfkVBsCv9UrjgyqCiQfS/Oosg=="],
|
||||
|
||||
"readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
|
||||
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
|
||||
|
||||
"resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="],
|
||||
|
||||
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
|
||||
|
||||
"responselike": ["responselike@2.0.1", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw=="],
|
||||
|
||||
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
|
||||
|
||||
"rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": "bin.js" }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
|
||||
|
||||
"roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="],
|
||||
|
||||
"rollup": ["rollup@3.29.5", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w=="],
|
||||
|
||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||
|
||||
"rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
|
||||
|
||||
"safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||
|
||||
"sanitize-filename": ["sanitize-filename@1.6.3", "", { "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg=="],
|
||||
|
||||
"sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="],
|
||||
|
||||
"semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||
|
||||
"semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="],
|
||||
|
||||
"serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="],
|
||||
|
||||
"setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
|
||||
|
||||
"simple-update-notifier": ["simple-update-notifier@1.1.0", "", { "dependencies": { "semver": "~7.0.0" } }, "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg=="],
|
||||
|
||||
"slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
|
||||
|
||||
"slice-ansi": ["slice-ansi@3.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ=="],
|
||||
|
||||
"smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
|
||||
|
||||
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
|
||||
|
||||
"spawn-command": ["spawn-command@0.0.2", "", {}, "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ=="],
|
||||
|
||||
"sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="],
|
||||
|
||||
"stat-mode": ["stat-mode@1.0.0", "", {}, "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg=="],
|
||||
|
||||
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
|
||||
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
||||
|
||||
"sumchecker": ["sumchecker@3.0.1", "", { "dependencies": { "debug": "^4.1.0" } }, "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg=="],
|
||||
|
||||
"supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
|
||||
|
||||
"svelte": ["svelte@5.38.6", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-ltBPlkvqk3bgCK7/N323atUpP3O3Y+DrGV4dcULrsSn4fZaaNnOmdplNznwfdWclAgvSr5rxjtzn/zJhRm6TKg=="],
|
||||
|
||||
"tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
|
||||
|
||||
"temp-file": ["temp-file@3.4.0", "", { "dependencies": { "async-exit-hook": "^2.0.1", "fs-extra": "^10.0.0" } }, "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg=="],
|
||||
|
||||
"text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="],
|
||||
|
||||
"tmp": ["tmp@0.2.5", "", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="],
|
||||
|
||||
"tmp-promise": ["tmp-promise@3.0.3", "", { "dependencies": { "tmp": "^0.2.0" } }, "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
|
||||
"tree-kill": ["tree-kill@1.2.2", "", { "bin": "cli.js" }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
|
||||
|
||||
"truncate-utf8-bytes": ["truncate-utf8-bytes@1.0.2", "", { "dependencies": { "utf8-byte-length": "^1.0.1" } }, "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ=="],
|
||||
|
||||
"tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
|
||||
|
||||
"tsutils": ["tsutils@3.21.0", "", { "dependencies": { "tslib": "^1.8.1" }, "peerDependencies": { "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA=="],
|
||||
|
||||
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
||||
|
||||
"type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="],
|
||||
|
||||
"typed-emitter": ["typed-emitter@2.1.0", "", { "optionalDependencies": { "rxjs": "*" } }, "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA=="],
|
||||
|
||||
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
||||
|
||||
"undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
|
||||
|
||||
"universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
|
||||
|
||||
"update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
|
||||
|
||||
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
||||
|
||||
"utf8-byte-length": ["utf8-byte-length@1.0.5", "", {}, "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA=="],
|
||||
|
||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||
|
||||
"verror": ["verror@1.10.1", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg=="],
|
||||
|
||||
"vite": ["vite@4.5.14", "", { "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", "rollup": "^3.27.1" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["less", "lightningcss", "sass", "stylus", "sugarss", "terser"], "bin": "bin/vite.js" }, "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
|
||||
|
||||
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||
|
||||
"xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="],
|
||||
|
||||
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||
|
||||
"yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||
|
||||
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||
|
||||
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
|
||||
|
||||
"yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="],
|
||||
|
||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||
|
||||
"zimmerframe": ["zimmerframe@1.1.2", "", {}, "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w=="],
|
||||
|
||||
"@babel/core/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||
|
||||
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="],
|
||||
|
||||
"@electron/get/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@typescript-eslint/utils/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="],
|
||||
|
||||
"app-builder-lib/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
|
||||
|
||||
"builder-util/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
|
||||
|
||||
"chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||
|
||||
"clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="],
|
||||
|
||||
"dir-compare/commander": ["commander@2.9.0", "", { "dependencies": { "graceful-readlink": ">= 1.0.0" } }, "sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A=="],
|
||||
|
||||
"dir-compare/minimatch": ["minimatch@3.0.4", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA=="],
|
||||
|
||||
"dmg-builder/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
|
||||
|
||||
"electron/@types/node": ["@types/node@22.18.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ=="],
|
||||
|
||||
"electron-builder/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
|
||||
|
||||
"electron-osx-sign/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
||||
"electron-osx-sign/isbinaryfile": ["isbinaryfile@3.0.3", "", { "dependencies": { "buffer-alloc": "^1.2.0" } }, "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw=="],
|
||||
|
||||
"electron-publish/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
|
||||
|
||||
"electron-updater/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
|
||||
|
||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
|
||||
|
||||
"fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
|
||||
|
||||
"fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||
|
||||
"minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||
|
||||
"rxjs/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"serialize-error/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="],
|
||||
|
||||
"simple-update-notifier/semver": ["semver@7.0.0", "", { "bin": "bin/semver.js" }, "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A=="],
|
||||
|
||||
"tar/mkdirp": ["mkdirp@1.0.4", "", { "bin": "bin/cmd.js" }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
|
||||
|
||||
"temp-file/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
|
||||
|
||||
"verror/core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
|
||||
|
||||
"@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||
|
||||
"@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="],
|
||||
|
||||
"@typescript-eslint/utils/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="],
|
||||
|
||||
"app-builder-lib/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
|
||||
|
||||
"builder-util/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
|
||||
|
||||
"dmg-builder/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
|
||||
|
||||
"electron-builder/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
|
||||
|
||||
"electron-osx-sign/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"electron-publish/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
|
||||
|
||||
"electron-updater/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
|
||||
|
||||
"electron/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
"filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||
|
||||
"temp-file/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
|
||||
}
|
||||
}
|
3
dev-app-update.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
provider: generic
|
||||
url: https://example.com/auto-updates
|
||||
updaterCacheDirName: electron-app-updater
|
24
electron-builder.yml
Normal file
|
@ -0,0 +1,24 @@
|
|||
appId: com.arx-ccn.eve-lite
|
||||
productName: eve-lite
|
||||
directories:
|
||||
buildResources: build
|
||||
files:
|
||||
- '!**/.vscode/*'
|
||||
- '!src/*'
|
||||
- '!electron.vite.config.{js,ts,mjs,cjs}'
|
||||
- '!{.eslintignore,.eslintrc.js,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
|
||||
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
|
||||
- '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
|
||||
asarUnpack:
|
||||
- resources/**
|
||||
linux:
|
||||
target:
|
||||
- AppImage
|
||||
maintainer: arx-ccn.com
|
||||
category: Utility
|
||||
appImage:
|
||||
artifactName: ${name}-${version}.${ext}
|
||||
npmRebuild: false
|
||||
publish:
|
||||
provider: generic
|
||||
url: https://example.com/auto-updates
|
11
electron.vite.config.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { defineConfig, externalizeDepsPlugin, bytecodePlugin } from 'electron-vite';
|
||||
|
||||
export default defineConfig({
|
||||
main: {
|
||||
plugins: [externalizeDepsPlugin(), bytecodePlugin()]
|
||||
},
|
||||
preload: {
|
||||
plugins: [externalizeDepsPlugin(), bytecodePlugin()]
|
||||
}
|
||||
// renderer: {}
|
||||
});
|
6100
package-lock.json
generated
Normal file
55
package.json
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "eve-lite",
|
||||
"version": "1.1.0",
|
||||
"description": "Eve Lite",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "arx-ccn.com",
|
||||
"homepage": "https://arx-ccn.com/eve-lite",
|
||||
"scripts": {
|
||||
"format": "prettier --write .",
|
||||
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
|
||||
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
|
||||
"typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false",
|
||||
"typecheck": "npm run typecheck:node && npm run typecheck:web",
|
||||
"start": "electron-vite preview",
|
||||
"dev": "concurrently -p \"[{time}] [{name}]\" -n=sveltekit,electron -c=red,blue \"electron-vite dev --watch\" \"npm run dev:sveltekit\"",
|
||||
"build": "npm run build:sveltekit; npm run typecheck && electron-vite build",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"build:win": "npm run build && electron-builder --win --config",
|
||||
"build:mac": "npm run build && electron-builder --mac --config",
|
||||
"build:linux": "npm run build && electron-builder --linux --config",
|
||||
"dev:sveltekit": "cd src/renderer; bun run dev",
|
||||
"build:sveltekit": "cd src/renderer; bun run build; rsync -avzp build/ ../../out/renderer"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron-toolkit/preload": "^1.0.3",
|
||||
"@electron-toolkit/utils": "^1.0.2",
|
||||
"@svelte-put/qr": "^2.1.0",
|
||||
"electron-serve": "^1.1.0",
|
||||
"electron-updater": "^5.3.0",
|
||||
"electron-window-state": "^5.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-toolkit/tsconfig": "^1.0.1",
|
||||
"@electron/notarize": "^1.2.3",
|
||||
"@types/node": "^18.15.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"concurrently": "^8.0.1",
|
||||
"electron": "^37.4.0",
|
||||
"electron-builder": "^23.6.0",
|
||||
"electron-vite": "^1.0.21",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-svelte": "^3.4.0",
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^4.2.2"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"minimatch@<3.0.5": ">=3.0.5"
|
||||
}
|
||||
}
|
||||
}
|
BIN
resources/icon.png
Normal file
After Width: | Height: | Size: 737 KiB |
5
src/main/env.d.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
76
src/main/index.ts
Normal file
|
@ -0,0 +1,76 @@
|
|||
import { app, shell, BrowserWindow } from 'electron';
|
||||
import { join } from 'path';
|
||||
import { electronApp, optimizer, is } from '@electron-toolkit/utils';
|
||||
import icon from '../../resources/icon.png?asset';
|
||||
import serve from 'electron-serve';
|
||||
import windowStateManager from 'electron-window-state';
|
||||
|
||||
import './lib/utils';
|
||||
import { addCacheHandling } from './lib/cache';
|
||||
|
||||
const serveURL = serve({
|
||||
directory: join(__dirname, '..', 'renderer'),
|
||||
scheme: 'eve'
|
||||
});
|
||||
|
||||
let mainWindow: BrowserWindow;
|
||||
function createWindow(): void {
|
||||
const windowState = windowStateManager({
|
||||
defaultWidth: 1366,
|
||||
defaultHeight: 768
|
||||
});
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
width: windowState.width,
|
||||
height: windowState.height,
|
||||
x: windowState.x,
|
||||
y: windowState.y,
|
||||
show: false,
|
||||
fullscreen: true,
|
||||
autoHideMenuBar: true,
|
||||
icon,
|
||||
webPreferences: {
|
||||
preload: join(__dirname, '../preload/index.js'),
|
||||
sandbox: false
|
||||
}
|
||||
});
|
||||
|
||||
windowState.manage(mainWindow);
|
||||
mainWindow.on('close', () => {
|
||||
windowState.saveState(mainWindow);
|
||||
});
|
||||
|
||||
mainWindow.on('ready-to-show', () => {
|
||||
mainWindow.show();
|
||||
});
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler((details) => {
|
||||
shell.openExternal(details.url);
|
||||
return { action: 'deny' };
|
||||
});
|
||||
if (is.dev) {
|
||||
loadVite();
|
||||
mainWindow.webContents.openDevTools();
|
||||
} else serveURL(mainWindow);
|
||||
}
|
||||
|
||||
function loadVite(): void {
|
||||
mainWindow.loadURL(import.meta.env.MAIN_VITE_ELECTRON_RENDERER_URL).catch((e) => {
|
||||
console.log('Error loading URL, retrying', e);
|
||||
setTimeout(() => {
|
||||
loadVite();
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
electronApp.setAppUserModelId('com.arx-ccn');
|
||||
|
||||
addCacheHandling();
|
||||
|
||||
app.on('browser-window-created', (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window);
|
||||
});
|
||||
|
||||
createWindow();
|
||||
});
|
72
src/main/lib/cache.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import { app, protocol, session } from 'electron';
|
||||
import { URL } from 'url';
|
||||
import { createHash } from 'crypto';
|
||||
import { mkdir, readFile, writeFile } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import { existsSync } from 'node:fs';
|
||||
|
||||
const CACHE_DIR = join(process.env.XDG_CACHE_HOME || app.getPath('appData'), 'eve-cache');
|
||||
|
||||
const shouldCache = (url: URL) => url.protocol === 'https';
|
||||
const key = (url: string) => createHash('sha256').update(url).digest('hex');
|
||||
const metaPath = (k: string) => join(CACHE_DIR, `${k}.meta`);
|
||||
const bodyPath = (k: string) => join(CACHE_DIR, `${k}.body`);
|
||||
|
||||
export async function addCacheHandling() {
|
||||
await mkdir(CACHE_DIR, { recursive: true });
|
||||
session.defaultSession.webRequest.onBeforeRequest(async (details, callback) => {
|
||||
const k = key(details.url);
|
||||
if (existsSync(bodyPath(k))) {
|
||||
const redir = `cache://${Buffer.from(details.url).toString('base64')}`;
|
||||
return callback({ redirectURL: redir });
|
||||
}
|
||||
|
||||
const url = new URL(details.url);
|
||||
const allowedProtocols = ['file:', 'devtools:', 'eve:'];
|
||||
const allowedLocalPorts = ['4269', '6942', '5173'];
|
||||
const allowedImageExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.svg'];
|
||||
const isAllowed =
|
||||
allowedProtocols.includes(url.protocol) ||
|
||||
(url.hostname === 'localhost' && allowedLocalPorts.includes(url.port)) ||
|
||||
allowedImageExtensions.some((ext) => url.pathname.endsWith(ext)) ||
|
||||
['api.unisvg.com'].includes(url.hostname) ||
|
||||
(url.hostname === 'primal.b-cdn.net' &&
|
||||
url.pathname === '/media-upload' &&
|
||||
url.searchParams.get('u')?.endsWith('png')) ||
|
||||
url.hostname === 'cdn.tailwindcss.com' ||
|
||||
(url.hostname === 'api.iconify.design' && url.pathname.endsWith('.json')) ||
|
||||
url.host === 'esm.sh'; // TODO: esm.sh should NOT be used
|
||||
|
||||
if (!isAllowed) {
|
||||
console.log(url);
|
||||
console.log('🚫 Blocked:', details.url);
|
||||
}
|
||||
callback({ cancel: !isAllowed });
|
||||
});
|
||||
|
||||
session.defaultSession.webRequest.onCompleted({ urls: ['<all_urls>'] }, async (details) => {
|
||||
if (!shouldCache(new URL(details.url))) return;
|
||||
try {
|
||||
const res = await fetch(details.url);
|
||||
if (!res.ok) return;
|
||||
const buf = Buffer.from(await res.arrayBuffer());
|
||||
const k = key(details.url);
|
||||
await writeFile(metaPath(k), res.headers.get('content-type') || 'application/octet-stream');
|
||||
await writeFile(bodyPath(k), buf);
|
||||
} catch {}
|
||||
});
|
||||
|
||||
protocol.registerSchemesAsPrivileged([{ scheme: 'eve-cache', privileges: { bypassCSP: true } }]);
|
||||
app.whenReady().then(() => {
|
||||
protocol.handle('eve-cache', async (req) => {
|
||||
const url = Buffer.from(req.url.slice('eve-cache://'.length), 'base64').toString();
|
||||
const k = key(url);
|
||||
const [mime, body] = await Promise.all([
|
||||
readFile(metaPath(k), 'utf8').catch(() => 'application/octet-stream'),
|
||||
readFile(bodyPath(k)).catch(() => null)
|
||||
]);
|
||||
if (!body) return new Response('Not found', { status: 404 });
|
||||
return new Response(body as unknown as BodyInit, { headers: { 'content-type': mime } });
|
||||
});
|
||||
});
|
||||
}
|
13
src/main/lib/utils.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { app, ipcMain } from 'electron';
|
||||
|
||||
ipcMain.on('appVersionSync', (event, arg) => {
|
||||
console.log(arg);
|
||||
let currentVersion = '';
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
currentVersion = process.env.npm_package_version || '';
|
||||
} else {
|
||||
currentVersion = app.getVersion();
|
||||
}
|
||||
event.returnValue = currentVersion;
|
||||
});
|
8
src/preload/index.d.ts
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { ElectronAPI } from '@electron-toolkit/preload';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
electron: ElectronAPI;
|
||||
api: unknown;
|
||||
}
|
||||
}
|
16
src/preload/index.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
// @ts-nocheck
|
||||
import { contextBridge, ipcRenderer } from 'electron';
|
||||
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
send: (channel: string, data: any) => {
|
||||
ipcRenderer.send(channel, data);
|
||||
},
|
||||
sendSync: (channel: string, data: any) => {
|
||||
return ipcRenderer.sendSync(channel, data);
|
||||
},
|
||||
receive: (channel: string, func: (arg0: any) => void) => {
|
||||
ipcRenderer.on(channel, (event, ...args) => func(...args));
|
||||
}
|
||||
});
|
13
src/renderer/.eslintignore
Normal file
|
@ -0,0 +1,13 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
20
src/renderer/.eslintrc.cjs
Normal file
|
@ -0,0 +1,20 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
||||
plugins: ['svelte3', '@typescript-eslint'],
|
||||
ignorePatterns: ['*.cjs'],
|
||||
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
|
||||
settings: {
|
||||
'svelte3/typescript': () => require('typescript')
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true
|
||||
}
|
||||
};
|
10
src/renderer/.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
2
src/renderer/.npmrc
Normal file
|
@ -0,0 +1,2 @@
|
|||
engine-strict=true
|
||||
shamefully-hoist=true
|
13
src/renderer/.prettierignore
Normal file
|
@ -0,0 +1,13 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
18
src/renderer/.prettierrc
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"semi": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": [
|
||||
"prettier-plugin-svelte"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
"options": {
|
||||
"parser": "svelte"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
38
src/renderer/README.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# create-svelte
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm create svelte@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm create svelte@latest my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To create a production version of your app:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
1017
src/renderer/bun.lock
Normal file
2483
src/renderer/package-lock.json
generated
Normal file
46
src/renderer/package.json
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "eve-lite-ui",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@cartamd/plugin-code": "^4.2.0",
|
||||
"@cartamd/plugin-math": "^4.3.1",
|
||||
"@cartamd/plugin-tikz": "^4.2.2",
|
||||
"@iconify/svelte": "^5.0.1",
|
||||
"@shikijs/rehype": "^3.13.0",
|
||||
"@svelte-put/qr": "^2.1.0",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@tailwindcss/vite": "^4.1.12",
|
||||
"carta-md": "^4.11.1",
|
||||
"isomorphic-dompurify": "^2.28.0",
|
||||
"katex": "^0.16.22",
|
||||
"nostr-tools": "^2.16.2",
|
||||
"rxjs": "^7.8.2",
|
||||
"shiki": "^3.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-static": "^3.0.6",
|
||||
"@sveltejs/kit": "^2.9.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"daisyui": "^5.0.50",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-svelte": "^3.4.0",
|
||||
"sass-embedded": "^1.93.2",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tailwindcss": "^4.1.12",
|
||||
"typescript": "~5.6.2",
|
||||
"vite": "^6.0.3"
|
||||
}
|
||||
}
|
92
src/renderer/src/app.css
Normal file
|
@ -0,0 +1,92 @@
|
|||
@import 'tailwindcss';
|
||||
@plugin "@tailwindcss/typography";
|
||||
|
||||
@plugin "daisyui" {
|
||||
themes: all;
|
||||
root: ':host, :root';
|
||||
}
|
||||
|
||||
* {
|
||||
scrollbar-color: rgba(from var(--color-base-200) r g b / 0.5) transparent;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
html {
|
||||
transition: color-scheme 0.3s ease;
|
||||
}
|
||||
|
||||
body {
|
||||
transition:
|
||||
background-color 0.3s ease,
|
||||
color 0.3s ease;
|
||||
}
|
||||
|
||||
.ccn-btn {
|
||||
@apply relative w-full rounded-xl p-2
|
||||
transition-all duration-200 ease-out
|
||||
hover:-translate-y-0.5 hover:shadow-lg
|
||||
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-info/60
|
||||
bg-base-200/20 hover:bg-base-200/40;
|
||||
}
|
||||
|
||||
.ccn-btn.is-active {
|
||||
@apply bg-info/15 text-info-content;
|
||||
}
|
||||
|
||||
.ccn-inner {
|
||||
@apply mx-auto flex flex-col items-center;
|
||||
}
|
||||
|
||||
.ccn-avatar {
|
||||
@apply avatar relative;
|
||||
}
|
||||
|
||||
.ccn-hex {
|
||||
@apply mask mask-hexagon-2 hover:mask-hexagon w-16 shadow-md ring-1 ring-base-300/60 transition;
|
||||
|
||||
transition: 0.2s cubic-bezier(0.36, 0, 0.63, 1);
|
||||
transform: scale(1) rotate(0deg);
|
||||
|
||||
&:hover {
|
||||
transition: 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
transform: scale(1.25) rotate(720deg);
|
||||
}
|
||||
|
||||
&.ccn-hex-large {
|
||||
@apply w-32;
|
||||
}
|
||||
|
||||
&.ccn-hex-extra-large {
|
||||
@apply w-48;
|
||||
&:hover {
|
||||
transform: scale(2) rotate(-720deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ccn-btn:hover .ccn-hex {
|
||||
@apply ring-info/50;
|
||||
}
|
||||
|
||||
.ccn-hex .ccn-img,
|
||||
.ccn-hex svg {
|
||||
@apply h-16 w-16 object-cover;
|
||||
}
|
||||
|
||||
.ccn-indicator {
|
||||
@apply absolute -right-1 -top-1 h-3 w-3 rounded-full
|
||||
bg-info ring-2 ring-base-100;
|
||||
}
|
||||
|
||||
.ccn-name {
|
||||
@apply mt-2 block w-full truncate text-center text-[14px] font-extrabold
|
||||
text-base-content/80;
|
||||
}
|
||||
|
||||
.ccn-btn:hover .ccn-name {
|
||||
@apply text-base-content;
|
||||
}
|
||||
|
||||
#arxlet-container {
|
||||
@apply min-h-screen;
|
||||
}
|
18
src/renderer/src/app.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Eve Lite</title>
|
||||
|
||||
<!-- this is a bit annoying, but for now we need to keep those, to enable the full tailwind & daisyui in arxlets -->
|
||||
<link href="https://esm.sh/daisyui@5/daisyui.css" rel="stylesheet" type="text/css" />
|
||||
<link href="https://esm.sh/daisyui@5/themes.css" rel="stylesheet" type="text/css" />
|
||||
<script src="https://esm.sh/@tailwindcss/browser@4" type="module"></script>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
BIN
src/renderer/src/assets/default-bg.png
Normal file
After Width: | Height: | Size: 2.3 MiB |
BIN
src/renderer/src/assets/nature-bg.png
Normal file
After Width: | Height: | Size: 3.1 MiB |
BIN
src/renderer/src/assets/ocean-bg.png
Normal file
After Width: | Height: | Size: 2 MiB |
BIN
src/renderer/src/assets/space-bg.png
Normal file
After Width: | Height: | Size: 1.9 MiB |
BIN
src/renderer/src/assets/sunset-bg.png
Normal file
After Width: | Height: | Size: 2 MiB |
72
src/renderer/src/lib/Uint8Array.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import { bytesToHex, hexToBytes } from 'nostr-tools/utils';
|
||||
|
||||
const isHex = (hex: string) => /^[0-9a-fA-F]+$/.test(hex) && hex.length % 2 === 0;
|
||||
|
||||
export function write_varint(bytes: number[], n: number): number {
|
||||
let len = 0;
|
||||
while (true) {
|
||||
let b = n & 0x7f;
|
||||
n >>= 7;
|
||||
if (n !== 0) b |= 0x80;
|
||||
bytes.push(b);
|
||||
len += 1;
|
||||
if (n === 0) break;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
export const write_tagged_varint = (bytes: number[], value: number, tagged: boolean): number =>
|
||||
write_varint(bytes, (value << 1) | (tagged ? 1 : 0));
|
||||
|
||||
export function write_string(bytes: number[], s: string) {
|
||||
if (s.length === 0) return write_tagged_varint(bytes, 0, false);
|
||||
|
||||
if (isHex(s)) {
|
||||
const parsed = hexToBytes(s);
|
||||
write_tagged_varint(bytes, parsed.length, true);
|
||||
bytes.push(...parsed);
|
||||
} else {
|
||||
const contentBytes = new TextEncoder().encode(s);
|
||||
write_tagged_varint(bytes, contentBytes.length, false);
|
||||
bytes.push(...contentBytes);
|
||||
}
|
||||
}
|
||||
|
||||
export const read_tagged_varint = (data: Uint8Array, offset: number): [number, boolean, number] => {
|
||||
const [value, bytes_read] = read_varint(data, offset);
|
||||
const tagged = (value & 1) === 1;
|
||||
const actual_value = value >> 1;
|
||||
return [actual_value, tagged, bytes_read];
|
||||
};
|
||||
|
||||
export function read_varint(buffer: Uint8Array, offset: number): [number, number] {
|
||||
let value = 0;
|
||||
let shift = 0;
|
||||
let bytesRead = 0;
|
||||
|
||||
while (offset + bytesRead < buffer.length) {
|
||||
const byte = buffer[offset + bytesRead];
|
||||
if (!byte) return [value, bytesRead]; // never gonna happen, but typescript is being a bitch
|
||||
bytesRead++;
|
||||
|
||||
value |= (byte & 0x7f) << shift;
|
||||
|
||||
if ((byte & 0x80) === 0) break;
|
||||
|
||||
shift += 7;
|
||||
}
|
||||
|
||||
return [value, bytesRead];
|
||||
}
|
||||
|
||||
export function read_string(data: Uint8Array, offset: number): [string, number] {
|
||||
const [length, tagged, varint_bytes] = read_tagged_varint(data, offset);
|
||||
offset += varint_bytes;
|
||||
|
||||
if (length === 0) return ['', varint_bytes];
|
||||
|
||||
const stringData = data.slice(offset, offset + length);
|
||||
|
||||
if (tagged) return [bytesToHex(stringData), varint_bytes + length];
|
||||
return [new TextDecoder().decode(stringData), varint_bytes + length];
|
||||
}
|
3
src/renderer/src/lib/arxletUtils.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
window.utils.timestampToDate = (timestamp: number): Date => {
|
||||
return new Date(timestamp * 1000);
|
||||
};
|
39
src/renderer/src/lib/backgrounds.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import ocean from '../assets/ocean-bg.png';
|
||||
import space from '../assets/space-bg.png';
|
||||
import nature from '../assets/nature-bg.png';
|
||||
import sunset from '../assets/sunset-bg.png';
|
||||
import defaultBg from '../assets/default-bg.png';
|
||||
|
||||
export const backgroundOptions = [
|
||||
{
|
||||
id: 'default',
|
||||
name: 'Default',
|
||||
preview: 'bg-gradient-to-br from-blue-50 to-indigo-100',
|
||||
image: defaultBg
|
||||
},
|
||||
{ id: 'minimal', name: 'Minimal', preview: 'bg-gray-50' },
|
||||
{
|
||||
id: 'nature',
|
||||
name: 'Nature',
|
||||
preview: 'bg-gradient-to-br from-green-100 to-emerald-200',
|
||||
image: nature
|
||||
},
|
||||
{
|
||||
id: 'sunset',
|
||||
name: 'Sunset',
|
||||
preview: 'bg-gradient-to-br from-orange-100 to-pink-200',
|
||||
image: sunset
|
||||
},
|
||||
{
|
||||
id: 'ocean',
|
||||
name: 'Ocean',
|
||||
preview: 'bg-gradient-to-br from-cyan-100 to-blue-200',
|
||||
image: ocean
|
||||
},
|
||||
{
|
||||
id: 'dark',
|
||||
name: 'Dark',
|
||||
preview: 'bg-gradient-to-br from-gray-800 to-gray-900',
|
||||
image: space
|
||||
}
|
||||
];
|
148
src/renderer/src/lib/components/AddressBar.svelte
Normal file
|
@ -0,0 +1,148 @@
|
|||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import Icon from '@iconify/svelte';
|
||||
import { navigationStore } from '$lib/navigation';
|
||||
import { onMount } from 'svelte';
|
||||
import { filter, of, tap } from 'rxjs';
|
||||
import Avatar from '$lib/components/User/Avatar.svelte';
|
||||
import LiquidGlass from './LiquidGlass.svelte';
|
||||
|
||||
const getAddress = (path: string) => 'eve://' + (path === '/' ? 'home' : path.substring(1));
|
||||
|
||||
let path = $derived(page.url.pathname + page.url.search);
|
||||
let addressBarValue = $derived(getAddress(path));
|
||||
let publicKey = $state('');
|
||||
let refreshIndex = $state(0);
|
||||
|
||||
$effect(() => {
|
||||
navigationStore.pushState(path);
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
const cleanup = navigationStore.initialize(page.url.pathname);
|
||||
|
||||
try {
|
||||
publicKey = await window.eve.getPublicKey();
|
||||
} catch (error) {
|
||||
console.error('Error getting public key:', error);
|
||||
}
|
||||
|
||||
const handleProfileUpdate = (event: CustomEvent) => {
|
||||
const { publicKey: updatedPublicKey, avatarUrl: newAvatarUrl } = event.detail;
|
||||
if (updatedPublicKey === publicKey) refreshIndex++;
|
||||
};
|
||||
window.addEventListener('profileUpdated', handleProfileUpdate);
|
||||
|
||||
return () => {
|
||||
cleanup?.();
|
||||
window.removeEventListener('profileUpdated', handleProfileUpdate);
|
||||
};
|
||||
});
|
||||
|
||||
function handleSearch() {
|
||||
const trimmedValue = addressBarValue.trim();
|
||||
|
||||
if (trimmedValue.startsWith('eve://')) {
|
||||
const path = trimmedValue.substring(6); // Remove 'eve://'
|
||||
let targetPath = path ? `/${path}` : '/';
|
||||
if (targetPath === '/home') targetPath = '/';
|
||||
navigationStore.navigateTo(targetPath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (trimmedValue) navigationStore.navigateTo(`/search?q=${encodeURIComponent(trimmedValue)}`);
|
||||
else navigationStore.navigateTo('/');
|
||||
}
|
||||
|
||||
const resetAddressBar = () => (addressBarValue = getAddress(path));
|
||||
|
||||
const handleKeyPress = (event: KeyboardEvent) =>
|
||||
of(event).pipe(
|
||||
filter((event) => event.key === 'Enter'),
|
||||
tap(handleSearch)
|
||||
);
|
||||
|
||||
function handleBlur() {
|
||||
if (!addressBarValue) resetAddressBar();
|
||||
}
|
||||
</script>
|
||||
|
||||
<LiquidGlass>
|
||||
<div class="flex items-center gap-3 p-3">
|
||||
<div class="flex gap-1">
|
||||
<button
|
||||
class="btn btn-ghost btn-sm btn-circle relative overflow-hidden
|
||||
transition-all duration-300 ease-out
|
||||
{!$navigationStore.canGoBack
|
||||
? 'btn-disabled opacity-30'
|
||||
: 'hover:btn-primary hover:scale-105 hover:shadow-lg'}"
|
||||
title="Back"
|
||||
onclick={() => navigationStore.goBack()}
|
||||
disabled={!$navigationStore.canGoBack}
|
||||
>
|
||||
<Icon icon="mdi:chevron-left" class="w-4 h-4 relative z-10 transition-all duration-200" />
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-br from-white/10 to-transparent opacity-0 hover:opacity-100 transition-opacity duration-300"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-ghost btn-sm btn-circle relative overflow-hidden
|
||||
transition-all duration-300 ease-out
|
||||
{!$navigationStore.canGoForward
|
||||
? 'btn-disabled opacity-30'
|
||||
: 'hover:btn-primary hover:scale-105 hover:shadow-lg'}"
|
||||
title="Forward"
|
||||
onclick={() => navigationStore.goForward()}
|
||||
disabled={!$navigationStore.canGoForward}
|
||||
>
|
||||
<Icon icon="mdi:chevron-right" class="w-4 h-4 relative z-10 transition-all duration-200" />
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-br from-white/10 to-transparent opacity-0 hover:opacity-100 transition-opacity duration-300"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-ghost btn-sm btn-circle hover:btn-secondary"
|
||||
title="Home"
|
||||
onclick={() => navigationStore.navigateTo('/')}
|
||||
>
|
||||
<Icon icon="mdi:home" class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form
|
||||
onsubmit={(e) => {
|
||||
e.preventDefault();
|
||||
handleSearch();
|
||||
}}
|
||||
class="flex-1 w-full"
|
||||
>
|
||||
<div class="join w-full">
|
||||
<input
|
||||
bind:value={addressBarValue}
|
||||
onkeyup={handleKeyPress}
|
||||
onkeydown={handleKeyPress}
|
||||
onkeypress={handleKeyPress}
|
||||
onclick={(e) => e.currentTarget.select()}
|
||||
onblur={handleBlur}
|
||||
type="text"
|
||||
placeholder="Search or enter eve:// address..."
|
||||
class="input input-bordered join-item w-full focus:outline-offset-0"
|
||||
/>
|
||||
<button type="submit" class="btn btn-neutral join-item">
|
||||
<Icon icon="mdi:magnify" class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="flex shrink">
|
||||
{#if publicKey}
|
||||
<button
|
||||
class="btn btn-ghost btn-circle p-1 hover:scale-105 transition-transform"
|
||||
onclick={() => navigationStore.navigateTo('/profile')}
|
||||
title="Profile"
|
||||
>
|
||||
<Avatar pubkey={publicKey} {refreshIndex} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</LiquidGlass>
|
44
src/renderer/src/lib/components/AppIcon.svelte
Normal file
|
@ -0,0 +1,44 @@
|
|||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
|
||||
let {
|
||||
icon,
|
||||
color,
|
||||
foregroundColor = 'white',
|
||||
strokeColor = foregroundColor,
|
||||
isHomeScreen = false
|
||||
}: {
|
||||
icon: string;
|
||||
color: string;
|
||||
foregroundColor?: string;
|
||||
strokeColor?: string;
|
||||
isHomeScreen?: boolean;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<div class="relative">
|
||||
<div
|
||||
class:w-20={isHomeScreen}
|
||||
class:h-20={isHomeScreen}
|
||||
class:w-12={!isHomeScreen}
|
||||
class:h-12={!isHomeScreen}
|
||||
class="rounded-3xl shadow-xl flex items-center justify-center transition-all duration-300 group-hover:shadow-2xl group-hover:scale-105"
|
||||
style="background: linear-gradient(135deg, {color}dd 0%, {color} 50%, {color}bb 100%)"
|
||||
>
|
||||
<Icon
|
||||
{icon}
|
||||
width="80%"
|
||||
style="color: {foregroundColor}; stroke: {strokeColor}; stroke-width: 0.5px;"
|
||||
class="drop-shadow-lg transition-all duration-300 group-hover:scale-110"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class:w-20={isHomeScreen}
|
||||
class:h-20={isHomeScreen}
|
||||
class:w-12={!isHomeScreen}
|
||||
class:h-12={!isHomeScreen}
|
||||
class="absolute inset-0 rounded-3xl opacity-0 group-hover:opacity-30 transition-all duration-500 blur-sm scale-110 pointer-events-none"
|
||||
style="background: radial-gradient(circle, {color}66 0%, transparent 70%)"
|
||||
/>
|
||||
</div>
|
150
src/renderer/src/lib/components/ArxletCard.svelte
Normal file
|
@ -0,0 +1,150 @@
|
|||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import type { Arxlet } from '../eve';
|
||||
import { onMount } from 'svelte';
|
||||
import LiquidGlass from './LiquidGlass.svelte';
|
||||
|
||||
let {
|
||||
arxlet
|
||||
}: {
|
||||
arxlet: Arxlet;
|
||||
} = $props();
|
||||
|
||||
let isInstalling = $state(false);
|
||||
let isInstalled = $state(false);
|
||||
let canUpdate = $state(false);
|
||||
|
||||
let icon = $derived(arxlet.icon ?? 'mdi:package-variant');
|
||||
let iconColor = $derived(arxlet.iconColor ?? '#7f0707');
|
||||
let version = $derived(arxlet.version ?? deriveVersion(arxlet.versionDate));
|
||||
|
||||
function deriveVersion(timestamp: number): string {
|
||||
const date = new Date(timestamp * 1000);
|
||||
const SCALE_FACTOR = 255 / 743;
|
||||
|
||||
const components = {
|
||||
year: date.getFullYear() - 2025,
|
||||
month: date.getMonth(),
|
||||
day: date.getDate() - 1,
|
||||
hour: date.getHours(),
|
||||
minute: date.getMinutes(),
|
||||
second: date.getSeconds()
|
||||
};
|
||||
|
||||
const dayHour = components.day * 24 + components.hour;
|
||||
const scaledDayHour = Math.floor(dayHour * SCALE_FACTOR);
|
||||
|
||||
const major = (((components.year & 0xf) << 4) | (components.month & 0xf))
|
||||
.toString(16)
|
||||
.padStart(2, '0');
|
||||
|
||||
const minor = scaledDayHour.toString(16).padStart(2, '0');
|
||||
|
||||
const totalSeconds = dayHour * 3600 + components.minute * 60 + components.second;
|
||||
const baseSeconds = scaledDayHour * (3600 / SCALE_FACTOR);
|
||||
const patch = Math.floor(totalSeconds - baseSeconds)
|
||||
.toString(16)
|
||||
.padStart(4, '0');
|
||||
|
||||
return `${major}.${minor}.${patch}`;
|
||||
}
|
||||
|
||||
onMount(load);
|
||||
|
||||
async function load() {
|
||||
const event = await window.eve.getSingleEventById(arxlet.eventId);
|
||||
|
||||
if (event) return (isInstalled = true);
|
||||
|
||||
const arxletInstalled = await window.eve.getArxlet(arxlet.id);
|
||||
if (arxletInstalled) {
|
||||
isInstalled = true;
|
||||
canUpdate = arxletInstalled.versionDate !== arxlet.versionDate;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleInstall() {
|
||||
if ((isInstalled && !canUpdate) || isInstalling) return;
|
||||
|
||||
isInstalling = true;
|
||||
|
||||
await window.eve.cloneRemoteEvent(arxlet.eventId);
|
||||
|
||||
isInstalled = true;
|
||||
isInstalling = false;
|
||||
canUpdate = false;
|
||||
|
||||
console.log(`Installing ${arxlet.name}...`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<LiquidGlass
|
||||
class="card shadow-lg hover:shadow-xl transition-all duration-300 border border-base-300 hover:border-primary/30"
|
||||
>
|
||||
<div class="card-body p-6">
|
||||
<div class="flex items-start gap-4 mb-4">
|
||||
<div class="relative flex-shrink-0 group">
|
||||
<div
|
||||
class="w-16 h-16 rounded-2xl shadow-lg hover:shadow-xl
|
||||
flex items-center justify-center relative overflow-hidden
|
||||
transition-all duration-300 ease-out hover:scale-105
|
||||
before:absolute before:inset-0 before:rounded-2xl
|
||||
before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-80
|
||||
after:absolute after:inset-0 after:rounded-2xl
|
||||
after:shadow-inner after:shadow-black/10"
|
||||
style="background: linear-gradient(135deg, {iconColor}dd 0%, {iconColor} 50%, {iconColor}bb 100%)"
|
||||
>
|
||||
<Icon
|
||||
{icon}
|
||||
class="w-8 h-8 text-white drop-shadow-md relative z-10
|
||||
group-hover:drop-shadow-lg transition-all duration-300"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="absolute inset-0 w-16 h-16 rounded-2xl
|
||||
opacity-0 hover:opacity-20 transition-all duration-300
|
||||
blur-sm scale-110"
|
||||
style="background: radial-gradient(circle, {iconColor}66 0%, transparent 70%)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<h3 class="card-title text-lg font-bold text-base-content truncate mb-1">
|
||||
{arxlet.name}
|
||||
</h3>
|
||||
<p class="text-base-content/80 text-sm leading-relaxed mb-1">
|
||||
Version: {version}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-base-content/80 text-sm leading-relaxed mb-4 line-clamp-3">
|
||||
{arxlet.description}
|
||||
</p>
|
||||
|
||||
<div class="card-actions justify-end">
|
||||
<button
|
||||
class="btn btn-sm {isInstalled && !canUpdate ? 'btn-success' : 'btn-primary'} {isInstalling
|
||||
? 'loading'
|
||||
: ''}"
|
||||
onclick={handleInstall}
|
||||
disabled={isInstalling || (isInstalled && !canUpdate)}
|
||||
>
|
||||
{#if isInstalling}
|
||||
<span class="loading loading-spinner loading-sm" />
|
||||
Installing...
|
||||
{:else if canUpdate}
|
||||
<Icon icon="mdi:update" class="w-4 h-4" />
|
||||
Update
|
||||
{:else if isInstalled}
|
||||
<Icon icon="mdi:check" class="w-4 h-4" />
|
||||
Installed
|
||||
{:else}
|
||||
<Icon icon="mdi:download" class="w-4 h-4" />
|
||||
Install
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</LiquidGlass>
|
47
src/renderer/src/lib/components/ArxletHeader.svelte
Normal file
|
@ -0,0 +1,47 @@
|
|||
<script lang="ts">
|
||||
import { currentArxletTitle } from '$lib/stores/settings';
|
||||
import AppIcon from './AppIcon.svelte';
|
||||
import LiquidGlass from './LiquidGlass.svelte';
|
||||
|
||||
let {
|
||||
title,
|
||||
subtitle,
|
||||
icon,
|
||||
iconColor,
|
||||
iconForegroundColor,
|
||||
iconStrokeColor
|
||||
}: {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
icon: string;
|
||||
iconColor: string;
|
||||
iconForegroundColor?: string;
|
||||
iconStrokeColor?: string;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<div class="sticky top-0 z-90">
|
||||
<LiquidGlass>
|
||||
<div class="bg-base-300/70 border-b-4 border-primary/50 w-full mx-auto px-16 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<AppIcon
|
||||
{icon}
|
||||
color={iconColor}
|
||||
foregroundColor={iconForegroundColor}
|
||||
strokeColor={iconStrokeColor}
|
||||
/>
|
||||
<div>
|
||||
<h1 class="text-2xl font-semibold text-base-content">
|
||||
{title}
|
||||
{#if $currentArxletTitle}
|
||||
- {$currentArxletTitle}
|
||||
{/if}
|
||||
</h1>
|
||||
<p class="text-base-content/70 text-sm">
|
||||
{subtitle}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</LiquidGlass>
|
||||
</div>
|
34
src/renderer/src/lib/components/ArxletIcon.svelte
Normal file
|
@ -0,0 +1,34 @@
|
|||
<script lang="ts">
|
||||
import { navigationStore } from '../navigation';
|
||||
import AppIcon from './AppIcon.svelte';
|
||||
|
||||
let { app, isUnique } = $props();
|
||||
|
||||
function onclick(event: MouseEvent) {
|
||||
if (app.id === 'ZZ-store') return navigationStore.navigateTo('/store');
|
||||
if (app.id === 'ZZ-settings') return navigationStore.navigateTo('/settings');
|
||||
if (app.id === 'ZZ-invite') return navigationStore.navigateTo('/ccn-info');
|
||||
if (isUnique) return navigationStore.navigateTo('/app/' + app.id);
|
||||
console.log(app);
|
||||
return navigationStore.navigateTo('/app/' + app.id + ':' + app.author);
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="group flex flex-col items-center gap-4 p-6 hover:scale-105 hover:-translate-y-2 transition-all duration-300 ease-out"
|
||||
{onclick}
|
||||
>
|
||||
<AppIcon
|
||||
icon={app.icon}
|
||||
color={app.iconColor}
|
||||
foregroundColor={app.iconForegroundColor}
|
||||
strokeColor={app.iconStrokeColor}
|
||||
isHomeScreen
|
||||
/>
|
||||
|
||||
<span
|
||||
class="text-base font-semibold text-base-content group-hover:text-primary transition-colors duration-300"
|
||||
>
|
||||
{app.name}
|
||||
</span>
|
||||
</button>
|
176
src/renderer/src/lib/components/CCNSelector.svelte
Normal file
|
@ -0,0 +1,176 @@
|
|||
<script lang="ts">
|
||||
import LiquidGlass from './LiquidGlass.svelte';
|
||||
import Dialog from './Dialog.svelte';
|
||||
import CcnList from './CCNSelector/CCNList.svelte';
|
||||
import { parseInviteCode } from '$lib/invites';
|
||||
|
||||
const ccns = window.eve.listCCNs();
|
||||
let addCCNDialog = $state(false);
|
||||
let dialogMode = $state<'main' | 'join' | 'create'>('main');
|
||||
let inviteCode = $state('');
|
||||
let ccnName = $state('');
|
||||
let ccnDescription = $state('');
|
||||
|
||||
let isValidInviteCode = $derived(checkInviteCode(inviteCode));
|
||||
|
||||
function checkInviteCode(inviteCode: string): boolean {
|
||||
try {
|
||||
let parsed = parseInviteCode(inviteCode as `${string}1${string}`);
|
||||
if (parsed) return true;
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function showAddCCNDialog() {
|
||||
addCCNDialog = true;
|
||||
dialogMode = 'main';
|
||||
}
|
||||
|
||||
function joinCCN() {
|
||||
dialogMode = 'join';
|
||||
inviteCode = '';
|
||||
}
|
||||
|
||||
function createCCN() {
|
||||
dialogMode = 'create';
|
||||
ccnName = '';
|
||||
ccnDescription = '';
|
||||
}
|
||||
|
||||
async function handleJoinSubmit() {
|
||||
if (inviteCode.trim()) {
|
||||
const parsed = parseInviteCode(inviteCode as `${string}1${string}`);
|
||||
if (parsed) {
|
||||
console.log(parsed);
|
||||
await window.eve.joinCCN(
|
||||
parsed.version,
|
||||
parsed.startIndex,
|
||||
parsed.name,
|
||||
parsed.description,
|
||||
parsed.key
|
||||
);
|
||||
window.location.reload();
|
||||
addCCNDialog = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCreateCCN() {
|
||||
if (ccnName.trim() && ccnDescription.trim()) {
|
||||
try {
|
||||
await window.eve.createCCN(ccnName.trim(), ccnDescription.trim());
|
||||
addCCNDialog = false;
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error('Failed to create CCN:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
dialogMode = 'main';
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog bind:open={addCCNDialog}>
|
||||
{#if dialogMode === 'main'}
|
||||
<div class="text-center p-4">
|
||||
<h3 class="font-bold text-lg mb-4">Add CCN</h3>
|
||||
<p class="text-gray-600 mb-6">Join an existing CCN or create a new one</p>
|
||||
|
||||
<div class="space-y-3">
|
||||
<button class="btn btn-primary btn-block" onclick={joinCCN}> Join with Invite Code </button>
|
||||
|
||||
<button class="btn btn-secondary btn-block" onclick={createCCN}> Create New CCN </button>
|
||||
</div>
|
||||
</div>
|
||||
{:else if dialogMode === 'join'}
|
||||
<div class="p-4">
|
||||
<div class="flex items-center mb-4">
|
||||
<button class="btn btn-sm btn-ghost mr-2" onclick={goBack}>←</button>
|
||||
<h3 class="font-bold text-lg">Join CCN</h3>
|
||||
</div>
|
||||
|
||||
<form onsubmit={handleJoinSubmit} class="space-y-4">
|
||||
<div class="form-control w-full">
|
||||
<label class="label" for="invite-code">
|
||||
<span class="label-text">Invite Code</span>
|
||||
</label>
|
||||
<input
|
||||
id="invite-code"
|
||||
type="text"
|
||||
placeholder="Enter invite code..."
|
||||
class="input input-bordered w-full"
|
||||
bind:value={inviteCode}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 justify-end">
|
||||
<button type="button" class="btn btn-ghost" onclick={goBack}> Cancel </button>
|
||||
<button type="submit" class="btn btn-primary" disabled={!isValidInviteCode}>
|
||||
Join CCN
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{:else if dialogMode === 'create'}
|
||||
<div class="p-4">
|
||||
<div class="flex items-center mb-4">
|
||||
<button class="btn btn-sm btn-ghost mr-2" onclick={goBack}>←</button>
|
||||
<h3 class="font-bold text-lg">Create New CCN</h3>
|
||||
</div>
|
||||
|
||||
<form onsubmit={handleCreateCCN} class="space-y-4">
|
||||
<div class="form-control w-full">
|
||||
<label class="label" for="ccn-name">
|
||||
<span class="label-text">CCN Name</span>
|
||||
</label>
|
||||
<input
|
||||
id="ccn-name"
|
||||
type="text"
|
||||
placeholder="Enter CCN name..."
|
||||
class="input input-bordered w-full"
|
||||
bind:value={ccnName}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control w-full">
|
||||
<label class="label" for="ccn-description">
|
||||
<span class="label-text">Description</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="ccn-description"
|
||||
placeholder="Enter CCN description..."
|
||||
class="textarea textarea-bordered w-full"
|
||||
bind:value={ccnDescription}
|
||||
required
|
||||
rows="3"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 justify-end">
|
||||
<button type="button" class="btn btn-ghost" onclick={goBack}> Cancel </button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
disabled={!ccnName.trim() || !ccnDescription.trim()}
|
||||
>
|
||||
Create CCN
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{/if}
|
||||
</Dialog>
|
||||
|
||||
<div class="w-24 bg-transparent overflow-auto border-primary/50 border-r-4">
|
||||
<LiquidGlass>
|
||||
{#await ccns then ccns}
|
||||
<CcnList {ccns} {showAddCCNDialog} />
|
||||
{/await}
|
||||
</LiquidGlass>
|
||||
</div>
|
39
src/renderer/src/lib/components/CCNSelector/CCNList.svelte
Normal file
|
@ -0,0 +1,39 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import type { CCN } from '$lib/eve';
|
||||
import Icon from '@iconify/svelte';
|
||||
import CcnListItem from '$lib/components/CCNSelector/CCNListItem.svelte';
|
||||
|
||||
let { ccns, showAddCCNDialog }: { ccns: CCN[]; showAddCCNDialog: () => void } = $props();
|
||||
let activeCCN: CCN | null = $state(null);
|
||||
|
||||
onMount(async () => {
|
||||
activeCCN = await window.eve.getActiveCCN();
|
||||
});
|
||||
</script>
|
||||
|
||||
<ul role="list" class="grid grid-cols-1 gap-2 h-[calc(100vh-4em)] overflow-y-auto">
|
||||
{#each ccns as ccn (ccn.publicKey)}
|
||||
<CcnListItem {ccn} {activeCCN} />
|
||||
{/each}
|
||||
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="ccn-btn"
|
||||
aria-label="New CCN"
|
||||
title="New CCN"
|
||||
onclick={showAddCCNDialog}
|
||||
>
|
||||
<div class="ccn-inner">
|
||||
<div class="ccn-avatar">
|
||||
<div class="ccn-hex">
|
||||
<Icon icon="mdi:plus" class="ccn-icon" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="ccn-name">New CCN</span>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
|
@ -0,0 +1,51 @@
|
|||
<script lang="ts">
|
||||
import type { CCN } from '$lib/eve';
|
||||
|
||||
let {
|
||||
ccn,
|
||||
activeCCN
|
||||
}: {
|
||||
ccn: CCN;
|
||||
activeCCN: CCN | null;
|
||||
} = $props();
|
||||
|
||||
function switchCCN() {
|
||||
window.eve.activateCCN(ccn.publicKey).then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="ccn-btn"
|
||||
class:is-active={ccn.publicKey === activeCCN?.publicKey}
|
||||
aria-pressed={ccn.publicKey === activeCCN?.publicKey}
|
||||
aria-label={ccn.name}
|
||||
title={ccn.name}
|
||||
onclick={switchCCN}
|
||||
>
|
||||
<div class="ccn-inner">
|
||||
<div class="ccn-avatar">
|
||||
<div class="ccn-hex">
|
||||
<img
|
||||
src={window.eve.getCCNAvatar(ccn.publicKey)}
|
||||
alt={'Avatar for ' + ccn.name}
|
||||
class="ccn-img"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if ccn.publicKey === activeCCN?.publicKey}
|
||||
<span class="ccn-indicator"></span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<span class="ccn-name">
|
||||
{ccn.name}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
49
src/renderer/src/lib/components/CopyButton.svelte
Normal file
|
@ -0,0 +1,49 @@
|
|||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
let copied = $state(false);
|
||||
|
||||
async function copyToClipboard() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(data);
|
||||
copied = true;
|
||||
setTimeout(() => {
|
||||
copied = false;
|
||||
}, 2000);
|
||||
} catch (err) {
|
||||
console.error('Failed to copy text: ', err);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="copy-btn btn gap-2 transition-all duration-300"
|
||||
class:btn-primary={!copied}
|
||||
class:btn-success={copied}
|
||||
class:animate-pulse={copied}
|
||||
onclick={copyToClipboard}
|
||||
disabled={copied}
|
||||
>
|
||||
<span class="icon-wrapper" class:animate-bounce={copied}>
|
||||
{#if copied}
|
||||
<Icon icon="tabler:check" class="w-4 h-4" />
|
||||
{:else}
|
||||
<Icon icon="tabler:copy" class="w-4 h-4" />
|
||||
{/if}
|
||||
</span>
|
||||
{copied ? 'Copied!' : 'Copy'}
|
||||
</button>
|
||||
|
||||
<style>
|
||||
@reference "tailwindcss";
|
||||
|
||||
.copy-btn {
|
||||
@apply relative overflow-hidden;
|
||||
}
|
||||
|
||||
.icon-wrapper {
|
||||
@apply transition-transform duration-200;
|
||||
}
|
||||
</style>
|
61
src/renderer/src/lib/components/Dialog.svelte
Normal file
|
@ -0,0 +1,61 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-dialog',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import LiquidGlass from './LiquidGlass.svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(),
|
||||
icon = '',
|
||||
title
|
||||
}: { open: boolean; icon?: string; title?: string } = $props();
|
||||
|
||||
let dialog: HTMLDialogElement;
|
||||
let target: HTMLDivElement;
|
||||
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
dialog.showModal();
|
||||
$host()?.dispatchEvent(new CustomEvent('open'));
|
||||
} else {
|
||||
dialog.close();
|
||||
$host()?.dispatchEvent(new CustomEvent('close'));
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const host = $host();
|
||||
if (!host) return;
|
||||
const firstChild = host.firstChild;
|
||||
if (!firstChild) return;
|
||||
if (firstChild instanceof HTMLDialogElement) return;
|
||||
target.innerHTML = '';
|
||||
host.removeChild(firstChild);
|
||||
target.appendChild(firstChild);
|
||||
});
|
||||
</script>
|
||||
|
||||
<dialog class="modal backdrop-blur-xl" onclose={() => (open = false)} bind:this={dialog}>
|
||||
<LiquidGlass class="modal-box">
|
||||
<div class="flex flex-row gap-3">
|
||||
{#if icon}
|
||||
<iconify-icon {icon} class="w-8 h-8 text-white"></iconify-icon>
|
||||
{/if}
|
||||
{#if title}
|
||||
<h2 class="flex-1 font-bold text-lg">{title}</h2>
|
||||
{:else}
|
||||
<div class="flex-1"></div>
|
||||
{/if}
|
||||
<form method="dialog">
|
||||
<button class="btn btn-sm btn-circle btn-ghost">✕</button>
|
||||
</form>
|
||||
</div>
|
||||
<div bind:this={target}>
|
||||
<slot />
|
||||
</div>
|
||||
</LiquidGlass>
|
||||
</dialog>
|
99
src/renderer/src/lib/components/LiquidGlass.svelte
Normal file
|
@ -0,0 +1,99 @@
|
|||
<script lang="ts">
|
||||
import { currentSeed } from '$lib/stores/settings';
|
||||
import { onMount } from 'svelte';
|
||||
import type { ClassValue } from 'svelte/elements';
|
||||
|
||||
const { class: classNames }: { class?: ClassValue } = $props();
|
||||
</script>
|
||||
|
||||
<div class={['glass-container', classNames]}>
|
||||
<div class="glass-filter" style:filter={`url(#apple-liquid-glass-${$currentSeed})`} />
|
||||
<div class="glass-overlay" />
|
||||
<div class="glass-specular" />
|
||||
<div class="glass-content">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<svg style="position: absolute; width: 0; height: 0;" aria-hidden="true">
|
||||
<defs>
|
||||
<filter
|
||||
id="apple-liquid-glass-{$currentSeed}"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-20%"
|
||||
y="-20%"
|
||||
width="140%"
|
||||
height="140%"
|
||||
>
|
||||
<feTurbulence
|
||||
type="fractalNoise"
|
||||
baseFrequency="0.005 0.005"
|
||||
numOctaves="4"
|
||||
seed={$currentSeed}
|
||||
result="noise"
|
||||
/>
|
||||
<feGaussianBlur in="noise" stdDeviation="2" result="blurred" />
|
||||
<feOffset in="blurred" result="offset">
|
||||
<animate
|
||||
attributeName="dx"
|
||||
values="0;20;33;0;-20;33;0"
|
||||
dur="13s"
|
||||
calcMode="linear"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
<animate
|
||||
attributeName="dy"
|
||||
values="0;20;-33;0"
|
||||
dur="7s"
|
||||
calcMode="linear"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</feOffset>
|
||||
<feDisplacementMap
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
scale="70"
|
||||
xChannelSelector="B"
|
||||
yChannelSelector="G"
|
||||
/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
<style>
|
||||
.glass-content {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
overflow: auto;
|
||||
}
|
||||
.glass-container {
|
||||
position: relative;
|
||||
font-weight: 600;
|
||||
background: transparent;
|
||||
overflow: hidden;
|
||||
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 2.2);
|
||||
}
|
||||
|
||||
.glass-filter {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
backdrop-filter: blur(5px);
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
.glass-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
background-color: rgba(from var(--color-base-200) r g b / 0.7);
|
||||
}
|
||||
|
||||
.glass-specular {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 2;
|
||||
border-radius: inherit;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
179
src/renderer/src/lib/components/NotePrinter.svelte
Normal file
|
@ -0,0 +1,179 @@
|
|||
<script lang="ts">
|
||||
import type { NostrEvent } from '../eve';
|
||||
import Avatar from '$lib/components/User/Avatar.svelte';
|
||||
import { formatDate } from '../utils.svelte';
|
||||
import ObjectPrinter from './ObjectPrinter.svelte';
|
||||
import UserName from '$lib/components/User/UserName.svelte';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
|
||||
let { note }: { note: NostrEvent } = $props();
|
||||
let showRaw = $state(false);
|
||||
|
||||
let formattedDate = $derived(formatDate(note.created_at));
|
||||
let noteKindName = $derived(
|
||||
{
|
||||
0: 'Profile Metadata',
|
||||
1: 'Text Note',
|
||||
3: 'Contact List',
|
||||
4: 'Encrypted DM',
|
||||
5: 'Event Deletion',
|
||||
6: 'Repost',
|
||||
7: 'Reaction',
|
||||
8: 'Badge Award',
|
||||
16: 'Generic Repost',
|
||||
40: 'Channel Creation',
|
||||
41: 'Channel Metadata',
|
||||
42: 'Channel Message',
|
||||
43: 'Channel Hide Message',
|
||||
44: 'Channel Mute User',
|
||||
1984: 'Report',
|
||||
9734: 'Zap Request',
|
||||
9735: 'Zap',
|
||||
10000: 'Mute List',
|
||||
10001: 'Pin List',
|
||||
10002: 'Relay List',
|
||||
30000: 'Categorized People',
|
||||
30001: 'Categorized Bookmarks',
|
||||
30008: 'Profile Badges',
|
||||
30009: 'Badge Definition',
|
||||
30017: 'Create or Update Stall',
|
||||
30018: 'Create or Update Product',
|
||||
30023: 'Long-form Content',
|
||||
30024: 'Draft Long-form Content',
|
||||
30078: 'Application Specific Data'
|
||||
}[note.kind] || 'Unknown Kind'
|
||||
);
|
||||
let parsedContent = $derived(parseContent(note));
|
||||
|
||||
function parseContent(note: NostrEvent) {
|
||||
if (!note.content) return '';
|
||||
|
||||
switch (note.kind) {
|
||||
case 0:
|
||||
try {
|
||||
return JSON.parse(note.content);
|
||||
} catch (e) {
|
||||
return note.content;
|
||||
}
|
||||
case 1:
|
||||
return note.content;
|
||||
case 7:
|
||||
return note.content || '👍';
|
||||
case 1059:
|
||||
case 1060:
|
||||
return '[Encrypted Message]';
|
||||
default:
|
||||
return note.content;
|
||||
}
|
||||
}
|
||||
|
||||
function truncateId(id, length = 8) {
|
||||
return id ? `${id.substring(0, length)}...${id.substring(id.length - length)}` : '';
|
||||
}
|
||||
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text);
|
||||
}
|
||||
|
||||
function getKindColor(kind) {
|
||||
const colors = {
|
||||
0: 'badge-info',
|
||||
1: 'badge-primary',
|
||||
3: 'badge-secondary',
|
||||
4: 'badge-warning',
|
||||
5: 'badge-error',
|
||||
6: 'badge-accent',
|
||||
7: 'badge-success',
|
||||
9735: 'badge-warning'
|
||||
};
|
||||
return colors[kind] || 'badge-neutral';
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if note}
|
||||
<div class="card bg-base-100 shadow-xl border border-base-300 mb-4">
|
||||
<!-- Card Header -->
|
||||
<div class="card-body">
|
||||
<div class="flex justify-between items-start mb-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<Avatar pubkey={note.pubkey} />
|
||||
<div>
|
||||
<UserName pubkey={note.pubkey} />
|
||||
<div class="text-sm opacity-70">{formattedDate}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="badge {getKindColor(note.kind)} badge-sm">
|
||||
Kind {note.kind}
|
||||
</div>
|
||||
<div class="badge badge-outline badge-sm">
|
||||
{noteKindName}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if note.kind === 0}
|
||||
<fieldset class="fieldset bg-base-200 border-base-300 rounded-box w-full border p-4">
|
||||
<legend class="fieldset-legend text-center"> Profile Information </legend>
|
||||
<ObjectPrinter obj={parsedContent} />
|
||||
</fieldset>
|
||||
{:else if note.kind === 7}
|
||||
<!-- Reaction Display -->
|
||||
<div class="text-center py-8">
|
||||
<div class="text-6xl mb-2">{parsedContent}</div>
|
||||
<div class="text-sm opacity-70">Reaction</div>
|
||||
</div>
|
||||
{:else if note.content}
|
||||
<div class="prose prose-sm max-w-none">
|
||||
<div class="whitespace-pre-wrap break-words">
|
||||
{@html parsedContent}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if note.tags && note.tags.length > 0}
|
||||
<fieldset class="fieldset bg-base-200 border-base-300 rounded-box w-full border p-4">
|
||||
<legend class="fieldset-legend text-center">Tags</legend>
|
||||
<div class="flex flex-wrap gap-2 card bg-base-200 p-6">
|
||||
{#each note.tags as tag}
|
||||
<div class="badge badge-outline badge-sm">
|
||||
{#if tag[0] === 'e'}
|
||||
<span class="mr-1">📝</span> Event: {truncateId(tag[1], 4)}
|
||||
{:else if tag[0] === 'p'}
|
||||
<span class="mr-1">👤</span> User: {truncateId(tag[1], 4)}
|
||||
{:else if tag[0] === 't'}
|
||||
<span class="mr-1">#</span> {tag[1]}
|
||||
{:else}
|
||||
{tag[0]}: {tag[1] || ''}
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</fieldset>
|
||||
{/if}
|
||||
|
||||
<fieldset class="fieldset bg-base-200 border-base-300 rounded-box w-full border p-4">
|
||||
<legend class="fieldset-legend text-center">Note Details</legend>
|
||||
<div>
|
||||
<span class="font-medium">Note ID:</span>
|
||||
<span class="ml-2 font-mono">{nip19.noteEncode(note.id)}</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="card-actions justify-end mt-4">
|
||||
<button class="btn btn-outline btn-sm" onclick={() => (showRaw = !showRaw)}>
|
||||
{showRaw ? 'Hide' : 'Show'} Raw JSON
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if showRaw}
|
||||
<ObjectPrinter obj={note} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="alert alert-info">
|
||||
<span>No note provided</span>
|
||||
</div>
|
||||
{/if}
|
85
src/renderer/src/lib/components/ObjectPrinter.svelte
Normal file
|
@ -0,0 +1,85 @@
|
|||
<script lang="ts">
|
||||
let { obj }: { obj: any } = $props();
|
||||
</script>
|
||||
|
||||
{#snippet printObject(object: any, depth: number = 0, path: string = '')}
|
||||
{#if object === null}
|
||||
<span class="text-neutral-content italic">null</span>
|
||||
{:else if object === undefined}
|
||||
<span class="text-neutral-content italic">undefined</span>
|
||||
{:else if Array.isArray(object)}
|
||||
{#if object.length === 0}
|
||||
<span class="text-base-content/60">[]</span>
|
||||
{:else}
|
||||
<div class="collapse collapse-arrow bg-base-200/50 rounded-box mb-1">
|
||||
<input type="checkbox" checked={depth < 2} />
|
||||
<div class="collapse-title text-sm font-medium text-primary">
|
||||
<span class="badge badge-primary badge-sm mr-2">{object.length}</span>
|
||||
Array
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<div class="space-y-1 pl-4 border-l-2 border-base-300">
|
||||
{#each object as item, index}
|
||||
<div class="flex items-start gap-2">
|
||||
<span class="badge badge-ghost badge-xs font-mono">{index}</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
{@render printObject(item, depth + 1, `${path}[${index}]`)}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else if typeof object === 'object'}
|
||||
{#if Object.keys(object).length === 0}
|
||||
<span class="text-base-content/60">{'{}'}</span>
|
||||
{:else if depth === 0}
|
||||
{@render printObjectInside(object, depth, path)}
|
||||
{:else}
|
||||
<div class="collapse collapse-arrow bg-base-200/50 rounded-box mb-1">
|
||||
<input type="checkbox" checked={depth < 4} />
|
||||
<div class="collapse-title text-sm font-medium text-secondary">
|
||||
<span class="badge badge-secondary badge-sm mr-2">
|
||||
{Object.keys(object).length}
|
||||
</span>
|
||||
Object
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
{@render printObjectInside(object, depth, path)}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else if typeof object === 'string'}
|
||||
<span class="text-success font-medium">"{object}"</span>
|
||||
{:else if typeof object === 'number'}
|
||||
<span class="text-info font-medium">{object}</span>
|
||||
{:else if typeof object === 'boolean'}
|
||||
<span class="text-warning font-medium">{object}</span>
|
||||
{:else if typeof object === 'function'}
|
||||
<span class="text-neutral-content italic">function</span>
|
||||
{:else}
|
||||
<span class="text-base-content">{String(object)}</span>
|
||||
{/if}
|
||||
{/snippet}
|
||||
|
||||
{#snippet printObjectInside(object: any, depth: number = 0, path: string = '')}
|
||||
<div class="space-y-1 pl-4 border-l-2 border-base-300">
|
||||
{#each Object.entries(object) as [key, value]}
|
||||
<div class="flex items-start gap-2">
|
||||
<span class="text-accent font-semibold text-sm min-w-0 break-words">
|
||||
"{key}":
|
||||
</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
{@render printObject(value, depth + 1, `${path}.${key}`)}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<div class="mockup-code bg-base-100 shadow-lg">
|
||||
<div class="px-4 py-2">
|
||||
{@render printObject(obj)}
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,28 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-arxlet-sublink'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
|
||||
const { href, arxlet, ...rest }: { href: string; arxlet?: string } = $props();
|
||||
|
||||
const arxletId = $derived(arxlet ? arxlet : page.params.id);
|
||||
</script>
|
||||
|
||||
{#if page.route.id === '/app/[id]'}
|
||||
<a {...rest} href="/app/{arxletId}/{href}">
|
||||
<slot />
|
||||
</a>
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
</style>
|
180
src/renderer/src/lib/components/PublicComponents/Combobox.svelte
Normal file
|
@ -0,0 +1,180 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-combobox'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import Icon from '@iconify/svelte';
|
||||
import LiquidGlass from '../LiquidGlass.svelte';
|
||||
|
||||
let {
|
||||
items = [],
|
||||
value = $bindable(),
|
||||
placeholder = 'Search...',
|
||||
displayValue = value,
|
||||
maxResults = Number.POSITIVE_INFINITY,
|
||||
filterFunction = defaultFilter
|
||||
}: {
|
||||
items?: string[];
|
||||
value?: string;
|
||||
placeholder?: string;
|
||||
displayValue?: string;
|
||||
maxResults?: number;
|
||||
filterFunction?: (items: string[], search: string) => string[];
|
||||
} = $props();
|
||||
|
||||
let search: string = $state(displayValue || '');
|
||||
let isOpen: boolean = $state(false);
|
||||
|
||||
let comboboxRef: HTMLDivElement;
|
||||
let inputRef: HTMLInputElement;
|
||||
|
||||
let dropdownElement: HTMLDivElement;
|
||||
let portalTarget: HTMLElement;
|
||||
let dropdownPosition = $state({ top: 0, left: 0, width: 0 });
|
||||
|
||||
function defaultFilter(items: string[], search: string): string[] {
|
||||
return items.filter((item) => item.toLowerCase().includes(search.toLowerCase()));
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
portalTarget = document.body;
|
||||
displayValue = value;
|
||||
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
comboboxRef &&
|
||||
!comboboxRef.contains(event.target as Node) &&
|
||||
dropdownElement &&
|
||||
!dropdownElement.contains(event.target as Node)
|
||||
) {
|
||||
isOpen = false;
|
||||
}
|
||||
};
|
||||
|
||||
const updatePosition = () => {
|
||||
if (inputRef && isOpen) {
|
||||
const rect = inputRef.getBoundingClientRect();
|
||||
dropdownPosition = {
|
||||
top: rect.bottom + window.scrollY + 4,
|
||||
left: rect.left + window.scrollX,
|
||||
width: rect.width
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('click', handleClickOutside);
|
||||
window.addEventListener('scroll', updatePosition, true);
|
||||
window.addEventListener('resize', updatePosition);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('click', handleClickOutside);
|
||||
window.removeEventListener('scroll', updatePosition, true);
|
||||
window.removeEventListener('resize', updatePosition);
|
||||
};
|
||||
});
|
||||
|
||||
const filtered = $derived(filterFunction(items, search).slice(0, maxResults));
|
||||
|
||||
$effect(() => {
|
||||
if (isOpen && inputRef) {
|
||||
const rect = inputRef.getBoundingClientRect();
|
||||
dropdownPosition = {
|
||||
top: rect.bottom + window.scrollY + 4,
|
||||
left: rect.left + window.scrollX,
|
||||
width: rect.width
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
function selectItem(item: string) {
|
||||
value = item;
|
||||
search = displayValue;
|
||||
isOpen = false;
|
||||
inputRef?.blur();
|
||||
$host()?.dispatchEvent(new CustomEvent('select', { detail: item }));
|
||||
}
|
||||
|
||||
function handleInputFocus() {
|
||||
isOpen = true;
|
||||
}
|
||||
|
||||
function handleInputChange() {
|
||||
$host()?.dispatchEvent(new CustomEvent('change', { detail: search }));
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape') {
|
||||
isOpen = false;
|
||||
inputRef?.blur();
|
||||
} else if (event.key === 'Enter' && filtered.length > 0) {
|
||||
selectItem(filtered[0]);
|
||||
} else if (event.key === 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
isOpen = true;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="relative" bind:this={comboboxRef}>
|
||||
<div class="relative">
|
||||
<input
|
||||
bind:this={inputRef}
|
||||
type="text"
|
||||
{placeholder}
|
||||
bind:value={search}
|
||||
onfocus={handleInputFocus}
|
||||
oninput={handleInputChange}
|
||||
onkeydown={handleKeydown}
|
||||
class="input input-bordered w-full pr-10 text-base-content"
|
||||
autocomplete="off"
|
||||
role="combobox"
|
||||
aria-expanded={isOpen}
|
||||
aria-haspopup="listbox"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (isOpen = !isOpen)}
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 p-1 hover:bg-base-200 rounded"
|
||||
aria-label="Toggle dropdown"
|
||||
>
|
||||
<Icon
|
||||
icon={isOpen ? 'mdi:chevron-up' : 'mdi:chevron-down'}
|
||||
class="w-5 h-5 text-base-content/70"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if isOpen && portalTarget}
|
||||
<div
|
||||
bind:this={dropdownElement}
|
||||
class="fixed z-50 rounded-lg shadow-lg max-h-60 overflow-y-auto"
|
||||
style="top: {dropdownPosition.top}px; left: {dropdownPosition.left}px; width: {dropdownPosition.width}px;"
|
||||
role="listbox"
|
||||
>
|
||||
<LiquidGlass class="border border-base-300">
|
||||
{#if filtered.length > 0}
|
||||
{#each filtered as item}
|
||||
<button
|
||||
type="button"
|
||||
class="w-full px-4 py-2 text-left hover:bg-base-200 focus:bg-base-200 focus:outline-none text-base-content border-b border-base-200 last:border-b-0"
|
||||
onclick={() => selectItem(item)}
|
||||
role="option"
|
||||
aria-selected={value === item}
|
||||
>
|
||||
<slot name="item" {item}>
|
||||
{item}
|
||||
</slot>
|
||||
</button>
|
||||
{/each}
|
||||
{:else}
|
||||
<div class="p-4 text-center text-base-content/70">
|
||||
<slot name="empty">No results found</slot>
|
||||
</div>
|
||||
{/if}
|
||||
</LiquidGlass>
|
||||
</div>
|
||||
{/if}
|
|
@ -0,0 +1,14 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'iconify-icon',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
|
||||
const props = $props();
|
||||
</script>
|
||||
|
||||
<Icon {...props} />
|
|
@ -0,0 +1,24 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-input',
|
||||
shadow: 'open'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
let {
|
||||
label,
|
||||
value = $bindable(),
|
||||
...others
|
||||
}: {
|
||||
label: string;
|
||||
value?: string;
|
||||
[key: string]: any;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<fieldset class="fieldset form-control rounded-box w-full border p-4">
|
||||
<legend class="fieldset-legend font-medium badge">{label}</legend>
|
||||
<input class="input input-bordered w-full" bind:value {...others} />
|
||||
<slot />
|
||||
</fieldset>
|
|
@ -0,0 +1,27 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-loading',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const {
|
||||
size = 'sm'
|
||||
}: {
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl';
|
||||
} = $props();
|
||||
|
||||
const actualSize =
|
||||
size === 'sm'
|
||||
? 'calc(var(--size-selector, .25rem) * 2)'
|
||||
: size === 'md'
|
||||
? 'calc(var(--size-selector, .25rem) * 4)'
|
||||
: size === 'lg'
|
||||
? 'calc(var(--size-selector, .25rem) * 8)'
|
||||
: 'calc(var(--size-selector, .25rem) * 16)';
|
||||
</script>
|
||||
|
||||
<span class="loading loading-spinner" style:width={actualSize} style:height={actualSize}></span>
|
|
@ -0,0 +1,14 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-logged-in-user-avatar',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import Avatar from '../User/Avatar.svelte';
|
||||
</script>
|
||||
|
||||
{#await window.eve.getPublicKey() then pubkey}
|
||||
<Avatar {pubkey} />
|
||||
{/await}
|
|
@ -0,0 +1,65 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-markdown',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import { Carta, Markdown } from 'carta-md';
|
||||
import DOMPurify from 'isomorphic-dompurify';
|
||||
import { math } from '@cartamd/plugin-math';
|
||||
import { tikz } from '@cartamd/plugin-tikz';
|
||||
import 'katex/dist/katex.min.css';
|
||||
import '@cartamd/plugin-code/default.css';
|
||||
import './markdown.css';
|
||||
|
||||
const carta = new Carta({
|
||||
sanitizer: DOMPurify.sanitize,
|
||||
extensions: [
|
||||
math(),
|
||||
tikz({
|
||||
class: 'tikz',
|
||||
postProcessing(html) {
|
||||
return html
|
||||
.replaceAll('#000000', 'var(--color-base-content)')
|
||||
.replaceAll('#000', 'var(--color-base-content)')
|
||||
.replaceAll('black', 'var(--color-base-content)')
|
||||
.replaceAll('#ffffff', 'var(--color-base-300)')
|
||||
.replaceAll('#fff', 'var(--color-base-300)')
|
||||
.replaceAll('white', 'var(--color-base-300)')
|
||||
.replaceAll('#ff0000', 'var(--color-error)')
|
||||
.replaceAll('#f00', 'var(--color-error)')
|
||||
.replaceAll('red', 'var(--color-error)')
|
||||
.replaceAll('#00ff00', 'var(--color-success)')
|
||||
.replaceAll('#0f0', 'var(--color-success)')
|
||||
.replaceAll('green', 'var(--color-success)')
|
||||
.replaceAll('#0000ff', 'var(--color-info)')
|
||||
.replaceAll('#00f', 'var(--color-info)')
|
||||
.replaceAll('blue', 'var(--color-info)')
|
||||
.replaceAll('#ffff00', 'var(--color-warning)')
|
||||
.replaceAll('#ff0', 'var(--color-warning)')
|
||||
.replaceAll('yellow', 'var(--color-warning)')
|
||||
.replaceAll('#808080', 'var(--color-neutral)')
|
||||
.replaceAll('#888888', 'var(--color-neutral)')
|
||||
.replaceAll('#999999', 'var(--color-neutral)')
|
||||
.replaceAll('gray', 'var(--color-neutral)')
|
||||
.replaceAll('grey', 'var(--color-neutral)')
|
||||
.replaceAll('#cccccc', 'var(--color-base-300)')
|
||||
.replaceAll('#f5f5f5', 'var(--color-base-200)')
|
||||
.replaceAll('#eeeeee', 'var(--color-base-100)');
|
||||
}
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
let value = '...';
|
||||
|
||||
let { content } = $props();
|
||||
</script>
|
||||
|
||||
<div class="prose prose-sm max-w-none">
|
||||
<p class="whitespace-pre-wrap break-words text-base-content leading-relaxed">
|
||||
<Markdown theme="eve" {carta} value={content} />
|
||||
</p>
|
||||
</div>
|
|
@ -0,0 +1,29 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-markdown-editor',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import { Carta, MarkdownEditor } from 'carta-md';
|
||||
import DOMPurify from 'isomorphic-dompurify';
|
||||
import { math } from '@cartamd/plugin-math';
|
||||
import { tikz } from '@cartamd/plugin-tikz';
|
||||
import { code } from '@cartamd/plugin-code';
|
||||
|
||||
import 'katex/dist/katex.min.css';
|
||||
import '@cartamd/plugin-code/default.css';
|
||||
import './markdown.css';
|
||||
|
||||
let { value = $bindable(), placeholder } = $props();
|
||||
|
||||
const carta = new Carta({
|
||||
sanitizer: DOMPurify.sanitize,
|
||||
extensions: [code(), math(), tikz()]
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="bg-base-300 text-base-content card p-4">
|
||||
<MarkdownEditor mode="tabs" theme="eve" {carta} bind:value />
|
||||
</div>
|
|
@ -0,0 +1,67 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-relative-time',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import type { NostrEvent } from '$lib/eve';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let props: { time?: Date | number | string; event?: NostrEvent } = $props();
|
||||
|
||||
let time = $derived(
|
||||
props.time
|
||||
? typeof props.time === 'number' || typeof props.time === 'string'
|
||||
? new Date(Number(props.time) * 1000)
|
||||
: props.time
|
||||
: props.event
|
||||
? new Date(props.event.created_at * 1000)
|
||||
: new Date()
|
||||
);
|
||||
|
||||
const relativeTime = $derived.by(() => {
|
||||
const sec = Math.floor(Date.now() / 1000) - time.getTime() / 1000;
|
||||
const past = sec >= 0;
|
||||
const n = Math.abs(sec);
|
||||
|
||||
const fmt = (value: number, text: string) => {
|
||||
const label = text + (value === 1 ? '' : 's');
|
||||
return past ? `${value.toFixed(0)} ${label} ago` : `in ${value.toFixed(0)} ${label}`;
|
||||
};
|
||||
|
||||
if (n < 5) return past ? 'just now' : 'soon';
|
||||
|
||||
if (n < 90) return fmt(n, 'second');
|
||||
if (n < 3600) return fmt(Math.round(n / 60), 'minute');
|
||||
|
||||
if (n < 86400) {
|
||||
const h = Math.round(n / 1800) / 2;
|
||||
return fmt(h, 'hour');
|
||||
}
|
||||
|
||||
if (n < 604800) {
|
||||
const d = Math.round(n / 21600) / 4;
|
||||
return fmt(d, 'day');
|
||||
}
|
||||
|
||||
return time.toLocaleDateString(undefined, { dateStyle: 'medium' });
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
const interval = setInterval(() => {
|
||||
time = new Date(time);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
});
|
||||
</script>
|
||||
|
||||
<time
|
||||
class="tooltip text-xs text-base-content/50"
|
||||
datetime={time.toISOString()}
|
||||
data-tip={time.toISOString()}
|
||||
>
|
||||
{relativeTime}
|
||||
</time>
|
|
@ -0,0 +1,23 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-user-reputation',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import { getReputationStore } from '$lib/stores/reputation';
|
||||
|
||||
const { pubkey } = $props();
|
||||
const repStore = getReputationStore(pubkey);
|
||||
</script>
|
||||
|
||||
<span class="inline-block">
|
||||
Reputation:
|
||||
{#if $repStore.loading}
|
||||
<span class="skeleton w-12 h-[1em] inline-block rounded-full" style="transform: translateY(10%)"
|
||||
></span>
|
||||
{:else}
|
||||
<b>{$repStore.reputation.toFixed(2)}</b>
|
||||
{/if}
|
||||
</span>
|
|
@ -0,0 +1,71 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-reputation-button',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import { getEventStore } from '$lib/stores/reputationEvent';
|
||||
|
||||
let {
|
||||
direction,
|
||||
event: eventId,
|
||||
reason
|
||||
}: {
|
||||
direction: '+' | '-';
|
||||
event: string;
|
||||
reason?: string;
|
||||
} = $props();
|
||||
|
||||
let publishing = $state(false);
|
||||
const eventStore = getEventStore(eventId);
|
||||
|
||||
async function click() {
|
||||
const { event, loading, reputationGiven, isOwnEvent } = $eventStore;
|
||||
if (publishing || loading || reputationGiven || isOwnEvent) return;
|
||||
|
||||
publishing = true;
|
||||
if (!event) {
|
||||
console.error('Event not found');
|
||||
publishing = false;
|
||||
return;
|
||||
}
|
||||
const tags = [
|
||||
['p', event.pubkey],
|
||||
['e', event.id!]
|
||||
];
|
||||
if (reason) tags.push(['reason', reason]);
|
||||
try {
|
||||
await window.eve.publish({
|
||||
pubkey: await window.eve.getPublicKey(),
|
||||
kind: 7,
|
||||
content: direction,
|
||||
tags,
|
||||
created_at: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Failed to publish reputation event', e);
|
||||
} finally {
|
||||
publishing = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="btn btn-primary btn-circle"
|
||||
onclick={click}
|
||||
disabled={publishing ||
|
||||
$eventStore.loading ||
|
||||
$eventStore.reputationGiven ||
|
||||
$eventStore.isOwnEvent}
|
||||
>
|
||||
{#if publishing || $eventStore.loading}
|
||||
<Icon icon="mdi:loading" />
|
||||
{:else if direction === '+'}
|
||||
<Icon icon="mdi:plus" />
|
||||
{:else if direction === '-'}
|
||||
<Icon icon="mdi:minus" />
|
||||
{/if}
|
||||
</button>
|
|
@ -0,0 +1,24 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-textarea',
|
||||
shadow: 'open'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
let {
|
||||
label,
|
||||
value = $bindable(),
|
||||
...others
|
||||
}: {
|
||||
label: string;
|
||||
value?: string;
|
||||
[key: string]: any;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<fieldset class="fieldset form-control rounded-box w-full border p-4">
|
||||
<legend class="fieldset-legend font-medium badge">{label}</legend>
|
||||
<textarea class="textarea textarea-bordered w-full" bind:value {...others}></textarea>
|
||||
<slot />
|
||||
</fieldset>
|
|
@ -0,0 +1,16 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-title',
|
||||
shadow: 'open'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
import { currentArxletTitle } from '$lib/stores/settings';
|
||||
|
||||
let { title } = $props();
|
||||
|
||||
$effect(() => {
|
||||
$currentArxletTitle = title;
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,75 @@
|
|||
@plugin 'daisyui';
|
||||
|
||||
.carta-theme__eve {
|
||||
background-color: transparent;
|
||||
color: var(--color-base-content);
|
||||
|
||||
table {
|
||||
@apply table rounded-box bg-neutral text-neutral-content;
|
||||
border: 2px solid var(--color-neutral);
|
||||
border-radius: var(--radius-box);
|
||||
th {
|
||||
@apply bg-base-100 text-base-content;
|
||||
&:hover {
|
||||
background: var(--color-base-200);
|
||||
}
|
||||
}
|
||||
tr:hover {
|
||||
background: var(--color-base-200);
|
||||
}
|
||||
td:hover {
|
||||
background: var(--color-base-300);
|
||||
}
|
||||
}
|
||||
|
||||
code:not(.carta-highlight code) {
|
||||
background: var(--color-neutral);
|
||||
color: var(--color-neutral-content);
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.tikz {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
* {
|
||||
font-size: var(--typography-base-css-0-font-size);
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.carta-font-code {
|
||||
color: var(--color-base-content);
|
||||
caret-color: var(--color-base-content) !important;
|
||||
line-height: 2 !important;
|
||||
min-height: 150px !important;
|
||||
}
|
||||
|
||||
.carta-icon {
|
||||
border-radius: 100%;
|
||||
background: rgba(from var(--color-primary) r g b / 0.8) !important;
|
||||
color: var(--color-primary-content);
|
||||
&:hover {
|
||||
background: var(--color-primary) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.carta-toolbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
button {
|
||||
padding: 0.5em;
|
||||
background: rgba(from var(--color-accent) r g b / 0.5);
|
||||
&.carta-active {
|
||||
background: rgba(from var(--color-accent) r g b / 0.8);
|
||||
}
|
||||
color: var(--color-accent-content);
|
||||
border-radius: 1em;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
&:hover {
|
||||
background: var(--color-accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
119
src/renderer/src/lib/components/RecentActivityItem.svelte
Normal file
|
@ -0,0 +1,119 @@
|
|||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import type { NostrEvent } from '../eve';
|
||||
import Avatar from '$lib/components/User/Avatar.svelte';
|
||||
import RelativeTime from './PublicComponents/RelativeTime.svelte';
|
||||
|
||||
let { activity }: { activity: NostrEvent } = $props();
|
||||
|
||||
let authorProfile = $state({
|
||||
name: 'Anonymous',
|
||||
avatar: null as string | null
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const profile = await window.eve.getProfile(activity.pubkey);
|
||||
if (profile) {
|
||||
authorProfile = {
|
||||
name: profile.name || profile.display_name || 'Anonymous',
|
||||
avatar: profile.picture || null
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load author profile:', error);
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
function getDescription() {
|
||||
if (activity.kind === 0) return 'updated their profile';
|
||||
if (activity.kind === 1) return 'wrote a note';
|
||||
if (activity.kind === 5) return 'deleted a note';
|
||||
if (activity.kind === 6) return 'reposted a note';
|
||||
if (activity.kind === 7) return 'reacted to a post';
|
||||
if (activity.kind === 892) return 'created a forum topic';
|
||||
if (activity.kind === 1111) return 'commented on something';
|
||||
if (activity.kind === 30420) return 'installed an arxlet';
|
||||
if (activity.kind === 30891) return 'created a forum category';
|
||||
return 'performed an action ' + activity.kind;
|
||||
}
|
||||
|
||||
function getIcon() {
|
||||
if (activity.kind === 0) return 'mdi:account-edit';
|
||||
if (activity.kind === 1) return 'mdi:note-text';
|
||||
if (activity.kind === 5) return 'mdi:delete';
|
||||
if (activity.kind === 6) return 'mdi:repeat';
|
||||
if (activity.kind === 7) return 'mdi:heart';
|
||||
if (activity.kind === 892) return 'mdi:forum';
|
||||
if (activity.kind === 1111) return 'mdi:comment-text';
|
||||
if (activity.kind === 30420) return 'mdi:package-variant';
|
||||
if (activity.kind === 30891) return 'mdi:forum';
|
||||
|
||||
return 'mdi:lightning-bolt';
|
||||
}
|
||||
|
||||
function getIconColor() {
|
||||
if (activity.kind === 0) return 'text-blue-500';
|
||||
if (activity.kind === 1 || activity.kind === 1111) return 'text-green-500';
|
||||
if (activity.kind === 5) return 'text-red-500';
|
||||
if (activity.kind === 6) return 'text-orange-500';
|
||||
if (activity.kind === 7) return 'text-red-500';
|
||||
if (activity.kind === 892) return 'text-pink-500';
|
||||
return 'text-secondary';
|
||||
}
|
||||
|
||||
let icon = getIcon();
|
||||
let iconColor = getIconColor();
|
||||
let description = getDescription();
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="group flex items-start gap-3 p-4 rounded-xl bg-gradient-to-r from-base-100/80 to-base-200/50 hover:from-base-100 hover:to-base-200/80 transition-all duration-300 hover:shadow-lg hover:-translate-y-0.5 border border-base-300/30 hover:border-base-300/50"
|
||||
>
|
||||
<div class="relative flex-shrink-0">
|
||||
<Avatar pubkey={activity.pubkey} />
|
||||
|
||||
<div
|
||||
class="absolute -bottom-1 -right-1 w-5 h-5 rounded-full bg-base-100 flex items-center justify-center ring-2 ring-base-100 group-hover:scale-110 transition-transform duration-300"
|
||||
>
|
||||
<Icon {icon} class="w-3 h-3 {iconColor}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<p
|
||||
class="text-sm font-semibold text-base-content group-hover:text-primary transition-colors duration-300 truncate"
|
||||
>
|
||||
{authorProfile.name}
|
||||
</p>
|
||||
<span class="text-xs text-base-content/50 font-medium">
|
||||
<RelativeTime time={activity.created_at} />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p
|
||||
class="text-sm text-base-content/70 group-hover:text-base-content/90 transition-colors duration-300"
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
|
||||
{#if activity.content && (activity.kind === 1 || activity.kind === 892 || activity.kind === 1111)}
|
||||
<p class="text-xs text-base-content/60 mt-2 line-clamp-2 italic">
|
||||
"{activity.content.substring(0, 80)}{activity.content.length > 80 ? '...' : ''}"
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.line-clamp-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
line-clamp: 2;
|
||||
}
|
||||
</style>
|
13
src/renderer/src/lib/components/SearchResult.svelte
Normal file
|
@ -0,0 +1,13 @@
|
|||
<script lang="ts">
|
||||
import type { NostrEvent } from 'nostr-tools';
|
||||
import Avatar from '$lib/components/User/Avatar.svelte';
|
||||
import Icon from '@iconify/svelte';
|
||||
import NotePrinter from './NotePrinter.svelte';
|
||||
import { formatDate } from '../utils.svelte';
|
||||
|
||||
let { result }: { result: NostrEvent } = $props();
|
||||
|
||||
let date = formatDate(result.created_at);
|
||||
</script>
|
||||
|
||||
<NotePrinter note={result} />
|
114
src/renderer/src/lib/components/Sidebar.svelte
Normal file
|
@ -0,0 +1,114 @@
|
|||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import RecentActivityItem from './RecentActivityItem.svelte';
|
||||
import type { NostrEvent } from '../eve';
|
||||
import Avatar from '$lib/components/User/Avatar.svelte';
|
||||
import LiquidGlass from './LiquidGlass.svelte';
|
||||
import UserName from './User/UserName.svelte';
|
||||
|
||||
let currentTime = $state(new Date());
|
||||
let recentActivity: NostrEvent[] = $state([]);
|
||||
|
||||
let currentPubkey = $state('');
|
||||
|
||||
onMount(() => {
|
||||
const interval = setInterval(() => {
|
||||
currentTime = new Date();
|
||||
}, 1000);
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
currentPubkey = await window.eve.getPublicKey();
|
||||
} catch (error) {
|
||||
console.error('Failed to load user profile:', error);
|
||||
}
|
||||
})();
|
||||
|
||||
window.eve
|
||||
.getAllEventsWithFilter({
|
||||
limit: 30
|
||||
})
|
||||
.then((events) => {
|
||||
recentActivity = events;
|
||||
});
|
||||
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
});
|
||||
|
||||
const formatTime = (date: Date) => {
|
||||
return date.toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
const formatDate = (date: Date) => {
|
||||
return date.toLocaleDateString([], {
|
||||
weekday: 'short',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="overflow-hidden h-[calc(100vh-4em)]">
|
||||
<LiquidGlass
|
||||
class="w-80 h-full shadow-2xl border-l-4 border-primary/50 flex flex-col overflow-scroll"
|
||||
>
|
||||
<div
|
||||
class="p-6 border-b border-base-300 bg-gradient-to-br from-primary/5 via-secondary/5 to-accent/5 flex-shrink-0"
|
||||
>
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<Avatar pubkey={currentPubkey} />
|
||||
<div class="flex-1 min-w-0">
|
||||
<h4 class="font-semibold text-base-content truncate">
|
||||
<UserName pubkey={currentPubkey} />
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<LiquidGlass class="text-center rounded-lg p-3">
|
||||
<div class="text-2xl font-bold text-base-content mb-1 font-mono tracking-wide">
|
||||
{formatTime(currentTime)}
|
||||
</div>
|
||||
<div class="text-sm text-base-content/70 font-medium">
|
||||
{formatDate(currentTime)}
|
||||
</div>
|
||||
</LiquidGlass>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 flex flex-col min-h-0 h-[calc(100vh-16em)] overflow-hidden">
|
||||
<div class="p-6 pb-4 flex-shrink-0">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-lg font-semibold text-base-content flex items-center gap-2">
|
||||
<Icon icon="mdi:pulse" class="w-5 h-5 text-secondary" />
|
||||
Activity Feed
|
||||
</h3>
|
||||
<button class="btn btn-ghost btn-xs gap-1">
|
||||
<Icon icon="mdi:refresh" class="w-3 h-3" />
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 px-6 pb-6 overflow-y-scroll">
|
||||
{#if recentActivity.length > 0}
|
||||
<div class="space-y-3">
|
||||
{#each recentActivity as activity}
|
||||
<RecentActivityItem {activity} />
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-center py-8">
|
||||
<Icon icon="mdi:inbox-outline" class="w-12 h-12 text-base-content/30 mx-auto mb-3" />
|
||||
<p class="text-sm text-base-content/60">No recent activity</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</LiquidGlass>
|
||||
</div>
|
32
src/renderer/src/lib/components/User/Avatar.svelte
Normal file
|
@ -0,0 +1,32 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-avatar',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
let {
|
||||
pubkey,
|
||||
refreshIndex = 0,
|
||||
size = 'small'
|
||||
}: {
|
||||
pubkey: string;
|
||||
refreshIndex?: number;
|
||||
size?: 'small' | 'medium' | 'large';
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<div class="avatar">
|
||||
<div
|
||||
class:w-10={size === 'small'}
|
||||
class:h-10={size === 'small'}
|
||||
class:w-16={size === 'medium'}
|
||||
class:h-16={size === 'medium'}
|
||||
class:w-20={size === 'large'}
|
||||
class:h-20={size === 'large'}
|
||||
class="mask mask-squircle"
|
||||
>
|
||||
<img src={window.eve.getAvatar(pubkey) + '#' + refreshIndex} />
|
||||
</div>
|
||||
</div>
|
33
src/renderer/src/lib/components/User/UserName.svelte
Normal file
|
@ -0,0 +1,33 @@
|
|||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'eve-username',
|
||||
shadow: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<script lang="ts">
|
||||
let { pubkey }: { pubkey: string } = $props();
|
||||
|
||||
let userProfile = $derived(window.eve.getProfile(pubkey));
|
||||
let anonName = $derived('anon' + pubkey.substr(0, 8) + ':' + pubkey.substr(-8));
|
||||
</script>
|
||||
|
||||
{#snippet skeleton()}
|
||||
<span class="inline-block skeleton h-[1em] w-32" style="transform: translateY(10%)"></span>
|
||||
{/snippet}
|
||||
|
||||
{#if !pubkey}
|
||||
{@render skeleton()}
|
||||
{:else}
|
||||
{#await userProfile}
|
||||
{@render skeleton()}
|
||||
{:then userProfile}
|
||||
{#if userProfile?.name}
|
||||
{userProfile.name}
|
||||
{:else}
|
||||
{anonName}
|
||||
{/if}
|
||||
{:catch}
|
||||
{anonName}
|
||||
{/await}
|
||||
{/if}
|
282
src/renderer/src/lib/eve.ts
Normal file
|
@ -0,0 +1,282 @@
|
|||
import { map, Observable } from 'rxjs';
|
||||
import { navigationStore } from './navigation';
|
||||
import { get } from 'svelte/store';
|
||||
|
||||
export interface NostrEvent {
|
||||
id?: string;
|
||||
pubkey: string;
|
||||
created_at: number;
|
||||
kind: number;
|
||||
tags: string[][];
|
||||
content: string;
|
||||
sig?: string;
|
||||
}
|
||||
|
||||
export interface Filter {
|
||||
ids?: string[];
|
||||
authors?: string[];
|
||||
kinds?: number[];
|
||||
since?: number;
|
||||
until?: number;
|
||||
limit?: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface Profile {
|
||||
name?: string;
|
||||
about?: string;
|
||||
picture?: string;
|
||||
nip05?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface Arxlet {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
icon?: string;
|
||||
iconColor?: string;
|
||||
iconForegroundColor?: string;
|
||||
iconStrokeColor?: string;
|
||||
script: string;
|
||||
version?: string;
|
||||
versionDate: number;
|
||||
eventId: string;
|
||||
}
|
||||
|
||||
export interface CCN {
|
||||
name: string;
|
||||
description: string;
|
||||
publicKey: string;
|
||||
}
|
||||
|
||||
export const ws = new WebSocket('ws://localhost:6942');
|
||||
|
||||
export class WindowEve {
|
||||
#_pubkey: string;
|
||||
|
||||
async publish(event: NostrEvent) {
|
||||
let realEvent = event;
|
||||
if (!event.sig) realEvent = await this.signEvent(event);
|
||||
const response = await fetch('http://localhost:4269/api/events', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(realEvent)
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to publish event');
|
||||
const data = await response.json();
|
||||
if (data.success) return true;
|
||||
throw new Error(data.message);
|
||||
}
|
||||
|
||||
async getSingleEventById(id: string) {
|
||||
const event = await fetch('http://localhost:4269/api/events/' + id);
|
||||
if (!event.ok) return null;
|
||||
const data = await event.json();
|
||||
return data as NostrEvent;
|
||||
}
|
||||
|
||||
async getSingleEventWithFilter(filter: Filter): Promise<NostrEvent | null> {
|
||||
const events = await this.getAllEventsWithFilter({ ...filter, limit: 1 });
|
||||
return events.length > 0 ? events[0] : null;
|
||||
}
|
||||
|
||||
async getAllEventsWithFilter(filter: Filter): Promise<NostrEvent[]> {
|
||||
const response = await fetch('http://localhost:4269/api/events', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(filter)
|
||||
});
|
||||
if (!response.ok) return [];
|
||||
const data = await response.json();
|
||||
return data as NostrEvent[];
|
||||
}
|
||||
|
||||
subscribeToEvents(filter: Filter) {
|
||||
return new Observable<NostrEvent>((subscriber) => {
|
||||
const subname = crypto.randomUUID();
|
||||
ws.send(JSON.stringify(['REQ', subname, filter]));
|
||||
ws.addEventListener('message', (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
if (!Array.isArray(data)) return;
|
||||
if (data[0] === 'EVENT' && data[1] === subname) subscriber.next(data[2]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
subscribeToProfile(pubkey: string) {
|
||||
return this.subscribeToEvents({
|
||||
kinds: [0],
|
||||
authors: [pubkey]
|
||||
}).pipe(
|
||||
map((event) => event.content),
|
||||
map((content) => JSON.parse(content)),
|
||||
map((profile) => profile as Profile)
|
||||
);
|
||||
}
|
||||
|
||||
async getProfile(pubkey: string): Promise<Profile | null> {
|
||||
try {
|
||||
const profile = await fetch(`http://localhost:4269/api/profile/${pubkey}`);
|
||||
if (!profile) return null;
|
||||
const data = await profile.json();
|
||||
return data as Profile;
|
||||
} catch (error) {
|
||||
console.error(`Failed to parse profile JSON for ${pubkey}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
getAvatar(pubkey: string): string {
|
||||
return `http://localhost:4269/api/avatars/${pubkey}`;
|
||||
}
|
||||
|
||||
async signEvent(
|
||||
event: Omit<NostrEvent, 'id' | 'sig' | 'pubkey' | 'created_at' | 'tags' | 'content'>
|
||||
): Promise<NostrEvent> {
|
||||
const realEvent = event as NostrEvent;
|
||||
if (!realEvent.created_at) realEvent.created_at = Math.floor(Date.now() / 1000);
|
||||
if (!realEvent.tags) realEvent.tags = [];
|
||||
if (!realEvent.content) realEvent.content = '';
|
||||
const signedEvent = await fetch('http://localhost:4269/api/sign', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(realEvent)
|
||||
});
|
||||
if (!signedEvent.ok) throw new Error('Failed to sign event');
|
||||
const data = await signedEvent.json();
|
||||
return data as NostrEvent;
|
||||
}
|
||||
|
||||
async getPublicKey(): Promise<string> {
|
||||
if (this.#_pubkey) return this.#_pubkey;
|
||||
const pubkey = await fetch('http://localhost:4269/api/pubkey');
|
||||
if (!pubkey.ok) throw new Error('Failed to fetch public key');
|
||||
const data = await pubkey.json();
|
||||
this.#_pubkey = data.pubkey as string;
|
||||
return this.#_pubkey;
|
||||
}
|
||||
|
||||
async getAllArxlets(): Promise<Arxlet[]> {
|
||||
const response = await fetch('http://localhost:4269/api/arxlets');
|
||||
if (!response.ok) return [];
|
||||
const data = await response.json();
|
||||
return data as Arxlet[];
|
||||
}
|
||||
|
||||
async getArxlet(id: string): Promise<Arxlet | null> {
|
||||
const arxlet = await fetch(`http://localhost:4269/api/arxlets/${id}`);
|
||||
if (!arxlet) return null;
|
||||
const data = await arxlet.json();
|
||||
if (data.error) return null;
|
||||
return data as Arxlet;
|
||||
}
|
||||
|
||||
async getRemoteArxlets(): Promise<Arxlet[]> {
|
||||
const response = await fetch('http://localhost:4269/api/arxlets-available');
|
||||
if (!response.ok) return [];
|
||||
const data = await response.json();
|
||||
return data as Arxlet[];
|
||||
}
|
||||
|
||||
async cloneRemoteEvent(eventId: string): Promise<NostrEvent> {
|
||||
const response = await fetch(`http://localhost:4269/api/clone-remote-event/${eventId}`);
|
||||
if (!response.ok) throw new Error('Failed to fetch event');
|
||||
const data = await response.json();
|
||||
if (data.error) throw new Error(data.error);
|
||||
const event = data as NostrEvent;
|
||||
return await this.signEvent(event);
|
||||
}
|
||||
|
||||
async listCCNs(): Promise<CCN[]> {
|
||||
const response = await fetch('http://localhost:4269/api/ccns');
|
||||
if (!response.ok) return [];
|
||||
const data = await response.json();
|
||||
return data as CCN[];
|
||||
}
|
||||
|
||||
getCCNIcon(pubkey: string): string {
|
||||
return `http://localhost:4269/api/ccns/icon/${pubkey}`;
|
||||
}
|
||||
|
||||
getCCNAvatar(pubkey: string): string {
|
||||
return `http://localhost:4269/api/ccns/avatar/${pubkey}`;
|
||||
}
|
||||
|
||||
async getActiveCCN(): Promise<CCN | null> {
|
||||
const response = await fetch('http://localhost:4269/api/ccns/active');
|
||||
if (!response.ok) return null;
|
||||
const data = await response.json();
|
||||
return data as CCN;
|
||||
}
|
||||
|
||||
async activateCCN(pubkey: string): Promise<void> {
|
||||
const response = await fetch(`http://localhost:4269/api/ccns/active`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ pubkey })
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to activate CCN');
|
||||
const data = await response.json();
|
||||
if (data.error) throw new Error(data.error);
|
||||
}
|
||||
|
||||
async createCCN(name: string, description: string): Promise<CCN> {
|
||||
const response = await fetch('http://localhost:4269/api/ccns/new', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ name, description })
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to create CCN');
|
||||
const data = await response.json();
|
||||
if (data.error) throw new Error(data.error);
|
||||
return data as CCN;
|
||||
}
|
||||
|
||||
async joinCCN(
|
||||
version: number,
|
||||
startIndex: string,
|
||||
name: string,
|
||||
description: string,
|
||||
key: Uint8Array
|
||||
): Promise<CCN> {
|
||||
console.log(key);
|
||||
const response = await fetch('http://localhost:4269/api/ccns/join', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ version, startIndex, name, description, key: [...key] })
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to join CCN');
|
||||
const data = await response.json();
|
||||
if (data.error) throw new Error(data.error);
|
||||
return data as CCN;
|
||||
}
|
||||
|
||||
get currentUrl() {
|
||||
const c = get(navigationStore);
|
||||
const url = new URL('eve://' + c.history[c.currentIndex].slice(1));
|
||||
if (url.hostname === '') url.hostname = 'home';
|
||||
return url;
|
||||
}
|
||||
|
||||
async generateInviteCode(): Promise<string> {
|
||||
const response = await fetch('http://localhost:4269/api/ccns/active/invite');
|
||||
if (!response.ok) throw new Error('Failed to generate invite code');
|
||||
const data = await response.json();
|
||||
if (data.error) throw new Error(data.error);
|
||||
return data.invite as string;
|
||||
}
|
||||
|
||||
async getReputation(user: string): Promise<number> {
|
||||
const response = await fetch(`http://localhost:4269/api/reputation/${user}`);
|
||||
if (!response.ok) throw new Error('Failed to get reputation');
|
||||
const data = await response.json();
|
||||
if (data.error) throw new Error(data.error);
|
||||
return data.reputation as number;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
eve: WindowEve;
|
||||
}
|
||||
}
|
||||
|
||||
window.eve = new WindowEve();
|
35
src/renderer/src/lib/invites.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { bech32m } from '@scure/base';
|
||||
import { read_string, read_varint } from './Uint8Array';
|
||||
import { hexToBytes } from 'nostr-tools/utils';
|
||||
|
||||
const INVITE_VERSION = 2;
|
||||
|
||||
export function parseInviteCode(inviteCode: `${string}1${string}`): {
|
||||
version: number;
|
||||
startIndex: string;
|
||||
name: string;
|
||||
description: string;
|
||||
inviter: string;
|
||||
key: Uint8Array;
|
||||
} {
|
||||
const decoded = bech32m.decode(inviteCode, false);
|
||||
if (decoded.prefix !== 'evelite') throw new Error('Invalid invite code');
|
||||
const inviteData = bech32m.fromWords(decoded.words);
|
||||
let offset = 0;
|
||||
const [version, bytesRead] = read_varint(inviteData, offset);
|
||||
offset += bytesRead;
|
||||
if (version !== INVITE_VERSION) throw new Error('Invalid invite version');
|
||||
const [name, nameLength] = read_string(inviteData, offset);
|
||||
offset += nameLength;
|
||||
const [description, descriptionLength] = read_string(inviteData, offset);
|
||||
offset += descriptionLength;
|
||||
const [inviter, inviterLength] = read_string(inviteData, offset);
|
||||
offset += inviterLength;
|
||||
if (inviterLength != 33) throw new Error('Invalid inviter length'); // 32 + 1
|
||||
const [key, keyLength] = read_string(inviteData, offset);
|
||||
offset += keyLength;
|
||||
if (keyLength != 33) throw new Error('Invalid invite key'); // 32 + 1
|
||||
const [startIndex, startIndexLength] = read_string(inviteData, offset);
|
||||
offset += startIndexLength;
|
||||
return { version, startIndex, name, description, inviter, key: hexToBytes(key) };
|
||||
}
|
156
src/renderer/src/lib/navigation.ts
Normal file
|
@ -0,0 +1,156 @@
|
|||
import { writable } from 'svelte/store';
|
||||
import { browser } from '$app/environment';
|
||||
import { goto } from '$app/navigation';
|
||||
import { currentArxletTitle } from './stores/settings';
|
||||
|
||||
export interface NavigationState {
|
||||
canGoBack: boolean;
|
||||
canGoForward: boolean;
|
||||
currentIndex: number;
|
||||
history: string[];
|
||||
}
|
||||
|
||||
function createNavigationStore() {
|
||||
const initialState: NavigationState = {
|
||||
canGoBack: false,
|
||||
canGoForward: false,
|
||||
currentIndex: 0,
|
||||
history: []
|
||||
};
|
||||
|
||||
const { subscribe, set, update } = writable<NavigationState>(initialState);
|
||||
|
||||
let isNavigating = false;
|
||||
|
||||
function updateNavigationState() {
|
||||
if (!browser) return;
|
||||
|
||||
currentArxletTitle.set('');
|
||||
|
||||
update((state) => {
|
||||
return {
|
||||
...state,
|
||||
canGoBack: window.history.length > 1 && state.currentIndex > 0,
|
||||
canGoForward: state.currentIndex < state.history.length - 1
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function pushState(url: string) {
|
||||
if (!browser || isNavigating) return;
|
||||
|
||||
update((state) => {
|
||||
const newHistory = [...state.history.slice(0, state.currentIndex + 1), url];
|
||||
const newIndex = newHistory.length - 1;
|
||||
|
||||
return {
|
||||
...state,
|
||||
history: newHistory,
|
||||
currentIndex: newIndex,
|
||||
canGoBack: newIndex > 0,
|
||||
canGoForward: false
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
if (!browser) return false;
|
||||
|
||||
let canGo = false;
|
||||
update((state) => {
|
||||
if (state.canGoBack) {
|
||||
canGo = true;
|
||||
const newIndex = state.currentIndex - 1;
|
||||
return {
|
||||
...state,
|
||||
currentIndex: newIndex,
|
||||
canGoBack: newIndex > 0,
|
||||
canGoForward: true
|
||||
};
|
||||
}
|
||||
return state;
|
||||
});
|
||||
|
||||
if (canGo) {
|
||||
isNavigating = true;
|
||||
window.history.go(-1);
|
||||
setTimeout(() => {
|
||||
isNavigating = false;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
return canGo;
|
||||
}
|
||||
|
||||
function goForward() {
|
||||
if (!browser) return false;
|
||||
|
||||
let canGo = false;
|
||||
update((state) => {
|
||||
if (state.canGoForward) {
|
||||
canGo = true;
|
||||
const newIndex = state.currentIndex + 1;
|
||||
return {
|
||||
...state,
|
||||
currentIndex: newIndex,
|
||||
canGoBack: true,
|
||||
canGoForward: newIndex < state.history.length - 1
|
||||
};
|
||||
}
|
||||
return state;
|
||||
});
|
||||
|
||||
if (canGo) {
|
||||
isNavigating = true;
|
||||
window.history.go(1);
|
||||
setTimeout(() => {
|
||||
isNavigating = false;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
return canGo;
|
||||
}
|
||||
|
||||
function navigateTo(url: string) {
|
||||
currentArxletTitle.set('');
|
||||
pushState(url);
|
||||
goto(url);
|
||||
}
|
||||
|
||||
function initialize(currentUrl: string) {
|
||||
if (!browser) return;
|
||||
|
||||
set({
|
||||
canGoBack: window.history.length > 1,
|
||||
canGoForward: false,
|
||||
currentIndex: 0,
|
||||
history: [currentUrl]
|
||||
});
|
||||
|
||||
const handlePopState = () => {
|
||||
currentArxletTitle.set('');
|
||||
if (!isNavigating) updateNavigationState();
|
||||
};
|
||||
|
||||
window.addEventListener('popstate', handlePopState);
|
||||
window.addEventListener('pushstate', () => {
|
||||
currentArxletTitle.set('');
|
||||
});
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('popstate', handlePopState);
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
pushState,
|
||||
goBack,
|
||||
goForward,
|
||||
navigateTo,
|
||||
initialize,
|
||||
updateNavigationState
|
||||
};
|
||||
}
|
||||
|
||||
export const navigationStore = createNavigationStore();
|
50
src/renderer/src/lib/stores/reputation.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { readable, type Readable } from 'svelte/store';
|
||||
|
||||
interface ReputationState {
|
||||
reputation: number;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
const reputationStores = new Map<string, Readable<ReputationState>>();
|
||||
|
||||
export function getReputationStore(pubkey: string): Readable<ReputationState> {
|
||||
if (reputationStores.has(pubkey)) {
|
||||
return reputationStores.get(pubkey)!;
|
||||
}
|
||||
|
||||
const store = readable<ReputationState>({ reputation: 0, loading: true }, (set) => {
|
||||
let isSubscribed = true;
|
||||
|
||||
async function getRep() {
|
||||
try {
|
||||
const reputation = await window.eve.getReputation(pubkey);
|
||||
if (isSubscribed) {
|
||||
set({ reputation, loading: false });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to get reputation for ${pubkey}:`, error);
|
||||
if (isSubscribed) {
|
||||
set({ reputation: 0, loading: false }); // Or handle error state differently
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getRep();
|
||||
|
||||
const subscription = window.eve
|
||||
.subscribeToEvents({
|
||||
kinds: [7],
|
||||
'#p': [pubkey]
|
||||
})
|
||||
.subscribe(() => getRep());
|
||||
|
||||
return () => {
|
||||
isSubscribed = false;
|
||||
subscription.unsubscribe();
|
||||
reputationStores.delete(pubkey);
|
||||
};
|
||||
});
|
||||
|
||||
reputationStores.set(pubkey, store);
|
||||
return store;
|
||||
}
|
96
src/renderer/src/lib/stores/reputationEvent.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
import { readable, type Readable } from 'svelte/store';
|
||||
|
||||
export interface EveEvent {
|
||||
id?: string;
|
||||
pubkey: string;
|
||||
created_at: number;
|
||||
kind: number;
|
||||
tags: string[][];
|
||||
content: string;
|
||||
sig?: string;
|
||||
}
|
||||
|
||||
interface EventStoreState {
|
||||
event: EveEvent | null;
|
||||
reputationGiven: boolean;
|
||||
isOwnEvent: boolean;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
const eventStores = new Map<string, Readable<EventStoreState>>();
|
||||
|
||||
export function getEventStore(eventId: string): Readable<EventStoreState> {
|
||||
if (eventStores.has(eventId)) {
|
||||
return eventStores.get(eventId)!;
|
||||
}
|
||||
|
||||
const store = readable<EventStoreState>(
|
||||
{
|
||||
event: null,
|
||||
reputationGiven: false,
|
||||
isOwnEvent: false,
|
||||
loading: true
|
||||
},
|
||||
(set) => {
|
||||
let pubkey: string;
|
||||
let subscription: { unsubscribe: () => void } | undefined;
|
||||
|
||||
async function load() {
|
||||
try {
|
||||
pubkey = await window.eve.getPublicKey();
|
||||
const event = await window.eve.getSingleEventById(eventId);
|
||||
|
||||
if (!event) {
|
||||
set({ event: null, isOwnEvent: false, reputationGiven: false, loading: false });
|
||||
return;
|
||||
}
|
||||
|
||||
const isOwnEvent = event.pubkey === pubkey;
|
||||
if (isOwnEvent) {
|
||||
set({ event, isOwnEvent: true, reputationGiven: false, loading: false });
|
||||
return;
|
||||
}
|
||||
|
||||
const repEvents = await window.eve.getAllEventsWithFilter({
|
||||
kinds: [7],
|
||||
authors: [pubkey],
|
||||
'#e': [eventId]
|
||||
});
|
||||
|
||||
const reputationGiven = repEvents.some((e) => e.content === '+' || e.content === '-');
|
||||
set({ event, isOwnEvent: false, reputationGiven, loading: false });
|
||||
|
||||
if (!reputationGiven) {
|
||||
subscription = window.eve
|
||||
.subscribeToEvents({
|
||||
kinds: [7],
|
||||
authors: [pubkey],
|
||||
'#e': [eventId]
|
||||
})
|
||||
.subscribe(() => {
|
||||
set({ event, isOwnEvent: false, reputationGiven: true, loading: false });
|
||||
if (subscription) {
|
||||
subscription.unsubscribe();
|
||||
subscription = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Error loading event ${eventId}`, e);
|
||||
set({ event: null, isOwnEvent: false, reputationGiven: false, loading: false });
|
||||
}
|
||||
}
|
||||
load();
|
||||
|
||||
return () => {
|
||||
if (subscription) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
eventStores.delete(eventId);
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
eventStores.set(eventId, store);
|
||||
return store;
|
||||
}
|
8
src/renderer/src/lib/stores/settings.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { localStorageStore } from '$lib/utils.svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const currentTheme = localStorageStore('theme', 'dark');
|
||||
export const currentBackground = localStorageStore('background', 'default');
|
||||
export const currentFontScale = localStorageStore('fontScale', 100);
|
||||
export const currentSeed = writable(Math.floor(Math.random() * 100000));
|
||||
export const currentArxletTitle = writable('');
|
34
src/renderer/src/lib/utils.svelte.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { get, writable, type Writable } from 'svelte/store';
|
||||
|
||||
export function formatDate(timestamp: number): string {
|
||||
const date = new Date(timestamp * 1000);
|
||||
const options: Intl.DateTimeFormatOptions = {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
second: 'numeric'
|
||||
};
|
||||
return date.toLocaleString(undefined, options);
|
||||
}
|
||||
|
||||
export function localStorageStore<T>(key: string, defaultValue: T) {
|
||||
const store = writable(defaultValue) as Writable<T>;
|
||||
const { subscribe, set, update } = store;
|
||||
|
||||
localStorage[key] && set(JSON.parse(localStorage[key]));
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
set: (value: T) => {
|
||||
localStorage[key] = JSON.stringify(value);
|
||||
set(value);
|
||||
},
|
||||
update: (cb: (value: T) => T) => {
|
||||
const updatedStore = cb(get(store));
|
||||
localStorage[key] = JSON.stringify(updatedStore);
|
||||
set(updatedStore);
|
||||
}
|
||||
};
|
||||
}
|
64
src/renderer/src/routes/+layout.svelte
Normal file
|
@ -0,0 +1,64 @@
|
|||
<script lang="ts">
|
||||
import '../app.css';
|
||||
import '$lib/eve';
|
||||
import AddressBar from '$lib/components/AddressBar.svelte';
|
||||
import { currentBackground, currentFontScale, currentTheme } from '$lib/stores/settings';
|
||||
import { backgroundOptions } from '$lib/backgrounds';
|
||||
import CCNSelector from '$lib/components/CCNSelector.svelte';
|
||||
|
||||
import '$lib/components/PublicComponents/Loading.svelte';
|
||||
import '$lib/components/PublicComponents/Markdown.svelte';
|
||||
import '$lib/components/PublicComponents/RelativeTime.svelte';
|
||||
import '$lib/components/PublicComponents/ArxletSublink.svelte';
|
||||
import '$lib/components/PublicComponents/IconifyIcon.svelte';
|
||||
import '$lib/components/PublicComponents/LoggedInUserAvatar.svelte';
|
||||
import '$lib/components/PublicComponents/Title.svelte';
|
||||
import '$lib/components/PublicComponents/Reputation.svelte';
|
||||
import '$lib/components/PublicComponents/MarkdownEditor.svelte';
|
||||
import '$lib/components/PublicComponents/ReputationButton.svelte';
|
||||
|
||||
import '$lib/components/User/Avatar.svelte';
|
||||
import '$lib/components/User/UserName.svelte';
|
||||
import Loading from '$lib/components/PublicComponents/Loading.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
let loading = $state(true);
|
||||
let isInOnboard = $state(false);
|
||||
|
||||
$effect(() => {
|
||||
document.documentElement.setAttribute('data-theme', $currentTheme);
|
||||
document.documentElement.style.fontSize = `${$currentFontScale}%`;
|
||||
});
|
||||
|
||||
const backgroundData = $derived(
|
||||
backgroundOptions.find((option) => option.id === $currentBackground)
|
||||
);
|
||||
|
||||
window.eve.listCCNs().then((ccns) => {
|
||||
loading = false;
|
||||
if (ccns.length === 0) {
|
||||
isInOnboard = true;
|
||||
goto('/onboard');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="absolute w-full">
|
||||
{#if loading}
|
||||
<Loading />
|
||||
{:else if isInOnboard}
|
||||
{@render children()}
|
||||
{:else}
|
||||
<div class="bg-fixed bg-cover" style="background-image: url({backgroundData?.image});">
|
||||
<AddressBar />
|
||||
<div class="flex flex-row h-[calc(100vh-4em)] w-full">
|
||||
<CCNSelector />
|
||||
<main class="overflow-auto bg-transparent w-full">
|
||||
{@render children()}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
1
src/renderer/src/routes/+layout.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export const ssr = false;
|
95
src/renderer/src/routes/+page.svelte
Normal file
|
@ -0,0 +1,95 @@
|
|||
<script lang="ts">
|
||||
import Sidebar from '$lib/components/Sidebar.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import type { Arxlet } from '$lib/eve';
|
||||
import Avatar from '$lib/components/User/Avatar.svelte';
|
||||
import ArxletIcon from '$lib/components/ArxletIcon.svelte';
|
||||
import LiquidGlass from '$lib/components/LiquidGlass.svelte';
|
||||
import UserName from '$lib/components/User/UserName.svelte';
|
||||
|
||||
const arxlets: Arxlet[] = $state([
|
||||
{
|
||||
id: 'ZZ-store',
|
||||
name: 'Store',
|
||||
description: 'Find arxlets to install',
|
||||
icon: 'mdi:storefront',
|
||||
iconColor: '#ff0000',
|
||||
script: ''
|
||||
},
|
||||
{
|
||||
id: 'ZZ-settings',
|
||||
name: 'Settings',
|
||||
description: 'Manage your settings',
|
||||
icon: 'mdi:cog',
|
||||
iconColor: '#3b82f6',
|
||||
script: ''
|
||||
},
|
||||
{
|
||||
id: 'ZZ-invite',
|
||||
name: 'Invite',
|
||||
description: 'Invite people to your CCN',
|
||||
icon: 'mingcute:invite-fill',
|
||||
iconColor: '#9922aa',
|
||||
script: ''
|
||||
}
|
||||
]);
|
||||
|
||||
let pubkey = $state('');
|
||||
|
||||
let currentTime = $state(new Date());
|
||||
|
||||
window.eve.getAllArxlets().then((installedArxlets) => {
|
||||
arxlets.push(...installedArxlets);
|
||||
arxlets.sort((a, b) => a.id.localeCompare(b.id));
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
const interval = setInterval(() => {
|
||||
currentTime = new Date();
|
||||
}, 1000);
|
||||
|
||||
window.eve.getPublicKey().then((key) => {
|
||||
pubkey = key;
|
||||
});
|
||||
|
||||
return () => clearInterval(interval);
|
||||
});
|
||||
|
||||
const formatGreeting = () => {
|
||||
const hour = currentTime.getHours();
|
||||
if (hour < 12) return 'Good morning';
|
||||
if (hour < 18) return 'Good afternoon';
|
||||
return 'Good evening';
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Eve Lite - Dashboard</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="w-full flex flex-row">
|
||||
<div class="flex-1 p-8">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<LiquidGlass class="p-8 rounded-2xl">
|
||||
<div class="flex flex-row items-center gap-4">
|
||||
<Avatar {pubkey} />
|
||||
<h2 class="text-2xl font-bold text-base-content">
|
||||
{formatGreeting()}, <UserName {pubkey} />!<br />
|
||||
</h2>
|
||||
</div>
|
||||
</LiquidGlass>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<LiquidGlass class="rounded-3xl shadow-2xl border border-base-300/50 p-8 max-w-4xl w-full">
|
||||
<div class="grid grid-cols-4 gap-8 mb-8">
|
||||
{#each arxlets as app}
|
||||
<ArxletIcon {app} isUnique={arxlets.filter((a) => a.id === app.id).length === 1} />
|
||||
{/each}
|
||||
</div>
|
||||
</LiquidGlass>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Sidebar />
|
||||
</div>
|
8
src/renderer/src/routes/app/[id]/+page.svelte
Normal file
|
@ -0,0 +1,8 @@
|
|||
<script>
|
||||
import { page } from '$app/state';
|
||||
import Arxlet from './arxlet.svelte';
|
||||
|
||||
let id = $derived(page.params.id);
|
||||
</script>
|
||||
|
||||
<Arxlet {id}></Arxlet>
|
|
@ -0,0 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
|
||||
import Arxlet from '../arxlet.svelte';
|
||||
|
||||
let id = $derived(page.params.id);
|
||||
let path = $derived(page.params.additional);
|
||||
</script>
|
||||
|
||||
<Arxlet {id} {path}></Arxlet>
|
80
src/renderer/src/routes/app/[id]/arxlet.svelte
Normal file
|
@ -0,0 +1,80 @@
|
|||
<script lang="ts">
|
||||
import { navigationStore } from '$lib/navigation';
|
||||
import type { Arxlet } from '$lib/eve';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import ArxletHeader from '$lib/components/ArxletHeader.svelte';
|
||||
import LiquidGlass from '$lib/components/LiquidGlass.svelte';
|
||||
|
||||
function universalBase64Encode(data: string) {
|
||||
return btoa(String.fromCharCode(...new TextEncoder().encode(data)));
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
document.body
|
||||
.querySelectorAll('script[type="module"][data-arxlet]')
|
||||
.forEach((script) => script.remove());
|
||||
}
|
||||
|
||||
const runArxlet = (module: string) => {
|
||||
cleanup();
|
||||
|
||||
const newScript = document.createElement('script');
|
||||
newScript.type = 'module';
|
||||
newScript.dataset.arxlet = 'true';
|
||||
const stringifiedModule = JSON.stringify(
|
||||
'data:text/javascript;base64,' + universalBase64Encode(module)
|
||||
);
|
||||
const stringifiedPath = JSON.stringify(path || '');
|
||||
newScript.innerHTML = `
|
||||
import { render } from ${stringifiedModule};
|
||||
render(document.getElementById('arxlet-container'), ${stringifiedPath});
|
||||
`;
|
||||
document.body.appendChild(newScript);
|
||||
};
|
||||
|
||||
const { id, path } = $props();
|
||||
|
||||
let arxlet: Arxlet | null = $state();
|
||||
|
||||
onMount(async () => {
|
||||
if (id === 'ZZ-store') return navigationStore.navigateTo('/store');
|
||||
const arxletData = await window.eve.getArxlet(id);
|
||||
if (!arxletData) navigationStore.navigateTo('/');
|
||||
arxlet = arxletData;
|
||||
if (!arxlet) return;
|
||||
runArxlet(arxlet.script);
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
cleanup();
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"svelte": "https://esm.sh/svelte/src/index-client.js",
|
||||
"svelte/internal": "https://esm.sh/svelte/src/internal/index.js",
|
||||
"svelte/internal/flags/legacy": "https://esm.sh/svelte/src/internal/flags/legacy.js",
|
||||
"svelte/internal/client": "https://esm.sh/svelte/src/internal/client/index.js",
|
||||
"rxjs": "https://esm.sh/rxjs/dist/esm/index.js",
|
||||
"rxjs/operators": "https://esm.sh/rxjs/dist/esm/operators/index.js",
|
||||
"vue": "https://esm.sh/vue@3.5.21/dist/vue.esm-browser.prod.js",
|
||||
"@vueuse/rxjs": "https://esm.sh/@vueuse/rxjs"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</svelte:head>
|
||||
|
||||
<ArxletHeader
|
||||
title={arxlet?.name ?? 'Loading...'}
|
||||
subtitle={arxlet?.description ?? 'No description'}
|
||||
icon={arxlet?.icon ?? 'mdi:loading'}
|
||||
iconColor={arxlet?.iconColor ?? '#000000'}
|
||||
iconForegroundColor={arxlet?.iconForegroundColor}
|
||||
iconStrokeColor={arxlet?.iconStrokeColor}
|
||||
/>
|
||||
<LiquidGlass>
|
||||
<div id="arxlet-container" />
|
||||
</LiquidGlass>
|
103
src/renderer/src/routes/ccn-info/+page.svelte
Normal file
|
@ -0,0 +1,103 @@
|
|||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import ArxletHeader from '$lib/components/ArxletHeader.svelte';
|
||||
import LiquidGlass from '$lib/components/LiquidGlass.svelte';
|
||||
import InvitesSection from './Invites/InvitesSection.svelte';
|
||||
|
||||
let copyStatus = $state('');
|
||||
</script>
|
||||
|
||||
<ArxletHeader
|
||||
title="CCN Information"
|
||||
subtitle="Details and identity information for your Closed Community Network"
|
||||
icon="mingcute:invite-fill"
|
||||
iconColor="#10b981"
|
||||
/>
|
||||
|
||||
<LiquidGlass class="min-h-full">
|
||||
<div class="max-w-6xl mx-auto p-6">
|
||||
{#await window.eve.getActiveCCN() then ccn}
|
||||
<div class="flex flex-row gap-2">
|
||||
<section class="bg-base-200 rounded-xl p-6">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<Icon icon="solar:letter-opened-bold-duotone" class="w-5 h-5" />
|
||||
<div>
|
||||
<h2 class="text-xl font-semibold text-base-content">Invite</h2>
|
||||
<p class="text-base-content/70 text-sm">Invite your friends to join your CCN</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<InvitesSection />
|
||||
</section>
|
||||
|
||||
<section class="flex flex-col space-y-2">
|
||||
<section class="bg-base-200 rounded-xl p-6">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<Icon icon="mdi:account-circle" class="w-6 h-6 text-primary" />
|
||||
<div>
|
||||
<h2 class="text-xl font-semibold text-base-content">Identity</h2>
|
||||
<p class="text-base-content/70 text-sm">Your CCN's primary identification</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-6 justify-center">
|
||||
<img
|
||||
src={window.eve.getCCNAvatar(ccn?.publicKey)}
|
||||
alt="CCN Avatar"
|
||||
class="ccn-hex ccn-hex-large transition-transform group-hover:scale-105"
|
||||
/>
|
||||
<div>
|
||||
<h3 class="text-2xl font-bold text-base-content mb-2">
|
||||
{ccn?.name || 'Unknown CCN'}
|
||||
</h3>
|
||||
<p class="text-base-content/70 mb-3">
|
||||
{ccn?.description || 'No description available'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bg-base-200 rounded-xl p-6">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<Icon icon="mdi:fingerprint" class="w-6 h-6 text-secondary" />
|
||||
<div>
|
||||
<h2 class="text-xl font-semibold text-base-content">Unique Identity Icon</h2>
|
||||
<p class="text-base-content/70 text-sm">
|
||||
Visual representation generated from your CCN's public key
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="flex flex-col items-center text-center">
|
||||
<img
|
||||
src={window.eve.getCCNIcon(ccn?.publicKey)}
|
||||
alt="CCN Icon"
|
||||
class="ccn-hex ccn-hex-extra-large"
|
||||
/>
|
||||
<p class="text-base-content/70 text-sm max-w-xs">
|
||||
This icon is mathematically derived from your public key and serves as a unique
|
||||
visual identifier.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="bg-base-100 rounded-lg p-4">
|
||||
<h4 class="font-medium text-base-content mb-2 flex items-center gap-2">
|
||||
<Icon icon="mdi:information-outline" class="w-4 h-4" />
|
||||
About Identity Icons
|
||||
</h4>
|
||||
<ul class="text-sm text-base-content/70 space-y-1">
|
||||
<li>Generated deterministically from your public key</li>
|
||||
<li>Provides visual verification of identity</li>
|
||||
<li>Cannot be forged</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
{/await}
|
||||
</div>
|
||||
</LiquidGlass>
|
|
@ -0,0 +1,25 @@
|
|||
<script lang="ts">
|
||||
import QR from '@svelte-put/qr/svg/QR.svelte';
|
||||
import CopyButton from '$lib/components/CopyButton.svelte';
|
||||
import Icon from '@iconify/svelte';
|
||||
|
||||
const invite = window.eve.generateInviteCode();
|
||||
</script>
|
||||
|
||||
{#await invite then invite}
|
||||
<div class="flex justify-center">
|
||||
<QR
|
||||
class="w-92 align-center"
|
||||
data={invite}
|
||||
moduleFill="#00badd"
|
||||
logo={'/favicon.png'}
|
||||
shape="circle"
|
||||
anchorOuterFill="#00ddba"
|
||||
anchorInnerFill="#00badd"
|
||||
/>
|
||||
</div>
|
||||
<div class="join w-92">
|
||||
<pre class="input w-full overflow-x-scroll">{invite}</pre>
|
||||
<CopyButton data={invite} />
|
||||
</div>
|
||||
{/await}
|
164
src/renderer/src/routes/onboard/+page.svelte
Normal file
|
@ -0,0 +1,164 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { parseInviteCode } from '$lib/invites';
|
||||
|
||||
window.eve.listCCNs().then((ccns) => {
|
||||
if (ccns.length > 0) return goto('/');
|
||||
});
|
||||
|
||||
let mode = $state<'initial' | 'join' | 'create'>('initial');
|
||||
let inviteCode = $state('');
|
||||
let ccnName = $state('');
|
||||
let ccnDescription = $state('');
|
||||
|
||||
let isValidInviteCode = $derived(checkInviteCode(inviteCode));
|
||||
|
||||
function checkInviteCode(inviteCode: string): boolean {
|
||||
try {
|
||||
let parsed = parseInviteCode(inviteCode as `${string}1${string}`);
|
||||
if (parsed) return true;
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function joinCCN() {
|
||||
mode = 'join';
|
||||
inviteCode = '';
|
||||
}
|
||||
|
||||
function createCCN() {
|
||||
mode = 'create';
|
||||
ccnName = '';
|
||||
ccnDescription = '';
|
||||
}
|
||||
|
||||
async function handleJoinSubmit() {
|
||||
if (inviteCode.trim()) {
|
||||
const parsed = parseInviteCode(inviteCode as `${string}1${string}`);
|
||||
if (parsed) {
|
||||
await window.eve.joinCCN(
|
||||
parsed.version,
|
||||
parsed.startIndex,
|
||||
parsed.name,
|
||||
parsed.description,
|
||||
parsed.key
|
||||
);
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCreateCCN() {
|
||||
if (ccnName.trim() && ccnDescription.trim()) {
|
||||
try {
|
||||
await window.eve.createCCN(ccnName.trim(), ccnDescription.trim());
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error('Failed to create CCN:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
mode = 'initial';
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex h-full w-full items-center justify-center">
|
||||
<div class="w-96">
|
||||
{#if mode === 'initial'}
|
||||
<div class="text-center p-4">
|
||||
<h3 class="font-bold text-lg mb-4">Welcome to Eve</h3>
|
||||
<p class="text-gray-600 mb-6">Join an existing CCN or create a new one</p>
|
||||
|
||||
<div class="space-y-3">
|
||||
<button class="btn btn-primary btn-block" onclick={joinCCN}>
|
||||
Join with Invite Code
|
||||
</button>
|
||||
|
||||
<button class="btn btn-secondary btn-block" onclick={createCCN}> Create New CCN </button>
|
||||
</div>
|
||||
</div>
|
||||
{:else if mode === 'join'}
|
||||
<div class="p-4">
|
||||
<div class="flex items-center mb-4">
|
||||
<button class="btn btn-sm btn-ghost mr-2" onclick={goBack}>←</button>
|
||||
<h3 class="font-bold text-lg">Join CCN</h3>
|
||||
</div>
|
||||
|
||||
<form onsubmit={handleJoinSubmit} class="space-y-4">
|
||||
<div class="form-control w-full">
|
||||
<label class="label" for="invite-code">
|
||||
<span class="label-text">Invite Code</span>
|
||||
</label>
|
||||
<input
|
||||
id="invite-code"
|
||||
type="text"
|
||||
placeholder="Enter invite code..."
|
||||
class="input input-bordered w-full"
|
||||
bind:value={inviteCode}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 justify-end">
|
||||
<button type="button" class="btn btn-ghost" onclick={goBack}> Cancel </button>
|
||||
<button type="submit" class="btn btn-primary" disabled={!isValidInviteCode}>
|
||||
Join CCN
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{:else if mode === 'create'}
|
||||
<div class="p-4">
|
||||
<div class="flex items-center mb-4">
|
||||
<button class="btn btn-sm btn-ghost mr-2" onclick={goBack}>←</button>
|
||||
<h3 class="font-bold text-lg">Create New CCN</h3>
|
||||
</div>
|
||||
|
||||
<form onsubmit={handleCreateCCN} class="space-y-4">
|
||||
<div class="form-control w-full">
|
||||
<label class="label" for="ccn-name">
|
||||
<span class="label-text">CCN Name</span>
|
||||
</label>
|
||||
<input
|
||||
id="ccn-name"
|
||||
type="text"
|
||||
placeholder="Enter CCN name..."
|
||||
class="input input-bordered w-full"
|
||||
bind:value={ccnName}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control w-full">
|
||||
<label class="label" for="ccn-description">
|
||||
<span class="label-text">Description</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="ccn-description"
|
||||
placeholder="Enter CCN description..."
|
||||
class="textarea textarea-bordered w-full"
|
||||
bind:value={ccnDescription}
|
||||
required
|
||||
rows="3"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 justify-end">
|
||||
<button type="button" class="btn btn-ghost" onclick={goBack}>Cancel</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
disabled={!ccnName.trim() || !ccnDescription.trim()}
|
||||
>
|
||||
Create CCN
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
248
src/renderer/src/routes/profile/+page.svelte
Normal file
|
@ -0,0 +1,248 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import Icon from '@iconify/svelte';
|
||||
import type { Profile } from '$lib/eve';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import ArxletHeader from '$lib/components/ArxletHeader.svelte';
|
||||
import Input from '$lib/components/PublicComponents/Input.svelte';
|
||||
import Textarea from '$lib/components/PublicComponents/Textarea.svelte';
|
||||
|
||||
let profile: Profile = $state({
|
||||
name: '',
|
||||
about: '',
|
||||
picture: ''
|
||||
});
|
||||
|
||||
let isLoading = $state(true);
|
||||
let isSaving = $state(false);
|
||||
let saveMessage = $state('');
|
||||
let publicKey = $state('');
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
publicKey = await window.eve.getPublicKey();
|
||||
const userProfile = await window.eve.getProfile(publicKey);
|
||||
if (userProfile) {
|
||||
profile = { ...userProfile };
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading profile:', error);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSave() {
|
||||
isSaving = true;
|
||||
saveMessage = '';
|
||||
|
||||
try {
|
||||
const event = await window.eve.signEvent({
|
||||
kind: 0,
|
||||
pubkey: publicKey,
|
||||
content: JSON.stringify(profile),
|
||||
tags: [],
|
||||
created_at: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
await window.eve.publish(event);
|
||||
saveMessage = 'Profile saved successfully!';
|
||||
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('profileUpdated', {
|
||||
detail: {
|
||||
publicKey,
|
||||
avatarUrl: profile.picture || window.eve.getAvatar(publicKey)
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
setTimeout(() => (saveMessage = ''), 3000);
|
||||
} catch (error) {
|
||||
console.error('Error saving profile:', error);
|
||||
saveMessage = 'Error saving profile. Please try again.';
|
||||
} finally {
|
||||
isSaving = false;
|
||||
}
|
||||
}
|
||||
|
||||
function resetChanges() {
|
||||
window.location.reload();
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Profile - EVE</title>
|
||||
</svelte:head>
|
||||
|
||||
<ArxletHeader
|
||||
title="Edit Profile"
|
||||
subtitle="Update your profile information"
|
||||
icon="mdi:user"
|
||||
iconColor="#3f00dd"
|
||||
/>
|
||||
|
||||
<div class="max-w-2xl mx-auto px-4 py-6">
|
||||
{#if isLoading}
|
||||
<div class="flex justify-center items-center py-12">
|
||||
<span class="loading loading-spinner loading-lg" />
|
||||
</div>
|
||||
{:else}
|
||||
<form on:submit|preventDefault={handleSave} class="space-y-6">
|
||||
<div class="bg-base-100 rounded-lg border border-base-300 shadow-sm overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-base-200 bg-base-50">
|
||||
<div class="flex items-center gap-3">
|
||||
<Icon icon="mdi:account-circle" class="w-5 h-5 text-primary" />
|
||||
<h3 class="text-lg font-medium text-base-content">Profile Picture</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-6">
|
||||
<div class="flex items-start gap-6">
|
||||
<div class="flex-shrink-0">
|
||||
<div class="avatar">
|
||||
<div
|
||||
class="w-20 h-20 rounded-full ring-2 ring-base-300 ring-offset-2 ring-offset-base-100"
|
||||
>
|
||||
{#if profile.picture}
|
||||
<img
|
||||
src={profile.picture}
|
||||
alt="Profile avatar"
|
||||
class="object-cover w-full h-full rounded-full"
|
||||
/>
|
||||
{:else}
|
||||
<img
|
||||
src={window.eve?.getAvatar?.(publicKey) || ''}
|
||||
alt="Default avatar"
|
||||
class="object-cover w-full h-full rounded-full"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
label="Avatar URL"
|
||||
placeholder="https://example.com/avatar.jpg"
|
||||
bind:value={profile.picture}
|
||||
>
|
||||
<p class="mt-1 text-xs text-base-content/60">
|
||||
Enter a direct link to your profile image
|
||||
</p>
|
||||
</Input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-base-100 rounded-lg border border-base-300 shadow-sm overflow-hidden px-6 py-4"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<Icon icon="mdi:card-account-details" class="w-5 h-5 text-primary" />
|
||||
<h3 class="text-lg font-medium text-base-content">Basic Information</h3>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
label="Display Name"
|
||||
placeholder="Enter your display name"
|
||||
bind:value={profile.name!}
|
||||
>
|
||||
<p class="text-xs text-base-content/60">This is how others will see your name</p>
|
||||
</Input>
|
||||
|
||||
<Textarea
|
||||
label="About"
|
||||
bind:value={profile.about!}
|
||||
placeholder="Tell others about yourself"
|
||||
rows="4"
|
||||
>
|
||||
<p class="text-xs text-base-content/60">
|
||||
Share your interests, background, or anything you'd like others to know
|
||||
</p>
|
||||
</Textarea>
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 rounded-lg border border-base-300 shadow-sm overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-base-200 bg-base-50">
|
||||
<div class="flex items-center gap-3">
|
||||
<Icon icon="mdi:key-variant" class="w-5 h-5 text-primary" />
|
||||
<h3 class="text-lg font-medium text-base-content">Identity</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-6 py-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="pubkey" class="text-sm font-medium text-base-content">Public Key</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
id="pubkey"
|
||||
value={nip19.npubEncode(publicKey)}
|
||||
type="text"
|
||||
readonly
|
||||
class="flex-1 px-3 py-2 text-sm font-mono border border-base-300 rounded-md bg-base-50 text-base-content/70"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="px-3 py-2 text-sm border border-base-300 rounded-md bg-base-100 hover:bg-base-200 transition-colors flex items-center gap-2"
|
||||
on:click={() => navigator.clipboard?.writeText(nip19.npubEncode(publicKey))}
|
||||
title="Copy to clipboard"
|
||||
>
|
||||
<Icon icon="mdi:content-copy" class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-xs text-base-content/60">
|
||||
This is your unique identifier that others can use to find you
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if saveMessage}
|
||||
<div
|
||||
class="px-4 py-3 rounded-lg border {saveMessage.includes('Error')
|
||||
? 'bg-error/10 border-error/20 text-error'
|
||||
: 'bg-success/10 border-success/20 text-success'}"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Icon
|
||||
icon={saveMessage.includes('Error') ? 'mdi:alert-circle' : 'mdi:check-circle'}
|
||||
class="w-4 h-4"
|
||||
/>
|
||||
<span class="text-sm font-medium">{saveMessage}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</form>
|
||||
|
||||
<!-- Action Bar -->
|
||||
<div
|
||||
class="sticky bottom-0 mt-6 -mx-4 px-4 py-4 bg-base-100/80 backdrop-blur-sm border-t border-base-200"
|
||||
>
|
||||
<div class="max-w-2xl mx-auto flex gap-3">
|
||||
<button
|
||||
type="button"
|
||||
class="px-4 py-2 text-sm border border-base-300 rounded-md bg-base-100 hover:bg-base-200 transition-colors flex items-center gap-2"
|
||||
disabled={isSaving}
|
||||
on:click={resetChanges}
|
||||
>
|
||||
<Icon icon="mdi:refresh" class="w-4 h-4" />
|
||||
Reset
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="flex-1 px-4 py-2 text-sm bg-primary text-primary-content rounded-md hover:bg-primary/90 transition-colors flex items-center justify-center gap-2 disabled:opacity-50"
|
||||
disabled={isSaving}
|
||||
form="profile-form"
|
||||
on:click={handleSave}
|
||||
>
|
||||
{#if isSaving}
|
||||
<span class="loading loading-spinner loading-sm" />
|
||||
Saving...
|
||||
{:else}
|
||||
<Icon icon="mdi:content-save" class="w-4 h-4" />
|
||||
Save Profile
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
63
src/renderer/src/routes/search/+page.svelte
Normal file
|
@ -0,0 +1,63 @@
|
|||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import Icon from '@iconify/svelte';
|
||||
import { navigationStore } from '$lib/navigation';
|
||||
import type { NostrEvent } from '$lib/eve';
|
||||
import NotePrinter from '$lib/components/NotePrinter.svelte';
|
||||
import Avatar from '$lib/components/User/Avatar.svelte';
|
||||
import SearchResult from '$lib/components/SearchResult.svelte';
|
||||
import ArxletHeader from '$lib/components/ArxletHeader.svelte';
|
||||
|
||||
const searchQuery = $derived(page.url.searchParams.get('q') || '');
|
||||
|
||||
let searchResults: NostrEvent[] = $state([]);
|
||||
|
||||
$effect(() => {
|
||||
if (searchQuery)
|
||||
window.eve
|
||||
.getAllEventsWithFilter({
|
||||
search: searchQuery
|
||||
})
|
||||
.then((results) => (searchResults = results));
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Eve Lite - Search: {searchQuery}</title>
|
||||
</svelte:head>
|
||||
|
||||
<ArxletHeader
|
||||
title="Search"
|
||||
subtitle={`Searching for "${searchQuery}"`}
|
||||
icon="mdi:search"
|
||||
iconColor="#aaaaaa"
|
||||
/>
|
||||
|
||||
<div class="p-6 max-w-6xl mx-auto">
|
||||
{#if searchQuery}
|
||||
<div class="stats shadow bg-base-200 w-full">
|
||||
<div class="stat">
|
||||
<div class="stat-title">Total Results</div>
|
||||
<div class="stat-value text-primary">{searchResults.length}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-6">
|
||||
{#each searchResults as result}
|
||||
<SearchResult {result} />
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="hero min-h-[60vh]">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<Icon icon="mdi:magnify" class="w-24 h-24 mx-auto mb-6 text-base-content/20" />
|
||||
<h1 class="text-3xl font-bold mb-4">No Search Query</h1>
|
||||
<p class="text-base-content/70">
|
||||
Enter a search term in the search bar above to find information.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|