+23
.gitignore
+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
+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
+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
+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
+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
+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
+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
+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
src/assets/icon/icon-128.png
This is a binary file and will not be displayed.
src/assets/icon/icon-16.png
src/assets/icon/icon-16.png
This is a binary file and will not be displayed.
src/assets/icon/icon-32.png
src/assets/icon/icon-32.png
This is a binary file and will not be displayed.
src/assets/icon/icon-48.png
src/assets/icon/icon-48.png
This is a binary file and will not be displayed.
+69
src/assets/logo.svg
+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
+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
+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
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
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
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
+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
+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
+
});