chrome extension for skeeting tweets at the sky

:rocket:

+23
.gitignore
··· 1 + # Dependencies 2 + node_modules/ 3 + 4 + # Build output 5 + dist/ 6 + 7 + # IDE and editor files 8 + .vscode/ 9 + .idea/ 10 + *.swp 11 + *.swo 12 + .DS_Store 13 + 14 + # Logs 15 + *.log 16 + npm-debug.log* 17 + yarn-debug.log* 18 + yarn-error.log* 19 + 20 + # Environment variables 21 + .env 22 + .env.local 23 + .env.*.local
+30
README.md
··· 1 + # skeet.FYI chrome extension 2 + 3 + A Chrome extension for quick skeeting your current browser tab over to bsky.app 4 + 5 + ## Authentication 6 + 7 + This extension uses OAuth for authentication with Bluesky, following the ATProto OAuth specification. Your credentials are securely stored in Chrome's local storage. 8 + 9 + ## Installation 10 + 11 + 1. Clone this repository, `bun install` and `bun run dev` 12 + 2. Open Chrome and navigate to `chrome://extensions/` 13 + 3. Enable "Developer mode" in the top right 14 + 4. Click "Load unpacked" and select the extension directory 15 + 16 +   17 + 18 + Feel free to report bugs / feature requests and PRs 19 + 20 + ## Contributing 21 + 22 + 1. Fork the repository 23 + 2. Create a feature branch 24 + 3. Commit your changes 25 + 4. Push to the branch 26 + 5. Create a Pull Request 27 + 28 + ## License 29 + 30 + MIT License
+63
biome.json
··· 1 + { 2 + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 + "vcs": { 4 + "enabled": false, 5 + "clientKind": "git", 6 + "useIgnoreFile": false 7 + }, 8 + "files": { 9 + "ignoreUnknown": true, 10 + "ignore": [ 11 + "build/**", 12 + "dist/**", 13 + "drizzle/**", 14 + "node_modules/**", 15 + "dump/", 16 + "tsconfig.json", 17 + ".next/**" 18 + ] 19 + }, 20 + "formatter": { 21 + "enabled": true, 22 + "formatWithErrors": false, 23 + "indentStyle": "space", 24 + "indentWidth": 2, 25 + "lineWidth": 80, 26 + "ignore": ["dist/**/*"] 27 + }, 28 + "organizeImports": { 29 + "enabled": true 30 + }, 31 + "linter": { 32 + "enabled": true, 33 + "rules": { 34 + "recommended": true, 35 + "suspicious": { 36 + "noExplicitAny": "off", 37 + "noArrayIndexKey": "off" 38 + }, 39 + "style": { 40 + "noNonNullAssertion": "off" 41 + }, 42 + "a11y": { 43 + "noSvgWithoutTitle": "off", 44 + "useMediaCaption": "off" 45 + } 46 + }, 47 + "ignore": ["dist/**/*"] 48 + }, 49 + "javascript": { 50 + "parser": { 51 + "unsafeParameterDecoratorsEnabled": true 52 + }, 53 + "formatter": { 54 + "quoteStyle": "single", 55 + "trailingCommas": "es5" 56 + } 57 + }, 58 + "json": { 59 + "formatter": { 60 + "indentWidth": 2 61 + } 62 + } 63 + }
+150
build.js
··· 1 + import * as esbuild from 'esbuild'; 2 + import { exec } from 'child_process'; 3 + import { promises as fs } from 'fs'; 4 + import path from 'path'; 5 + 6 + // Helper function to execute shell commands 7 + async function execCommand(command) { 8 + return new Promise((resolve, reject) => { 9 + exec(command, (error, stdout, stderr) => { 10 + if (error) { 11 + console.error(`Error executing command: ${error}`); 12 + reject(error); 13 + return; 14 + } 15 + if (stderr) { 16 + console.warn(`Command stderr: ${stderr}`); 17 + } 18 + resolve(stdout); 19 + }); 20 + }); 21 + } 22 + 23 + // Helper function to ensure directory exists 24 + async function ensureDir(dir) { 25 + try { 26 + await fs.mkdir(dir, { recursive: true }); 27 + } catch (error) { 28 + if (error.code !== 'EEXIST') { 29 + throw error; 30 + } 31 + } 32 + } 33 + 34 + // Main build function 35 + async function build() { 36 + try { 37 + console.log('Starting build process...'); 38 + 39 + // Clean dist directory 40 + await execCommand('rm -rf dist'); 41 + await ensureDir('dist'); 42 + await ensureDir('dist/scripts'); 43 + await ensureDir('dist/lib'); 44 + await ensureDir('dist/assets/css'); 45 + await ensureDir('dist/assets/icon'); 46 + await ensureDir('dist/pages'); 47 + 48 + // Copy OAuth-related files from pack to src 49 + console.log('Copying OAuth-related files from pack to src...'); 50 + 51 + // Create src/scripts directory if it doesn't exist 52 + await ensureDir('src/scripts'); 53 + 54 + // Build JavaScript files with minification 55 + console.log('Building and minifying JavaScript files...'); 56 + await esbuild.build({ 57 + entryPoints: [ 58 + 'src/scripts/popup.js', 59 + 'src/scripts/background.js', 60 + 'src/scripts/content-script.js', 61 + 'src/scripts/extension-id-provider.js', 62 + ], 63 + bundle: true, 64 + outdir: 'dist/scripts', 65 + format: 'esm', 66 + platform: 'browser', 67 + target: ['chrome90'], 68 + loader: { 69 + '.js': 'jsx', 70 + '.ts': 'ts', 71 + }, 72 + define: { 73 + 'process.env.NODE_ENV': '"production"', 74 + }, 75 + minify: true, 76 + drop: ['console'], 77 + }); 78 + 79 + // Build the API TypeScript file with minification 80 + console.log('Building and minifying API TypeScript file...'); 81 + await esbuild.build({ 82 + entryPoints: ['src/lib/api.ts'], 83 + bundle: true, 84 + outdir: 'dist/lib', 85 + format: 'esm', 86 + platform: 'browser', 87 + target: ['chrome90'], 88 + loader: { 89 + '.ts': 'ts', 90 + }, 91 + define: { 92 + 'process.env.NODE_ENV': '"production"', 93 + }, 94 + minify: true, 95 + drop: ['console'], 96 + }); 97 + 98 + // Copy static files 99 + console.log('Copying static files...'); 100 + 101 + // Copy manifest.json 102 + await fs.copyFile('manifest.json', 'dist/manifest.json'); 103 + 104 + // Copy HTML files 105 + const htmlFiles = [ 106 + { src: 'src/pages/popup.html', dest: 'dist/pages/popup.html' }, 107 + ]; 108 + 109 + for (const file of htmlFiles) { 110 + try { 111 + console.log(`Copying ${file.src} to ${file.dest}`); 112 + await fs.copyFile(file.src, file.dest); 113 + } catch (error) { 114 + console.error(`Error copying ${file.src}: ${error.message}`); 115 + } 116 + } 117 + 118 + // Copy icon files 119 + const iconDir = 'src/assets/icon'; 120 + const iconDestDir = 'dist/assets/icon'; 121 + try { 122 + const iconFiles = await fs.readdir(iconDir); 123 + for (const file of iconFiles) { 124 + if (file.endsWith('.png')) { 125 + console.log(`Copying icon file: ${file}`); 126 + await fs.copyFile(path.join(iconDir, file), path.join(iconDestDir, file)); 127 + } 128 + } 129 + } catch (error) { 130 + console.error(`Error copying icon files: ${error.message}`); 131 + } 132 + 133 + // Copy logo.svg file 134 + try { 135 + await ensureDir('dist/assets'); 136 + console.log('Copying logo.svg file'); 137 + await fs.copyFile('src/assets/logo.svg', 'dist/assets/logo.svg'); 138 + } catch (error) { 139 + console.error(`Error copying logo.svg file: ${error.message}`); 140 + } 141 + 142 + console.log('Build completed successfully!'); 143 + } catch (error) { 144 + console.error('Build failed:', error); 145 + process.exit(1); 146 + } 147 + } 148 + 149 + // Run the build 150 + build();
+640
bun.lock
··· 1 + { 2 + "lockfileVersion": 1, 3 + "workspaces": { 4 + "": { 5 + "name": "skeet-fyi", 6 + "dependencies": { 7 + "@atproto/api": "^0.14.10", 8 + }, 9 + "devDependencies": { 10 + "@biomejs/biome": "^1.9.4", 11 + "@unocss/cli": "^0.58.5", 12 + "@unocss/preset-uno": "^0.58.5", 13 + "@unocss/preset-wind": "^0.58.5", 14 + "@unocss/reset": "^0.58.5", 15 + "chokidar-cli": "^3.0.0", 16 + "concurrently": "^8.2.2", 17 + "cross-env": "^7.0.3", 18 + "esbuild": "^0.20.1", 19 + "unocss": "^0.58.5", 20 + }, 21 + }, 22 + }, 23 + "packages": { 24 + "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], 25 + 26 + "@antfu/install-pkg": ["@antfu/install-pkg@1.0.0", "", { "dependencies": { "package-manager-detector": "^0.2.8", "tinyexec": "^0.3.2" } }, "sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw=="], 27 + 28 + "@antfu/utils": ["@antfu/utils@0.7.10", "", {}, "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww=="], 29 + 30 + "@atproto/api": ["@atproto/api@0.14.10", "", { "dependencies": { "@atproto/common-web": "^0.4.0", "@atproto/lexicon": "^0.4.9", "@atproto/syntax": "^0.4.0", "@atproto/xrpc": "^0.6.11", "await-lock": "^2.2.2", "multiformats": "^9.9.0", "tlds": "^1.234.0", "zod": "^3.23.8" } }, "sha512-NzKKii5XfUwxBDF0p6ud3NeQh/CCbtVowJd4C7zIYR8cWLX6RAbfANMCyP4tmFmbvUfWQ42+GectYQVuCoBxNw=="], 31 + 32 + "@atproto/common-web": ["@atproto/common-web@0.4.0", "", { "dependencies": { "graphemer": "^1.4.0", "multiformats": "^9.9.0", "uint8arrays": "3.0.0", "zod": "^3.23.8" } }, "sha512-ZYL0P9myHybNgwh/hBY0HaBzqiLR1B5/ie5bJpLQAg0whRzNA28t8/nU2vh99tbsWcAF0LOD29M8++LyENJLNQ=="], 33 + 34 + "@atproto/lexicon": ["@atproto/lexicon@0.4.9", "", { "dependencies": { "@atproto/common-web": "^0.4.0", "@atproto/syntax": "^0.4.0", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-/tmEuHQFr51V2V7EAVJzaA40sqJ7ylAZpR962VbOsPtmcdOHvezbjVHYEMXgfb927hS+xqbVyzBTbu5w9v8prA=="], 35 + 36 + "@atproto/syntax": ["@atproto/syntax@0.4.0", "", {}, "sha512-b9y5ceHS8YKOfP3mdKmwAx5yVj9294UN7FG2XzP6V5aKUdFazEYRnR9m5n5ZQFKa3GNvz7de9guZCJ/sUTcOAA=="], 37 + 38 + "@atproto/xrpc": ["@atproto/xrpc@0.6.11", "", { "dependencies": { "@atproto/lexicon": "^0.4.9", "zod": "^3.23.8" } }, "sha512-J2cZP8FjoDN0UkyTYBlCvKvxwBbDm4dld47u6FQK30RJy9YpSiUkdxJJ10NYqpi7JVny3M0qWQgpWJDV94+PdA=="], 39 + 40 + "@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="], 41 + 42 + "@babel/compat-data": ["@babel/compat-data@7.26.8", "", {}, "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ=="], 43 + 44 + "@babel/core": ["@babel/core@7.26.10", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.10", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", "@babel/helpers": "^7.26.10", "@babel/parser": "^7.26.10", "@babel/template": "^7.26.9", "@babel/traverse": "^7.26.10", "@babel/types": "^7.26.10", "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-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ=="], 45 + 46 + "@babel/generator": ["@babel/generator@7.27.0", "", { "dependencies": { "@babel/parser": "^7.27.0", "@babel/types": "^7.27.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw=="], 47 + 48 + "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.25.9", "", { "dependencies": { "@babel/types": "^7.25.9" } }, "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g=="], 49 + 50 + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.0", "", { "dependencies": { "@babel/compat-data": "^7.26.8", "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA=="], 51 + 52 + "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.27.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", "@babel/helper-replace-supers": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/traverse": "^7.27.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg=="], 53 + 54 + "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ=="], 55 + 56 + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw=="], 57 + 58 + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.26.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw=="], 59 + 60 + "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.25.9", "", { "dependencies": { "@babel/types": "^7.25.9" } }, "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ=="], 61 + 62 + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="], 63 + 64 + "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.26.5", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", "@babel/traverse": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg=="], 65 + 66 + "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA=="], 67 + 68 + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="], 69 + 70 + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], 71 + 72 + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.25.9", "", {}, "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw=="], 73 + 74 + "@babel/helpers": ["@babel/helpers@7.27.0", "", { "dependencies": { "@babel/template": "^7.27.0", "@babel/types": "^7.27.0" } }, "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg=="], 75 + 76 + "@babel/parser": ["@babel/parser@7.27.0", "", { "dependencies": { "@babel/types": "^7.27.0" }, "bin": "./bin/babel-parser.js" }, "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg=="], 77 + 78 + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA=="], 79 + 80 + "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ=="], 81 + 82 + "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.26.3", "", { "dependencies": { "@babel/helper-module-transforms": "^7.26.0", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ=="], 83 + 84 + "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.27.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-create-class-features-plugin": "^7.27.0", "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/plugin-syntax-typescript": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fRGGjO2UEGPjvEcyAZXRXAS8AfdaQoq7HnxAbJoAoW10B9xOKesmmndJv+Sym2a+9FHWZ9KbyyLCe9s0Sn5jtg=="], 85 + 86 + "@babel/preset-typescript": ["@babel/preset-typescript@7.27.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "@babel/plugin-syntax-jsx": "^7.25.9", "@babel/plugin-transform-modules-commonjs": "^7.26.3", "@babel/plugin-transform-typescript": "^7.27.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vxaPFfJtHhgeOVXRKuHpHPAOgymmy8V8I65T1q53R7GCZlefKeCaTyDs3zOPHTTbmquvNlQYC5klEvWsBAtrBQ=="], 87 + 88 + "@babel/runtime": ["@babel/runtime@7.27.0", "", { "dependencies": { "regenerator-runtime": "^0.14.0" } }, "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw=="], 89 + 90 + "@babel/template": ["@babel/template@7.27.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/parser": "^7.27.0", "@babel/types": "^7.27.0" } }, "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA=="], 91 + 92 + "@babel/traverse": ["@babel/traverse@7.27.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.27.0", "@babel/parser": "^7.27.0", "@babel/template": "^7.27.0", "@babel/types": "^7.27.0", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA=="], 93 + 94 + "@babel/types": ["@babel/types@7.27.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg=="], 95 + 96 + "@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="], 97 + 98 + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="], 99 + 100 + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="], 101 + 102 + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="], 103 + 104 + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="], 105 + 106 + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="], 107 + 108 + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="], 109 + 110 + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="], 111 + 112 + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="], 113 + 114 + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.20.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g=="], 115 + 116 + "@esbuild/android-arm": ["@esbuild/android-arm@0.20.2", "", { "os": "android", "cpu": "arm" }, "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w=="], 117 + 118 + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.20.2", "", { "os": "android", "cpu": "arm64" }, "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg=="], 119 + 120 + "@esbuild/android-x64": ["@esbuild/android-x64@0.20.2", "", { "os": "android", "cpu": "x64" }, "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg=="], 121 + 122 + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.20.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA=="], 123 + 124 + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.20.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA=="], 125 + 126 + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.20.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw=="], 127 + 128 + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.20.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw=="], 129 + 130 + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.20.2", "", { "os": "linux", "cpu": "arm" }, "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg=="], 131 + 132 + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.20.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A=="], 133 + 134 + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.20.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig=="], 135 + 136 + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.20.2", "", { "os": "linux", "cpu": "none" }, "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ=="], 137 + 138 + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.20.2", "", { "os": "linux", "cpu": "none" }, "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA=="], 139 + 140 + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.20.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg=="], 141 + 142 + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.20.2", "", { "os": "linux", "cpu": "none" }, "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg=="], 143 + 144 + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.20.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ=="], 145 + 146 + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.20.2", "", { "os": "linux", "cpu": "x64" }, "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw=="], 147 + 148 + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.20.2", "", { "os": "none", "cpu": "x64" }, "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ=="], 149 + 150 + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.20.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ=="], 151 + 152 + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.20.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w=="], 153 + 154 + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.20.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ=="], 155 + 156 + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.20.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ=="], 157 + 158 + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.20.2", "", { "os": "win32", "cpu": "x64" }, "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ=="], 159 + 160 + "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], 161 + 162 + "@iconify/utils": ["@iconify/utils@2.3.0", "", { "dependencies": { "@antfu/install-pkg": "^1.0.0", "@antfu/utils": "^8.1.0", "@iconify/types": "^2.0.0", "debug": "^4.4.0", "globals": "^15.14.0", "kolorist": "^1.8.0", "local-pkg": "^1.0.0", "mlly": "^1.7.4" } }, "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA=="], 163 + 164 + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], 165 + 166 + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], 167 + 168 + "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], 169 + 170 + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], 171 + 172 + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], 173 + 174 + "@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=="], 175 + 176 + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], 177 + 178 + "@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=="], 179 + 180 + "@polka/url": ["@polka/url@1.0.0-next.28", "", {}, "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw=="], 181 + 182 + "@rollup/pluginutils": ["@rollup/pluginutils@5.1.4", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ=="], 183 + 184 + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.37.0", "", { "os": "android", "cpu": "arm" }, "sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ=="], 185 + 186 + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.37.0", "", { "os": "android", "cpu": "arm64" }, "sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA=="], 187 + 188 + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.37.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA=="], 189 + 190 + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.37.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ=="], 191 + 192 + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.37.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA=="], 193 + 194 + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.37.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA=="], 195 + 196 + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.37.0", "", { "os": "linux", "cpu": "arm" }, "sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w=="], 197 + 198 + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.37.0", "", { "os": "linux", "cpu": "arm" }, "sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag=="], 199 + 200 + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.37.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA=="], 201 + 202 + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.37.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ=="], 203 + 204 + "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA=="], 205 + 206 + "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.37.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ=="], 207 + 208 + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw=="], 209 + 210 + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA=="], 211 + 212 + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.37.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A=="], 213 + 214 + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.37.0", "", { "os": "linux", "cpu": "x64" }, "sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ=="], 215 + 216 + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.37.0", "", { "os": "linux", "cpu": "x64" }, "sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w=="], 217 + 218 + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.37.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg=="], 219 + 220 + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.37.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA=="], 221 + 222 + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.37.0", "", { "os": "win32", "cpu": "x64" }, "sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA=="], 223 + 224 + "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], 225 + 226 + "@unocss/astro": ["@unocss/astro@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9", "@unocss/reset": "0.58.9", "@unocss/vite": "0.58.9" }, "peerDependencies": { "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0" }, "optionalPeers": ["vite"] }, "sha512-VWfHNC0EfawFxLfb3uI+QcMGBN+ju+BYtutzeZTjilLKj31X2UpqIh8fepixL6ljgZzB3fweqg2xtUMC0gMnoQ=="], 227 + 228 + "@unocss/cli": ["@unocss/cli@0.58.9", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@rollup/pluginutils": "^5.1.0", "@unocss/config": "0.58.9", "@unocss/core": "0.58.9", "@unocss/preset-uno": "0.58.9", "cac": "^6.7.14", "chokidar": "^3.6.0", "colorette": "^2.0.20", "consola": "^3.2.3", "fast-glob": "^3.3.2", "magic-string": "^0.30.8", "pathe": "^1.1.2", "perfect-debounce": "^1.0.0" }, "bin": { "unocss": "bin/unocss.mjs" } }, "sha512-q7qlwX3V6UaqljWUQ5gMj36yTA9eLuuRywahdQWt1ioy4aPF/MEEfnMBZf/ntrqf5tIT5TO8fE11nvCco2Q/sA=="], 229 + 230 + "@unocss/config": ["@unocss/config@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9", "unconfig": "^0.3.11" } }, "sha512-90wRXIyGNI8UenWxvHUcH4l4rgq813MsTzYWsf6ZKyLLvkFjV2b2EfGXI27GPvZ7fVE1OAqx+wJNTw8CyQxwag=="], 231 + 232 + "@unocss/core": ["@unocss/core@0.58.9", "", {}, "sha512-wYpPIPPsOIbIoMIDuH8ihehJk5pAZmyFKXIYO/Kro98GEOFhz6lJoLsy6/PZuitlgp2/TSlubUuWGjHWvp5osw=="], 233 + 234 + "@unocss/extractor-arbitrary-variants": ["@unocss/extractor-arbitrary-variants@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9" } }, "sha512-M/BvPdbEEMdhcFQh/z2Bf9gylO1Ky/ZnpIvKWS1YJPLt4KA7UWXSUf+ZNTFxX+X58Is5qAb5hNh/XBQmL3gbXg=="], 235 + 236 + "@unocss/inspector": ["@unocss/inspector@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9", "@unocss/rule-utils": "0.58.9", "gzip-size": "^6.0.0", "sirv": "^2.0.4" } }, "sha512-uRzqkCNeBmEvFePXcfIFcQPMlCXd9/bLwa5OkBthiOILwQdH1uRIW3GWAa2SWspu+kZLP0Ly3SjZ9Wqi+5ZtTw=="], 237 + 238 + "@unocss/postcss": ["@unocss/postcss@0.58.9", "", { "dependencies": { "@unocss/config": "0.58.9", "@unocss/core": "0.58.9", "@unocss/rule-utils": "0.58.9", "css-tree": "^2.3.1", "fast-glob": "^3.3.2", "magic-string": "^0.30.8", "postcss": "^8.4.38" } }, "sha512-PnKmH6Qhimw35yO6u6yx9SHaX2NmvbRNPDvMDHA/1xr3M8L0o8U88tgKbWfm65NEGF3R1zJ9A8rjtZn/LPkgPA=="], 239 + 240 + "@unocss/preset-attributify": ["@unocss/preset-attributify@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9" } }, "sha512-ucP+kXRFcwmBmHohUVv31bE/SejMAMo7Hjb0QcKVLyHlzRWUJsfNR+jTAIGIUSYxN7Q8MeigYsongGo3nIeJnQ=="], 241 + 242 + "@unocss/preset-icons": ["@unocss/preset-icons@0.58.9", "", { "dependencies": { "@iconify/utils": "^2.1.22", "@unocss/core": "0.58.9", "ofetch": "^1.3.4" } }, "sha512-9dS48+yAunsbS0ylOW2Wisozwpn3nGY1CqTiidkUnrMnrZK3al579A7srUX9NyPWWDjprO7eU/JkWbdDQSmFFA=="], 243 + 244 + "@unocss/preset-mini": ["@unocss/preset-mini@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9", "@unocss/extractor-arbitrary-variants": "0.58.9", "@unocss/rule-utils": "0.58.9" } }, "sha512-m4aDGYtueP8QGsU3FsyML63T/w5Mtr4htme2jXy6m50+tzC1PPHaIBstMTMQfLc6h8UOregPJyGHB5iYQZGEvQ=="], 245 + 246 + "@unocss/preset-tagify": ["@unocss/preset-tagify@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9" } }, "sha512-obh75XrRmxYwrQMflzvhQUMeHwd/R9bEDhTWUW9aBTolBy4eNypmQwOhHCKh5Xi4Dg6o0xj6GWC/jcCj1SPLog=="], 247 + 248 + "@unocss/preset-typography": ["@unocss/preset-typography@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9", "@unocss/preset-mini": "0.58.9" } }, "sha512-hrsaqKlcZni3Vh4fwXC+lP9e92FQYbqtmlZw2jpxlVwwH5aLzwk4d4MiFQGyhCfzuSDYm0Zd52putFVV02J7bA=="], 249 + 250 + "@unocss/preset-uno": ["@unocss/preset-uno@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9", "@unocss/preset-mini": "0.58.9", "@unocss/preset-wind": "0.58.9", "@unocss/rule-utils": "0.58.9" } }, "sha512-Fze+X2Z/EegCkRdDRgwwvFBmXBenNR1AG8KxAyz8iPeWbhOBaRra2sn2ScryrfH6SbJHpw26ZyJXycAdS0Fq3A=="], 251 + 252 + "@unocss/preset-web-fonts": ["@unocss/preset-web-fonts@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9", "ofetch": "^1.3.4" } }, "sha512-XtiO+Z+RYnNYomNkS2XxaQiY++CrQZKOfNGw5htgIrb32QtYVQSkyYQ3jDw7JmMiCWlZ4E72cV/zUb++WrZLxg=="], 253 + 254 + "@unocss/preset-wind": ["@unocss/preset-wind@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9", "@unocss/preset-mini": "0.58.9", "@unocss/rule-utils": "0.58.9" } }, "sha512-7l+7Vx5UoN80BmJKiqDXaJJ6EUqrnUQYv8NxCThFi5lYuHzxsYWZPLU3k3XlWRUQt8XL+6rYx7mMBmD7EUSHyw=="], 255 + 256 + "@unocss/reset": ["@unocss/reset@0.58.9", "", {}, "sha512-nA2pg3tnwlquq+FDOHyKwZvs20A6iBsKPU7Yjb48JrNnzoaXqE+O9oN6782IG2yKVW4AcnsAnAnM4cxXhGzy1w=="], 257 + 258 + "@unocss/rule-utils": ["@unocss/rule-utils@0.58.9", "", { "dependencies": { "@unocss/core": "^0.58.9", "magic-string": "^0.30.8" } }, "sha512-45bDa+elmlFLthhJmKr2ltKMAB0yoXnDMQ6Zp5j3OiRB7dDMBkwYRPvHLvIe+34Ey7tDt/kvvDPtWMpPl2quUQ=="], 259 + 260 + "@unocss/scope": ["@unocss/scope@0.58.9", "", {}, "sha512-BIwcpx0R3bE0rYa9JVDJTk0GX32EBvnbvufBpNkWfC5tb7g+B7nMkVq9ichanksYCCxrIQQo0mrIz5PNzu9sGA=="], 261 + 262 + "@unocss/transformer-attributify-jsx": ["@unocss/transformer-attributify-jsx@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9" } }, "sha512-jpL3PRwf8t43v1agUdQn2EHGgfdWfvzsMxFtoybO88xzOikzAJaaouteNtojc/fQat2T9iBduDxVj5egdKmhdQ=="], 263 + 264 + "@unocss/transformer-attributify-jsx-babel": ["@unocss/transformer-attributify-jsx-babel@0.58.9", "", { "dependencies": { "@babel/core": "^7.24.3", "@babel/plugin-syntax-jsx": "^7.24.1", "@babel/preset-typescript": "^7.24.1", "@unocss/core": "0.58.9" } }, "sha512-UGaQoGZg+3QrsPtnGHPECmsGn4EQb2KSdZ4eGEn2YssjKv+CcQhzRvpEUgnuF/F+jGPkCkS/G/YEQBHRWBY54Q=="], 265 + 266 + "@unocss/transformer-compile-class": ["@unocss/transformer-compile-class@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9" } }, "sha512-l2VpCqelJ6Tgc1kfSODxBtg7fCGPVRr2EUzTg1LrGYKa2McbKuc/wV/2DWKHGxL6+voWi7a2C9XflqGDXXutuQ=="], 267 + 268 + "@unocss/transformer-directives": ["@unocss/transformer-directives@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9", "@unocss/rule-utils": "0.58.9", "css-tree": "^2.3.1" } }, "sha512-pLOUsdoY2ugVntJXg0xuGjO9XZ2xCiMxTPRtpZ4TsEzUtdEzMswR06Y8VWvNciTB/Zqxcz9ta8rD0DKePOfSuw=="], 269 + 270 + "@unocss/transformer-variant-group": ["@unocss/transformer-variant-group@0.58.9", "", { "dependencies": { "@unocss/core": "0.58.9" } }, "sha512-3A6voHSnFcyw6xpcZT6oxE+KN4SHRnG4z862tdtWvRGcN+jGyNr20ylEZtnbk4xj0VNMeGHHQRZ0WLvmrAwvOQ=="], 271 + 272 + "@unocss/vite": ["@unocss/vite@0.58.9", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@rollup/pluginutils": "^5.1.0", "@unocss/config": "0.58.9", "@unocss/core": "0.58.9", "@unocss/inspector": "0.58.9", "@unocss/scope": "0.58.9", "@unocss/transformer-directives": "0.58.9", "chokidar": "^3.6.0", "fast-glob": "^3.3.2", "magic-string": "^0.30.8" }, "peerDependencies": { "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0" } }, "sha512-mmppBuulAHCal+sC0Qz36Y99t0HicAmznpj70Kzwl7g/yvXwm58/DW2OnpCWw+uA8/JBft/+z3zE+XvrI+T1HA=="], 273 + 274 + "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], 275 + 276 + "ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], 277 + 278 + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], 279 + 280 + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], 281 + 282 + "await-lock": ["await-lock@2.2.2", "", {}, "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw=="], 283 + 284 + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], 285 + 286 + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], 287 + 288 + "browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" } }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="], 289 + 290 + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], 291 + 292 + "camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], 293 + 294 + "caniuse-lite": ["caniuse-lite@1.0.30001707", "", {}, "sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw=="], 295 + 296 + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], 297 + 298 + "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], 299 + 300 + "chokidar-cli": ["chokidar-cli@3.0.0", "", { "dependencies": { "chokidar": "^3.5.2", "lodash.debounce": "^4.0.8", "lodash.throttle": "^4.1.1", "yargs": "^13.3.0" }, "bin": { "chokidar": "index.js" } }, "sha512-xVW+Qeh7z15uZRxHOkP93Ux8A0xbPzwK4GaqD8dQOYc34TlkqUhVSS59fK36DOp5WdJlrRzlYSy02Ht99FjZqQ=="], 301 + 302 + "cliui": ["cliui@5.0.0", "", { "dependencies": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", "wrap-ansi": "^5.1.0" } }, "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA=="], 303 + 304 + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], 305 + 306 + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], 307 + 308 + "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], 309 + 310 + "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=="], 311 + 312 + "confbox": ["confbox@0.2.1", "", {}, "sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg=="], 313 + 314 + "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], 315 + 316 + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], 317 + 318 + "cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], 319 + 320 + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], 321 + 322 + "css-tree": ["css-tree@2.3.1", "", { "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" } }, "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw=="], 323 + 324 + "date-fns": ["date-fns@2.30.0", "", { "dependencies": { "@babel/runtime": "^7.21.0" } }, "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw=="], 325 + 326 + "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], 327 + 328 + "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], 329 + 330 + "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], 331 + 332 + "destr": ["destr@2.0.3", "", {}, "sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ=="], 333 + 334 + "duplexer": ["duplexer@0.1.2", "", {}, "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="], 335 + 336 + "electron-to-chromium": ["electron-to-chromium@1.5.123", "", {}, "sha512-refir3NlutEZqlKaBLK0tzlVLe5P2wDKS7UQt/3SpibizgsRAPOsqQC3ffw1nlv3ze5gjRQZYHoPymgVZkplFA=="], 337 + 338 + "emoji-regex": ["emoji-regex@7.0.3", "", {}, "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="], 339 + 340 + "esbuild": ["esbuild@0.20.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.20.2", "@esbuild/android-arm": "0.20.2", "@esbuild/android-arm64": "0.20.2", "@esbuild/android-x64": "0.20.2", "@esbuild/darwin-arm64": "0.20.2", "@esbuild/darwin-x64": "0.20.2", "@esbuild/freebsd-arm64": "0.20.2", "@esbuild/freebsd-x64": "0.20.2", "@esbuild/linux-arm": "0.20.2", "@esbuild/linux-arm64": "0.20.2", "@esbuild/linux-ia32": "0.20.2", "@esbuild/linux-loong64": "0.20.2", "@esbuild/linux-mips64el": "0.20.2", "@esbuild/linux-ppc64": "0.20.2", "@esbuild/linux-riscv64": "0.20.2", "@esbuild/linux-s390x": "0.20.2", "@esbuild/linux-x64": "0.20.2", "@esbuild/netbsd-x64": "0.20.2", "@esbuild/openbsd-x64": "0.20.2", "@esbuild/sunos-x64": "0.20.2", "@esbuild/win32-arm64": "0.20.2", "@esbuild/win32-ia32": "0.20.2", "@esbuild/win32-x64": "0.20.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g=="], 341 + 342 + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], 343 + 344 + "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], 345 + 346 + "exsolve": ["exsolve@1.0.4", "", {}, "sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw=="], 347 + 348 + "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=="], 349 + 350 + "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], 351 + 352 + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], 353 + 354 + "find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], 355 + 356 + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], 357 + 358 + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], 359 + 360 + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], 361 + 362 + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], 363 + 364 + "globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="], 365 + 366 + "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], 367 + 368 + "gzip-size": ["gzip-size@6.0.0", "", { "dependencies": { "duplexer": "^0.1.2" } }, "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q=="], 369 + 370 + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], 371 + 372 + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], 373 + 374 + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], 375 + 376 + "is-fullwidth-code-point": ["is-fullwidth-code-point@2.0.0", "", {}, "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w=="], 377 + 378 + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], 379 + 380 + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], 381 + 382 + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], 383 + 384 + "iso-datestring-validator": ["iso-datestring-validator@2.2.2", "", {}, "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA=="], 385 + 386 + "jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], 387 + 388 + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], 389 + 390 + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], 391 + 392 + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], 393 + 394 + "kolorist": ["kolorist@1.8.0", "", {}, "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="], 395 + 396 + "local-pkg": ["local-pkg@1.1.1", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.0.1", "quansync": "^0.2.8" } }, "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg=="], 397 + 398 + "locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], 399 + 400 + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], 401 + 402 + "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], 403 + 404 + "lodash.throttle": ["lodash.throttle@4.1.1", "", {}, "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="], 405 + 406 + "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], 407 + 408 + "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], 409 + 410 + "mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="], 411 + 412 + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], 413 + 414 + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], 415 + 416 + "mlly": ["mlly@1.7.4", "", { "dependencies": { "acorn": "^8.14.0", "pathe": "^2.0.1", "pkg-types": "^1.3.0", "ufo": "^1.5.4" } }, "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw=="], 417 + 418 + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], 419 + 420 + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 421 + 422 + "multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 423 + 424 + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 425 + 426 + "node-fetch-native": ["node-fetch-native@1.6.6", "", {}, "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ=="], 427 + 428 + "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], 429 + 430 + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], 431 + 432 + "ofetch": ["ofetch@1.4.1", "", { "dependencies": { "destr": "^2.0.3", "node-fetch-native": "^1.6.4", "ufo": "^1.5.4" } }, "sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw=="], 433 + 434 + "p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], 435 + 436 + "p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], 437 + 438 + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], 439 + 440 + "package-manager-detector": ["package-manager-detector@0.2.11", "", { "dependencies": { "quansync": "^0.2.7" } }, "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ=="], 441 + 442 + "path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], 443 + 444 + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], 445 + 446 + "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], 447 + 448 + "perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="], 449 + 450 + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], 451 + 452 + "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], 453 + 454 + "pkg-types": ["pkg-types@2.1.0", "", { "dependencies": { "confbox": "^0.2.1", "exsolve": "^1.0.1", "pathe": "^2.0.3" } }, "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A=="], 455 + 456 + "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="], 457 + 458 + "quansync": ["quansync@0.2.10", "", {}, "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A=="], 459 + 460 + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], 461 + 462 + "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], 463 + 464 + "regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="], 465 + 466 + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], 467 + 468 + "require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="], 469 + 470 + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], 471 + 472 + "rollup": ["rollup@4.37.0", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.37.0", "@rollup/rollup-android-arm64": "4.37.0", "@rollup/rollup-darwin-arm64": "4.37.0", "@rollup/rollup-darwin-x64": "4.37.0", "@rollup/rollup-freebsd-arm64": "4.37.0", "@rollup/rollup-freebsd-x64": "4.37.0", "@rollup/rollup-linux-arm-gnueabihf": "4.37.0", "@rollup/rollup-linux-arm-musleabihf": "4.37.0", "@rollup/rollup-linux-arm64-gnu": "4.37.0", "@rollup/rollup-linux-arm64-musl": "4.37.0", "@rollup/rollup-linux-loongarch64-gnu": "4.37.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.37.0", "@rollup/rollup-linux-riscv64-gnu": "4.37.0", "@rollup/rollup-linux-riscv64-musl": "4.37.0", "@rollup/rollup-linux-s390x-gnu": "4.37.0", "@rollup/rollup-linux-x64-gnu": "4.37.0", "@rollup/rollup-linux-x64-musl": "4.37.0", "@rollup/rollup-win32-arm64-msvc": "4.37.0", "@rollup/rollup-win32-ia32-msvc": "4.37.0", "@rollup/rollup-win32-x64-msvc": "4.37.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg=="], 473 + 474 + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], 475 + 476 + "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], 477 + 478 + "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], 479 + 480 + "set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="], 481 + 482 + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], 483 + 484 + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], 485 + 486 + "shell-quote": ["shell-quote@1.8.2", "", {}, "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA=="], 487 + 488 + "sirv": ["sirv@2.0.4", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ=="], 489 + 490 + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], 491 + 492 + "spawn-command": ["spawn-command@0.0.2", "", {}, "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ=="], 493 + 494 + "string-width": ["string-width@3.1.0", "", { "dependencies": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } }, "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w=="], 495 + 496 + "strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "^4.1.0" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], 497 + 498 + "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], 499 + 500 + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], 501 + 502 + "tlds": ["tlds@1.256.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-ZmyVB9DAw+FFTmLElGYJgdZFsKLYd/I59Bg9NHkCGPwAbVZNRilFWDMAdX8UG+bHuv7kfursd5XGqo/9wi26lA=="], 503 + 504 + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], 505 + 506 + "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], 507 + 508 + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], 509 + 510 + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 511 + 512 + "ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="], 513 + 514 + "uint8arrays": ["uint8arrays@3.0.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA=="], 515 + 516 + "unconfig": ["unconfig@0.3.13", "", { "dependencies": { "@antfu/utils": "^0.7.7", "defu": "^6.1.4", "jiti": "^1.21.0" } }, "sha512-N9Ph5NC4+sqtcOjPfHrRcHekBCadCXWTBzp2VYYbySOHW0PfD9XLCeXshTXjkPYwLrBr9AtSeU0CZmkYECJhng=="], 517 + 518 + "unocss": ["unocss@0.58.9", "", { "dependencies": { "@unocss/astro": "0.58.9", "@unocss/cli": "0.58.9", "@unocss/core": "0.58.9", "@unocss/extractor-arbitrary-variants": "0.58.9", "@unocss/postcss": "0.58.9", "@unocss/preset-attributify": "0.58.9", "@unocss/preset-icons": "0.58.9", "@unocss/preset-mini": "0.58.9", "@unocss/preset-tagify": "0.58.9", "@unocss/preset-typography": "0.58.9", "@unocss/preset-uno": "0.58.9", "@unocss/preset-web-fonts": "0.58.9", "@unocss/preset-wind": "0.58.9", "@unocss/reset": "0.58.9", "@unocss/transformer-attributify-jsx": "0.58.9", "@unocss/transformer-attributify-jsx-babel": "0.58.9", "@unocss/transformer-compile-class": "0.58.9", "@unocss/transformer-directives": "0.58.9", "@unocss/transformer-variant-group": "0.58.9", "@unocss/vite": "0.58.9" }, "peerDependencies": { "@unocss/webpack": "0.58.9", "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0" }, "optionalPeers": ["@unocss/webpack", "vite"] }, "sha512-aqANXXP0RrtN4kSaTLn/7I6wh8o45LUdVgPzGu7Fan2DfH2+wpIs6frlnlHlOymnb+52dp6kXluQinddaUKW1A=="], 519 + 520 + "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], 521 + 522 + "vite": ["vite@5.4.15", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-6ANcZRivqL/4WtwPGTKNaosuNJr5tWiftOC7liM7G9+rMb8+oeJeyzymDu4rTN93seySBmbjSfsS3Vzr19KNtA=="], 523 + 524 + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], 525 + 526 + "which-module": ["which-module@2.0.1", "", {}, "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="], 527 + 528 + "wrap-ansi": ["wrap-ansi@5.1.0", "", { "dependencies": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", "strip-ansi": "^5.0.0" } }, "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q=="], 529 + 530 + "y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], 531 + 532 + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], 533 + 534 + "yargs": ["yargs@13.3.2", "", { "dependencies": { "cliui": "^5.0.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^13.1.2" } }, "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw=="], 535 + 536 + "yargs-parser": ["yargs-parser@13.1.2", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg=="], 537 + 538 + "zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], 539 + 540 + "@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], 541 + 542 + "@iconify/utils/@antfu/utils": ["@antfu/utils@8.1.1", "", {}, "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ=="], 543 + 544 + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], 545 + 546 + "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], 547 + 548 + "concurrently/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=="], 549 + 550 + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], 551 + 552 + "mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], 553 + 554 + "mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], 555 + 556 + "pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], 557 + 558 + "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], 559 + 560 + "rollup/@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="], 561 + 562 + "vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], 563 + 564 + "wrap-ansi/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], 565 + 566 + "concurrently/yargs/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=="], 567 + 568 + "concurrently/yargs/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=="], 569 + 570 + "concurrently/yargs/y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], 571 + 572 + "concurrently/yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], 573 + 574 + "mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], 575 + 576 + "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], 577 + 578 + "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], 579 + 580 + "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], 581 + 582 + "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], 583 + 584 + "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], 585 + 586 + "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], 587 + 588 + "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], 589 + 590 + "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], 591 + 592 + "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], 593 + 594 + "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], 595 + 596 + "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], 597 + 598 + "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], 599 + 600 + "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], 601 + 602 + "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], 603 + 604 + "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], 605 + 606 + "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], 607 + 608 + "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], 609 + 610 + "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], 611 + 612 + "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], 613 + 614 + "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], 615 + 616 + "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], 617 + 618 + "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], 619 + 620 + "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], 621 + 622 + "wrap-ansi/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], 623 + 624 + "concurrently/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], 625 + 626 + "concurrently/yargs/cliui/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=="], 627 + 628 + "concurrently/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], 629 + 630 + "concurrently/yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], 631 + 632 + "concurrently/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], 633 + 634 + "wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], 635 + 636 + "concurrently/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], 637 + 638 + "concurrently/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], 639 + } 640 + }
+35
manifest.json
··· 1 + { 2 + "manifest_version": 3, 3 + "name": "skeet.FYI", 4 + "version": "1.1.1", 5 + "description": "chrome extension for skeeting tweets at the sky", 6 + "icons": { 7 + "16": "assets/icon/icon-16.png", 8 + "32": "assets/icon/icon-32.png", 9 + "48": "assets/icon/icon-48.png", 10 + "128": "assets/icon/icon-128.png" 11 + }, 12 + "permissions": ["storage", "tabs", "activeTab", "scripting"], 13 + "action": { 14 + "default_popup": "pages/popup.html" 15 + }, 16 + "background": { 17 + "service_worker": "scripts/background.js" 18 + }, 19 + "content_scripts": [ 20 + { 21 + "js": ["scripts/content-script.js"], 22 + "matches": ["https://skeet.fyi/oauth-callback*"], 23 + "run_at": "document_start" 24 + } 25 + ], 26 + "externally_connectable": { 27 + "matches": ["https://skeet.fyi/*"] 28 + }, 29 + "web_accessible_resources": [ 30 + { 31 + "resources": ["scripts/extension-id-provider.js"], 32 + "matches": ["https://skeet.fyi/*"] 33 + } 34 + ] 35 + }
+36
package.json
··· 1 + { 2 + "name": "skeet-fyi", 3 + "version": "1.1.1", 4 + "description": "chrome extension for skeeting tweets at the sky", 5 + "private": true, 6 + "type": "module", 7 + "scripts": { 8 + "build:js": "bun run build.js", 9 + "build:css": "unocss \"src/**/*.{html,js,ts}\" -o dist/styles.css", 10 + "build": "bun run build:js && bun run build:css", 11 + "dev": "bun run build && bun run watch", 12 + "watch": "concurrently \"chokidar \\\"src/**/*.{json,js,ts,html,css,png}\\\" \\\"manifest.json\\\" --ignore \\\"**/dist/**\\\" --ignore \\\"**/node_modules/**\\\" -c \\\"bun run build:oauth\\\"\" \"unocss \\\"src/**/*.{html,js,ts}\\\" --watch -o dist/styles.css\"", 13 + "clean": "rm -rf dist", 14 + "format": "biome format --write .", 15 + "lint": "biome lint .", 16 + "test": "echo \"Error: no test specified\" && exit 1" 17 + }, 18 + "keywords": ["chrome-extension", "manifest-v3"], 19 + "author": "", 20 + "license": "MIT", 21 + "devDependencies": { 22 + "@biomejs/biome": "^1.9.4", 23 + "@unocss/cli": "^0.58.5", 24 + "@unocss/preset-uno": "^0.58.5", 25 + "@unocss/preset-wind": "^0.58.5", 26 + "@unocss/reset": "^0.58.5", 27 + "chokidar-cli": "^3.0.0", 28 + "concurrently": "^8.2.2", 29 + "cross-env": "^7.0.3", 30 + "esbuild": "^0.20.1", 31 + "unocss": "^0.58.5" 32 + }, 33 + "dependencies": { 34 + "@atproto/api": "^0.14.10" 35 + } 36 + }
+219
src/assets/css/styles.css
··· 1 + /* Base styles */ 2 + @import "@unocss/reset/tailwind.css"; 3 + 4 + /* Custom Properties */ 5 + :root { 6 + --primary-50: rgb(240 249 255); 7 + --primary-100: rgb(224 242 254); 8 + --primary-200: rgb(186 230 253); 9 + --primary-300: rgb(125 211 252); 10 + --primary-400: rgb(56 189 248); 11 + --primary-500: rgb(14 165 233); 12 + --primary-600: rgb(2 132 199); 13 + --primary-700: rgb(3 105 161); 14 + --primary-800: rgb(7 89 133); 15 + --primary-900: rgb(12 74 110); 16 + } 17 + 18 + /* Utility classes */ 19 + .space-y-4 > * + * { 20 + margin-top: 1rem; 21 + } 22 + 23 + .space-y-2 > * + * { 24 + margin-top: 0.5rem; 25 + } 26 + 27 + .space-y-0\.5 > * + * { 28 + margin-top: 0.125rem; 29 + } 30 + 31 + .bg-primary-600 { 32 + background-color: var(--primary-600); 33 + } 34 + 35 + .bg-primary-700 { 36 + background-color: var(--primary-700); 37 + } 38 + 39 + .bg-primary-800 { 40 + background-color: var(--primary-800); 41 + } 42 + 43 + .bg-red-50 { 44 + background-color: rgb(254 242 242); 45 + } 46 + 47 + .text-red-600 { 48 + color: rgb(220 38 38); 49 + } 50 + 51 + .shadow-lg { 52 + box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); 53 + } 54 + 55 + .font-medium { 56 + font-weight: 500; 57 + } 58 + 59 + .transition-all { 60 + transition-property: all; 61 + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 62 + transition-duration: 200ms; 63 + } 64 + 65 + .transition-colors { 66 + transition-property: color, background-color, border-color; 67 + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 68 + transition-duration: 200ms; 69 + } 70 + 71 + .duration-200 { 72 + transition-duration: 200ms; 73 + } 74 + 75 + .ease-in-out { 76 + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 77 + } 78 + 79 + .animate-pulse { 80 + animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; 81 + } 82 + 83 + @keyframes pulse { 84 + 0%, 85 + 100% { 86 + opacity: 1; 87 + } 88 + 50% { 89 + opacity: 0.5; 90 + } 91 + } 92 + 93 + /* Form elements */ 94 + input:focus { 95 + outline: none; 96 + border-color: transparent; 97 + box-shadow: 0 0 0 2px var(--primary-500); 98 + } 99 + 100 + button:disabled { 101 + opacity: 0.5; 102 + cursor: not-allowed; 103 + } 104 + 105 + /* Hover states */ 106 + .hover\:bg-primary-700:hover { 107 + background-color: var(--primary-700); 108 + } 109 + 110 + .hover\:text-red-600:hover { 111 + color: rgb(220 38 38); 112 + } 113 + 114 + .hover\:border-red-200:hover { 115 + border-color: rgb(254 202 202); 116 + } 117 + 118 + .hover\:bg-red-50:hover { 119 + background-color: rgb(254 242 242); 120 + } 121 + 122 + .active\:bg-primary-800:active { 123 + background-color: var(--primary-800); 124 + } 125 + 126 + /* Additional utility classes */ 127 + .block { 128 + display: block; 129 + } 130 + 131 + .inline-block { 132 + display: inline-block; 133 + } 134 + 135 + .p-6 { 136 + padding: 1.5rem; 137 + } 138 + 139 + .px-4 { 140 + padding-left: 1rem; 141 + padding-right: 1rem; 142 + } 143 + 144 + .py-2\.5 { 145 + padding-top: 0.625rem; 146 + padding-bottom: 0.625rem; 147 + } 148 + 149 + .px-3 { 150 + padding-left: 0.75rem; 151 + padding-right: 0.75rem; 152 + } 153 + 154 + .py-1\.5 { 155 + padding-top: 0.375rem; 156 + padding-bottom: 0.375rem; 157 + } 158 + 159 + .mt-3 { 160 + margin-top: 0.75rem; 161 + } 162 + 163 + .rounded-lg { 164 + border-radius: 0.5rem; 165 + } 166 + 167 + .text-sm { 168 + font-size: 0.875rem; 169 + line-height: 1.25rem; 170 + } 171 + 172 + .text-gray-400 { 173 + color: rgb(156 163 175); 174 + } 175 + 176 + .text-gray-600 { 177 + color: rgb(75 85 99); 178 + } 179 + 180 + .placeholder\:text-gray-400::placeholder { 181 + color: rgb(156 163 175); 182 + } 183 + 184 + .w-full { 185 + width: 100%; 186 + } 187 + 188 + .min-h-\[200px\] { 189 + min-height: 200px; 190 + } 191 + 192 + .border-gray-100 { 193 + border-color: rgb(243 244 246); 194 + } 195 + 196 + .border-gray-200 { 197 + border-color: rgb(229 231 235); 198 + } 199 + 200 + .bg-gray-50 { 201 + background-color: rgb(249 250 251); 202 + } 203 + 204 + .focus\:ring-2:focus { 205 + box-shadow: 0 0 0 2px var(--primary-500); 206 + } 207 + 208 + .focus\:ring-primary-500:focus { 209 + --ring-color: var(--primary-500); 210 + } 211 + 212 + .focus\:border-transparent:focus { 213 + border-color: transparent; 214 + } 215 + 216 + .focus\:outline-none:focus { 217 + outline: 2px solid transparent; 218 + outline-offset: 2px; 219 + }
src/assets/icon/icon-128.png

This is a binary file and will not be displayed.

src/assets/icon/icon-16.png

This is a binary file and will not be displayed.

src/assets/icon/icon-32.png

This is a binary file and will not be displayed.

src/assets/icon/icon-48.png

This is a binary file and will not be displayed.

+69
src/assets/logo.svg
··· 1 + <?xml version="1.0" standalone="no"?> 2 + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" 3 + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> 4 + <svg version="1.0" xmlns="http://www.w3.org/2000/svg" 5 + width="1500.000000pt" height="972.000000pt" viewBox="0 0 1500.000000 972.000000" 6 + preserveAspectRatio="xMidYMid meet"> 7 + 8 + <g transform="translate(0.000000,972.000000) scale(0.100000,-0.100000)" 9 + fill="#000000" stroke="none"> 10 + <path d="M150 4860 l0 -4770 4765 0 4765 0 0 935 0 935 -75 0 -75 0 0 -855 0 11 + -855 -4610 0 -4610 0 0 4610 0 4610 4610 0 4610 0 0 -855 0 -855 75 0 75 0 0 12 + 935 0 935 -4765 0 -4765 0 0 -4770z"/> 13 + <path d="M5465 5578 c-2 -7 -3 -391 -2 -853 l2 -840 125 0 125 0 7 60 c5 33 5 14 + 87 0 120 -4 33 -4 89 0 124 4 36 4 91 -1 123 l-8 58 89 0 88 0 -5 -77 c-4 -43 15 + -2 -98 2 -123 l8 -45 57 -3 57 -3 -1 -109 c0 -60 3 -114 7 -120 4 -6 81 -10 16 + 220 -10 l213 0 8 67 c3 36 3 92 -2 122 l-9 56 -150 3 -150 2 3 96 c6 140 4 17 + 144 -66 144 l-57 0 0 120 0 120 57 0 57 0 7 34 c3 19 4 76 3 125 l-4 91 121 0 18 + 122 0 7 65 c3 35 3 89 0 120 l-7 55 -187 -2 -186 -3 -6 -55 c-3 -30 -3 -83 1 19 + -117 l6 -62 -60 -3 -61 -3 -8 -45 c-4 -25 -5 -80 -2 -122 l6 -78 -86 0 -86 0 20 + 2 83 c1 45 2 119 2 165 -1 101 -1 144 -1 252 1 47 1 103 1 125 0 22 0 76 0 21 + 120 1 124 -3 217 -9 226 -9 15 -244 11 -249 -3z"/> 22 + <path d="M9367 5543 c-3 -27 -4 -137 -3 -245 l3 -198 -117 0 c-137 0 -130 7 23 + -130 -120 0 -127 -7 -120 129 -120 l117 0 -1 -330 c-1 -182 1 -348 4 -368 l6 24 + -37 57 -3 57 -3 -1 -109 c0 -60 3 -114 7 -120 4 -6 90 -10 250 -10 l244 0 7 25 + 56 c7 58 1 165 -11 183 -4 7 -68 11 -183 11 l-177 0 0 365 0 365 181 0 181 0 26 + 7 38 c8 48 8 131 0 171 l-6 31 -182 0 -181 0 3 222 c1 123 0 233 -3 246 -5 21 27 + -9 22 -129 22 l-123 0 -6 -47z"/> 28 + <path d="M11688 5543 c-5 -40 -4 -1506 1 -1625 l1 -38 125 0 c121 0 125 1 130 29 + 23 3 12 4 176 2 365 l-2 342 241 0 242 0 6 31 c8 40 8 167 0 197 l-6 22 -242 30 + 0 -241 0 0 245 0 245 241 0 242 0 6 23 c3 12 6 56 6 97 0 41 -3 85 -6 98 l-6 31 + 22 -368 0 -367 0 -5 -47z"/> 32 + <path d="M12786 5538 c-6 -70 -7 -319 0 -385 l5 -53 61 0 61 0 -7 -56 c-3 -31 33 + -3 -85 0 -120 l7 -64 61 0 61 0 -3 -101 c-5 -146 -4 -149 66 -149 l57 0 -2 34 + -332 c-2 -183 0 -348 2 -365 l6 -33 123 0 124 0 5 53 c3 28 5 193 4 365 l-2 35 + 312 57 0 57 0 7 46 c4 26 4 82 1 125 l-5 79 59 0 c71 0 73 3 67 145 l-3 95 57 36 + 0 c52 0 58 2 63 23 3 12 4 121 3 242 l-3 220 -123 3 c-100 2 -123 0 -128 -12 37 + -8 -20 -10 -209 -5 -393 l2 -83 -60 0 -60 0 -6 -55 c-4 -30 -4 -84 0 -120 l7 38 + -65 -119 0 -118 0 0 117 0 118 -60 3 -60 3 3 212 c1 117 0 227 -3 245 l-6 32 39 + -124 0 -124 0 -5 -52z"/> 40 + <path d="M14194 5577 c-2 -7 -3 -60 -2 -118 l3 -104 90 -3 90 -3 0 -609 0 41 + -610 -86 0 c-70 0 -88 -3 -93 -16 -8 -20 -8 -198 0 -218 5 -14 42 -16 309 -16 42 + l303 0 6 23 c3 12 6 58 6 102 0 129 3 125 -99 125 l-86 0 0 610 0 610 86 0 43 + c70 0 88 3 93 16 3 9 6 55 6 104 0 49 -3 95 -6 104 -5 14 -42 16 -310 16 -243 44 + 0 -306 -3 -310 -13z"/> 45 + <path d="M4424 5076 c-3 -14 -4 -68 -2 -120 l3 -95 -60 -3 -60 -3 -3 -100 c-4 46 + -144 -4 -145 66 -145 l57 0 -3 -95 c-2 -53 -1 -107 2 -120 l6 -25 243 0 242 0 47 + 0 -120 0 -120 -271 0 c-239 0 -273 -2 -278 -16 -3 -9 -6 -58 -6 -109 0 -51 3 48 + -100 6 -109 5 -14 45 -16 340 -16 l334 0 6 24 c3 13 4 66 2 119 l-3 96 60 3 49 + 60 3 8 64 c4 34 4 88 0 120 l-8 56 -60 3 -60 3 0 117 0 117 -241 3 -242 2 0 50 + 125 1 125 271 2 271 3 6 60 c3 33 3 85 0 115 l-6 55 -337 3 -338 2 -6 -24z"/> 51 + <path d="M6924 5054 c-4 -26 -4 -80 -1 -120 l5 -74 -73 0 -74 0 -7 -35 c-3 52 + -20 -4 -76 -2 -125 l4 -89 -45 -3 -46 -3 -3 -95 c-4 -133 -1 -140 51 -140 l43 53 + 0 -4 -90 c-2 -49 -1 -105 2 -125 l7 -35 74 0 74 0 -6 -64 c-3 -35 -2 -89 1 54 + -120 l7 -56 309 0 308 0 7 73 c4 39 3 95 -2 122 l-8 50 -255 3 -255 2 0 120 0 55 + 120 317 0 316 0 6 48 c3 26 5 115 5 197 0 83 -2 171 -5 198 l-6 47 -60 0 -60 56 + 0 7 65 c3 35 3 89 0 120 l-7 55 -309 0 -308 0 -7 -46z m491 -319 l0 -125 -190 57 + 0 -190 0 0 125 0 125 190 0 190 0 0 -125z"/> 58 + <path d="M8144 5044 c-3 -31 -4 -85 0 -120 l7 -64 -75 0 -75 0 -7 -36 c-4 -20 59 + -4 -76 -2 -125 l5 -89 -42 0 c-53 0 -55 -5 -55 -120 0 -115 2 -120 54 -120 60 + l42 0 -4 -97 c-2 -55 1 -110 7 -125 10 -27 13 -28 81 -28 l71 0 -7 -64 c-4 61 + -35 -3 -89 0 -120 l7 -56 309 0 308 0 8 67 c3 36 3 92 -2 122 l-9 56 -255 3 62 + -255 2 0 120 0 120 317 0 316 0 6 38 c3 20 5 114 5 207 0 94 -2 187 -5 208 63 + l-6 37 -59 0 -60 0 7 64 c4 35 3 89 0 120 l-7 56 -309 0 -309 0 -7 -56z m491 64 + -309 l0 -125 -190 0 -190 0 0 125 0 125 190 0 190 0 0 -125z"/> 65 + <path d="M10685 4358 c-3 -7 -4 -116 -2 -243 l2 -230 155 0 155 0 8 60 c5 33 66 + 5 87 0 120 -5 33 -5 83 -1 110 5 28 6 83 2 123 l-6 72 -154 0 c-115 0 -156 -3 67 + -159 -12z"/> 68 + </g> 69 + </svg>
+629
src/lib/api.ts
··· 1 + /** 2 + * Utility functions for making authenticated requests to Bluesky PDS using OAuth tokens with DPoP 3 + */ 4 + 5 + /** 6 + * Generate a DPoP token for a request 7 + * @param {Object} dpopKey - The DPoP key from the session 8 + * @param {string} method - HTTP method (GET, POST, etc.) 9 + * @param {string} url - Full URL of the request 10 + * @param {string|null} nonce - Optional nonce from previous response 11 + * @param {string|null} accessTokenHash - Optional hash of the access token 12 + * @returns {Promise<string>} - DPoP token 13 + */ 14 + async function generateDpopToken(dpopKey, method, url, nonce, accessTokenHash) { 15 + try { 16 + // console.log(`Generating DPoP token for ${method} ${url}${nonce ? ' with nonce' : ''}`); 17 + 18 + // For DPoP we need to use the jwk from the header 19 + const jwtParts = dpopKey.jwt.split('.'); 20 + const headerJson = urlSafeBase64Decode(jwtParts[0]); 21 + const header = JSON.parse(headerJson); 22 + const jwk = header.jwk; 23 + 24 + // console.log('JWT header parsed successfully'); 25 + 26 + // Create a random JTI (JWT ID) - similar to generateToken() in Python 27 + const jti = Array.from(crypto.getRandomValues(new Uint8Array(16))) 28 + .map(b => b.toString(16).padStart(2, '0')) 29 + .join(''); 30 + 31 + // Create the DPoP token header 32 + const dpopHeader = { 33 + typ: "dpop+jwt", 34 + alg: "ES256", 35 + jwk 36 + }; 37 + 38 + // Create the DPoP token payload - match the Python authserver_dpop_jwt function 39 + const now = Math.floor(Date.now() / 1000); 40 + // Create payload with TypeScript-friendly approach 41 + const dpopPayload = { 42 + jti, 43 + htm: method, 44 + htu: url, 45 + iat: now, 46 + // Match Python's 30-second expiration 47 + exp: now + 30, 48 + // Initialize optional fields with undefined 49 + nonce: undefined, 50 + ath: undefined 51 + }; 52 + 53 + // Add nonce if provided - match how Python handles this 54 + if (nonce) { 55 + dpopPayload.nonce = nonce; 56 + // console.log(`Using nonce: ${nonce}`); 57 + } 58 + 59 + // Add access token hash if provided (ath field) 60 + if (accessTokenHash) { 61 + dpopPayload.ath = accessTokenHash; 62 + // console.log('Using access token hash'); 63 + } 64 + 65 + // Encode header and payload using URL-safe base64 66 + const encodedHeader = urlSafeBase64Encode(JSON.stringify(dpopHeader)); 67 + const encodedPayload = urlSafeBase64Encode(JSON.stringify(dpopPayload)); 68 + 69 + // Create the signing input 70 + const signingInput = `${encodedHeader}.${encodedPayload}`; 71 + 72 + // Import the private key 73 + const privateKey = await crypto.subtle.importKey( 74 + 'pkcs8', 75 + _base64ToArrayBuffer(dpopKey.key), 76 + { 77 + name: 'ECDSA', 78 + namedCurve: 'P-256' 79 + }, 80 + false, 81 + ['sign'] 82 + ); 83 + 84 + // Sign the token 85 + const signature = await crypto.subtle.sign( 86 + { 87 + name: 'ECDSA', 88 + hash: { name: 'SHA-256' } 89 + }, 90 + privateKey, 91 + new TextEncoder().encode(signingInput) 92 + ); 93 + 94 + // Encode the signature using URL-safe base64 95 + const encodedSignature = urlSafeBase64EncodeBuf(signature); 96 + 97 + // console.log(`DPoP token generated successfully`); 98 + 99 + // Return the complete DPoP token 100 + return `${signingInput}.${encodedSignature}`; 101 + } catch (error) { 102 + console.error('Error generating DPoP token:', error); 103 + throw error; 104 + } 105 + } 106 + 107 + /** 108 + * URL-safe base64 encode 109 + * @param {string} str - String to encode 110 + * @returns {string} - URL-safe base64 encoded string 111 + */ 112 + function urlSafeBase64Encode(str) { 113 + return btoa(str) 114 + .replace(/\+/g, '-') 115 + .replace(/\//g, '_') 116 + .replace(/=/g, ''); 117 + } 118 + 119 + /** 120 + * URL-safe base64 encode for ArrayBuffer 121 + * @param {ArrayBuffer} buf - Buffer to encode 122 + * @returns {string} - URL-safe base64 encoded string 123 + */ 124 + function urlSafeBase64EncodeBuf(buf) { 125 + const bytes = new Uint8Array(buf); 126 + let binary = ''; 127 + for (let i = 0; i < bytes.byteLength; i++) { 128 + binary += String.fromCharCode(bytes[i]); 129 + } 130 + return btoa(binary) 131 + .replace(/\+/g, '-') 132 + .replace(/\//g, '_') 133 + .replace(/=/g, ''); 134 + } 135 + 136 + /** 137 + * URL-safe base64 decode 138 + * @param {string} str - URL-safe base64 encoded string 139 + * @returns {string} - Decoded string 140 + */ 141 + function urlSafeBase64Decode(str) { 142 + // Replace URL-safe characters and add padding 143 + const base64 = str.replace(/-/g, '+').replace(/_/g, '/'); 144 + const paddedBase64 = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, '='); 145 + 146 + // Decode 147 + return atob(paddedBase64); 148 + } 149 + 150 + /** 151 + * Convert base64 to ArrayBuffer 152 + * @param {string} base64 - Base64 string 153 + * @returns {ArrayBuffer} - ArrayBuffer 154 + */ 155 + function _base64ToArrayBuffer(base64) { 156 + // Handle URL-safe base64 157 + const base64Str = base64.replace(/-/g, '+').replace(/_/g, '/'); 158 + const paddedStr = base64Str.padEnd(base64Str.length + (4 - base64Str.length % 4) % 4, '='); 159 + 160 + const binary = atob(paddedStr); 161 + const bytes = new Uint8Array(binary.length); 162 + for (let i = 0; i < binary.length; i++) { 163 + bytes[i] = binary.charCodeAt(i); 164 + } 165 + return bytes.buffer; 166 + } 167 + 168 + /** 169 + * Calculate SHA-256 hash of a string (for PKCE S256 code challenge) 170 + * @param {string} str - String to hash 171 + * @returns {Promise<string>} - Base64url-encoded SHA-256 hash 172 + */ 173 + async function sha256(str) { 174 + try { 175 + // Encode the string as UTF-8 176 + const data = new TextEncoder().encode(str); 177 + 178 + // Calculate the SHA-256 hash 179 + const hashBuffer = await crypto.subtle.digest('SHA-256', data); 180 + 181 + // Convert to base64url encoding 182 + return urlSafeBase64EncodeBuf(hashBuffer); 183 + } catch (error) { 184 + console.error('Error calculating SHA-256 hash:', error); 185 + throw error; 186 + } 187 + } 188 + 189 + /** 190 + * Get the profile information for a user 191 + * @param {string} [userDid] - The DID of the user to fetch (defaults to current user) 192 + * @returns {Promise<Object>} - User profile data 193 + */ 194 + export async function getUserProfile(userDid) { 195 + try { 196 + // If no userDid provided, use the authenticated user's DID 197 + if (!userDid) { 198 + const { did } = await getOAuthSession(); 199 + userDid = did; 200 + } 201 + 202 + // console.log(`Fetching profile for user: ${userDid}`); 203 + 204 + // Use the repo.getRecord endpoint to fetch the profile 205 + // This endpoint requires the repo (user DID), collection, and rkey parameters 206 + const endpoint = `/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(userDid)}&collection=app.bsky.actor.profile&rkey=self`; 207 + 208 + // Make the authenticated request 209 + const profileData = await pdsAuthedReq('GET', endpoint, null); 210 + 211 + // console.log('Profile data retrieved successfully'); 212 + 213 + return profileData; 214 + } catch (error) { 215 + console.error('Error fetching user profile:', error); 216 + throw error; 217 + } 218 + } 219 + 220 + /** 221 + * Get the avatar image URL for a user 222 + * @param {Object} profileData - The profile data returned from getUserProfile 223 + * @returns {string|null} - The URL to the avatar image, or null if not available 224 + */ 225 + export function getAvatarUrl(profileData) { 226 + try { 227 + // Check if the profile has an avatar 228 + // Based on the actual structure shown in the example 229 + if ( 230 + profileData?.raw?.value?.avatar?.ref?.$link 231 + ) { 232 + // Extract the necessary information 233 + const userDid = profileData.did || profileData.raw.uri.split('/')[2]; // Extract DID from URI 234 + const avatarCid = profileData.raw.value.avatar.ref.$link; 235 + 236 + // Get the PDS URL from the session 237 + // For this we'll need to access the session data 238 + const getSessionData = async () => { 239 + const { session } = await getOAuthSession(); 240 + return session.info.aud; 241 + }; 242 + 243 + // We need to return a promise since we have async operations 244 + return getSessionData().then(pdsUrl => { 245 + // Construct the avatar URL with the correct PDS URL 246 + const avatarUrl = `${pdsUrl}xrpc/com.atproto.sync.getBlob?did=${encodeURIComponent(userDid)}&cid=${encodeURIComponent(avatarCid)}`; 247 + 248 + // console.log(`Avatar URL constructed: ${avatarUrl}`); 249 + 250 + return avatarUrl; 251 + }); 252 + } 253 + 254 + // console.log('No avatar found in profile data'); 255 + return null; 256 + } catch (error) { 257 + console.error('Error constructing avatar URL:', error); 258 + return null; 259 + } 260 + } 261 + 262 + /** 263 + * Get full profile information including a constructed avatar URL 264 + * @param {string} [userDid] - The DID of the user to fetch (defaults to current user) 265 + * @returns {Promise<Object>} - Enhanced user profile data with avatar URL 266 + */ 267 + export async function getFullProfile(userDid) { 268 + try { 269 + // Get the profile data 270 + const profileData = await getUserProfile(userDid); 271 + 272 + // Create an enhanced profile object with key information extracted 273 + const enhancedProfile = { 274 + did: profileData.uri.split('/')[2], 275 + handle: null, // We need an additional API call to get this 276 + displayName: profileData.value?.displayName || null, 277 + description: profileData.value?.description || null, 278 + avatar: '', // Will be populated later 279 + raw: profileData // Include the raw data for further processing if needed 280 + }; 281 + 282 + // Get the avatar URL - this is now async 283 + const avatarUrlResult = await getAvatarUrl(enhancedProfile); 284 + if (avatarUrlResult) { 285 + enhancedProfile.avatar = avatarUrlResult; 286 + } 287 + 288 + // If we have the DID, get the handle 289 + if (enhancedProfile.did) { 290 + try { 291 + // We need to use the correct endpoint for resolving a DID to handle 292 + // This should be com.atproto.identity.getHandle but we're simplifying for now 293 + const handleData = await pdsAuthedReq( 294 + 'GET', 295 + `/xrpc/com.atproto.repo.describeRepo?repo=${encodeURIComponent(enhancedProfile.did)}`, 296 + null 297 + ); 298 + 299 + if (handleData && handleData.handle) { 300 + enhancedProfile.handle = handleData.handle; 301 + } 302 + } catch (err) { 303 + console.warn('Could not resolve handle from DID:', err); 304 + // Continue without the handle 305 + } 306 + } 307 + 308 + // console.log('Enhanced profile:', enhancedProfile); 309 + 310 + return enhancedProfile; 311 + } catch (error) { 312 + console.error('Error getting full profile:', error); 313 + throw error; 314 + } 315 + } 316 + 317 + /** 318 + * Resolve a handle to a DID or vice versa 319 + * @param {string} identifier - Either a handle (e.g., user.bsky.social) or a DID 320 + * @returns {Promise<Object>} - Resolution data 321 + */ 322 + export async function resolveIdentifier(identifier) { 323 + try { 324 + let endpoint; 325 + 326 + if (identifier.startsWith('did:')) { 327 + // Resolving a DID to a handle 328 + endpoint = `/xrpc/com.atproto.identity.resolveHandle?handle=${encodeURIComponent(identifier)}`; 329 + } else { 330 + // Resolving a handle to a DID 331 + endpoint = `/xrpc/com.atproto.identity.resolveHandle?handle=${encodeURIComponent(identifier)}`; 332 + } 333 + 334 + const resolutionData = await pdsAuthedReq('GET', endpoint, null); 335 + 336 + // console.log(`Resolved ${identifier} successfully:`, resolutionData); 337 + 338 + return resolutionData; 339 + } catch (error) { 340 + console.error(`Error resolving identifier ${identifier}:`, error); 341 + throw error; 342 + } 343 + } 344 + 345 + /** 346 + * Get the OAuth session data from Chrome storage 347 + * @returns {Promise<Object>} - Session data 348 + */ 349 + async function getOAuthSession() { 350 + // Get the stored OAuth data 351 + const storedData = await chrome.storage.local.get([ 352 + 'atcute-oauth:sessions' 353 + ]); 354 + 355 + if (!storedData || !storedData['atcute-oauth:sessions']) { 356 + throw new Error('No OAuth session found'); 357 + } 358 + 359 + const sessionsObj = storedData['atcute-oauth:sessions']; 360 + const sessionKeys = Object.keys(sessionsObj); 361 + 362 + if (!sessionKeys.length) { 363 + throw new Error('No OAuth sessions available'); 364 + } 365 + 366 + // Get the first session (the DID) 367 + const did = sessionKeys[0]; 368 + const session = sessionsObj[did].value; 369 + 370 + if (!session?.token?.access) { 371 + throw new Error('Invalid OAuth session: missing access token'); 372 + } 373 + 374 + return { 375 + did, 376 + session, 377 + accessToken: session.token.access 378 + }; 379 + } 380 + 381 + /** 382 + * Get the DPoP key from the OAuth states 383 + * @returns {Promise<Object>} - DPoP key 384 + */ 385 + async function getDpopKey() { 386 + const storedData = await chrome.storage.local.get(['atcute-oauth:states']); 387 + 388 + if (!storedData || !storedData['atcute-oauth:states']) { 389 + throw new Error('No OAuth states found'); 390 + } 391 + 392 + const statesObj = storedData['atcute-oauth:states']; 393 + 394 + // Find the most recent state with a dpopKey 395 + let dpopKey = null; 396 + let latestExpiresAt = 0; 397 + 398 + // Use a type-safe approach for iterating through states 399 + Object.entries(statesObj).forEach(([stateKey, stateData]) => { 400 + // Cast the unknown state to a type with expected properties 401 + const state = stateData as { 402 + value?: { dpopKey?: any }, 403 + expiresAt?: number 404 + }; 405 + 406 + if (state.value?.dpopKey && state.expiresAt && state.expiresAt > latestExpiresAt) { 407 + dpopKey = state.value.dpopKey; 408 + latestExpiresAt = state.expiresAt; 409 + } 410 + }); 411 + 412 + if (!dpopKey) { 413 + throw new Error('No DPoP key found in states'); 414 + } 415 + 416 + return dpopKey; 417 + } 418 + 419 + /** 420 + * Store a DPoP nonce for a specific origin 421 + * @param {string} origin - The origin domain 422 + * @param {string} nonce - The nonce value 423 + * @returns {Promise<void>} 424 + */ 425 + async function storeDpopNonce(origin, nonce) { 426 + // Get current nonces 427 + const storedData = await chrome.storage.local.get(['atcute-oauth:dpopNonces']); 428 + const noncesObj = storedData['atcute-oauth:dpopNonces'] || {}; 429 + 430 + // Update with new nonce 431 + noncesObj[origin] = { 432 + value: nonce, 433 + expiresAt: Date.now() + 600000 // 10 minutes, matching Python's 10 minute expiry 434 + }; 435 + 436 + // Store updated nonces 437 + await chrome.storage.local.set({ 'atcute-oauth:dpopNonces': noncesObj }); 438 + // console.log(`Stored new DPoP nonce for ${origin}: ${nonce}`); 439 + } 440 + 441 + /** 442 + * Get a stored DPoP nonce for a specific origin 443 + * @param {string} origin - The origin domain 444 + * @returns {Promise<string|null>} - The nonce or null if not found 445 + */ 446 + async function getDpopNonce(origin) { 447 + const storedData = await chrome.storage.local.get(['atcute-oauth:dpopNonces']); 448 + const noncesObj = storedData['atcute-oauth:dpopNonces']; 449 + 450 + if (noncesObj && noncesObj[origin] && noncesObj[origin].value) { 451 + return noncesObj[origin].value; 452 + } 453 + 454 + return null; 455 + } 456 + 457 + /** 458 + * Make an authenticated request to the Bluesky PDS using DPoP 459 + * @param {string} method - HTTP method (GET, POST, etc.) 460 + * @param {string} endpoint - PDS endpoint (e.g., /xrpc/com.atproto.repo.createRecord) 461 + * @param {Object|null} body - Request body (for POST, PUT, etc.) 462 + * @returns {Promise<Object>} - Response data 463 + */ 464 + export async function pdsAuthedReq(method, endpoint, body) { 465 + try { 466 + // Get the OAuth session 467 + const { did, session, accessToken } = await getOAuthSession(); 468 + 469 + // Get the DPoP key 470 + const dpopKey = await getDpopKey(); 471 + 472 + // CRITICAL: Verify that the endpoint starts with /xrpc/com.atproto. 473 + if (!endpoint.startsWith('/xrpc/com.atproto.')) { 474 + throw new Error('OAuth tokens can only be used with PDS endpoints (/xrpc/com.atproto.*)'); 475 + } 476 + 477 + // Get the PDS URL from the session's audience field (aud) - this is crucial 478 + // In Python this is getting audit from identityData.identity.pds.href 479 + const pdsUrl = session.info.aud; 480 + 481 + if (!pdsUrl) { 482 + throw new Error('No PDS URL (aud) found in session'); 483 + } 484 + 485 + // Construct the full URL - ensure no double slashes 486 + const url = pdsUrl.endsWith('/') && endpoint.startsWith('/') 487 + ? `${pdsUrl}${endpoint.substring(1)}` 488 + : `${pdsUrl}${endpoint}`; 489 + 490 + // console.log(`Making authenticated request to: ${method} ${url}`); 491 + 492 + // Get the origin for nonce storage 493 + const urlObj = new URL(url); 494 + const origin = urlObj.origin; 495 + 496 + // Get stored nonce for this origin if available 497 + const nonce = await getDpopNonce(origin); 498 + 499 + // Calculate the access token hash for the DPoP token (ath field) 500 + const accessTokenHash = await sha256(accessToken); 501 + 502 + // Generate the DPoP token with the access token hash 503 + // TypeScript-friendly call with explicit null when appropriate 504 + const dpopToken = await generateDpopToken( 505 + dpopKey, 506 + method, 507 + url, 508 + nonce || null, 509 + accessTokenHash 510 + ); 511 + 512 + // Prepare request options with TypeScript-friendly structure 513 + // Define the options object with a more complete type 514 + const options = { 515 + method, 516 + headers: { 517 + 'Content-Type': 'application/json', 518 + 'Authorization': `DPoP ${accessToken}`, 519 + 'DPoP': dpopToken 520 + }, 521 + // Add an empty body property that will be populated if needed 522 + body: undefined as string | undefined 523 + }; 524 + 525 + // Add body if provided 526 + if (body) { 527 + options.body = JSON.stringify(body); 528 + } 529 + 530 + // Make the request 531 + let response = await fetch(url, options); 532 + 533 + // Check for DPoP nonce in response headers 534 + const dpopNonce = response.headers.get('dpop-nonce'); 535 + if (dpopNonce && dpopNonce !== nonce) { 536 + // Store the new nonce 537 + await storeDpopNonce(origin, dpopNonce); 538 + 539 + // Check if we need to retry with the new nonce 540 + if (response.status === 400 || response.status === 401) { 541 + const responseData = await response.clone().json(); 542 + 543 + // Check for use_dpop_nonce error, similar to Python's retry logic 544 + if (responseData.error === 'use_dpop_nonce') { 545 + // console.log('Received use_dpop_nonce error, retrying with new nonce'); 546 + 547 + // Generate a new DPoP token with the new nonce 548 + // Ensuring we correctly handle the TypeScript type concerns 549 + const newDpopToken = await generateDpopToken( 550 + dpopKey, method, url, dpopNonce, accessTokenHash 551 + ); 552 + 553 + // Create a new request with the updated DPoP token 554 + const newOptions = { 555 + ...options, 556 + headers: { 557 + ...options.headers, 558 + 'DPoP': newDpopToken 559 + } 560 + }; 561 + 562 + // Make the request again 563 + // console.log('Retrying request with new DPoP token'); 564 + response = await fetch(url, newOptions); 565 + } 566 + } 567 + } 568 + 569 + // Check if the response is OK 570 + if (!response.ok) { 571 + let errorData; 572 + try { 573 + errorData = await response.json(); 574 + } catch (e) { 575 + errorData = { error: 'Failed to parse error response', message: await response.text() }; 576 + } 577 + 578 + console.error('PDS HTTP Error:', { 579 + status: response.status, 580 + statusText: response.statusText, 581 + error: errorData 582 + }); 583 + 584 + throw new Error(`PDS HTTP Error: ${JSON.stringify(errorData)}`); 585 + } 586 + 587 + // Parse and return the response data 588 + return await response.json(); 589 + } catch (error) { 590 + console.error('Error making authenticated request to PDS:', error); 591 + throw error; 592 + } 593 + } 594 + 595 + /** 596 + * Create a post on Bluesky 597 + * @param {string} text - Post text 598 + * @returns {Promise<Object>} - Response data with URI and CID of the created post 599 + */ 600 + export async function createPost(text) { 601 + try { 602 + // Get the user's DID 603 + const { did } = await getOAuthSession(); 604 + 605 + // Create the current timestamp in the format Bluesky expects 606 + const now = new Date().toISOString(); 607 + 608 + // Prepare the request body 609 + // This is explicitly defined as a non-null object to satisfy TypeScript 610 + const postBody = { 611 + repo: did, 612 + collection: 'app.bsky.feed.post', 613 + record: { 614 + '$type': 'app.bsky.feed.post', 615 + text, 616 + createdAt: now 617 + } 618 + }; 619 + 620 + // console.log('Creating post with body:', postBody); 621 + 622 + // Use the com.atproto.repo.createRecord endpoint 623 + // Explicitly pass the body as an object (not null) 624 + return await pdsAuthedReq('POST', '/xrpc/com.atproto.repo.createRecord', postBody); 625 + } catch (error) { 626 + console.error('Error creating post:', error); 627 + throw error; 628 + } 629 + }
+99
src/pages/popup.html
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8"> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 + <title>Skeet FYI</title> 7 + <link rel="stylesheet" href="../styles.css"> 8 + </head> 9 + <body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 font-sans transition-colors"> 10 + <div class="w-[300px] flex flex-col"> 11 + <header class="flex justify-between items-center flex-shrink-0"> 12 + <a href="https://skeet.fyi" target="_blank" class="block"> 13 + <img src="../assets/logo.svg" alt="skeet.FYI Logo" class="h-12 w-auto [filter:invert(0)_brightness(0.2)] dark:[filter:invert(1)_brightness(0.8)] transition-[filter]"> 14 + </a> 15 + <div id="user-section"> 16 + <!-- User info will be inserted here when logged in --> 17 + </div> 18 + </header> 19 + <main class="flex-grow overflow-y-auto"> 20 + <div id="content"> 21 + <!-- Login form will be inserted here when logged out --> 22 + <div id="login-container" class="space-y-3 w-[200px] mt-12 mx-auto"> 23 + <form id="loginForm"> 24 + <label> 25 + <input autocomplete="true" autofocus id="identityInput" 26 + placeholder="handle.bsky.social or did:plc:..." required 27 + type="text" 28 + class="w-full px-2 py-1 text-sm bg-gray-50 dark:bg-gray-800 29 + border border-gray-200 dark:border-gray-700 30 + text-gray-900 dark:text-gray-100 31 + focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent 32 + transition-all placeholder:text-gray-400 dark:placeholder:text-gray-500 rounded-md" 33 + > 34 + </label> 35 + <button type="button" id="loginBtn" 36 + class="border-none mt-2 mb-4 px-4 py-2 text-xs uppercase font-medium 37 + text-white bg-primary-600 dark:bg-primary-500 38 + hover:bg-primary-700 dark:hover:bg-primary-600 39 + active:bg-primary-800 dark:active:bg-primary-700 40 + transition-colors duration-200 ease-in-out 41 + disabled:opacity-50 disabled:cursor-not-allowed rounded-md"> 42 + login with a.i.r 43 + </button> 44 + </form> 45 + <p id="status" class="text-xs text-gray-500 dark:text-gray-400 mt-2 hidden"></p> 46 + </div> 47 + <div id="skeet" class="hidden"> 48 + <div class="p-4 space-y-3"> 49 + <textarea id="skeet-text" 50 + class="w-[calc(100%-1rem)] p-2 text-xs bg-gray-50 dark:bg-gray-800 51 + border border-gray-200 dark:border-gray-700 52 + text-gray-900 dark:text-gray-100 rounded-lg 53 + focus:outline-none focus:ring-2 focus:ring-primary-500 54 + focus:border-transparent resize-y min-h-[150px]" 55 + maxlength="300" 56 + placeholder="What's on your mind?"></textarea> 57 + <div class="flex justify-between items-center"> 58 + <p class="text-xs text-gray-500 dark:text-gray-400"><span id="char-count">300</span>/300</p> 59 + <button id="skeet-button" 60 + class="px-4 py-2 border-none text-xs font-medium uppercase text-white 61 + bg-primary-600 dark:bg-primary-500 rounded-md 62 + hover:bg-primary-700 dark:hover:bg-primary-600 63 + transition-colors 64 + disabled:opacity-50 disabled:cursor-not-allowed 65 + disabled:bg-gray-400 dark:disabled:bg-gray-600 66 + disabled:hover:bg-gray-400 dark:disabled:hover:bg-gray-600"> 67 + Skeet 68 + </button> 69 + </div> 70 + </div> 71 + </div> 72 + </div> 73 + </main> 74 + <footer class="flex-shrink-0"> 75 + <div class="flex justify-end space-x-2 items-end p-4"> 76 + <div id="logout-section"> 77 + <a id="logoutLink" class="hidden cursor-pointer text-xs font-medium text-gray-600 dark:text-gray-400 78 + hover:text-primary-600 dark:hover:text-primary-400"> 79 + Logout 80 + </a> 81 + </div> 82 + <div id="theme-toggle-section"> 83 + <button id="theme-toggle" class="border-none p-2 text-gray-500 dark:text-gray-400 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"> 84 + <!-- Sun icon --> 85 + <svg class="w-5 h-5 hidden dark:block" fill="currentColor" viewBox="0 0 20 20"> 86 + <path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"/> 87 + </svg> 88 + <!-- Moon icon --> 89 + <svg class="w-5 h-5 block dark:hidden" fill="currentColor" viewBox="0 0 20 20"> 90 + <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"/> 91 + </svg> 92 + </button> 93 + </div> 94 + </div> 95 + </footer> 96 + </div> 97 + <script type="module" src="../scripts/popup.js"></script> 98 + </body> 99 + </html>
+1
src/scripts/background.js
··· 1 + var l=new Map,s=1e3*60*60*24;chrome.runtime.onInstalled.addListener(t=>{t.reason==="install"&&chrome.storage.local.set({skeetData:{initialized:!0,timestamp:new Date().toISOString()}})});async function d(t){try{let o=l.get(t);if(o&&Date.now()-o.timestamp<s)return o.isConnected;let e=await fetch(`https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=${t}`,{method:"GET",headers:{Accept:"application/json"}});if(!e.ok)return!1;let c=!!(await e.json()).did;return l.set(t,{isConnected:c,timestamp:Date.now()}),c}catch{return!1}}function h(t){a("Extracting domain from URL:",t);try{return new URL(t).hostname}catch{return null}}async function u(t){a("Updating badge for tab:",t);try{let o=await chrome.tabs.get(t);if(!(o!=null&&o.url))return;let e=h(o.url);if(!e)return;let r=await d(e),c=r?"\u2713":"";await chrome.action.setBadgeText({text:c,tabId:t}),r&&await chrome.action.setBadgeBackgroundColor({color:"#0ea5e9",tabId:t})}catch{}}chrome.tabs.onUpdated.addListener((t,o,e)=>{o.status==="complete"&&e.url&&u(t)});chrome.tabs.onActivated.addListener(({tabId:t})=>{u(t)});var i=[],f=100;function a(t,o,e){let r={timestamp:new Date().toISOString(),type:t,message:o,data:typeof e=="object"?JSON.parse(JSON.stringify(e)):e};i.length>f&&i.shift()}chrome.runtime.onMessage.addListener((t,o,e)=>{try{if(a("info",`Received message of type: ${t.type}`,{message:t,sender:o?{id:o.id,url:o.url,origin:o.origin,tab:o.tab?{id:o.tab.id,url:o.tab.url}:null}:"unknown"}),t.type==="log_to_background")a(t.logType||"info",t.message,t.data),e({success:!0});else if(t.type==="get_background_logs")e({success:!0,logs:i});else if(t.type==="oauth_callback_log")a("info","Received OAuth callback log from content script",t.data),e({success:!0});else{if(t.type==="getData")return chrome.storage.local.get("skeetData",r=>{e({success:!0,data:r.skeetData})}),!0;if(t.type==="popup_oauth_callback"){a("info","Received popup OAuth callback from content script",t.data);try{chrome.runtime.sendMessage({type:"popup_oauth_callback",data:t.data},r=>{if(chrome.runtime.lastError){a("error","Error forwarding popup_oauth_callback",chrome.runtime.lastError);let c={...t.data,timestamp:Date.now()};a("info","Storing OAuth callback data",c),chrome.storage.local.set({oauth_callback_data:c},()=>{chrome.storage.local.get(["oauth_callback_data"],n=>{n&&n.oauth_callback_data?a("info","Successfully stored and verified OAuth callback data",n.oauth_callback_data):a("error","Failed to verify stored OAuth callback data",n)})})}else a("info","Successfully forwarded popup_oauth_callback",r)})}catch(r){a("error","Exception forwarding popup_oauth_callback",r);let c={...t.data,timestamp:Date.now()};a("info","Storing OAuth callback data after exception",c),chrome.storage.local.set({oauth_callback_data:c},()=>{chrome.storage.local.get(["oauth_callback_data"],n=>{n&&n.oauth_callback_data?a("info","Successfully stored and verified OAuth callback data after exception",n.oauth_callback_data):a("error","Failed to verify stored OAuth callback data after exception",n)})})}e({success:!0})}else{if(t.type==="initiate_oauth")return a("info","Initiating OAuth flow",t.data),initiateOAuth(t.data,e),!0;if(t.type==="auth_complete"){a("info","Authentication complete, notifying extension pages",t.data);try{chrome.runtime.sendMessage({type:"auth_status_update",data:{authenticated:!0,did:t.data.did}},r=>{chrome.runtime.lastError?a("info","No listeners for auth_status_update (expected if popup is closed)",chrome.runtime.lastError):a("info","Successfully sent auth_status_update",r)})}catch(r){a("error","Exception sending auth_status_update",r)}e({success:!0})}else{if(t.type==="get_auth_status")return a("info","Getting auth status"),getAuthStatus(e),!0;if(t.type==="logout")return a("info","Logging out user"),logout(e),!0;a("warning","Received unknown message type",{type:t.type}),e({success:!1,error:"Unknown message type"})}}}}catch(r){a("error","Error handling message",{error:r.toString(),stack:r.stack,message:t}),e({success:!1,error:r.toString()})}});async function p(){try{let t=await chrome.storage.local.get(null);return a("info","Current storage contents",t),t}catch(t){return a("error","Error checking storage",t),{}}}p();
+1
src/scripts/content-script.js
··· 1 + function e(c,...s){chrome.runtime.sendMessage({type:"log_message",data:{message:c,args:JSON.stringify(s)}})}(function(){if(e("Content script loaded for:",window.location.href),window.location.href.includes("skeet.fyi/oauth-callback")){let s=function(t,n,r){if(c){e("OAuth callback already processed, ignoring duplicate");return}e("Processing OAuth callback with:",{code:t?t.substring(0,10)+"...":null,state:n,iss:r}),c=!0,e("Sending oauth_callback message to popup"),chrome.runtime.sendMessage({type:"oauth_callback_log",data:{code:t,state:n,iss:r}}),chrome.runtime.sendMessage({type:"popup_oauth_callback",data:{code:t,state:n,iss:r}},function(o){if(chrome.runtime.lastError){e("Error sending message to popup:",chrome.runtime.lastError),chrome.storage.local.set({oauth_callback_data:{code:t,state:n,iss:r,timestamp:Date.now()}},function(){e("Stored OAuth callback data for later retrieval")});try{e("Posting success message to window"),window.postMessage({type:"oauth_callback_response",success:!0,message:"Authentication successful! You can close this window."},"*"),e("Posted success message to window")}catch(a){e("Error posting message to window:",a)}return}e("Received response from popup:",o);try{e("Posting message to window"),window.postMessage({type:"oauth_callback_response",success:o==null?void 0:o.success,error:o==null?void 0:o.error,data:o==null?void 0:o.data,message:o!=null&&o.success?"Authentication successful! You can close this window.":"Authentication failed."},"*"),e("Posted message to window successfully")}catch(a){e("Error posting message to window:",a)}})},i=function(){if(e("Checking URL parameters..."),c){e("Skipping URL parameter check as callback was already processed");return}let t=new URLSearchParams(window.location.search),n=new URLSearchParams(window.location.hash.substring(1));e("URL search params:",Object.fromEntries(t.entries())),e("URL hash params:",Object.fromEntries(n.entries()));let r=t.get("code")||n.get("code"),o=t.get("state")||n.get("state"),a=t.get("iss")||n.get("iss");e("Extracted parameters:",{code:r?r.substring(0,10)+"...":null,state:o,iss:a}),r&&o&&a?(e("Found OAuth parameters in URL, calling handleOAuthCallback"),s(r,o,a)):e("Missing required OAuth parameters in URL",{code:!!r,state:!!o,iss:!!a})},l=function(){e("Extension content script is ready, ID:",chrome.runtime.id);try{let t=document.createElement("script");t.src=chrome.runtime.getURL("scripts/extension-id-provider.js"),t.dataset.extensionId=chrome.runtime.id,document.head?(document.head.appendChild(t),e("External script injected successfully")):document.documentElement?(document.documentElement.appendChild(t),e("External script injected to documentElement")):document.addEventListener("DOMContentLoaded",function(){document.head.appendChild(t),e("External script injected after DOMContentLoaded")})}catch(t){e("Error setting up extension ID:",t);try{let n=new CustomEvent("extension_ready",{detail:{extensionId:chrome.runtime.id}});window.dispatchEvent(n),e("Dispatched extension_ready event directly")}catch(n){e("Error dispatching event:",n)}}},c=!1;window.addEventListener("oauth_callback",function(t){let{code:n,state:r,iss:o}=t.detail;s(n,r,o)}),e("Setting timeout to check URL parameters in 500ms"),setTimeout(i,500),l()}})();
+1
src/scripts/extension-id-provider.js
··· 1 + (function(){let e=document.currentScript.dataset.extensionId;window.EXTENSION_ID=e,window.dispatchEvent(new CustomEvent("extension_ready",{detail:{extensionId:e}}))})();
+48
src/scripts/popup.js
··· 1 + async function ie(t,e,r,n,o){try{let a=t.jwt.split("."),i=_e(a[0]),c=JSON.parse(i).jwk,d=Array.from(crypto.getRandomValues(new Uint8Array(16))).map(v=>v.toString(16).padStart(2,"0")).join(""),h={typ:"dpop+jwt",alg:"ES256",jwk:c},w=Math.floor(Date.now()/1e3),u={jti:d,htm:e,htu:r,iat:w,exp:w+30,nonce:void 0,ath:void 0};n&&(u.nonce=n),o&&(u.ath=o);let f=ce(JSON.stringify(h)),p=ce(JSON.stringify(u)),g=`${f}.${p}`,m=await crypto.subtle.importKey("pkcs8",Ue(t.key),{name:"ECDSA",namedCurve:"P-256"},!1,["sign"]),y=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},m,new TextEncoder().encode(g)),S=le(y);return`${g}.${S}`}catch(a){throw a}}function ce(t){return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function le(t){let e=new Uint8Array(t),r="";for(let n=0;n<e.byteLength;n++)r+=String.fromCharCode(e[n]);return btoa(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function _e(t){let e=t.replace(/-/g,"+").replace(/_/g,"/"),r=e.padEnd(e.length+(4-e.length%4)%4,"=");return atob(r)}function Ue(t){let e=t.replace(/-/g,"+").replace(/_/g,"/"),r=e.padEnd(e.length+(4-e.length%4)%4,"="),n=atob(r),o=new Uint8Array(n.length);for(let a=0;a<n.length;a++)o[a]=n.charCodeAt(a);return o.buffer}async function Ae(t){try{let e=new TextEncoder().encode(t),r=await crypto.subtle.digest("SHA-256",e);return le(r)}catch(e){throw e}}async function De(t){try{if(!t){let{did:n}=await j();t=n}let e=`/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(t)}&collection=app.bsky.actor.profile&rkey=self`;return await J("GET",e,null)}catch(e){throw e}}function Pe(t){var e,r,n,o;try{if((o=(n=(r=(e=t==null?void 0:t.raw)==null?void 0:e.value)==null?void 0:r.avatar)==null?void 0:n.ref)!=null&&o.$link){let a=t.did||t.raw.uri.split("/")[2],i=t.raw.value.avatar.ref.$link;return(async()=>{let{session:c}=await j();return c.info.aud})().then(c=>`${c}xrpc/com.atproto.sync.getBlob?did=${encodeURIComponent(a)}&cid=${encodeURIComponent(i)}`)}return null}catch{return null}}async function z(t){var e,r;try{let n=await De(t),o={did:n.uri.split("/")[2],handle:null,displayName:((e=n.value)==null?void 0:e.displayName)||null,description:((r=n.value)==null?void 0:r.description)||null,avatar:"",raw:n},a=await Pe(o);if(a&&(o.avatar=a),o.did)try{let i=await J("GET",`/xrpc/com.atproto.repo.describeRepo?repo=${encodeURIComponent(o.did)}`,null);i&&i.handle&&(o.handle=i.handle)}catch{}return o}catch(n){throw n}}async function j(){var a;let t=await chrome.storage.local.get(["atcute-oauth:sessions"]);if(!t||!t["atcute-oauth:sessions"])throw new Error("No OAuth session found");let e=t["atcute-oauth:sessions"],r=Object.keys(e);if(!r.length)throw new Error("No OAuth sessions available");let n=r[0],o=e[n].value;if(!((a=o==null?void 0:o.token)!=null&&a.access))throw new Error("Invalid OAuth session: missing access token");return{did:n,session:o,accessToken:o.token.access}}async function $e(){let t=await chrome.storage.local.get(["atcute-oauth:states"]);if(!t||!t["atcute-oauth:states"])throw new Error("No OAuth states found");let e=t["atcute-oauth:states"],r=null,n=0;if(Object.entries(e).forEach(([o,a])=>{var s;let i=a;(s=i.value)!=null&&s.dpopKey&&i.expiresAt&&i.expiresAt>n&&(r=i.value.dpopKey,n=i.expiresAt)}),!r)throw new Error("No DPoP key found in states");return r}async function Te(t,e){let n=(await chrome.storage.local.get(["atcute-oauth:dpopNonces"]))["atcute-oauth:dpopNonces"]||{};n[t]={value:e,expiresAt:Date.now()+6e5},await chrome.storage.local.set({"atcute-oauth:dpopNonces":n})}async function Le(t){let r=(await chrome.storage.local.get(["atcute-oauth:dpopNonces"]))["atcute-oauth:dpopNonces"];return r&&r[t]&&r[t].value?r[t].value:null}async function J(t,e,r){try{let{did:n,session:o,accessToken:a}=await j(),i=await $e();if(!e.startsWith("/xrpc/com.atproto."))throw new Error("OAuth tokens can only be used with PDS endpoints (/xrpc/com.atproto.*)");let s=o.info.aud;if(!s)throw new Error("No PDS URL (aud) found in session");let c=s.endsWith("/")&&e.startsWith("/")?`${s}${e.substring(1)}`:`${s}${e}`,h=new URL(c).origin,w=await Le(h),u=await Ae(a),f=await ie(i,t,c,w||null,u),p={method:t,headers:{"Content-Type":"application/json",Authorization:`DPoP ${a}`,DPoP:f},body:void 0};r&&(p.body=JSON.stringify(r));let g=await fetch(c,p),m=g.headers.get("dpop-nonce");if(m&&m!==w&&(await Te(h,m),(g.status===400||g.status===401)&&(await g.clone().json()).error==="use_dpop_nonce")){let S=await ie(i,t,c,m,u),v={...p,headers:{...p.headers,DPoP:S}};g=await fetch(c,v)}if(!g.ok){let y;try{y=await g.json()}catch{y={error:"Failed to parse error response",message:await g.text()}}throw new Error(`PDS HTTP Error: ${JSON.stringify(y)}`)}return await g.json()}catch(n){throw n}}async function de(t){try{let{did:e}=await j(),r=new Date().toISOString();return await J("POST","/xrpc/com.atproto.repo.createRecord",{repo:e,collection:"app.bsky.feed.post",record:{$type:"app.bsky.feed.post",text:t,createdAt:r}})}catch(e){throw e}}var W=class t{name;controller;signal;static storage;constructor(e){if(!t.storage)try{t.storage=chrome.storage}catch{try{t.storage=browser.storage}catch{throw"Unsupported browser"}}this.name=e.name,this.controller=new AbortController,this.signal=this.controller.signal,this.sessions=this.createStore("sessions",({token:r})=>r.refresh?null:r.expires_at??null),this.states=this.createStore("states",r=>Date.now()+6e5),this.dpopNonces=this.createStore("dpopNonces",r=>Date.now()+6e5)}sessions;states;dpopNonces;dispose(){this.controller.abort()}createStore(e,r){let n=`${this.name}:${e}`,o=async s=>{try{await t.storage.local.set({[n]:s})}catch{}},a=async()=>{if(this.signal.aborted)throw new Error("store closed");try{return(await t.storage.local.get(n))[n]||{}}catch{return{}}},i=null;return i=setInterval(async()=>{if(!this.signal.aborted)try{let s=await a(),c=Date.now(),d=!1;for(let h in s){let w=s[h].expiresAt;w!==null&&c>w&&(d=!0,delete s[h])}d&&await o(s)}catch(s){if(s.message.includes("Extension context invalidated.")){i&&clearInterval(i);return}}},1e4),this.signal.addEventListener("abort",()=>clearInterval(i)),{async get(s){let c=await a(),d=c[s];if(!d)return;let h=d.expiresAt;if(h!==null&&Date.now()>h){delete c[s],await o(c);return}return d.value},async set(s,c){let d=await a();d[s]={expiresAt:r(c),value:c},await o(d)},async delete(s){let c=await a();c[s]!==void 0&&(delete c[s],await o(c))},async keys(){let s=await a();return Object.keys(s)}}}},O,ne,L,M=t=>{({client_id:O,redirect_uri:ne}=t.metadata),L=new W({name:t.storageName??"atcute-oauth"})},b=class extends Error{name="ResolverError"},$=class extends Error{sub;name="TokenRefreshError";constructor(e,r,n){super(r,n),this.sub=e}},R=class extends Error{response;data;name="OAuthResponseError";error;description;constructor(e,r){var c,d;let n=ue((c=he(r))==null?void 0:c.error),o=ue((d=he(r))==null?void 0:d.error_description),a=n?`"${n}"`:"unknown",i=o?`: ${o}`:"",s=`OAuth ${a} error${i}`;super(s),this.response=e,this.data=r,this.error=n,this.description=o}get status(){return this.response.status}get headers(){return this.response.headers}},G=class extends Error{response;status;name="FetchResponseError";constructor(e,r,n){super(n),this.response=e,this.status=r}},ue=t=>typeof t=="string"?t:void 0,he=t=>typeof t=="object"&&t!==null&&!Array.isArray(t)?t:void 0,Ce=t=>Ie(t,"#atproto_pds","AtprotoPersonalDataServer"),Ie=(t,e,r)=>{var a;let n=t.id+e,o=(a=t.service)==null?void 0:a.find(i=>i.id===e||i.id===n);if(!(!o||o.type!==r||typeof o.serviceEndpoint!="string"))return Oe(o.serviceEndpoint)},Oe=t=>{let e;try{e=new URL(t)}catch{return}let r=e.protocol;if(e.hostname&&(r==="http:"||r==="https:"))return t},je="https://public.api.bsky.app",H=t=>{var e;return(e=t.get("content-type"))==null?void 0:e.split(";")[0]},Be=t=>t.startsWith("did:"),Re=/^([a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*(?:\.[a-zA-Z]{2,}))$/,Ne=async t=>{let e=je+`/xrpc/com.atproto.identity.resolveHandle?handle=${t}`,r=await fetch(e);if(r.status===400)throw new b("domain handle not found");if(!r.ok)throw new b("directory is unreachable");return(await r.json()).did},Me=async t=>{let e=t.indexOf(":",4),r=t.slice(4,e),n=t.slice(e+1),o;if(r==="plc"){let a=await fetch(`https://plc.directory/${t}`);if(a.status===404)throw new b("did not found in directory");if(!a.ok)throw new b("directory is unreachable");o=await a.json()}else if(r==="web"){if(!Re.test(n))throw new b("invalid identifier");let a=await fetch(`https://${n}/.well-known/did.json`);if(!a.ok)throw new b("did document is unreachable");o=await a.json()}else throw new b("unsupported did method");return o},He=async t=>{let e=new URL("/.well-known/oauth-protected-resource",t),r=await fetch(e,{redirect:"manual",headers:{accept:"application/json"}});if(r.status!==200||H(r.headers)!=="application/json")throw new b("unexpected response");let n=await r.json();if(n.resource!==e.origin)throw new b("unexpected issuer");return n},Ke=async t=>{let e=new URL("/.well-known/oauth-authorization-server",t),r=await fetch(e,{redirect:"manual",headers:{accept:"application/json"}});if(r.status!==200||H(r.headers)!=="application/json")throw new b("unexpected response");let n=await r.json();if(n.issuer!==e.origin)throw new b("unexpected issuer");if(!n.client_id_metadata_document_supported)throw new b("authorization server does not support 'client_id_metadata_document'");if(!n.pushed_authorization_request_endpoint)throw new b("authorization server does not support 'pushed_authorization request'");if(n.response_types_supported&&!n.response_types_supported.includes("code"))throw new b("authorization server does not support 'code' response type");return n},fe=async t=>{let e;Be(t)?e=t:e=await Ne(t);let r=await Me(e),n=Ce(r);if(!n)throw new b("missing pds endpoint");return{identity:{id:e,raw:t,pds:new URL(n)},metadata:await Fe(n)}},Fe=async t=>{var o;let e=await He(t);if(((o=e.authorization_servers)==null?void 0:o.length)!==1)throw new b("expected exactly one authorization server in the listing");let r=e.authorization_servers[0],n=await Ke(r);if(n.protected_resources&&!n.protected_resources.includes(e.resource))throw new b("server is not in authorization server's jurisdiction");return n},qe="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict",ze=(t=21)=>{let e="",r=t;for(;r--;)e+=qe[Math.random()*64|0];return e},N=new TextEncoder,pe=navigator.locks,C=t=>{let e=[];for(let r=0;r<t.byteLength;r+=32768)e.push(String.fromCharCode.apply(null,t.subarray(r,r+32768)));return btoa(e.join("")).replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")},Je=t=>{try{let e=atob(t.replace(/-/g,"+").replace(/_/g,"/").replace(/\s/g,"")),r=new Uint8Array(e.length);for(let n=0;n<e.length;n++)r[n]=e.charCodeAt(n);return r}catch(e){throw new TypeError("invalid base64url",{cause:e})}},ge=async t=>{let e=N.encode(t),r=await crypto.subtle.digest("SHA-256",e);return C(new Uint8Array(r))},we=t=>C(crypto.getRandomValues(new Uint8Array(t))),We=()=>we(16),Ge=async()=>{let t=we(32);return{verifier:t,challenge:await ge(t),method:"S256"}};function A(t,e){if(t==null){e??="value is null/empty";let r=Error().stack;if(r){let n=r.split(` 2 + `);if(n.length>2){let o=n[2].trimStart();throw o=o.replace(/^at/,""),o=o.trimStart(),`${o}: 3 + ${typeof t}: ${e}`}}throw`${typeof t}: ${e}`}return t}var me={name:"ECDSA",namedCurve:"P-256"},Ve=async()=>{let t=await crypto.subtle.generateKey(me,!0,["sign","verify"]),e=await crypto.subtle.exportKey("pkcs8",t.privateKey),{ext:r,key_ops:n,...o}=await crypto.subtle.exportKey("jwk",t.publicKey);return{typ:"ES256",key:C(new Uint8Array(e)),jwt:C(N.encode(JSON.stringify({typ:"dpop+jwt",alg:"ES256",jwk:o})))}},Ze=(t,e)=>{let r=e.jwt,n=crypto.subtle.importKey("pkcs8",Je(e.key),me,!0,["sign"]),o=(a,i,s,c)=>{let d=Date.now()/1e3|0,h={iss:t,iat:d,jti:ze(12),htm:a,htu:i,nonce:s,ath:c};return C(N.encode(JSON.stringify(h)))};return async(a,i,s,c)=>{let d=o(a,i,s,c),h=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},await n,N.encode(r+"."+d)),w=C(new Uint8Array(h));return r+"."+d+"."+w}},ye=(t,e,r)=>{let n=A(L),o=A(n.dpopNonces),a=Ze(t,e);return async(i,s)=>{let c=s==null&&i instanceof Request?i:new Request(i,s),d=c.headers.get("authorization"),h=d!=null&&d.startsWith("DPoP ")?await ge(d.slice(5)):void 0,{method:w,url:u}=c,{origin:f}=new URL(u),p;try{p=await o.get(f)}catch{}let g=await a(w,u,p,h);c.headers.set("dpop",g);let m=await fetch(c),y=m.headers.get("dpop-nonce");if(!y||y===p)return m;try{await o.set(f,y)}catch{}if(!await Xe(m,r)||i===c||(s==null?void 0:s.body)instanceof ReadableStream)return m;let S=await a(w,u,y,h),v=new Request(i,s);return v.headers.set("dpop",S),await fetch(v)}},Xe=async(t,e)=>{if((e===void 0||!e)&&t.status===401){let r=t.headers.get("www-authenticate");if(r!=null&&r.startsWith("DPoP"))return r.includes('error="use_dpop_nonce"')}if((e===void 0||e)&&t.status===400&&H(t.headers)==="application/json")try{let r=await t.clone().json();return typeof r=="object"&&(r==null?void 0:r.error)==="use_dpop_nonce"}catch{return!1}return!1},Ye=(t,e)=>{let r={};for(let n=0,o=e.length;n<o;n++){let a=e[n];r[a]=t[a]}return r},T=class{#t;#e;constructor(e,r){this.#t=e,this.#e=ye(O,r,!0)}async request(e,r){let n=this.#t[`${e}_endpoint`];if(!n)throw new Error(`no endpoint for ${e}`);let o=await this.#e(n,{method:"post",headers:{"content-type":"application/json"},body:JSON.stringify({...r,client_id:O})});if(H(o.headers)!=="application/json")throw new G(o,2,"unexpected content-type");let a=await o.json();if(o.ok)return a;throw new R(o,a)}async revoke(e){try{await this.request("revocation",{token:e})}catch{}}async exchangeCode(e,r){let n=await this.request("token",{grant_type:"authorization_code",redirect_uri:ne,code:e,code_verifier:r});try{return await this.#n(n)}catch(o){throw await this.revoke(n.access_token),o}}async refresh({sub:e,token:r}){if(!r.refresh)throw new $(e,"no refresh token available");let n=await this.request("token",{grant_type:"refresh_token",refresh_token:r.refresh});if(!n.sub)throw new $(e,"missing value for sub in token response");if(e!==n.sub)throw new $(e,`sub mismatch in token response; got ${n.sub}`);try{return this.#r(n)}catch(o){throw await this.revoke(n.access_token),o}}#r(e){if(!e.sub)throw new TypeError("missing sub field in token response");if(!e.scope)throw new TypeError("missing scope field in token response");if(e.token_type!=="DPoP")throw new TypeError("token response returned a non-dpop token");return{scope:e.scope,refresh:e.refresh_token,access:e.access_token,type:e.token_type,expires_at:typeof e.expires_in=="number"?Date.now()+e.expires_in*1e3:void 0}}async#n(e){let r=e.sub;if(!r)throw new TypeError("missing sub field in token response");let n=this.#r(e),o=await fe(r);if(o.metadata.issuer!==this.#t.issuer)throw new TypeError(`issuer mismatch; got ${o.metadata.issuer}`);return{token:n,info:{sub:r,aud:o.identity.pds.href,server:Ye(o.metadata,["issuer","authorization_endpoint","introspection_endpoint","pushed_authorization_request_endpoint","revocation_endpoint","token_endpoint"])}}}},B=new Map,V=async(t,e)=>{var s,c;(s=e==null?void 0:e.signal)==null||s.throwIfAborted();let r=nt;e!=null&&e.noCache?r=et:e!=null&&e.allowStale&&(r=Qe);let n;for(;n=B.get(t);){try{let{isFresh:d,value:h}=await n;if(d||r(h))return h}catch{}(c=e==null?void 0:e.signal)==null||c.throwIfAborted()}let o=async()=>{let d=A(L),h=await A(d.sessions).get(t);if(h&&r(h))return{isFresh:!1,value:h};let w=await tt(t,h);return await ke(t,w),{isFresh:!0,value:w}},a;if(pe?a=pe.request(`atcute-oauth:${t}`,o):a=o(),a=a.finally(()=>B.delete(t)),B.has(t))throw new Error("concurrent request for the same key");B.set(t,a);let{value:i}=await a;return i},ke=async(t,e)=>{try{let r=A(L);await A(r.sessions).set(t,e)}catch(r){throw await rt(e),r}},be=async t=>{let e=A(L);await A(e.sessions).delete(t)},Qe=()=>!0,et=()=>!1,tt=async(t,e)=>{if(e===void 0)throw new $(t,"session deleted by another tab");let{dpopKey:r,info:n,token:o}=e,a=new T(n.server,r);try{let i=await a.refresh({sub:n.sub,token:o});return{dpopKey:r,info:n,token:i}}catch(i){throw i instanceof R&&i.status===400&&i.error==="invalid_grant"?new $(t,"session was revoked",{cause:i}):i}},rt=async({dpopKey:t,info:e,token:r})=>{await new T(e.server,t).revoke(r.refresh??r.access)},nt=({token:t})=>{let e=t.expires_at;return e==null||Date.now()+6e4<=e},ot=async({metadata:t,identity:e,scope:r})=>{let n=We(),o=await Ge(),a=await Ve(),i={redirect_uri:ne,code_challenge:o.challenge,code_challenge_method:o.method,state:n,login_hint:e==null?void 0:e.raw,response_mode:"fragment",response_type:"code",display:"page",scope:r},s=A(L);await A(s.states).set(n,{dpopKey:a,metadata:t,verifier:o.verifier});let d=await new T(t,a).request("pushed_authorization_request",i),h=new URL(t.authorization_endpoint);return h.searchParams.set("client_id",O),h.searchParams.set("request_uri",d.request_uri),h},Z=class{session;#t;#e;constructor(e){this.session=e,this.#t=ye(O,e.dpopKey,!1)}get sub(){return this.session.info.sub}getSession(e){let r=V(this.session.info.sub,e);return r.then(n=>{this.session=n}).finally(()=>{this.#e=void 0}),this.#e=r,r}async signOut(){let e=this.session.info.sub;try{let{dpopKey:r,info:n,token:o}=await V(e,{allowStale:!0});await new T(n.server,r).revoke(o.refresh??o.access)}finally{await be(e)}}async handle(e,r){await this.#e;let n=new Headers(r==null?void 0:r.headers),o=this.session,a=new URL(e,o.info.aud);n.set("authorization",`${o.token.type} ${o.token.access}`);let i=await this.#t(a,{...r,headers:n});if(!at(i))return i;try{this.#e?o=await this.#e:o=await this.getSession()}catch{return i}return(r==null?void 0:r.body)instanceof ReadableStream?i:(a=new URL(e,o.info.aud),n.set("authorization",`${o.token.type} ${o.token.access}`),await this.#t(a,{...r,headers:n}))}},at=t=>{if(t.status!==401)return!1;let e=t.headers.get("www-authenticate");return e!=null&&(e.startsWith("Bearer ")||e.startsWith("DPoP "))&&e.includes('error="invalid_token"')};function E(t,e){if(t==null){e??="value is null/empty";let r=Error().stack;if(r){let n=r.split(` 4 + `);if(n.length>2){let o=n[2].trimStart();throw o=o.replace(/^at/,""),o=o.trimStart(),`${o}: 5 + ${typeof t}: ${e}`}}throw`${typeof t}: ${e}`}return t}function st(t){let e=window.open(t,"_blank");return e&&e.focus(),e}var X=class{container;timer;constructor(){this.timer=null,this.container=document.createElement("div"),this.container.classList.add("biskuvi-toast-container"),document.body.appendChild(this.container)}show(e,r="info",n=3e3){if(document.hidden)return;this.timer&&clearTimeout(this.timer);let o=new Y(e,r),a=this.container.lastChild;if(a)try{this.container.removeChild(a)}catch(i){i.name!=="NotFoundError"&&void 0}this.timer=setTimeout(()=>{o.element.style.animation="slideOut 250ms ease-in",setTimeout(()=>{this.container.removeChild(o.element)},250)},n),this.container.appendChild(o.element)}},Y=class{element;constructor(e,r){this.element=document.createElement("div"),this.element.classList.add("biskuvi-toast",r),this.element.textContent=e}},k={userHandle:"skeet_user_handle",userDid:"skeet_user_did",language:"skeet_language",colorScheme:"skeet_color_scheme",bookmarkServerUrl:"skeet_bookmark_server_url",bookmarkFeedUrl:"skeet_bookmark_feed_url",clientMetadataJsonUrl:"skeet_client_metadata_json_url",oauthCallbackUrl:"skeet_oauth_callback_url"};async function it(t){switch(t){case 1:return new Q;default:throw"Not implemented"}}var Q=class{async isBookmarked(e){return(await(await this.fetch("/xrpc/app.biskuvi.bookmark.isBookmarked",e)).json()).is_bookmarked===!0}async arePostsBookmarked(e){let n=await(await this.fetch("/xrpc/app.biskuvi.bookmark.arePostsBookmarked",null,{uris:e})).json();return E(n.uris)}async addBookmark(e){await this.fetch("/xrpc/app.biskuvi.bookmark.addBookmark",e)}async removeBookmark(e){await this.fetch("/xrpc/app.biskuvi.bookmark.removeBookmark",e)}async fetch(e,r,n){let o=E(D.bookmarkServerUrl)+e;r&&(o+=`?uri=${r}`);let a=E(D.oAuthUserAgent),i;if(n?i=await a.handle(o,{headers:{"Content-Type":"application/json"},method:"POST",body:JSON.stringify(n)}):i=await a.handle(o),!i.ok)throw new Error("Invalid response status");return i}};function ct(){try{return E(chrome)}catch{try{return E(browser)}catch{throw"Unsupported browser"}}}var oe=ct();async function ve(t){return await oe.storage.local.set(t)}async function K(t,e=[]){let r=t;return e.length>0&&(r=r.filter(n=>!e.includes(n))),await oe.storage.local.get(r)}async function ee(t){return await oe.storage.local.remove(t)}var lt={bskyUrl:"https://bsky.app",bookmarkPageUrlAlias:"/bookmarks",handleResolverUrl:"https://api.bsky.app",didResolverUrl:"https://plc.directory"},I={language:"en",bookmarkServerUrl:"https://bookmarks.bskv.site",bookmarkFeedUrl:"https://bsky.app/profile/bookmarks.bskv.site/feed/bookmarks",clientMetadataJsonUrl:"https://skeet.fyi/client-metadata.json",oauthCallbackUrl:"https://skeet.fyi/oauth-callback"},D=class t{static userDid;static userHandle;static language;static bookmarkServerUrl;static bookmarkFeedUrl;static clientMetadataJsonUrl;static oauthCallbackUrl;static root;static oAuthSession;static oAuthUserAgent;static bookmarkManager;static toaster;static fallbackIsBookmarked;static async init(){t.bookmarkManager=await it(1);let e=await K(Object.values(k));t.userDid=e[k.userDid],t.language=e[k.language]||I.language,t.bookmarkServerUrl=e[k.bookmarkServerUrl]||I.bookmarkServerUrl,t.bookmarkFeedUrl=e[k.bookmarkFeedUrl]||I.bookmarkFeedUrl,t.clientMetadataJsonUrl=e[k.clientMetadataJsonUrl]||I.clientMetadataJsonUrl,t.oauthCallbackUrl=e[k.oauthCallbackUrl]||I.oauthCallbackUrl,t.toaster=new X}};async function dt(t){let e;try{e=await fetch(t)}catch(r){throw`getDid: ${r.message}`}if(!e.ok)throw`response is not OK: ${e.status}`;return await e.json()}async function ut(t){let e=lt.didResolverUrl+"/"+t;return E(await dt(e))}async function Ee(t){if(!t.startsWith("did:plc:"))throw"identity does not begin with did:plc:";let e=E((await ut(t)).alsoKnownAs[0]),r="at://";return e.startsWith(r)&&(e=e.substring(r.length)),e}function F(){return{metadata:{client_id:E(D.clientMetadataJsonUrl),redirect_uri:E(D.oauthCallbackUrl)}}}function l(t,e,r){try{chrome.runtime.sendMessage({type:"log_to_background",logType:t,message:`[POPUP] ${e}`,data:r})}catch{}}async function xe(t){var o;l("info","Popup handling OAuth callback",t);let{code:e,state:r,iss:n}=t;if(!e||!r||!n)return l("error","Missing required OAuth parameters",{code:!!e,state:!!r,iss:!!n}),{success:!1,error:"Missing required OAuth parameters"};try{l("info","Initializing OAuth"),await D.init(),M(F()),l("info","Getting state data from storage",{state:r});let a=await L.states.get(r);if(!a){l("error","No state data found for state",{state:r});try{let s=await chrome.storage.local.get(null);l("info","All storage contents for debugging",s);let c=s["atcute-oauth:states"]||{};l("info","Available states",Object.keys(c))}catch(s){l("error","Error checking storage",s)}return{success:!1,error:"Invalid state parameter or session expired"}}l("info","Found state data",{stateDataExists:!!a,dpopKeyExists:!!(a!=null&&a.dpopKey),verifierExists:!!(a!=null&&a.verifier),metadataExists:!!(a!=null&&a.metadata)}),l("info","Creating OAuth client");let i=new T(a.metadata,a.dpopKey);try{l("info","Exchanging code for tokens",{code:e.substring(0,10)+"...",verifier:a.verifier.substring(0,10)+"..."});let s=await i.exchangeCode(e,a.verifier);l("info","Exchanged code for tokens successfully",{tokenExists:!!(s!=null&&s.token),infoExists:!!(s!=null&&s.info),sub:(o=s==null?void 0:s.info)==null?void 0:o.sub}),l("info","Saving session"),await ke(s.info.sub,s);let c=s.info.sub;l("info","Resolving handle from DID",{did:c});let d=await Ee(c);return l("info","Storing user info in storage",{did:c,handle:d}),await ve({[k.userDid]:c,[k.userHandle]:d}),l("info","Sending auth_complete message",{did:c,handle:d}),chrome.runtime.sendMessage({type:"auth_complete",data:{did:c,handle:d}},h=>{chrome.runtime.lastError?l("warning","Error sending auth_complete message (expected if no listeners)",chrome.runtime.lastError):l("info","auth_complete message sent successfully",h)}),l("info","Authentication successful!",{did:c,handle:d}),{success:!0,data:{did:c,handle:d}}}catch(s){return l("error","Error exchanging code for tokens",{error:s.toString(),stack:s.stack}),{success:!1,error:s.message||"Error exchanging code for tokens"}}}catch(a){return l("error","Error handling OAuth callback",{error:a.toString(),stack:a.stack}),{success:!1,error:a.message||"Error handling OAuth callback"}}}chrome.runtime.onMessage.addListener((t,e,r)=>{try{if(t.type==="popup_oauth_callback")return l("info","Popup received OAuth callback",t.data),xe(t.data).then(n=>{l("info","OAuth callback result",n),r(n),n.success&&(l("info","Updating UI after successful login",{did:n.data.did,handle:n.data.handle}),ae(n.data.did,n.data.handle))}).catch(n=>{l("error","Error in handleOAuthCallback",{error:n.toString(),stack:n.stack}),r({success:!1,error:n.message||"Unknown error"})}),!0;t.type==="auth_status_update"&&(l("info","Received auth status update",t.data),t.data.authenticated&&t.data.did&&l("info","Auth status update indicates successful login",{did:t.data.did}))}catch(n){l("error","Error handling message in popup",{error:n.toString(),stack:n.stack,message:t}),r({success:!1,error:n.toString()})}});function ae(t,e){if(!document.getElementById("content")){l("warning","Cannot update UI - popup elements not found");return}l("info","Updating UI elements for logged in state");let r=document.getElementById("login-container"),n=document.getElementById("skeet"),o=document.getElementById("logoutLink"),a=document.getElementById("status");if(r&&n&&o){r.classList.add("hidden"),n.classList.remove("hidden"),o.classList.remove("hidden"),l("info","Setting up logout button");let i=o.cloneNode(!0);o.parentNode.replaceChild(i,o),i.addEventListener("click",async()=>{l("info","Logout button clicked");try{try{await D.init(),M(F());let c=await V(t,{allowStale:!0});await new Z(c).signOut()}catch(c){l("warning","Error during signOut, falling back to deleteSession",c),await be(t)}await ee([k.userDid,k.userHandle]),l("info","Logout successful, updating UI"),r.classList.remove("hidden"),n.classList.add("hidden"),i.classList.add("hidden");let s=document.getElementById("user-section");s&&(s.innerHTML="")}catch(s){l("error","Error during logout",s),a&&(a.innerText=s.toString())}}),z(t).then(({displayName:s,avatar:c})=>{l("info","Got user profile",{displayName:s,avatar:c}),re({displayName:s,userHandle:e,avatar:c}),te()}).catch(s=>{l("error","Error getting user profile:",s),re({displayName:e,userHandle:e,avatar:""}),te()}),l("info","UI updated successfully")}else l("warning","Some UI elements not found",{loginContainer:!!r,skeetContainer:!!n,logoutLink:!!o})}async function ht(){l("info","Checking for stored OAuth callback data");let t=await K(["oauth_callback_data"]);if(t.oauth_callback_data){l("info","Found stored OAuth callback data",t.oauth_callback_data);let e=t.oauth_callback_data.timestamp||0,r=Date.now(),n=r-5*60*1e3;if(e>n){l("info","Processing stored OAuth callback data",{age:(r-e)/1e3,maxAgeSeconds:5*60});let o=await xe(t.oauth_callback_data);o.success?(l("info","Successfully processed stored OAuth data, updating UI"),ae(o.data.did,o.data.handle)):l("warning","Failed to process stored OAuth data",o),l("info","Clearing stored OAuth callback data"),await ee(["oauth_callback_data"])}else l("info","Stored OAuth callback data is too old, removing it",{age:(r-e)/1e3,maxAgeSeconds:5*60}),await ee(["oauth_callback_data"])}else l("info","No stored OAuth callback data found"),await pt()}async function pt(){l("info","Checking for existing OAuth session");try{await D.init(),M(F());let t=await chrome.storage.local.get(["atcute-oauth:sessions"]);if(t&&t["atcute-oauth:sessions"]){let e=t["atcute-oauth:sessions"],r=Object.keys(e);if(r.length>0){let n=r[0];l("info","Found existing session for DID:",n);let o=null,a=await K([k.userHandle]);if(a[k.userHandle])o=a[k.userHandle],l("info","Found stored handle:",o);else try{o=await Ee(n),l("info","Resolved handle from DID:",o),await ve({[k.userDid]:n,[k.userHandle]:o})}catch(i){l("error","Error resolving handle from DID:",i)}if(o)return l("info","Updating UI with existing session data"),ae(n,o),!0}}return l("info","No existing session found"),!1}catch(t){return l("error","Error checking existing session:",t),!1}}function te(){let t=document.getElementById("skeet-text"),e=document.getElementById("char-count"),r=document.getElementById("skeet-button"),n="",o=-1,a=0,i=!1,s=document.querySelectorAll("#mention");for(let u of s)u.remove();let c=document.createElement("button");c.id="mention",c.className="text-primary-500 dark:text-primary-400 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 p-2 mr-2 hidden border-none rounded-md",c.textContent="@",c.title="Add mention",e.parentNode.insertBefore(c,e),chrome.tabs.query({active:!0,currentWindow:!0},async u=>{var f,p,g;if((f=u[0])!=null&&f.url){n=u[0].url;let m=n.match(/https?:\/\/(x\.com|twitter\.com)\/([^/]+)\/status\/(\d+)/);if(m){i=!0;let[y,S,v,_]=m,P=`x/${v}/status/${_}`;try{let[U]=await chrome.scripting.executeScript({target:{tabId:u[0].id},func:()=>{let x=document.querySelector('[data-testid="tweetText"]');return x?x.textContent:null}});if(U!=null&&U.result){let x=U.result.trim(),q=`#SKEETED 6 + ${P}`,se=300-q.length-2,Se=x.length>se?`${x.substring(0,se-3)}...`:x;t.value=`${Se} 7 + 8 + ${q}`}else t.value=`#SKEETED 9 + ${P}`;d()}catch{t.value=`#SKEETED 10 + ${P}`,d()}}else t.value=`${n} 11 + 12 + `,d();try{let S=new URL(n).hostname,v=await chrome.storage.local.get(["atcute-oauth:sessions"]);l("info","Session data for domain check",v);let _=v["atcute-oauth:sessions"];if(_){let P=Object.keys(_)[0],U=_[P];if((g=(p=U==null?void 0:U.value)==null?void 0:p.token)!=null&&g.access){let x=await fetch(`https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=${S}`,{headers:{Authorization:`Bearer ${U.value.token.access}`,Accept:"application/json"}});x.ok&&(await x.json()).did&&c.classList.remove("hidden")}}}catch{}}});function d(){let u=t.value,f=u.match(/https?:\/\/(x\.com|twitter\.com)\/([^/]+)\/status\/(\d+)/);if(f){let[g,m,y]=f;u=u.replace(g,`x/${m}/status/${y}`)}else n&&u.includes(n)&&(u=u.replace(n,"x".repeat(39)));let p=300-u.length;e.textContent=p,r.disabled=u.trim().length===0||p<0,p<0?(e.classList.add("text-red-500","dark:text-red-400"),e.classList.remove("text-gray-500","dark:text-gray-400")):(e.classList.remove("text-red-500","dark:text-red-400"),e.classList.add("text-gray-500","dark:text-gray-400"))}function h(){let f=`@${new URL(n).hostname}`,p=t.selectionStart;if(o===p-a)t.value=t.value.slice(0,o)+t.value.slice(o+a),t.selectionStart=o,t.selectionEnd=o,o=-1,a=0;else{let g=t.value.slice(0,p),m=t.value.slice(p);t.value=g+f+m,o=p,a=f.length,t.selectionStart=p+f.length,t.selectionEnd=p+f.length}d(),t.focus()}async function w(){try{r.disabled=!0,r.innerHTML='<span class="inline-block animate-pulse">...</span>';let u=t.value.trim(),f=u.match(/https?:\/\/(x\.com|twitter\.com)\/([^/]+)\/status\/(\d+)/);if(f){let[g,m]=f,y=`x/${g}/status/${m}`,v=u.split(` 13 + `).filter(x=>x.trim()).filter(x=>!x.includes("x.com")&&!x.includes("twitter.com")&&x!=="#SKEETED").join(` 14 + `).trim(),_=`#SKEETED 15 + ${y}`,P=300-_.length-2,U=v.length>P?`${v.substring(0,P-3)}...`:v;u=U?`${U} 16 + 17 + ${_}`:_}let p=await de(u);if(i&&(p!=null&&p.uri)){let[g,m]=p.uri.split("/").slice(-3),y=`https://bsky.app/profile/${g}/post/${m}`;t.value="",d();let S=document.createElement("div");S.className="mt-12 p-3 bg-gray-50 dark:bg-gray-800 rounded-lg",S.innerHTML=` 18 + <div class="flex items-center gap-2 p-2 bg-white dark:bg-gray-900 rounded border border-gray-200 dark:border-gray-700"> 19 + <div class="flex-grow font-mono text-xs text-gray-800 dark:text-gray-200 overflow-hidden text-ellipsis whitespace-nowrap"> 20 + #SKEETED 21 + ${y} 22 + </div> 23 + <button id="copy-button" class="flex-shrink-0 text-primary-500 dark:text-primary-400 hover:text-primary-600 dark:hover:text-primary-300 p-2 border-none"> 24 + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 25 + <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect> 26 + <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path> 27 + </svg> 28 + </button> 29 + </div> 30 + `;let v=document.getElementById("skeet");v.innerHTML="",v.appendChild(S);let _=document.getElementById("copy-button");_.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(`#SKEETED 31 + ${y}`),_.innerHTML=` 32 + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 33 + <polyline points="20 6 9 17 4 12"></polyline> 34 + </svg> 35 + `,setTimeout(()=>{_.innerHTML=` 36 + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 37 + <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect> 38 + <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path> 39 + </svg> 40 + `},2e3)}catch{}})}else setTimeout(()=>{t.value="",d(),r.innerHTML="Skeet",r.disabled=!1},2e3)}catch(u){r.innerHTML="Skeet",r.disabled=!1;let f=document.createElement("div");f.className="mt-3 p-2 text-sm text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/50 rounded-lg text-center",f.textContent=u.message||"Failed to post",r.parentNode.appendChild(f),setTimeout(()=>f.remove(),3e3)}}t.addEventListener("input",d),c.addEventListener("click",h),r.addEventListener("click",w)}function ft(){chrome.storage.local.get(["theme"],({theme:e})=>{e==="dark"||!e&&window.matchMedia("(prefers-color-scheme: dark)").matches?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")}),document.getElementById("theme-toggle").addEventListener("click",()=>{let e=document.documentElement.classList.toggle("dark");chrome.storage.local.set({theme:e?"dark":"light"})}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",e=>{chrome.storage.local.get(["theme"],({theme:r})=>{r||(e.matches?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark"))})})}function re(t){let e=document.getElementById("user-section");e.innerHTML=` 41 + <div class="flex items-end justify-between"> 42 + <img src="${t.avatar}" alt="Profile Avatar" class="w-8 rounded-full"> 43 + <div class="ml-[3px]"> 44 + <div class="font-medium text-xs text-gray-900 dark:text-gray-100">${t.displayName}</div> 45 + <div class="text-xs text-gray-500 dark:text-gray-400">@${t.userHandle}</div> 46 + </div> 47 + </div> 48 + `}(async()=>{let t=await K([k.userDid,k.userHandle,k.colorScheme]);ft();let e=E(document.getElementById("login-container")),r=E(document.getElementById("loginForm")),n=E(document.getElementById("skeet")),o=E(document.getElementById("logoutLink")),a=document.getElementById("user-section"),i=E(document.getElementById("identityInput")),s=E(document.getElementById("loginBtn")),c=E(document.getElementById("status")),d=t[k.userDid],h=t[k.userHandle];if(await ht(),d&&h){e.classList.add("hidden"),n.classList.remove("hidden"),o.classList.remove("hidden");let{displayName:w,avatar:u}=await z(d);l("info","Got user profile",{displayName:w,avatar:u}),re({displayName:w,userHandle:h,avatar:u}),te()}s.addEventListener("click",async w=>{w.preventDefault(),s.disabled=!0,s.style.cursor="progress",c.innerText="Setting up login page ...",i.disabled=!0,i.style.cursor="progress";try{await D.init(),M(F());let{identity:u,metadata:f}=await fe(i.value),p=await ot({metadata:f,identity:u,scope:"atproto transition:generic"});E(st(E(p))).focus(),c.innerText="Check opened window / tab"}catch(u){c.innerText=u,s.style.cursor="",s.disabled=!1,i.disabled=!1,i.style.cursor=""}return!1})})();
+170
uno.config.js
··· 1 + import { defineConfig, presetUno } from 'unocss'; 2 + 3 + export default defineConfig({ 4 + presets: [presetUno()], 5 + theme: { 6 + colors: { 7 + primary: { 8 + 50: '#f0f9ff', 9 + 100: '#e0f2fe', 10 + 200: '#bae6fd', 11 + 300: '#7dd3fc', 12 + 400: '#38bdf8', 13 + 500: '#0ea5e9', 14 + 600: '#0284c7', 15 + 700: '#0369a1', 16 + 800: '#075985', 17 + 900: '#0c4a6e', 18 + }, 19 + }, 20 + }, 21 + rules: [ 22 + ['transition-filter', { transition: 'filter 0.2s ease-in-out' }], 23 + ['filter-dark-logo', { filter: 'invert(1) brightness(0.8)' }], 24 + ['filter-light-logo', { filter: 'invert(0) brightness(0.2)' }], 25 + ], 26 + safelist: [ 27 + // Layout 28 + 'flex', 29 + 'flex-col', 30 + 'items-center', 31 + 'items-start', 32 + 'items-end', 33 + 'justify-between', 34 + 'justify-center', 35 + 'space-y-4', 36 + 'space-y-3', 37 + 'space-y-2', 38 + 'space-y-0.5', 39 + 'w-full', 40 + 'w-[300px]', 41 + 'w-[200px]', 42 + 'w-[100px]', 43 + 'w-10', 44 + 'w-5', 45 + 'h-5', 46 + 'h-8', 47 + 'min-h-[200px]', 48 + 'w-auto', 49 + 'block', 50 + 'hidden', 51 + 'inline-block', 52 + 53 + // Spacing 54 + 'p-6', 55 + 'p-4', 56 + 'p-3', 57 + 'p-2', 58 + 'px-4', 59 + 'px-2', 60 + 'py-3', 61 + 'py-2', 62 + 'py-1', 63 + 'mt-6', 64 + 'mt-3', 65 + 'mx-auto', 66 + 'ml-[3px]', 67 + 68 + // Typography 69 + 'text-base', 70 + 'text-sm', 71 + 'text-xs', 72 + 'font-medium', 73 + 'text-center', 74 + 'font-sans', 75 + 76 + // Colors 77 + 'bg-white', 78 + 'bg-gray-50', 79 + 'bg-gray-100', 80 + 'bg-gray-700', 81 + 'bg-gray-800', 82 + 'bg-gray-900', 83 + 'bg-primary-500', 84 + 'bg-primary-600', 85 + 'bg-red-50', 86 + 'bg-red-900/50', 87 + 'text-gray-100', 88 + 'text-gray-400', 89 + 'text-gray-500', 90 + 'text-gray-600', 91 + 'text-gray-900', 92 + 'text-primary-600', 93 + 'text-red-400', 94 + 'text-red-600', 95 + 'border-gray-100', 96 + 'border-gray-200', 97 + 'border-gray-700', 98 + 'border-none', 99 + 'text-green-600', 100 + 'text-green-400', 101 + 'bg-green-50', 102 + 'bg-green-900/50', 103 + 'dark:text-green-400', 104 + 'dark:bg-green-900/50', 105 + 106 + // Borders 107 + 'border', 108 + 'border-b', 109 + 'border-t', 110 + 'rounded-lg', 111 + 'rounded-xl', 112 + 'rounded-full', 113 + 114 + // Effects 115 + 'shadow-lg', 116 + 'transition-all', 117 + 'transition-colors', 118 + 'transition-[filter]', 119 + 'duration-200', 120 + 'ease-in-out', 121 + 'animate-pulse', 122 + 'cursor-pointer', 123 + '[filter:invert(0)_brightness(0.2)]', 124 + '[filter:invert(1)_brightness(0.8)]', 125 + 126 + // Dark mode 127 + 'dark:bg-gray-800', 128 + 'dark:bg-gray-900', 129 + 'dark:bg-primary-500', 130 + 'dark:bg-primary-600', 131 + 'dark:bg-red-900/50', 132 + 'dark:text-gray-100', 133 + 'dark:text-gray-400', 134 + 'dark:text-gray-500', 135 + 'dark:text-red-400', 136 + 'dark:border-gray-700', 137 + 'dark:block', 138 + 'dark:hidden', 139 + 'dark:[filter:invert(1)_brightness(0.8)]', 140 + 141 + // Interactive 142 + 'hover:bg-gray-100', 143 + 'hover:bg-primary-700', 144 + 'hover:text-red-600', 145 + 'hover:border-red-200', 146 + 'hover:bg-red-50', 147 + 'hover:text-primary-700', 148 + 'dark:hover:bg-gray-700', 149 + 'dark:hover:bg-primary-600', 150 + 'dark:hover:text-red-400', 151 + 'active:bg-primary-800', 152 + 'dark:active:bg-primary-700', 153 + 'focus:ring-2', 154 + 'focus:ring-primary-500', 155 + 'focus:border-transparent', 156 + 'focus:outline-none', 157 + 'placeholder:text-gray-400', 158 + 'dark:placeholder:text-gray-500', 159 + 'disabled:opacity-50', 160 + 'disabled:cursor-not-allowed', 161 + 162 + // Form 163 + 'resize-none', 164 + 'w-full', 165 + 'px-3', 166 + 'py-2', 167 + 'space-y-3', 168 + 'hidden', 169 + ], 170 + });