Monorepo for Tangled
0

Configure Feed

Select the types of activity you want to include in your feed.

web: init with scaffolding

Signed-off-by: dawn <dawn@tangled.org>

dawn (Jul 8, 2026, 11:23 PM +0300) 5ff15074 3fc289e5

+5721
+49
.tangled/workflows/web.yml
··· 1 + when: 2 + - event: ["push", "pull_request"] 3 + branch: master 4 + paths: 5 + - web/** 6 + - input.css 7 + - tailwind.config.js 8 + - flake.nix 9 + - flake.lock 10 + - nix/pkgs/web-static-files.nix 11 + 12 + engine: microvm 13 + image: nixos 14 + 15 + dependencies: 16 + - nodejs 17 + 18 + steps: 19 + - name: install web deps 20 + command: | 21 + cd web 22 + corepack pnpm install --frozen-lockfile 23 + 24 + - name: lint web 25 + command: | 26 + cd web 27 + corepack pnpm run lint 28 + 29 + - name: typecheck web 30 + command: | 31 + cd web 32 + corepack pnpm run check 33 + 34 + - name: test web 35 + command: | 36 + cd web 37 + corepack pnpm run test:unit -- --run 38 + 39 + - name: sync web static assets 40 + command: | 41 + out=$(nix build .#web-static-files --no-link --print-out-paths) 42 + mkdir -p web/static 43 + rm -rf web/static/fonts web/static/logos 44 + cp -fr --no-preserve=ownership,mode "$out"/* web/static 45 + 46 + - name: build web 47 + command: | 48 + cd web 49 + corepack pnpm run build
+8
flake.nix
··· 152 152 appview-static-files = self.callPackage ./nix/pkgs/appview-static-files.nix { 153 153 inherit htmx-src htmx-ws-src lucide-src inter-fonts-src ibm-plex-mono-src actor-typeahead-src mermaid-src hls-src mathjax-src; 154 154 }; 155 + web-static-files = self.callPackage ./nix/pkgs/web-static-files.nix { 156 + inherit inter-fonts-src ibm-plex-mono-src; 157 + }; 155 158 appview = self.callPackage ./nix/pkgs/appview.nix {}; 156 159 blog = self.callPackage ./nix/pkgs/blog.nix {}; 157 160 docs = self.callPackage ./nix/pkgs/docs.nix { ··· 208 211 (packages) 209 212 appview 210 213 appview-static-files 214 + web-static-files 211 215 blog 212 216 lexgen 213 217 goat ··· 367 371 packages'.tap 368 372 pkgs.e2fsprogs 369 373 pkgs.util-linux 374 + pkgs.pnpm 370 375 ] 371 376 ++ pkgs.lib.optionals pkgs.stdenv.isLinux [ 372 377 pkgs.parted ··· 380 385 [ -d appview/pages/static/icons ] && [ ! -w appview/pages/static/icons ] && chmod -R u+rwX appview/pages/static 381 386 # no preserve is needed because watch-tailwind will want to be able to overwrite 382 387 cp -fr --no-preserve=ownership,mode ${packages'.appview-static-files}/* appview/pages/static 388 + mkdir -p web/static 389 + rm -rf web/static/fonts web/static/logos 390 + cp -fr --no-preserve=ownership,mode ${packages'.web-static-files}/* web/static 383 391 export TANGLED_OAUTH_CLIENT_KID="$(date +%s)" 384 392 export TANGLED_OAUTH_CLIENT_SECRET="$(${packages'.goat}/bin/goat key generate -t P-256 | grep -A1 "Secret Key" | tail -n1 | awk '{print $1}')" 385 393 # Make xcrun (Nix stub) able to find ld from the system Command Line Tools.
+18
nix/pkgs/web-static-files.nix
··· 1 + { 2 + runCommandLocal, 3 + inter-fonts-src, 4 + ibm-plex-mono-src, 5 + dolly, 6 + }: 7 + runCommandLocal "web-static-files" {} '' 8 + mkdir -p $out/{fonts,logos} 9 + 10 + cp -f ${inter-fonts-src}/web/InterVariable*.woff2 $out/fonts/ 11 + cp -f ${inter-fonts-src}/web/InterDisplay*.woff2 $out/fonts/ 12 + cp -f ${ibm-plex-mono-src}/fonts/complete/woff2/IBMPlexMono*.woff2 $out/fonts/ 13 + 14 + ${dolly}/bin/dolly -output $out/logos/dolly.png -size 180 15 + ${dolly}/bin/dolly -output $out/logos/dolly.ico -size 48 16 + ${dolly}/bin/dolly -output $out/logos/dolly.svg -color currentColor -favicon 17 + ${dolly}/bin/dolly -output $out/logos/logotype.svg -kind logotype -color currentColor 18 + ''
+9
pnpm-lock.yaml
··· 1 + lockfileVersion: '9.0' 2 + 3 + settings: 4 + autoInstallPeers: true 5 + excludeLinksFromLockfile: false 6 + 7 + importers: 8 + 9 + .: {}
+26
web/.gitignore
··· 1 + node_modules 2 + 3 + # Output 4 + .output 5 + .vercel 6 + .netlify 7 + .wrangler 8 + /.svelte-kit 9 + /build 10 + 11 + # OS 12 + .DS_Store 13 + Thumbs.db 14 + 15 + # Env 16 + .env 17 + .env.* 18 + !.env.example 19 + !.env.test 20 + 21 + # Vite 22 + vite.config.js.timestamp-* 23 + vite.config.ts.timestamp-* 24 + # Playwright 25 + test-results 26 + .vscode/
+1
web/.npmrc
··· 1 + engine-strict=true
+9
web/.prettierignore
··· 1 + # Package Managers 2 + package-lock.json 3 + pnpm-lock.yaml 4 + yarn.lock 5 + bun.lock 6 + bun.lockb 7 + 8 + # Miscellaneous 9 + /static/
+8
web/.vscode/extensions.json
··· 1 + { 2 + "recommendations": [ 3 + "svelte.svelte-vscode", 4 + "esbenp.prettier-vscode", 5 + "dbaeumer.vscode-eslint", 6 + "bradlc.vscode-tailwindcss" 7 + ] 8 + }
+5
web/.vscode/settings.json
··· 1 + { 2 + "files.associations": { 3 + "*.css": "tailwindcss" 4 + } 5 + }
+23
web/Containerfile
··· 1 + FROM node:24-slim AS deps 2 + WORKDIR /app 3 + RUN corepack enable 4 + COPY package.json pnpm-lock.yaml ./ 5 + RUN corepack pnpm install --frozen-lockfile 6 + 7 + FROM node:24-slim AS build 8 + WORKDIR /app 9 + RUN corepack enable 10 + COPY --from=deps /app/node_modules ./node_modules 11 + COPY . . 12 + RUN corepack pnpm run build 13 + 14 + FROM node:24-slim 15 + WORKDIR /app 16 + ENV NODE_ENV=production 17 + ENV HOST=0.0.0.0 18 + ENV PORT=3000 19 + COPY --from=build /app/build ./build 20 + COPY --from=build /app/package.json ./package.json 21 + COPY --from=build /app/node_modules ./node_modules 22 + EXPOSE 3000 23 + CMD ["node", "build"]
+42
web/README.md
··· 1 + # sv 2 + 3 + Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli). 4 + 5 + ## Creating a project 6 + 7 + If you're seeing this, you've probably already done this step. Congrats! 8 + 9 + ```sh 10 + # create a new project 11 + npx sv create my-app 12 + ``` 13 + 14 + To recreate this project with the same configuration: 15 + 16 + ```sh 17 + # recreate this project 18 + npx sv@0.16.2 create --template minimal --types ts --add prettier eslint vitest="usages:unit" playwright tailwindcss="plugins:typography" sveltekit-adapter="adapter:node" --no-install web 19 + ``` 20 + 21 + ## Developing 22 + 23 + Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 24 + 25 + ```sh 26 + npm run dev 27 + 28 + # or start the server and open the app in a new browser tab 29 + npm run dev -- --open 30 + ``` 31 + 32 + ## Building 33 + 34 + To create a production version of your app: 35 + 36 + ```sh 37 + npm run build 38 + ``` 39 + 40 + You can preview the production build with `npm run preview`. 41 + 42 + > To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
+41
web/eslint.config.js
··· 1 + import prettier from 'eslint-config-prettier'; 2 + import path from 'node:path'; 3 + import js from '@eslint/js'; 4 + import svelte from 'eslint-plugin-svelte'; 5 + import { defineConfig, includeIgnoreFile } from 'eslint/config'; 6 + import globals from 'globals'; 7 + import ts from 'typescript-eslint'; 8 + 9 + const gitignorePath = path.resolve(import.meta.dirname, '.gitignore'); 10 + 11 + export default defineConfig( 12 + includeIgnoreFile(gitignorePath), 13 + js.configs.recommended, 14 + ts.configs.recommended, 15 + svelte.configs.recommended, 16 + prettier, 17 + svelte.configs.prettier, 18 + { 19 + languageOptions: { globals: { ...globals.browser, ...globals.node } }, 20 + rules: { 21 + // typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects. 22 + // see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors 23 + 'no-undef': 'off' 24 + } 25 + }, 26 + { 27 + files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'], 28 + languageOptions: { 29 + parserOptions: { 30 + projectService: true, 31 + extraFileExtensions: ['.svelte'], 32 + parser: ts.parser 33 + } 34 + } 35 + }, 36 + { 37 + // Override or add rule settings here, such as: 38 + // 'svelte/button-has-type': 'error' 39 + rules: {} 40 + } 41 + );
+54
web/package.json
··· 1 + { 2 + "name": "web", 3 + "private": true, 4 + "version": "0.0.1", 5 + "type": "module", 6 + "packageManager": "pnpm@11.10.0", 7 + "scripts": { 8 + "dev": "vite dev", 9 + "build": "vite build", 10 + "preview": "vite preview --host 0.0.0.0", 11 + "start": "node build", 12 + "prepare": "svelte-kit sync || echo ''", 13 + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 14 + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 15 + "lint": "prettier --check . && eslint .", 16 + "format": "prettier --write .", 17 + "test:unit": "vitest", 18 + "test": "vitest --run && playwright test", 19 + "ci": "prettier --check . && eslint . && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json && vitest --run && vite build", 20 + "test:e2e": "playwright test" 21 + }, 22 + "devDependencies": { 23 + "@eslint/js": "^10.0.1", 24 + "@iconify-json/lucide": "^1.2.116", 25 + "@playwright/test": "^1.60.0", 26 + "@sveltejs/adapter-node": "^5.5.4", 27 + "@sveltejs/kit": "^2.63.0", 28 + "@sveltejs/vite-plugin-svelte": "^7.1.2", 29 + "@tailwindcss/vite": "^4.3.2", 30 + "@types/node": "^24", 31 + "eslint": "^10.4.1", 32 + "eslint-config-prettier": "^10.1.8", 33 + "eslint-plugin-svelte": "^3.19.0", 34 + "globals": "^17.6.0", 35 + "prettier": "^3.8.3", 36 + "prettier-plugin-svelte": "^4.1.0", 37 + "prettier-plugin-tailwindcss": "^0.8.0", 38 + "svelte": "^5.56.1", 39 + "svelte-check": "^4.6.0", 40 + "tailwindcss": "^4.3.2", 41 + "typescript": "^6.0.3", 42 + "typescript-eslint": "^8.60.1", 43 + "unplugin-icons": "^23.0.1", 44 + "vite": "^8.0.16", 45 + "vitest": "^4.1.8" 46 + }, 47 + "dependencies": { 48 + "@atcute/atproto": "^4.0.3", 49 + "@atcute/client": "^5.1.1", 50 + "@atcute/identity-resolver": "^2.0.1", 51 + "@atcute/lexicons": "^2.0.2", 52 + "@atcute/oauth-browser-client": "^4.0.1" 53 + } 54 + }
+6
web/playwright.config.ts
··· 1 + import { defineConfig } from '@playwright/test'; 2 + 3 + export default defineConfig({ 4 + webServer: { command: 'pnpm run build && pnpm run preview', port: 4173 }, 5 + testMatch: '**/*.e2e.{ts,js}' 6 + });
+3122
web/pnpm-lock.yaml
··· 1 + lockfileVersion: '9.0' 2 + 3 + settings: 4 + autoInstallPeers: true 5 + excludeLinksFromLockfile: false 6 + 7 + importers: 8 + 9 + .: 10 + dependencies: 11 + '@atcute/atproto': 12 + specifier: ^4.0.3 13 + version: 4.0.3(@atcute/lexicons@2.0.2) 14 + '@atcute/client': 15 + specifier: ^5.1.1 16 + version: 5.1.1(@atcute/lexicons@2.0.2)(typescript@6.0.3) 17 + '@atcute/identity-resolver': 18 + specifier: ^2.0.1 19 + version: 2.0.1(@atcute/identity@2.0.1(@atcute/lexicons@2.0.2)(typescript@6.0.3))(@atcute/lexicons@2.0.2)(typescript@6.0.3) 20 + '@atcute/lexicons': 21 + specifier: ^2.0.2 22 + version: 2.0.2 23 + '@atcute/oauth-browser-client': 24 + specifier: ^4.0.1 25 + version: 4.0.1(@atcute/identity-resolver@2.0.1(@atcute/identity@2.0.1(@atcute/lexicons@2.0.2)(typescript@6.0.3))(@atcute/lexicons@2.0.2)(typescript@6.0.3))(@atcute/lexicons@2.0.2)(typescript@6.0.3) 26 + devDependencies: 27 + '@eslint/js': 28 + specifier: ^10.0.1 29 + version: 10.0.1(eslint@10.6.0(jiti@2.7.0)) 30 + '@iconify-json/lucide': 31 + specifier: ^1.2.116 32 + version: 1.2.116 33 + '@playwright/test': 34 + specifier: ^1.60.0 35 + version: 1.61.1 36 + '@sveltejs/adapter-node': 37 + specifier: ^5.5.4 38 + version: 5.5.7(@sveltejs/kit@2.69.1(@sveltejs/vite-plugin-svelte@7.1.3(svelte@5.56.4(@typescript-eslint/types@8.63.0))(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.56.4(@typescript-eslint/types@8.63.0))(typescript@6.0.3)(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0))) 39 + '@sveltejs/kit': 40 + specifier: ^2.63.0 41 + version: 2.69.1(@sveltejs/vite-plugin-svelte@7.1.3(svelte@5.56.4(@typescript-eslint/types@8.63.0))(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.56.4(@typescript-eslint/types@8.63.0))(typescript@6.0.3)(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)) 42 + '@sveltejs/vite-plugin-svelte': 43 + specifier: ^7.1.2 44 + version: 7.1.3(svelte@5.56.4(@typescript-eslint/types@8.63.0))(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)) 45 + '@tailwindcss/vite': 46 + specifier: ^4.3.2 47 + version: 4.3.2(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)) 48 + '@types/node': 49 + specifier: ^24 50 + version: 24.13.2 51 + eslint: 52 + specifier: ^10.4.1 53 + version: 10.6.0(jiti@2.7.0) 54 + eslint-config-prettier: 55 + specifier: ^10.1.8 56 + version: 10.1.8(eslint@10.6.0(jiti@2.7.0)) 57 + eslint-plugin-svelte: 58 + specifier: ^3.19.0 59 + version: 3.20.0(eslint@10.6.0(jiti@2.7.0))(svelte@5.56.4(@typescript-eslint/types@8.63.0)) 60 + globals: 61 + specifier: ^17.6.0 62 + version: 17.7.0 63 + prettier: 64 + specifier: ^3.8.3 65 + version: 3.9.4 66 + prettier-plugin-svelte: 67 + specifier: ^4.1.0 68 + version: 4.1.1(prettier@3.9.4)(svelte@5.56.4(@typescript-eslint/types@8.63.0)) 69 + prettier-plugin-tailwindcss: 70 + specifier: ^0.8.0 71 + version: 0.8.0(prettier-plugin-svelte@4.1.1(prettier@3.9.4)(svelte@5.56.4(@typescript-eslint/types@8.63.0)))(prettier@3.9.4) 72 + svelte: 73 + specifier: ^5.56.1 74 + version: 5.56.4(@typescript-eslint/types@8.63.0) 75 + svelte-check: 76 + specifier: ^4.6.0 77 + version: 4.7.1(picomatch@4.0.5)(svelte@5.56.4(@typescript-eslint/types@8.63.0))(typescript@6.0.3) 78 + tailwindcss: 79 + specifier: ^4.3.2 80 + version: 4.3.2 81 + typescript: 82 + specifier: ^6.0.3 83 + version: 6.0.3 84 + typescript-eslint: 85 + specifier: ^8.60.1 86 + version: 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) 87 + unplugin-icons: 88 + specifier: ^23.0.1 89 + version: 23.0.1(svelte@5.56.4(@typescript-eslint/types@8.63.0)) 90 + vite: 91 + specifier: ^8.0.16 92 + version: 8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) 93 + vitest: 94 + specifier: ^4.1.8 95 + version: 4.1.10(@types/node@24.13.2)(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)) 96 + 97 + packages: 98 + 99 + '@antfu/install-pkg@1.1.0': 100 + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} 101 + 102 + '@atcute/atproto@4.0.3': 103 + resolution: {integrity: sha512-BNylfO7nK0yYBpSpnGhOYgrJTeZWrXHPrb6tOQmp9A3Am0epctIWm6/5lPC4ZNPHpUbwr5w/LzH/v7kjAoKEDg==} 104 + peerDependencies: 105 + '@atcute/lexicons': ^2.0.0 106 + 107 + '@atcute/client@5.1.1': 108 + resolution: {integrity: sha512-cn5/Zi/qo37WtQG6gzIC7JPs0RDzX9Z4eaceX45SpKgLZoc3fCFDJcE7C8xsbxBNfjry2T6PmUxWA8obebZsEQ==} 109 + peerDependencies: 110 + '@atcute/lexicons': ^2.0.0 111 + 112 + '@atcute/identity-resolver@2.0.1': 113 + resolution: {integrity: sha512-0enA9w7XnbbqsZ5Rcl6jXLf7ZZuwFQ9dBmxFq3qOxPHLaCETsqsrQflXDPqiM27TnZwYq8sqCV5D1mFOksggDQ==} 114 + peerDependencies: 115 + '@atcute/identity': ^2.0.0 116 + '@atcute/lexicons': ^2.0.0 117 + 118 + '@atcute/identity@2.0.1': 119 + resolution: {integrity: sha512-FEURUvl30SyyWWikkvm+MLz0Snuf0OF10L/qxRhWjj6qDB5Ib+XWhiBuwidjvhCkrCepTUNLbj4TlUm/gHaUig==} 120 + peerDependencies: 121 + '@atcute/lexicons': ^2.0.0 122 + 123 + '@atcute/lexicons@2.0.2': 124 + resolution: {integrity: sha512-ATBADJAy4KQ76NB86BjgYKrRdbDRUo76Cbqna4WIfQAgN105Rcy972MiNKs+BSmcOOM3WakilgTm0CXD4RC0iA==} 125 + 126 + '@atcute/multibase@1.2.4': 127 + resolution: {integrity: sha512-WeX12hvFZEim6C+cyv7Eqd93w6DzubNWQGmTFBghjsEuXvMe4HbBCYvsti0OUnbA5qLBPlsTyssQUJeLlHCzIw==} 128 + 129 + '@atcute/oauth-browser-client@4.0.1': 130 + resolution: {integrity: sha512-k5GGDFWUqTifbi7bMk4LhwG12XWNJop9atZ3ocBpzHJvXboTqp7E2zaD/arhJWxHXp5+0A1R3EKXdHsVbWjHyA==} 131 + peerDependencies: 132 + '@atcute/identity-resolver': ^2.0.0 133 + '@atcute/lexicons': ^2.0.0 134 + 135 + '@atcute/oauth-crypto@1.0.1': 136 + resolution: {integrity: sha512-ghC8ceFx0r6pi5X3dNoET1K6PNg8afeAOZLD4PKLhrpVYdRtRrgY4uqAe3ojtSIjoS6GXmVm063CoJ2xtg/MoQ==} 137 + 138 + '@atcute/oauth-keyset@0.1.2': 139 + resolution: {integrity: sha512-2CUazWBWRjSEoYZDaLS4zEPgCOcr9LgnMhPr1pzr9I+DytRnoXmrdbRs4xBVg4iUdXtdzU48DsMaGi6bHXaFcg==} 140 + 141 + '@atcute/oauth-types@1.0.1': 142 + resolution: {integrity: sha512-9uFP/nK0PgPDsaNbLArzrCHvTZO1k04cSEX5jZ75W2Jh7Jxbh/CSTenSrad3CZXuX6y6hDquEtl6H/IqLtTmHw==} 143 + 144 + '@atcute/uint8array@1.1.3': 145 + resolution: {integrity: sha512-2KLcMQHUFtntY3tEjdyqqq1tR9hvPFndluWFCa637QY0cMyvq0fHSnhmZeWaSRIXMCwVDY3TLLWHNOHEWFb11g==} 146 + 147 + '@atcute/util-fetch@2.0.1': 148 + resolution: {integrity: sha512-ugWTOLemA8OxSOj7c8q6ncRmBGFDHSwwE1YinO+PCtaw6WLQFGBfHn+yikQ0e3wTK2t4IPjQ5PxZcRXm961ZVA==} 149 + 150 + '@atcute/util-text@1.3.3': 151 + resolution: {integrity: sha512-WhedTmg/msFhrdwXw9RjnNcDl8Vmisxl4+Vzyf5k3+8Gj5TKQg72dLSDtBNmNLd61RbHjgfQRBgE0ez6q/jciw==} 152 + 153 + '@emnapi/core@1.11.1': 154 + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} 155 + 156 + '@emnapi/runtime@1.11.1': 157 + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} 158 + 159 + '@emnapi/wasi-threads@1.2.2': 160 + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} 161 + 162 + '@eslint-community/eslint-utils@4.9.1': 163 + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} 164 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 165 + peerDependencies: 166 + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 167 + 168 + '@eslint-community/regexpp@4.12.2': 169 + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} 170 + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 171 + 172 + '@eslint/config-array@0.23.5': 173 + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} 174 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 175 + 176 + '@eslint/config-helpers@0.6.0': 177 + resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} 178 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 179 + 180 + '@eslint/core@1.2.1': 181 + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} 182 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 183 + 184 + '@eslint/js@10.0.1': 185 + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} 186 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 187 + peerDependencies: 188 + eslint: ^10.0.0 189 + peerDependenciesMeta: 190 + eslint: 191 + optional: true 192 + 193 + '@eslint/object-schema@3.0.5': 194 + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} 195 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 196 + 197 + '@eslint/plugin-kit@0.7.2': 198 + resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} 199 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 200 + 201 + '@humanfs/core@0.19.2': 202 + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} 203 + engines: {node: '>=18.18.0'} 204 + 205 + '@humanfs/node@0.16.8': 206 + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} 207 + engines: {node: '>=18.18.0'} 208 + 209 + '@humanfs/types@0.15.0': 210 + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} 211 + engines: {node: '>=18.18.0'} 212 + 213 + '@humanwhocodes/module-importer@1.0.1': 214 + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 215 + engines: {node: '>=12.22'} 216 + 217 + '@humanwhocodes/retry@0.4.3': 218 + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} 219 + engines: {node: '>=18.18'} 220 + 221 + '@iconify-json/lucide@1.2.116': 222 + resolution: {integrity: sha512-mbwPmiUXaZyLMSeQOxiTqz2fmZikD9qiGnMBiev47UUNY9uGCEgMg9iUYwaJzCtJTDtAIyK4vokfIpqsVorgSw==} 223 + 224 + '@iconify/types@2.0.0': 225 + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} 226 + 227 + '@iconify/utils@3.1.4': 228 + resolution: {integrity: sha512-b1S7B1k9ohZ+iNTi2ATxbRYG9fTrJmUT0rc46bvVnNxqNRGW7dyo/vRREwyniI5IRN2RSJHDcm+s3BjWrSAjHw==} 229 + 230 + '@jridgewell/gen-mapping@0.3.13': 231 + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} 232 + 233 + '@jridgewell/remapping@2.3.5': 234 + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} 235 + 236 + '@jridgewell/resolve-uri@3.1.2': 237 + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 238 + engines: {node: '>=6.0.0'} 239 + 240 + '@jridgewell/sourcemap-codec@1.5.5': 241 + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} 242 + 243 + '@jridgewell/trace-mapping@0.3.31': 244 + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} 245 + 246 + '@napi-rs/wasm-runtime@1.1.6': 247 + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} 248 + peerDependencies: 249 + '@emnapi/core': ^1.7.1 250 + '@emnapi/runtime': ^1.7.1 251 + 252 + '@oxc-project/types@0.138.0': 253 + resolution: {integrity: sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==} 254 + 255 + '@playwright/test@1.61.1': 256 + resolution: {integrity: sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==} 257 + engines: {node: '>=18'} 258 + hasBin: true 259 + 260 + '@polka/url@1.0.0-next.29': 261 + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} 262 + 263 + '@rolldown/binding-android-arm64@1.1.4': 264 + resolution: {integrity: sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw==} 265 + engines: {node: ^20.19.0 || >=22.12.0} 266 + cpu: [arm64] 267 + os: [android] 268 + 269 + '@rolldown/binding-darwin-arm64@1.1.4': 270 + resolution: {integrity: sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ==} 271 + engines: {node: ^20.19.0 || >=22.12.0} 272 + cpu: [arm64] 273 + os: [darwin] 274 + 275 + '@rolldown/binding-darwin-x64@1.1.4': 276 + resolution: {integrity: sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg==} 277 + engines: {node: ^20.19.0 || >=22.12.0} 278 + cpu: [x64] 279 + os: [darwin] 280 + 281 + '@rolldown/binding-freebsd-x64@1.1.4': 282 + resolution: {integrity: sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ==} 283 + engines: {node: ^20.19.0 || >=22.12.0} 284 + cpu: [x64] 285 + os: [freebsd] 286 + 287 + '@rolldown/binding-linux-arm-gnueabihf@1.1.4': 288 + resolution: {integrity: sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA==} 289 + engines: {node: ^20.19.0 || >=22.12.0} 290 + cpu: [arm] 291 + os: [linux] 292 + 293 + '@rolldown/binding-linux-arm64-gnu@1.1.4': 294 + resolution: {integrity: sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w==} 295 + engines: {node: ^20.19.0 || >=22.12.0} 296 + cpu: [arm64] 297 + os: [linux] 298 + libc: [glibc] 299 + 300 + '@rolldown/binding-linux-arm64-musl@1.1.4': 301 + resolution: {integrity: sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng==} 302 + engines: {node: ^20.19.0 || >=22.12.0} 303 + cpu: [arm64] 304 + os: [linux] 305 + libc: [musl] 306 + 307 + '@rolldown/binding-linux-ppc64-gnu@1.1.4': 308 + resolution: {integrity: sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg==} 309 + engines: {node: ^20.19.0 || >=22.12.0} 310 + cpu: [ppc64] 311 + os: [linux] 312 + libc: [glibc] 313 + 314 + '@rolldown/binding-linux-s390x-gnu@1.1.4': 315 + resolution: {integrity: sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ==} 316 + engines: {node: ^20.19.0 || >=22.12.0} 317 + cpu: [s390x] 318 + os: [linux] 319 + libc: [glibc] 320 + 321 + '@rolldown/binding-linux-x64-gnu@1.1.4': 322 + resolution: {integrity: sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw==} 323 + engines: {node: ^20.19.0 || >=22.12.0} 324 + cpu: [x64] 325 + os: [linux] 326 + libc: [glibc] 327 + 328 + '@rolldown/binding-linux-x64-musl@1.1.4': 329 + resolution: {integrity: sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ==} 330 + engines: {node: ^20.19.0 || >=22.12.0} 331 + cpu: [x64] 332 + os: [linux] 333 + libc: [musl] 334 + 335 + '@rolldown/binding-openharmony-arm64@1.1.4': 336 + resolution: {integrity: sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA==} 337 + engines: {node: ^20.19.0 || >=22.12.0} 338 + cpu: [arm64] 339 + os: [openharmony] 340 + 341 + '@rolldown/binding-wasm32-wasi@1.1.4': 342 + resolution: {integrity: sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg==} 343 + engines: {node: ^20.19.0 || >=22.12.0} 344 + cpu: [wasm32] 345 + 346 + '@rolldown/binding-win32-arm64-msvc@1.1.4': 347 + resolution: {integrity: sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA==} 348 + engines: {node: ^20.19.0 || >=22.12.0} 349 + cpu: [arm64] 350 + os: [win32] 351 + 352 + '@rolldown/binding-win32-x64-msvc@1.1.4': 353 + resolution: {integrity: sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ==} 354 + engines: {node: ^20.19.0 || >=22.12.0} 355 + cpu: [x64] 356 + os: [win32] 357 + 358 + '@rolldown/pluginutils@1.0.1': 359 + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} 360 + 361 + '@rollup/plugin-commonjs@29.0.3': 362 + resolution: {integrity: sha512-ZaOxZceP7SOUW7Lqw5IRVweSQYWaeIPnXIGLiB690EBA3FGJTO40EEr2L5yZplJWsgTCogILRSpcAe7+U0Otdg==} 363 + engines: {node: '>=16.0.0 || 14 >= 14.17'} 364 + peerDependencies: 365 + rollup: ^2.68.0||^3.0.0||^4.0.0 366 + peerDependenciesMeta: 367 + rollup: 368 + optional: true 369 + 370 + '@rollup/plugin-json@6.1.0': 371 + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} 372 + engines: {node: '>=14.0.0'} 373 + peerDependencies: 374 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 375 + peerDependenciesMeta: 376 + rollup: 377 + optional: true 378 + 379 + '@rollup/plugin-node-resolve@16.0.3': 380 + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} 381 + engines: {node: '>=14.0.0'} 382 + peerDependencies: 383 + rollup: ^2.78.0||^3.0.0||^4.0.0 384 + peerDependenciesMeta: 385 + rollup: 386 + optional: true 387 + 388 + '@rollup/plugin-replace@6.0.3': 389 + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} 390 + engines: {node: '>=14.0.0'} 391 + peerDependencies: 392 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 393 + peerDependenciesMeta: 394 + rollup: 395 + optional: true 396 + 397 + '@rollup/pluginutils@5.4.0': 398 + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} 399 + engines: {node: '>=14.0.0'} 400 + peerDependencies: 401 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 402 + peerDependenciesMeta: 403 + rollup: 404 + optional: true 405 + 406 + '@rollup/rollup-android-arm-eabi@4.62.2': 407 + resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==} 408 + cpu: [arm] 409 + os: [android] 410 + 411 + '@rollup/rollup-android-arm64@4.62.2': 412 + resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==} 413 + cpu: [arm64] 414 + os: [android] 415 + 416 + '@rollup/rollup-darwin-arm64@4.62.2': 417 + resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==} 418 + cpu: [arm64] 419 + os: [darwin] 420 + 421 + '@rollup/rollup-darwin-x64@4.62.2': 422 + resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==} 423 + cpu: [x64] 424 + os: [darwin] 425 + 426 + '@rollup/rollup-freebsd-arm64@4.62.2': 427 + resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==} 428 + cpu: [arm64] 429 + os: [freebsd] 430 + 431 + '@rollup/rollup-freebsd-x64@4.62.2': 432 + resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==} 433 + cpu: [x64] 434 + os: [freebsd] 435 + 436 + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': 437 + resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} 438 + cpu: [arm] 439 + os: [linux] 440 + libc: [glibc] 441 + 442 + '@rollup/rollup-linux-arm-musleabihf@4.62.2': 443 + resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} 444 + cpu: [arm] 445 + os: [linux] 446 + libc: [musl] 447 + 448 + '@rollup/rollup-linux-arm64-gnu@4.62.2': 449 + resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} 450 + cpu: [arm64] 451 + os: [linux] 452 + libc: [glibc] 453 + 454 + '@rollup/rollup-linux-arm64-musl@4.62.2': 455 + resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} 456 + cpu: [arm64] 457 + os: [linux] 458 + libc: [musl] 459 + 460 + '@rollup/rollup-linux-loong64-gnu@4.62.2': 461 + resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} 462 + cpu: [loong64] 463 + os: [linux] 464 + libc: [glibc] 465 + 466 + '@rollup/rollup-linux-loong64-musl@4.62.2': 467 + resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} 468 + cpu: [loong64] 469 + os: [linux] 470 + libc: [musl] 471 + 472 + '@rollup/rollup-linux-ppc64-gnu@4.62.2': 473 + resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} 474 + cpu: [ppc64] 475 + os: [linux] 476 + libc: [glibc] 477 + 478 + '@rollup/rollup-linux-ppc64-musl@4.62.2': 479 + resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} 480 + cpu: [ppc64] 481 + os: [linux] 482 + libc: [musl] 483 + 484 + '@rollup/rollup-linux-riscv64-gnu@4.62.2': 485 + resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} 486 + cpu: [riscv64] 487 + os: [linux] 488 + libc: [glibc] 489 + 490 + '@rollup/rollup-linux-riscv64-musl@4.62.2': 491 + resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} 492 + cpu: [riscv64] 493 + os: [linux] 494 + libc: [musl] 495 + 496 + '@rollup/rollup-linux-s390x-gnu@4.62.2': 497 + resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} 498 + cpu: [s390x] 499 + os: [linux] 500 + libc: [glibc] 501 + 502 + '@rollup/rollup-linux-x64-gnu@4.62.2': 503 + resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} 504 + cpu: [x64] 505 + os: [linux] 506 + libc: [glibc] 507 + 508 + '@rollup/rollup-linux-x64-musl@4.62.2': 509 + resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} 510 + cpu: [x64] 511 + os: [linux] 512 + libc: [musl] 513 + 514 + '@rollup/rollup-openbsd-x64@4.62.2': 515 + resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} 516 + cpu: [x64] 517 + os: [openbsd] 518 + 519 + '@rollup/rollup-openharmony-arm64@4.62.2': 520 + resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==} 521 + cpu: [arm64] 522 + os: [openharmony] 523 + 524 + '@rollup/rollup-win32-arm64-msvc@4.62.2': 525 + resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==} 526 + cpu: [arm64] 527 + os: [win32] 528 + 529 + '@rollup/rollup-win32-ia32-msvc@4.62.2': 530 + resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==} 531 + cpu: [ia32] 532 + os: [win32] 533 + 534 + '@rollup/rollup-win32-x64-gnu@4.62.2': 535 + resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==} 536 + cpu: [x64] 537 + os: [win32] 538 + 539 + '@rollup/rollup-win32-x64-msvc@4.62.2': 540 + resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==} 541 + cpu: [x64] 542 + os: [win32] 543 + 544 + '@standard-schema/spec@1.1.0': 545 + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} 546 + 547 + '@sveltejs/acorn-typescript@1.0.10': 548 + resolution: {integrity: sha512-4WfKk68eTih+MiJD4fSbxN7E8kVBmTMPWHUPYjvl2N0rMs53YLTT8/YjKU5Dtnz5LqDjl7LEw4U7lXR2W3J5WA==} 549 + peerDependencies: 550 + acorn: ^8.9.0 551 + 552 + '@sveltejs/adapter-node@5.5.7': 553 + resolution: {integrity: sha512-uOfc9eVlI3A37RRSaKcgrheBYPrfJwC9VMqDp8x/O6tlKdcLLvHThSWD0KNIbjQ/d+7bwLGx3vx6aowAcRfd2g==} 554 + peerDependencies: 555 + '@sveltejs/kit': ^2.4.0 556 + 557 + '@sveltejs/kit@2.69.1': 558 + resolution: {integrity: sha512-+nz8Fx/cElzb2ZPHC+6Ll3y3NEVIe4Na75PeplLlyTmd1dBXAjz2KR14y1ZgNjb2ThfAYzulu+PFy1UE3RCUzA==} 559 + engines: {node: '>=18.13'} 560 + hasBin: true 561 + peerDependencies: 562 + '@opentelemetry/api': ^1.0.0 563 + '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0 564 + svelte: ^4.0.0 || ^5.0.0-next.0 565 + typescript: ^5.3.3 || ^6.0.0 566 + vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0 567 + peerDependenciesMeta: 568 + '@opentelemetry/api': 569 + optional: true 570 + typescript: 571 + optional: true 572 + 573 + '@sveltejs/load-config@0.2.0': 574 + resolution: {integrity: sha512-1LgZ/qUqSoq+QorD83lk2hka79Px0wXNW2q5V1nZlxGhQgw1jrsIbVz5YiCeucVLo4XvFLjXukUaQjIiqowkcg==} 575 + engines: {node: '>= 18.0.0'} 576 + 577 + '@sveltejs/vite-plugin-svelte@7.1.3': 578 + resolution: {integrity: sha512-/m4ZJPE75eUhSH9/thfK4cfahVHYXc8wZNGE0UeRziFVNylDFHtmEujh8jfaDy7+ztx6ywvMAwiFJda9dVMJ6A==} 579 + engines: {node: ^20.19 || ^22.12 || >=24} 580 + peerDependencies: 581 + svelte: ^5.46.4 582 + vite: ^8.0.0-beta.7 || ^8.0.0 583 + 584 + '@tailwindcss/node@4.3.2': 585 + resolution: {integrity: sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==} 586 + 587 + '@tailwindcss/oxide-android-arm64@4.3.2': 588 + resolution: {integrity: sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==} 589 + engines: {node: '>= 20'} 590 + cpu: [arm64] 591 + os: [android] 592 + 593 + '@tailwindcss/oxide-darwin-arm64@4.3.2': 594 + resolution: {integrity: sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==} 595 + engines: {node: '>= 20'} 596 + cpu: [arm64] 597 + os: [darwin] 598 + 599 + '@tailwindcss/oxide-darwin-x64@4.3.2': 600 + resolution: {integrity: sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==} 601 + engines: {node: '>= 20'} 602 + cpu: [x64] 603 + os: [darwin] 604 + 605 + '@tailwindcss/oxide-freebsd-x64@4.3.2': 606 + resolution: {integrity: sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==} 607 + engines: {node: '>= 20'} 608 + cpu: [x64] 609 + os: [freebsd] 610 + 611 + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': 612 + resolution: {integrity: sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==} 613 + engines: {node: '>= 20'} 614 + cpu: [arm] 615 + os: [linux] 616 + 617 + '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': 618 + resolution: {integrity: sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==} 619 + engines: {node: '>= 20'} 620 + cpu: [arm64] 621 + os: [linux] 622 + libc: [glibc] 623 + 624 + '@tailwindcss/oxide-linux-arm64-musl@4.3.2': 625 + resolution: {integrity: sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==} 626 + engines: {node: '>= 20'} 627 + cpu: [arm64] 628 + os: [linux] 629 + libc: [musl] 630 + 631 + '@tailwindcss/oxide-linux-x64-gnu@4.3.2': 632 + resolution: {integrity: sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==} 633 + engines: {node: '>= 20'} 634 + cpu: [x64] 635 + os: [linux] 636 + libc: [glibc] 637 + 638 + '@tailwindcss/oxide-linux-x64-musl@4.3.2': 639 + resolution: {integrity: sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==} 640 + engines: {node: '>= 20'} 641 + cpu: [x64] 642 + os: [linux] 643 + libc: [musl] 644 + 645 + '@tailwindcss/oxide-wasm32-wasi@4.3.2': 646 + resolution: {integrity: sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==} 647 + engines: {node: '>=14.0.0'} 648 + cpu: [wasm32] 649 + bundledDependencies: 650 + - '@napi-rs/wasm-runtime' 651 + - '@emnapi/core' 652 + - '@emnapi/runtime' 653 + - '@tybys/wasm-util' 654 + - '@emnapi/wasi-threads' 655 + - tslib 656 + 657 + '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': 658 + resolution: {integrity: sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==} 659 + engines: {node: '>= 20'} 660 + cpu: [arm64] 661 + os: [win32] 662 + 663 + '@tailwindcss/oxide-win32-x64-msvc@4.3.2': 664 + resolution: {integrity: sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==} 665 + engines: {node: '>= 20'} 666 + cpu: [x64] 667 + os: [win32] 668 + 669 + '@tailwindcss/oxide@4.3.2': 670 + resolution: {integrity: sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==} 671 + engines: {node: '>= 20'} 672 + 673 + '@tailwindcss/vite@4.3.2': 674 + resolution: {integrity: sha512-eHpMeX4JXfVNJDEcsouTeCBubJBTcTLigeaw/NTUW6PB5ATKKXdyonnXgTBX2VuRbjz1hjfz6C5XAhr52ImQXA==} 675 + peerDependencies: 676 + vite: ^5.2.0 || ^6 || ^7 || ^8 677 + 678 + '@tybys/wasm-util@0.10.3': 679 + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} 680 + 681 + '@types/chai@5.2.3': 682 + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} 683 + 684 + '@types/cookie@0.6.0': 685 + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} 686 + 687 + '@types/deep-eql@4.0.2': 688 + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} 689 + 690 + '@types/esrecurse@4.3.1': 691 + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} 692 + 693 + '@types/estree@1.0.9': 694 + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} 695 + 696 + '@types/json-schema@7.0.15': 697 + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 698 + 699 + '@types/node@24.13.2': 700 + resolution: {integrity: sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==} 701 + 702 + '@types/resolve@1.20.2': 703 + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} 704 + 705 + '@types/trusted-types@2.0.7': 706 + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} 707 + 708 + '@typescript-eslint/eslint-plugin@8.63.0': 709 + resolution: {integrity: sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==} 710 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 711 + peerDependencies: 712 + '@typescript-eslint/parser': ^8.63.0 713 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 714 + typescript: '>=4.8.4 <6.1.0' 715 + 716 + '@typescript-eslint/parser@8.63.0': 717 + resolution: {integrity: sha512-gwh4gvvlaVDKKxyfxMG+Gnu1u9X0OQBwyGLkbwB65dIzBKnxeRiJlNFqlI3zwVhNXJIs6qV7mlFCn/BIajlVig==} 718 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 719 + peerDependencies: 720 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 721 + typescript: '>=4.8.4 <6.1.0' 722 + 723 + '@typescript-eslint/project-service@8.63.0': 724 + resolution: {integrity: sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==} 725 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 726 + peerDependencies: 727 + typescript: '>=4.8.4 <6.1.0' 728 + 729 + '@typescript-eslint/scope-manager@8.63.0': 730 + resolution: {integrity: sha512-uUyfMWCnDSN8bCpcrY8nGP2BLkQ9Xn0GsipcONcpIDWhwhO4ZSyHvyS14U3X75mzxWxL3I2UZIrenTzdzcJO8A==} 731 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 732 + 733 + '@typescript-eslint/tsconfig-utils@8.63.0': 734 + resolution: {integrity: sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==} 735 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 736 + peerDependencies: 737 + typescript: '>=4.8.4 <6.1.0' 738 + 739 + '@typescript-eslint/type-utils@8.63.0': 740 + resolution: {integrity: sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==} 741 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 742 + peerDependencies: 743 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 744 + typescript: '>=4.8.4 <6.1.0' 745 + 746 + '@typescript-eslint/types@8.63.0': 747 + resolution: {integrity: sha512-xyLtl9DUBBFrcJS4x2pIqGLH68/tC2uOa4Z7pUteW09D3bXnnXUom4dyPikzWgB7llmIc1zoeI3aoUdC4rPK/Q==} 748 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 749 + 750 + '@typescript-eslint/typescript-estree@8.63.0': 751 + resolution: {integrity: sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==} 752 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 753 + peerDependencies: 754 + typescript: '>=4.8.4 <6.1.0' 755 + 756 + '@typescript-eslint/utils@8.63.0': 757 + resolution: {integrity: sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==} 758 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 759 + peerDependencies: 760 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 761 + typescript: '>=4.8.4 <6.1.0' 762 + 763 + '@typescript-eslint/visitor-keys@8.63.0': 764 + resolution: {integrity: sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==} 765 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 766 + 767 + '@vitest/expect@4.1.10': 768 + resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} 769 + 770 + '@vitest/mocker@4.1.10': 771 + resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} 772 + peerDependencies: 773 + msw: ^2.4.9 774 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 775 + peerDependenciesMeta: 776 + msw: 777 + optional: true 778 + vite: 779 + optional: true 780 + 781 + '@vitest/pretty-format@4.1.10': 782 + resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} 783 + 784 + '@vitest/runner@4.1.10': 785 + resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} 786 + 787 + '@vitest/snapshot@4.1.10': 788 + resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} 789 + 790 + '@vitest/spy@4.1.10': 791 + resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} 792 + 793 + '@vitest/utils@4.1.10': 794 + resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} 795 + 796 + acorn-jsx@5.3.2: 797 + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 798 + peerDependencies: 799 + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 800 + 801 + acorn@8.17.0: 802 + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} 803 + engines: {node: '>=0.4.0'} 804 + hasBin: true 805 + 806 + ajv@6.15.0: 807 + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} 808 + 809 + aria-query@5.3.1: 810 + resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==} 811 + engines: {node: '>= 0.4'} 812 + 813 + assertion-error@2.0.1: 814 + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 815 + engines: {node: '>=12'} 816 + 817 + axobject-query@4.1.0: 818 + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} 819 + engines: {node: '>= 0.4'} 820 + 821 + balanced-match@4.0.4: 822 + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} 823 + engines: {node: 18 || 20 || >=22} 824 + 825 + brace-expansion@5.0.7: 826 + resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} 827 + engines: {node: 18 || 20 || >=22} 828 + 829 + chai@6.2.2: 830 + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} 831 + engines: {node: '>=18'} 832 + 833 + chokidar@4.0.3: 834 + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 835 + engines: {node: '>= 14.16.0'} 836 + 837 + clsx@2.1.1: 838 + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} 839 + engines: {node: '>=6'} 840 + 841 + commondir@1.0.1: 842 + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} 843 + 844 + confbox@0.1.8: 845 + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} 846 + 847 + confbox@0.2.4: 848 + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} 849 + 850 + convert-source-map@2.0.0: 851 + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} 852 + 853 + cookie@0.6.0: 854 + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} 855 + engines: {node: '>= 0.6'} 856 + 857 + cross-spawn@7.0.6: 858 + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 859 + engines: {node: '>= 8'} 860 + 861 + cssesc@3.0.0: 862 + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 863 + engines: {node: '>=4'} 864 + hasBin: true 865 + 866 + debug@4.4.3: 867 + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} 868 + engines: {node: '>=6.0'} 869 + peerDependencies: 870 + supports-color: '*' 871 + peerDependenciesMeta: 872 + supports-color: 873 + optional: true 874 + 875 + deep-is@0.1.4: 876 + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 877 + 878 + deepmerge@4.3.1: 879 + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 880 + engines: {node: '>=0.10.0'} 881 + 882 + detect-libc@2.1.2: 883 + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} 884 + engines: {node: '>=8'} 885 + 886 + devalue@5.8.1: 887 + resolution: {integrity: sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==} 888 + 889 + enhanced-resolve@5.21.6: 890 + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} 891 + engines: {node: '>=10.13.0'} 892 + 893 + es-errors@1.3.0: 894 + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 895 + engines: {node: '>= 0.4'} 896 + 897 + es-module-lexer@2.3.0: 898 + resolution: {integrity: sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==} 899 + 900 + escape-string-regexp@4.0.0: 901 + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 902 + engines: {node: '>=10'} 903 + 904 + eslint-config-prettier@10.1.8: 905 + resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} 906 + hasBin: true 907 + peerDependencies: 908 + eslint: '>=7.0.0' 909 + 910 + eslint-plugin-svelte@3.20.0: 911 + resolution: {integrity: sha512-AElKLVt7Hjy4d7ljwhrhw9hux60DCxCNkmK8cY/aAXvjs8tpR7PvU4DlyI/SA1PaJww1gh0wPGo2pbyURuEwxQ==} 912 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 913 + peerDependencies: 914 + eslint: ^8.57.1 || ^9.0.0 || ^10.0.0 915 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 916 + peerDependenciesMeta: 917 + svelte: 918 + optional: true 919 + 920 + eslint-scope@8.4.0: 921 + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} 922 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 923 + 924 + eslint-scope@9.1.2: 925 + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} 926 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 927 + 928 + eslint-visitor-keys@3.4.3: 929 + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 930 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 931 + 932 + eslint-visitor-keys@4.2.1: 933 + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} 934 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 935 + 936 + eslint-visitor-keys@5.0.1: 937 + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} 938 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 939 + 940 + eslint@10.6.0: 941 + resolution: {integrity: sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==} 942 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 943 + hasBin: true 944 + peerDependencies: 945 + jiti: '*' 946 + peerDependenciesMeta: 947 + jiti: 948 + optional: true 949 + 950 + esm-env@1.2.2: 951 + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} 952 + 953 + espree@10.4.0: 954 + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} 955 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 956 + 957 + espree@11.2.0: 958 + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} 959 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 960 + 961 + esquery@1.7.0: 962 + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} 963 + engines: {node: '>=0.10'} 964 + 965 + esrap@2.2.13: 966 + resolution: {integrity: sha512-m8jH5hZgJE2RRUK/jjkGPcJEDAV+dYnZYFkosQaPTcE+Yw4xynXHOo6FUdwaWBtdR3b1MMa7wEDTSHeR2VWsGA==} 967 + peerDependencies: 968 + '@typescript-eslint/types': ^8.2.0 969 + peerDependenciesMeta: 970 + '@typescript-eslint/types': 971 + optional: true 972 + 973 + esrecurse@4.3.0: 974 + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 975 + engines: {node: '>=4.0'} 976 + 977 + estraverse@5.3.0: 978 + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 979 + engines: {node: '>=4.0'} 980 + 981 + estree-walker@2.0.2: 982 + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 983 + 984 + estree-walker@3.0.3: 985 + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 986 + 987 + esutils@2.0.3: 988 + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 989 + engines: {node: '>=0.10.0'} 990 + 991 + expect-type@1.4.0: 992 + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} 993 + engines: {node: '>=12.0.0'} 994 + 995 + exsolve@1.1.0: 996 + resolution: {integrity: sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==} 997 + 998 + fast-deep-equal@3.1.3: 999 + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 1000 + 1001 + fast-json-stable-stringify@2.1.0: 1002 + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 1003 + 1004 + fast-levenshtein@2.0.6: 1005 + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 1006 + 1007 + fdir@6.5.0: 1008 + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} 1009 + engines: {node: '>=12.0.0'} 1010 + peerDependencies: 1011 + picomatch: ^3 || ^4 1012 + peerDependenciesMeta: 1013 + picomatch: 1014 + optional: true 1015 + 1016 + file-entry-cache@8.0.0: 1017 + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} 1018 + engines: {node: '>=16.0.0'} 1019 + 1020 + find-up@5.0.0: 1021 + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 1022 + engines: {node: '>=10'} 1023 + 1024 + flat-cache@4.0.1: 1025 + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} 1026 + engines: {node: '>=16'} 1027 + 1028 + flatted@3.4.2: 1029 + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} 1030 + 1031 + fsevents@2.3.2: 1032 + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 1033 + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1034 + os: [darwin] 1035 + 1036 + fsevents@2.3.3: 1037 + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 1038 + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1039 + os: [darwin] 1040 + 1041 + function-bind@1.1.2: 1042 + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 1043 + 1044 + glob-parent@6.0.2: 1045 + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 1046 + engines: {node: '>=10.13.0'} 1047 + 1048 + globals@16.5.0: 1049 + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} 1050 + engines: {node: '>=18'} 1051 + 1052 + globals@17.7.0: 1053 + resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==} 1054 + engines: {node: '>=18'} 1055 + 1056 + graceful-fs@4.2.11: 1057 + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 1058 + 1059 + hasown@2.0.4: 1060 + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} 1061 + engines: {node: '>= 0.4'} 1062 + 1063 + ignore@5.3.2: 1064 + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 1065 + engines: {node: '>= 4'} 1066 + 1067 + ignore@7.0.5: 1068 + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} 1069 + engines: {node: '>= 4'} 1070 + 1071 + import-meta-resolve@4.2.0: 1072 + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} 1073 + 1074 + imurmurhash@0.1.4: 1075 + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1076 + engines: {node: '>=0.8.19'} 1077 + 1078 + is-core-module@2.16.2: 1079 + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} 1080 + engines: {node: '>= 0.4'} 1081 + 1082 + is-extglob@2.1.1: 1083 + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1084 + engines: {node: '>=0.10.0'} 1085 + 1086 + is-glob@4.0.3: 1087 + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1088 + engines: {node: '>=0.10.0'} 1089 + 1090 + is-module@1.0.0: 1091 + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} 1092 + 1093 + is-reference@1.2.1: 1094 + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} 1095 + 1096 + is-reference@3.0.3: 1097 + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} 1098 + 1099 + isexe@2.0.0: 1100 + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1101 + 1102 + jiti@2.7.0: 1103 + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} 1104 + hasBin: true 1105 + 1106 + json-buffer@3.0.1: 1107 + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 1108 + 1109 + json-schema-traverse@0.4.1: 1110 + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1111 + 1112 + json-stable-stringify-without-jsonify@1.0.1: 1113 + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 1114 + 1115 + keyv@4.5.4: 1116 + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 1117 + 1118 + kleur@4.1.5: 1119 + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} 1120 + engines: {node: '>=6'} 1121 + 1122 + known-css-properties@0.37.0: 1123 + resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==} 1124 + 1125 + levn@0.4.1: 1126 + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 1127 + engines: {node: '>= 0.8.0'} 1128 + 1129 + lightningcss-android-arm64@1.32.0: 1130 + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} 1131 + engines: {node: '>= 12.0.0'} 1132 + cpu: [arm64] 1133 + os: [android] 1134 + 1135 + lightningcss-darwin-arm64@1.32.0: 1136 + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} 1137 + engines: {node: '>= 12.0.0'} 1138 + cpu: [arm64] 1139 + os: [darwin] 1140 + 1141 + lightningcss-darwin-x64@1.32.0: 1142 + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} 1143 + engines: {node: '>= 12.0.0'} 1144 + cpu: [x64] 1145 + os: [darwin] 1146 + 1147 + lightningcss-freebsd-x64@1.32.0: 1148 + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} 1149 + engines: {node: '>= 12.0.0'} 1150 + cpu: [x64] 1151 + os: [freebsd] 1152 + 1153 + lightningcss-linux-arm-gnueabihf@1.32.0: 1154 + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} 1155 + engines: {node: '>= 12.0.0'} 1156 + cpu: [arm] 1157 + os: [linux] 1158 + 1159 + lightningcss-linux-arm64-gnu@1.32.0: 1160 + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} 1161 + engines: {node: '>= 12.0.0'} 1162 + cpu: [arm64] 1163 + os: [linux] 1164 + libc: [glibc] 1165 + 1166 + lightningcss-linux-arm64-musl@1.32.0: 1167 + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} 1168 + engines: {node: '>= 12.0.0'} 1169 + cpu: [arm64] 1170 + os: [linux] 1171 + libc: [musl] 1172 + 1173 + lightningcss-linux-x64-gnu@1.32.0: 1174 + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} 1175 + engines: {node: '>= 12.0.0'} 1176 + cpu: [x64] 1177 + os: [linux] 1178 + libc: [glibc] 1179 + 1180 + lightningcss-linux-x64-musl@1.32.0: 1181 + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} 1182 + engines: {node: '>= 12.0.0'} 1183 + cpu: [x64] 1184 + os: [linux] 1185 + libc: [musl] 1186 + 1187 + lightningcss-win32-arm64-msvc@1.32.0: 1188 + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} 1189 + engines: {node: '>= 12.0.0'} 1190 + cpu: [arm64] 1191 + os: [win32] 1192 + 1193 + lightningcss-win32-x64-msvc@1.32.0: 1194 + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} 1195 + engines: {node: '>= 12.0.0'} 1196 + cpu: [x64] 1197 + os: [win32] 1198 + 1199 + lightningcss@1.32.0: 1200 + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} 1201 + engines: {node: '>= 12.0.0'} 1202 + 1203 + lilconfig@2.1.0: 1204 + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} 1205 + engines: {node: '>=10'} 1206 + 1207 + local-pkg@1.2.1: 1208 + resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} 1209 + engines: {node: '>=14'} 1210 + 1211 + locate-character@3.0.0: 1212 + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} 1213 + 1214 + locate-path@6.0.0: 1215 + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 1216 + engines: {node: '>=10'} 1217 + 1218 + magic-string@0.30.21: 1219 + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} 1220 + 1221 + minimatch@10.2.5: 1222 + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} 1223 + engines: {node: 18 || 20 || >=22} 1224 + 1225 + mlly@1.8.2: 1226 + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} 1227 + 1228 + mri@1.2.0: 1229 + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} 1230 + engines: {node: '>=4'} 1231 + 1232 + mrmime@2.0.1: 1233 + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} 1234 + engines: {node: '>=10'} 1235 + 1236 + ms@2.1.3: 1237 + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1238 + 1239 + nanoid@3.3.15: 1240 + resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} 1241 + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1242 + hasBin: true 1243 + 1244 + nanoid@5.1.16: 1245 + resolution: {integrity: sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==} 1246 + engines: {node: ^18 || >=20} 1247 + hasBin: true 1248 + 1249 + natural-compare@1.4.0: 1250 + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1251 + 1252 + obug@2.1.3: 1253 + resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} 1254 + engines: {node: '>=12.20.0'} 1255 + 1256 + optionator@0.9.4: 1257 + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} 1258 + engines: {node: '>= 0.8.0'} 1259 + 1260 + p-limit@3.1.0: 1261 + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1262 + engines: {node: '>=10'} 1263 + 1264 + p-locate@5.0.0: 1265 + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1266 + engines: {node: '>=10'} 1267 + 1268 + package-manager-detector@1.7.0: 1269 + resolution: {integrity: sha512-xg1eHpwYL/D/HEdWw2goFZP6vV0FH7W+PZ5rFkGjdIDLtxq7EkzBUeT3m+lndYCt8wKbmofUu1MUdMCXkCk9ZQ==} 1270 + 1271 + path-exists@4.0.0: 1272 + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1273 + engines: {node: '>=8'} 1274 + 1275 + path-key@3.1.1: 1276 + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1277 + engines: {node: '>=8'} 1278 + 1279 + path-parse@1.0.7: 1280 + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 1281 + 1282 + pathe@2.0.3: 1283 + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} 1284 + 1285 + picocolors@1.1.1: 1286 + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 1287 + 1288 + picomatch@4.0.5: 1289 + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} 1290 + engines: {node: '>=12'} 1291 + 1292 + pkg-types@1.3.1: 1293 + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} 1294 + 1295 + pkg-types@2.3.1: 1296 + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} 1297 + 1298 + playwright-core@1.61.1: 1299 + resolution: {integrity: sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==} 1300 + engines: {node: '>=18'} 1301 + hasBin: true 1302 + 1303 + playwright@1.61.1: 1304 + resolution: {integrity: sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==} 1305 + engines: {node: '>=18'} 1306 + hasBin: true 1307 + 1308 + postcss-load-config@3.1.4: 1309 + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} 1310 + engines: {node: '>= 10'} 1311 + peerDependencies: 1312 + postcss: '>=8.0.9' 1313 + ts-node: '>=9.0.0' 1314 + peerDependenciesMeta: 1315 + postcss: 1316 + optional: true 1317 + ts-node: 1318 + optional: true 1319 + 1320 + postcss-safe-parser@7.0.1: 1321 + resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} 1322 + engines: {node: '>=18.0'} 1323 + peerDependencies: 1324 + postcss: ^8.4.31 1325 + 1326 + postcss-scss@4.0.9: 1327 + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} 1328 + engines: {node: '>=12.0'} 1329 + peerDependencies: 1330 + postcss: ^8.4.29 1331 + 1332 + postcss-selector-parser@7.1.4: 1333 + resolution: {integrity: sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==} 1334 + engines: {node: '>=4'} 1335 + 1336 + postcss@8.5.16: 1337 + resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} 1338 + engines: {node: ^10 || ^12 || >=14} 1339 + 1340 + prelude-ls@1.2.1: 1341 + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1342 + engines: {node: '>= 0.8.0'} 1343 + 1344 + prettier-plugin-svelte@4.1.1: 1345 + resolution: {integrity: sha512-wXvbXMjSvb4C9ENWTHXyd+ihakKCsJ6rJhLP6/8HFNj4GkZr48jqL9PoKsl2sk7SyCZRTnJ7O2TTowUpOxP/KA==} 1346 + engines: {node: '>=20'} 1347 + peerDependencies: 1348 + prettier: ^3.0.0 1349 + svelte: ^5.0.0 1350 + 1351 + prettier-plugin-tailwindcss@0.8.0: 1352 + resolution: {integrity: sha512-V8ITGH87yuBDF6JpEZTOVlUz/saAwqb8f3HRgUj8Lh+tGCcrmorhsLpYqzygwFwK0PE2Ib6Mv3M7T/uE2tZV1g==} 1353 + engines: {node: '>=20.19'} 1354 + peerDependencies: 1355 + '@ianvs/prettier-plugin-sort-imports': '*' 1356 + '@prettier/plugin-hermes': '*' 1357 + '@prettier/plugin-oxc': '*' 1358 + '@prettier/plugin-pug': '*' 1359 + '@shopify/prettier-plugin-liquid': '*' 1360 + '@trivago/prettier-plugin-sort-imports': '*' 1361 + '@zackad/prettier-plugin-twig': '*' 1362 + prettier: ^3.0 1363 + prettier-plugin-astro: '*' 1364 + prettier-plugin-css-order: '*' 1365 + prettier-plugin-jsdoc: '*' 1366 + prettier-plugin-marko: '*' 1367 + prettier-plugin-multiline-arrays: '*' 1368 + prettier-plugin-organize-attributes: '*' 1369 + prettier-plugin-organize-imports: '*' 1370 + prettier-plugin-sort-imports: '*' 1371 + prettier-plugin-svelte: '*' 1372 + peerDependenciesMeta: 1373 + '@ianvs/prettier-plugin-sort-imports': 1374 + optional: true 1375 + '@prettier/plugin-hermes': 1376 + optional: true 1377 + '@prettier/plugin-oxc': 1378 + optional: true 1379 + '@prettier/plugin-pug': 1380 + optional: true 1381 + '@shopify/prettier-plugin-liquid': 1382 + optional: true 1383 + '@trivago/prettier-plugin-sort-imports': 1384 + optional: true 1385 + '@zackad/prettier-plugin-twig': 1386 + optional: true 1387 + prettier-plugin-astro: 1388 + optional: true 1389 + prettier-plugin-css-order: 1390 + optional: true 1391 + prettier-plugin-jsdoc: 1392 + optional: true 1393 + prettier-plugin-marko: 1394 + optional: true 1395 + prettier-plugin-multiline-arrays: 1396 + optional: true 1397 + prettier-plugin-organize-attributes: 1398 + optional: true 1399 + prettier-plugin-organize-imports: 1400 + optional: true 1401 + prettier-plugin-sort-imports: 1402 + optional: true 1403 + prettier-plugin-svelte: 1404 + optional: true 1405 + 1406 + prettier@3.9.4: 1407 + resolution: {integrity: sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==} 1408 + engines: {node: '>=14'} 1409 + hasBin: true 1410 + 1411 + punycode@2.3.1: 1412 + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1413 + engines: {node: '>=6'} 1414 + 1415 + quansync@0.2.11: 1416 + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} 1417 + 1418 + readdirp@4.1.2: 1419 + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} 1420 + engines: {node: '>= 14.18.0'} 1421 + 1422 + resolve@1.22.12: 1423 + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} 1424 + engines: {node: '>= 0.4'} 1425 + hasBin: true 1426 + 1427 + rolldown@1.1.4: 1428 + resolution: {integrity: sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA==} 1429 + engines: {node: ^20.19.0 || >=22.12.0} 1430 + hasBin: true 1431 + 1432 + rollup@4.62.2: 1433 + resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==} 1434 + engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1435 + hasBin: true 1436 + 1437 + sade@1.8.1: 1438 + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} 1439 + engines: {node: '>=6'} 1440 + 1441 + semver@7.8.5: 1442 + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} 1443 + engines: {node: '>=10'} 1444 + hasBin: true 1445 + 1446 + set-cookie-parser@3.1.1: 1447 + resolution: {integrity: sha512-vM9SUhjsUYs6UeJUmygc5Ofm5eQGe85riob5ju6XCgFGJI5PLV4nrDAQpQjd+LkFBpAkADn5BQQpZ9EUNkyLuA==} 1448 + 1449 + shebang-command@2.0.0: 1450 + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1451 + engines: {node: '>=8'} 1452 + 1453 + shebang-regex@3.0.0: 1454 + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1455 + engines: {node: '>=8'} 1456 + 1457 + siginfo@2.0.0: 1458 + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 1459 + 1460 + sirv@3.0.2: 1461 + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} 1462 + engines: {node: '>=18'} 1463 + 1464 + source-map-js@1.2.1: 1465 + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1466 + engines: {node: '>=0.10.0'} 1467 + 1468 + stackback@0.0.2: 1469 + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 1470 + 1471 + std-env@4.1.0: 1472 + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} 1473 + 1474 + supports-preserve-symlinks-flag@1.0.0: 1475 + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 1476 + engines: {node: '>= 0.4'} 1477 + 1478 + svelte-check@4.7.1: 1479 + resolution: {integrity: sha512-FGUOmAqxXdN/H9Zm8slrqO7SLtFisXRB7rfOsHNJ3MLTD2po/+Stg8XyErkpumPHbuUiYTcqrEIzxpVWKTLqtg==} 1480 + engines: {node: '>= 18.0.0'} 1481 + hasBin: true 1482 + peerDependencies: 1483 + svelte: ^4.0.0 || ^5.0.0-next.0 1484 + typescript: '>=5.0.0' 1485 + 1486 + svelte-eslint-parser@1.8.0: 1487 + resolution: {integrity: sha512-mikR1qwIVy3t5WthUoAXkMwxkXvabZP9FJgdx35Ei7EbGWmctva1Pih16Koeor/bdNNq8NXHlwKGS6NkYTawLg==} 1488 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: 10.34.1} 1489 + peerDependencies: 1490 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 1491 + peerDependenciesMeta: 1492 + svelte: 1493 + optional: true 1494 + 1495 + svelte@5.56.4: 1496 + resolution: {integrity: sha512-/d0QHehmRuJW8gVz395MTkPcPozxzdjBMBE8oEYGz8O3b9KTMzzQ9ZHJQLuFKOHOPQbU6kx/X4iid/EBBzH7iw==} 1497 + engines: {node: '>=18'} 1498 + 1499 + tailwindcss@4.3.2: 1500 + resolution: {integrity: sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==} 1501 + 1502 + tapable@2.3.3: 1503 + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} 1504 + engines: {node: '>=6'} 1505 + 1506 + tinybench@2.9.0: 1507 + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 1508 + 1509 + tinyexec@1.2.4: 1510 + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} 1511 + engines: {node: '>=18'} 1512 + 1513 + tinyglobby@0.2.17: 1514 + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} 1515 + engines: {node: '>=12.0.0'} 1516 + 1517 + tinyrainbow@3.1.0: 1518 + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} 1519 + engines: {node: '>=14.0.0'} 1520 + 1521 + totalist@3.0.1: 1522 + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} 1523 + engines: {node: '>=6'} 1524 + 1525 + ts-api-utils@2.5.0: 1526 + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} 1527 + engines: {node: '>=18.12'} 1528 + peerDependencies: 1529 + typescript: '>=4.8.4' 1530 + 1531 + tslib@2.8.1: 1532 + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1533 + 1534 + type-check@0.4.0: 1535 + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 1536 + engines: {node: '>= 0.8.0'} 1537 + 1538 + typescript-eslint@8.63.0: 1539 + resolution: {integrity: sha512-xgwXyzG4sK9ALkBxbyGkTMMOS+imnW65iPhxCQMK83KhxyoDNW7l+IDqEf9vMdoUidHpOoS967RCq4eMiTexwQ==} 1540 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1541 + peerDependencies: 1542 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 1543 + typescript: '>=4.8.4 <6.1.0' 1544 + 1545 + typescript@6.0.3: 1546 + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} 1547 + engines: {node: '>=14.17'} 1548 + hasBin: true 1549 + 1550 + ufo@1.6.4: 1551 + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} 1552 + 1553 + undici-types@7.18.2: 1554 + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} 1555 + 1556 + unicode-segmenter@0.14.5: 1557 + resolution: {integrity: sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==} 1558 + 1559 + unplugin-icons@23.0.1: 1560 + resolution: {integrity: sha512-rv0XEJepajKzDLvRUWASM8K+8+/CCfZn2jtogXqg6RIp7kpatRc/aFrVJn8ANQA09e++lPEEv9yX8cC9enc+QQ==} 1561 + peerDependencies: 1562 + '@svgr/core': '>=7.0.0' 1563 + '@svgx/core': ^1.0.1 1564 + '@vue/compiler-sfc': ^3.0.2 1565 + svelte: ^3.0.0 || ^4.0.0 || ^5.0.0 1566 + peerDependenciesMeta: 1567 + '@svgr/core': 1568 + optional: true 1569 + '@svgx/core': 1570 + optional: true 1571 + '@vue/compiler-sfc': 1572 + optional: true 1573 + svelte: 1574 + optional: true 1575 + 1576 + unplugin@2.3.11: 1577 + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} 1578 + engines: {node: '>=18.12.0'} 1579 + 1580 + uri-js@4.4.1: 1581 + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1582 + 1583 + util-deprecate@1.0.2: 1584 + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 1585 + 1586 + valibot@1.4.2: 1587 + resolution: {integrity: sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg==} 1588 + peerDependencies: 1589 + typescript: '>=5' 1590 + peerDependenciesMeta: 1591 + typescript: 1592 + optional: true 1593 + 1594 + vite@8.1.3: 1595 + resolution: {integrity: sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==} 1596 + engines: {node: ^20.19.0 || >=22.12.0} 1597 + hasBin: true 1598 + peerDependencies: 1599 + '@types/node': ^20.19.0 || >=22.12.0 1600 + '@vitejs/devtools': ^0.3.0 1601 + esbuild: ^0.27.0 || ^0.28.0 1602 + jiti: '>=1.21.0' 1603 + less: ^4.0.0 1604 + sass: ^1.70.0 1605 + sass-embedded: ^1.70.0 1606 + stylus: '>=0.54.8' 1607 + sugarss: ^5.0.0 1608 + terser: ^5.16.0 1609 + tsx: ^4.8.1 1610 + yaml: ^2.4.2 1611 + peerDependenciesMeta: 1612 + '@types/node': 1613 + optional: true 1614 + '@vitejs/devtools': 1615 + optional: true 1616 + esbuild: 1617 + optional: true 1618 + jiti: 1619 + optional: true 1620 + less: 1621 + optional: true 1622 + sass: 1623 + optional: true 1624 + sass-embedded: 1625 + optional: true 1626 + stylus: 1627 + optional: true 1628 + sugarss: 1629 + optional: true 1630 + terser: 1631 + optional: true 1632 + tsx: 1633 + optional: true 1634 + yaml: 1635 + optional: true 1636 + 1637 + vitefu@1.1.3: 1638 + resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} 1639 + peerDependencies: 1640 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 1641 + peerDependenciesMeta: 1642 + vite: 1643 + optional: true 1644 + 1645 + vitest@4.1.10: 1646 + resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} 1647 + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} 1648 + hasBin: true 1649 + peerDependencies: 1650 + '@edge-runtime/vm': '*' 1651 + '@opentelemetry/api': ^1.9.0 1652 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 1653 + '@vitest/browser-playwright': 4.1.10 1654 + '@vitest/browser-preview': 4.1.10 1655 + '@vitest/browser-webdriverio': 4.1.10 1656 + '@vitest/coverage-istanbul': 4.1.10 1657 + '@vitest/coverage-v8': 4.1.10 1658 + '@vitest/ui': 4.1.10 1659 + happy-dom: '*' 1660 + jsdom: '*' 1661 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 1662 + peerDependenciesMeta: 1663 + '@edge-runtime/vm': 1664 + optional: true 1665 + '@opentelemetry/api': 1666 + optional: true 1667 + '@types/node': 1668 + optional: true 1669 + '@vitest/browser-playwright': 1670 + optional: true 1671 + '@vitest/browser-preview': 1672 + optional: true 1673 + '@vitest/browser-webdriverio': 1674 + optional: true 1675 + '@vitest/coverage-istanbul': 1676 + optional: true 1677 + '@vitest/coverage-v8': 1678 + optional: true 1679 + '@vitest/ui': 1680 + optional: true 1681 + happy-dom: 1682 + optional: true 1683 + jsdom: 1684 + optional: true 1685 + 1686 + webpack-virtual-modules@0.6.2: 1687 + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} 1688 + 1689 + which@2.0.2: 1690 + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1691 + engines: {node: '>= 8'} 1692 + hasBin: true 1693 + 1694 + why-is-node-running@2.3.0: 1695 + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 1696 + engines: {node: '>=8'} 1697 + hasBin: true 1698 + 1699 + word-wrap@1.2.5: 1700 + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} 1701 + engines: {node: '>=0.10.0'} 1702 + 1703 + yaml@1.10.3: 1704 + resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} 1705 + engines: {node: '>= 6'} 1706 + 1707 + yaml@2.9.0: 1708 + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} 1709 + engines: {node: '>= 14.6'} 1710 + hasBin: true 1711 + 1712 + yocto-queue@0.1.0: 1713 + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 1714 + engines: {node: '>=10'} 1715 + 1716 + zimmerframe@1.1.4: 1717 + resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} 1718 + 1719 + snapshots: 1720 + 1721 + '@antfu/install-pkg@1.1.0': 1722 + dependencies: 1723 + package-manager-detector: 1.7.0 1724 + tinyexec: 1.2.4 1725 + 1726 + '@atcute/atproto@4.0.3(@atcute/lexicons@2.0.2)': 1727 + dependencies: 1728 + '@atcute/lexicons': 2.0.2 1729 + 1730 + '@atcute/client@5.1.1(@atcute/lexicons@2.0.2)(typescript@6.0.3)': 1731 + dependencies: 1732 + '@atcute/identity': 2.0.1(@atcute/lexicons@2.0.2)(typescript@6.0.3) 1733 + '@atcute/lexicons': 2.0.2 1734 + transitivePeerDependencies: 1735 + - typescript 1736 + 1737 + '@atcute/identity-resolver@2.0.1(@atcute/identity@2.0.1(@atcute/lexicons@2.0.2)(typescript@6.0.3))(@atcute/lexicons@2.0.2)(typescript@6.0.3)': 1738 + dependencies: 1739 + '@atcute/identity': 2.0.1(@atcute/lexicons@2.0.2)(typescript@6.0.3) 1740 + '@atcute/lexicons': 2.0.2 1741 + '@atcute/util-fetch': 2.0.1(typescript@6.0.3) 1742 + valibot: 1.4.2(typescript@6.0.3) 1743 + transitivePeerDependencies: 1744 + - typescript 1745 + 1746 + '@atcute/identity@2.0.1(@atcute/lexicons@2.0.2)(typescript@6.0.3)': 1747 + dependencies: 1748 + '@atcute/lexicons': 2.0.2 1749 + valibot: 1.4.2(typescript@6.0.3) 1750 + transitivePeerDependencies: 1751 + - typescript 1752 + 1753 + '@atcute/lexicons@2.0.2': 1754 + dependencies: 1755 + '@atcute/uint8array': 1.1.3 1756 + '@atcute/util-text': 1.3.3 1757 + '@standard-schema/spec': 1.1.0 1758 + esm-env: 1.2.2 1759 + 1760 + '@atcute/multibase@1.2.4': 1761 + dependencies: 1762 + '@atcute/uint8array': 1.1.3 1763 + 1764 + '@atcute/oauth-browser-client@4.0.1(@atcute/identity-resolver@2.0.1(@atcute/identity@2.0.1(@atcute/lexicons@2.0.2)(typescript@6.0.3))(@atcute/lexicons@2.0.2)(typescript@6.0.3))(@atcute/lexicons@2.0.2)(typescript@6.0.3)': 1765 + dependencies: 1766 + '@atcute/client': 5.1.1(@atcute/lexicons@2.0.2)(typescript@6.0.3) 1767 + '@atcute/identity-resolver': 2.0.1(@atcute/identity@2.0.1(@atcute/lexicons@2.0.2)(typescript@6.0.3))(@atcute/lexicons@2.0.2)(typescript@6.0.3) 1768 + '@atcute/lexicons': 2.0.2 1769 + '@atcute/multibase': 1.2.4 1770 + '@atcute/oauth-crypto': 1.0.1(typescript@6.0.3) 1771 + '@atcute/oauth-types': 1.0.1(typescript@6.0.3) 1772 + nanoid: 5.1.16 1773 + transitivePeerDependencies: 1774 + - typescript 1775 + 1776 + '@atcute/oauth-crypto@1.0.1(typescript@6.0.3)': 1777 + dependencies: 1778 + '@atcute/multibase': 1.2.4 1779 + '@atcute/uint8array': 1.1.3 1780 + nanoid: 5.1.16 1781 + valibot: 1.4.2(typescript@6.0.3) 1782 + transitivePeerDependencies: 1783 + - typescript 1784 + 1785 + '@atcute/oauth-keyset@0.1.2(typescript@6.0.3)': 1786 + dependencies: 1787 + '@atcute/oauth-crypto': 1.0.1(typescript@6.0.3) 1788 + transitivePeerDependencies: 1789 + - typescript 1790 + 1791 + '@atcute/oauth-types@1.0.1(typescript@6.0.3)': 1792 + dependencies: 1793 + '@atcute/identity': 2.0.1(@atcute/lexicons@2.0.2)(typescript@6.0.3) 1794 + '@atcute/lexicons': 2.0.2 1795 + '@atcute/oauth-keyset': 0.1.2(typescript@6.0.3) 1796 + valibot: 1.4.2(typescript@6.0.3) 1797 + transitivePeerDependencies: 1798 + - typescript 1799 + 1800 + '@atcute/uint8array@1.1.3': {} 1801 + 1802 + '@atcute/util-fetch@2.0.1(typescript@6.0.3)': 1803 + dependencies: 1804 + valibot: 1.4.2(typescript@6.0.3) 1805 + transitivePeerDependencies: 1806 + - typescript 1807 + 1808 + '@atcute/util-text@1.3.3': 1809 + dependencies: 1810 + unicode-segmenter: 0.14.5 1811 + 1812 + '@emnapi/core@1.11.1': 1813 + dependencies: 1814 + '@emnapi/wasi-threads': 1.2.2 1815 + tslib: 2.8.1 1816 + optional: true 1817 + 1818 + '@emnapi/runtime@1.11.1': 1819 + dependencies: 1820 + tslib: 2.8.1 1821 + optional: true 1822 + 1823 + '@emnapi/wasi-threads@1.2.2': 1824 + dependencies: 1825 + tslib: 2.8.1 1826 + optional: true 1827 + 1828 + '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0))': 1829 + dependencies: 1830 + eslint: 10.6.0(jiti@2.7.0) 1831 + eslint-visitor-keys: 3.4.3 1832 + 1833 + '@eslint-community/regexpp@4.12.2': {} 1834 + 1835 + '@eslint/config-array@0.23.5': 1836 + dependencies: 1837 + '@eslint/object-schema': 3.0.5 1838 + debug: 4.4.3 1839 + minimatch: 10.2.5 1840 + transitivePeerDependencies: 1841 + - supports-color 1842 + 1843 + '@eslint/config-helpers@0.6.0': 1844 + dependencies: 1845 + '@eslint/core': 1.2.1 1846 + 1847 + '@eslint/core@1.2.1': 1848 + dependencies: 1849 + '@types/json-schema': 7.0.15 1850 + 1851 + '@eslint/js@10.0.1(eslint@10.6.0(jiti@2.7.0))': 1852 + optionalDependencies: 1853 + eslint: 10.6.0(jiti@2.7.0) 1854 + 1855 + '@eslint/object-schema@3.0.5': {} 1856 + 1857 + '@eslint/plugin-kit@0.7.2': 1858 + dependencies: 1859 + '@eslint/core': 1.2.1 1860 + levn: 0.4.1 1861 + 1862 + '@humanfs/core@0.19.2': 1863 + dependencies: 1864 + '@humanfs/types': 0.15.0 1865 + 1866 + '@humanfs/node@0.16.8': 1867 + dependencies: 1868 + '@humanfs/core': 0.19.2 1869 + '@humanfs/types': 0.15.0 1870 + '@humanwhocodes/retry': 0.4.3 1871 + 1872 + '@humanfs/types@0.15.0': {} 1873 + 1874 + '@humanwhocodes/module-importer@1.0.1': {} 1875 + 1876 + '@humanwhocodes/retry@0.4.3': {} 1877 + 1878 + '@iconify-json/lucide@1.2.116': 1879 + dependencies: 1880 + '@iconify/types': 2.0.0 1881 + 1882 + '@iconify/types@2.0.0': {} 1883 + 1884 + '@iconify/utils@3.1.4': 1885 + dependencies: 1886 + '@antfu/install-pkg': 1.1.0 1887 + '@iconify/types': 2.0.0 1888 + import-meta-resolve: 4.2.0 1889 + 1890 + '@jridgewell/gen-mapping@0.3.13': 1891 + dependencies: 1892 + '@jridgewell/sourcemap-codec': 1.5.5 1893 + '@jridgewell/trace-mapping': 0.3.31 1894 + 1895 + '@jridgewell/remapping@2.3.5': 1896 + dependencies: 1897 + '@jridgewell/gen-mapping': 0.3.13 1898 + '@jridgewell/trace-mapping': 0.3.31 1899 + 1900 + '@jridgewell/resolve-uri@3.1.2': {} 1901 + 1902 + '@jridgewell/sourcemap-codec@1.5.5': {} 1903 + 1904 + '@jridgewell/trace-mapping@0.3.31': 1905 + dependencies: 1906 + '@jridgewell/resolve-uri': 3.1.2 1907 + '@jridgewell/sourcemap-codec': 1.5.5 1908 + 1909 + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': 1910 + dependencies: 1911 + '@emnapi/core': 1.11.1 1912 + '@emnapi/runtime': 1.11.1 1913 + '@tybys/wasm-util': 0.10.3 1914 + optional: true 1915 + 1916 + '@oxc-project/types@0.138.0': {} 1917 + 1918 + '@playwright/test@1.61.1': 1919 + dependencies: 1920 + playwright: 1.61.1 1921 + 1922 + '@polka/url@1.0.0-next.29': {} 1923 + 1924 + '@rolldown/binding-android-arm64@1.1.4': 1925 + optional: true 1926 + 1927 + '@rolldown/binding-darwin-arm64@1.1.4': 1928 + optional: true 1929 + 1930 + '@rolldown/binding-darwin-x64@1.1.4': 1931 + optional: true 1932 + 1933 + '@rolldown/binding-freebsd-x64@1.1.4': 1934 + optional: true 1935 + 1936 + '@rolldown/binding-linux-arm-gnueabihf@1.1.4': 1937 + optional: true 1938 + 1939 + '@rolldown/binding-linux-arm64-gnu@1.1.4': 1940 + optional: true 1941 + 1942 + '@rolldown/binding-linux-arm64-musl@1.1.4': 1943 + optional: true 1944 + 1945 + '@rolldown/binding-linux-ppc64-gnu@1.1.4': 1946 + optional: true 1947 + 1948 + '@rolldown/binding-linux-s390x-gnu@1.1.4': 1949 + optional: true 1950 + 1951 + '@rolldown/binding-linux-x64-gnu@1.1.4': 1952 + optional: true 1953 + 1954 + '@rolldown/binding-linux-x64-musl@1.1.4': 1955 + optional: true 1956 + 1957 + '@rolldown/binding-openharmony-arm64@1.1.4': 1958 + optional: true 1959 + 1960 + '@rolldown/binding-wasm32-wasi@1.1.4': 1961 + dependencies: 1962 + '@emnapi/core': 1.11.1 1963 + '@emnapi/runtime': 1.11.1 1964 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) 1965 + optional: true 1966 + 1967 + '@rolldown/binding-win32-arm64-msvc@1.1.4': 1968 + optional: true 1969 + 1970 + '@rolldown/binding-win32-x64-msvc@1.1.4': 1971 + optional: true 1972 + 1973 + '@rolldown/pluginutils@1.0.1': {} 1974 + 1975 + '@rollup/plugin-commonjs@29.0.3(rollup@4.62.2)': 1976 + dependencies: 1977 + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) 1978 + commondir: 1.0.1 1979 + estree-walker: 2.0.2 1980 + fdir: 6.5.0(picomatch@4.0.5) 1981 + is-reference: 1.2.1 1982 + magic-string: 0.30.21 1983 + picomatch: 4.0.5 1984 + optionalDependencies: 1985 + rollup: 4.62.2 1986 + 1987 + '@rollup/plugin-json@6.1.0(rollup@4.62.2)': 1988 + dependencies: 1989 + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) 1990 + optionalDependencies: 1991 + rollup: 4.62.2 1992 + 1993 + '@rollup/plugin-node-resolve@16.0.3(rollup@4.62.2)': 1994 + dependencies: 1995 + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) 1996 + '@types/resolve': 1.20.2 1997 + deepmerge: 4.3.1 1998 + is-module: 1.0.0 1999 + resolve: 1.22.12 2000 + optionalDependencies: 2001 + rollup: 4.62.2 2002 + 2003 + '@rollup/plugin-replace@6.0.3(rollup@4.62.2)': 2004 + dependencies: 2005 + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) 2006 + magic-string: 0.30.21 2007 + optionalDependencies: 2008 + rollup: 4.62.2 2009 + 2010 + '@rollup/pluginutils@5.4.0(rollup@4.62.2)': 2011 + dependencies: 2012 + '@types/estree': 1.0.9 2013 + estree-walker: 2.0.2 2014 + picomatch: 4.0.5 2015 + optionalDependencies: 2016 + rollup: 4.62.2 2017 + 2018 + '@rollup/rollup-android-arm-eabi@4.62.2': 2019 + optional: true 2020 + 2021 + '@rollup/rollup-android-arm64@4.62.2': 2022 + optional: true 2023 + 2024 + '@rollup/rollup-darwin-arm64@4.62.2': 2025 + optional: true 2026 + 2027 + '@rollup/rollup-darwin-x64@4.62.2': 2028 + optional: true 2029 + 2030 + '@rollup/rollup-freebsd-arm64@4.62.2': 2031 + optional: true 2032 + 2033 + '@rollup/rollup-freebsd-x64@4.62.2': 2034 + optional: true 2035 + 2036 + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': 2037 + optional: true 2038 + 2039 + '@rollup/rollup-linux-arm-musleabihf@4.62.2': 2040 + optional: true 2041 + 2042 + '@rollup/rollup-linux-arm64-gnu@4.62.2': 2043 + optional: true 2044 + 2045 + '@rollup/rollup-linux-arm64-musl@4.62.2': 2046 + optional: true 2047 + 2048 + '@rollup/rollup-linux-loong64-gnu@4.62.2': 2049 + optional: true 2050 + 2051 + '@rollup/rollup-linux-loong64-musl@4.62.2': 2052 + optional: true 2053 + 2054 + '@rollup/rollup-linux-ppc64-gnu@4.62.2': 2055 + optional: true 2056 + 2057 + '@rollup/rollup-linux-ppc64-musl@4.62.2': 2058 + optional: true 2059 + 2060 + '@rollup/rollup-linux-riscv64-gnu@4.62.2': 2061 + optional: true 2062 + 2063 + '@rollup/rollup-linux-riscv64-musl@4.62.2': 2064 + optional: true 2065 + 2066 + '@rollup/rollup-linux-s390x-gnu@4.62.2': 2067 + optional: true 2068 + 2069 + '@rollup/rollup-linux-x64-gnu@4.62.2': 2070 + optional: true 2071 + 2072 + '@rollup/rollup-linux-x64-musl@4.62.2': 2073 + optional: true 2074 + 2075 + '@rollup/rollup-openbsd-x64@4.62.2': 2076 + optional: true 2077 + 2078 + '@rollup/rollup-openharmony-arm64@4.62.2': 2079 + optional: true 2080 + 2081 + '@rollup/rollup-win32-arm64-msvc@4.62.2': 2082 + optional: true 2083 + 2084 + '@rollup/rollup-win32-ia32-msvc@4.62.2': 2085 + optional: true 2086 + 2087 + '@rollup/rollup-win32-x64-gnu@4.62.2': 2088 + optional: true 2089 + 2090 + '@rollup/rollup-win32-x64-msvc@4.62.2': 2091 + optional: true 2092 + 2093 + '@standard-schema/spec@1.1.0': {} 2094 + 2095 + '@sveltejs/acorn-typescript@1.0.10(acorn@8.17.0)': 2096 + dependencies: 2097 + acorn: 8.17.0 2098 + 2099 + '@sveltejs/adapter-node@5.5.7(@sveltejs/kit@2.69.1(@sveltejs/vite-plugin-svelte@7.1.3(svelte@5.56.4(@typescript-eslint/types@8.63.0))(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.56.4(@typescript-eslint/types@8.63.0))(typescript@6.0.3)(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)))': 2100 + dependencies: 2101 + '@rollup/plugin-commonjs': 29.0.3(rollup@4.62.2) 2102 + '@rollup/plugin-json': 6.1.0(rollup@4.62.2) 2103 + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.62.2) 2104 + '@rollup/plugin-replace': 6.0.3(rollup@4.62.2) 2105 + '@sveltejs/kit': 2.69.1(@sveltejs/vite-plugin-svelte@7.1.3(svelte@5.56.4(@typescript-eslint/types@8.63.0))(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.56.4(@typescript-eslint/types@8.63.0))(typescript@6.0.3)(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)) 2106 + rollup: 4.62.2 2107 + 2108 + '@sveltejs/kit@2.69.1(@sveltejs/vite-plugin-svelte@7.1.3(svelte@5.56.4(@typescript-eslint/types@8.63.0))(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)))(svelte@5.56.4(@typescript-eslint/types@8.63.0))(typescript@6.0.3)(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0))': 2109 + dependencies: 2110 + '@standard-schema/spec': 1.1.0 2111 + '@sveltejs/acorn-typescript': 1.0.10(acorn@8.17.0) 2112 + '@sveltejs/vite-plugin-svelte': 7.1.3(svelte@5.56.4(@typescript-eslint/types@8.63.0))(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)) 2113 + '@types/cookie': 0.6.0 2114 + acorn: 8.17.0 2115 + cookie: 0.6.0 2116 + devalue: 5.8.1 2117 + esm-env: 1.2.2 2118 + kleur: 4.1.5 2119 + magic-string: 0.30.21 2120 + mrmime: 2.0.1 2121 + set-cookie-parser: 3.1.1 2122 + sirv: 3.0.2 2123 + svelte: 5.56.4(@typescript-eslint/types@8.63.0) 2124 + vite: 8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) 2125 + optionalDependencies: 2126 + typescript: 6.0.3 2127 + 2128 + '@sveltejs/load-config@0.2.0': {} 2129 + 2130 + '@sveltejs/vite-plugin-svelte@7.1.3(svelte@5.56.4(@typescript-eslint/types@8.63.0))(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0))': 2131 + dependencies: 2132 + deepmerge: 4.3.1 2133 + magic-string: 0.30.21 2134 + obug: 2.1.3 2135 + svelte: 5.56.4(@typescript-eslint/types@8.63.0) 2136 + vite: 8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) 2137 + vitefu: 1.1.3(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)) 2138 + 2139 + '@tailwindcss/node@4.3.2': 2140 + dependencies: 2141 + '@jridgewell/remapping': 2.3.5 2142 + enhanced-resolve: 5.21.6 2143 + jiti: 2.7.0 2144 + lightningcss: 1.32.0 2145 + magic-string: 0.30.21 2146 + source-map-js: 1.2.1 2147 + tailwindcss: 4.3.2 2148 + 2149 + '@tailwindcss/oxide-android-arm64@4.3.2': 2150 + optional: true 2151 + 2152 + '@tailwindcss/oxide-darwin-arm64@4.3.2': 2153 + optional: true 2154 + 2155 + '@tailwindcss/oxide-darwin-x64@4.3.2': 2156 + optional: true 2157 + 2158 + '@tailwindcss/oxide-freebsd-x64@4.3.2': 2159 + optional: true 2160 + 2161 + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': 2162 + optional: true 2163 + 2164 + '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': 2165 + optional: true 2166 + 2167 + '@tailwindcss/oxide-linux-arm64-musl@4.3.2': 2168 + optional: true 2169 + 2170 + '@tailwindcss/oxide-linux-x64-gnu@4.3.2': 2171 + optional: true 2172 + 2173 + '@tailwindcss/oxide-linux-x64-musl@4.3.2': 2174 + optional: true 2175 + 2176 + '@tailwindcss/oxide-wasm32-wasi@4.3.2': 2177 + optional: true 2178 + 2179 + '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': 2180 + optional: true 2181 + 2182 + '@tailwindcss/oxide-win32-x64-msvc@4.3.2': 2183 + optional: true 2184 + 2185 + '@tailwindcss/oxide@4.3.2': 2186 + optionalDependencies: 2187 + '@tailwindcss/oxide-android-arm64': 4.3.2 2188 + '@tailwindcss/oxide-darwin-arm64': 4.3.2 2189 + '@tailwindcss/oxide-darwin-x64': 4.3.2 2190 + '@tailwindcss/oxide-freebsd-x64': 4.3.2 2191 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.2 2192 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.2 2193 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.2 2194 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.2 2195 + '@tailwindcss/oxide-linux-x64-musl': 4.3.2 2196 + '@tailwindcss/oxide-wasm32-wasi': 4.3.2 2197 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.2 2198 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.2 2199 + 2200 + '@tailwindcss/vite@4.3.2(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0))': 2201 + dependencies: 2202 + '@tailwindcss/node': 4.3.2 2203 + '@tailwindcss/oxide': 4.3.2 2204 + tailwindcss: 4.3.2 2205 + vite: 8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) 2206 + 2207 + '@tybys/wasm-util@0.10.3': 2208 + dependencies: 2209 + tslib: 2.8.1 2210 + optional: true 2211 + 2212 + '@types/chai@5.2.3': 2213 + dependencies: 2214 + '@types/deep-eql': 4.0.2 2215 + assertion-error: 2.0.1 2216 + 2217 + '@types/cookie@0.6.0': {} 2218 + 2219 + '@types/deep-eql@4.0.2': {} 2220 + 2221 + '@types/esrecurse@4.3.1': {} 2222 + 2223 + '@types/estree@1.0.9': {} 2224 + 2225 + '@types/json-schema@7.0.15': {} 2226 + 2227 + '@types/node@24.13.2': 2228 + dependencies: 2229 + undici-types: 7.18.2 2230 + 2231 + '@types/resolve@1.20.2': {} 2232 + 2233 + '@types/trusted-types@2.0.7': {} 2234 + 2235 + '@typescript-eslint/eslint-plugin@8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': 2236 + dependencies: 2237 + '@eslint-community/regexpp': 4.12.2 2238 + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) 2239 + '@typescript-eslint/scope-manager': 8.63.0 2240 + '@typescript-eslint/type-utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) 2241 + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) 2242 + '@typescript-eslint/visitor-keys': 8.63.0 2243 + eslint: 10.6.0(jiti@2.7.0) 2244 + ignore: 7.0.5 2245 + natural-compare: 1.4.0 2246 + ts-api-utils: 2.5.0(typescript@6.0.3) 2247 + typescript: 6.0.3 2248 + transitivePeerDependencies: 2249 + - supports-color 2250 + 2251 + '@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': 2252 + dependencies: 2253 + '@typescript-eslint/scope-manager': 8.63.0 2254 + '@typescript-eslint/types': 8.63.0 2255 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) 2256 + '@typescript-eslint/visitor-keys': 8.63.0 2257 + debug: 4.4.3 2258 + eslint: 10.6.0(jiti@2.7.0) 2259 + typescript: 6.0.3 2260 + transitivePeerDependencies: 2261 + - supports-color 2262 + 2263 + '@typescript-eslint/project-service@8.63.0(typescript@6.0.3)': 2264 + dependencies: 2265 + '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@6.0.3) 2266 + '@typescript-eslint/types': 8.63.0 2267 + debug: 4.4.3 2268 + typescript: 6.0.3 2269 + transitivePeerDependencies: 2270 + - supports-color 2271 + 2272 + '@typescript-eslint/scope-manager@8.63.0': 2273 + dependencies: 2274 + '@typescript-eslint/types': 8.63.0 2275 + '@typescript-eslint/visitor-keys': 8.63.0 2276 + 2277 + '@typescript-eslint/tsconfig-utils@8.63.0(typescript@6.0.3)': 2278 + dependencies: 2279 + typescript: 6.0.3 2280 + 2281 + '@typescript-eslint/type-utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': 2282 + dependencies: 2283 + '@typescript-eslint/types': 8.63.0 2284 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) 2285 + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) 2286 + debug: 4.4.3 2287 + eslint: 10.6.0(jiti@2.7.0) 2288 + ts-api-utils: 2.5.0(typescript@6.0.3) 2289 + typescript: 6.0.3 2290 + transitivePeerDependencies: 2291 + - supports-color 2292 + 2293 + '@typescript-eslint/types@8.63.0': {} 2294 + 2295 + '@typescript-eslint/typescript-estree@8.63.0(typescript@6.0.3)': 2296 + dependencies: 2297 + '@typescript-eslint/project-service': 8.63.0(typescript@6.0.3) 2298 + '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@6.0.3) 2299 + '@typescript-eslint/types': 8.63.0 2300 + '@typescript-eslint/visitor-keys': 8.63.0 2301 + debug: 4.4.3 2302 + minimatch: 10.2.5 2303 + semver: 7.8.5 2304 + tinyglobby: 0.2.17 2305 + ts-api-utils: 2.5.0(typescript@6.0.3) 2306 + typescript: 6.0.3 2307 + transitivePeerDependencies: 2308 + - supports-color 2309 + 2310 + '@typescript-eslint/utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': 2311 + dependencies: 2312 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) 2313 + '@typescript-eslint/scope-manager': 8.63.0 2314 + '@typescript-eslint/types': 8.63.0 2315 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) 2316 + eslint: 10.6.0(jiti@2.7.0) 2317 + typescript: 6.0.3 2318 + transitivePeerDependencies: 2319 + - supports-color 2320 + 2321 + '@typescript-eslint/visitor-keys@8.63.0': 2322 + dependencies: 2323 + '@typescript-eslint/types': 8.63.0 2324 + eslint-visitor-keys: 5.0.1 2325 + 2326 + '@vitest/expect@4.1.10': 2327 + dependencies: 2328 + '@standard-schema/spec': 1.1.0 2329 + '@types/chai': 5.2.3 2330 + '@vitest/spy': 4.1.10 2331 + '@vitest/utils': 4.1.10 2332 + chai: 6.2.2 2333 + tinyrainbow: 3.1.0 2334 + 2335 + '@vitest/mocker@4.1.10(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0))': 2336 + dependencies: 2337 + '@vitest/spy': 4.1.10 2338 + estree-walker: 3.0.3 2339 + magic-string: 0.30.21 2340 + optionalDependencies: 2341 + vite: 8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) 2342 + 2343 + '@vitest/pretty-format@4.1.10': 2344 + dependencies: 2345 + tinyrainbow: 3.1.0 2346 + 2347 + '@vitest/runner@4.1.10': 2348 + dependencies: 2349 + '@vitest/utils': 4.1.10 2350 + pathe: 2.0.3 2351 + 2352 + '@vitest/snapshot@4.1.10': 2353 + dependencies: 2354 + '@vitest/pretty-format': 4.1.10 2355 + '@vitest/utils': 4.1.10 2356 + magic-string: 0.30.21 2357 + pathe: 2.0.3 2358 + 2359 + '@vitest/spy@4.1.10': {} 2360 + 2361 + '@vitest/utils@4.1.10': 2362 + dependencies: 2363 + '@vitest/pretty-format': 4.1.10 2364 + convert-source-map: 2.0.0 2365 + tinyrainbow: 3.1.0 2366 + 2367 + acorn-jsx@5.3.2(acorn@8.17.0): 2368 + dependencies: 2369 + acorn: 8.17.0 2370 + 2371 + acorn@8.17.0: {} 2372 + 2373 + ajv@6.15.0: 2374 + dependencies: 2375 + fast-deep-equal: 3.1.3 2376 + fast-json-stable-stringify: 2.1.0 2377 + json-schema-traverse: 0.4.1 2378 + uri-js: 4.4.1 2379 + 2380 + aria-query@5.3.1: {} 2381 + 2382 + assertion-error@2.0.1: {} 2383 + 2384 + axobject-query@4.1.0: {} 2385 + 2386 + balanced-match@4.0.4: {} 2387 + 2388 + brace-expansion@5.0.7: 2389 + dependencies: 2390 + balanced-match: 4.0.4 2391 + 2392 + chai@6.2.2: {} 2393 + 2394 + chokidar@4.0.3: 2395 + dependencies: 2396 + readdirp: 4.1.2 2397 + 2398 + clsx@2.1.1: {} 2399 + 2400 + commondir@1.0.1: {} 2401 + 2402 + confbox@0.1.8: {} 2403 + 2404 + confbox@0.2.4: {} 2405 + 2406 + convert-source-map@2.0.0: {} 2407 + 2408 + cookie@0.6.0: {} 2409 + 2410 + cross-spawn@7.0.6: 2411 + dependencies: 2412 + path-key: 3.1.1 2413 + shebang-command: 2.0.0 2414 + which: 2.0.2 2415 + 2416 + cssesc@3.0.0: {} 2417 + 2418 + debug@4.4.3: 2419 + dependencies: 2420 + ms: 2.1.3 2421 + 2422 + deep-is@0.1.4: {} 2423 + 2424 + deepmerge@4.3.1: {} 2425 + 2426 + detect-libc@2.1.2: {} 2427 + 2428 + devalue@5.8.1: {} 2429 + 2430 + enhanced-resolve@5.21.6: 2431 + dependencies: 2432 + graceful-fs: 4.2.11 2433 + tapable: 2.3.3 2434 + 2435 + es-errors@1.3.0: {} 2436 + 2437 + es-module-lexer@2.3.0: {} 2438 + 2439 + escape-string-regexp@4.0.0: {} 2440 + 2441 + eslint-config-prettier@10.1.8(eslint@10.6.0(jiti@2.7.0)): 2442 + dependencies: 2443 + eslint: 10.6.0(jiti@2.7.0) 2444 + 2445 + eslint-plugin-svelte@3.20.0(eslint@10.6.0(jiti@2.7.0))(svelte@5.56.4(@typescript-eslint/types@8.63.0)): 2446 + dependencies: 2447 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) 2448 + '@jridgewell/sourcemap-codec': 1.5.5 2449 + eslint: 10.6.0(jiti@2.7.0) 2450 + esutils: 2.0.3 2451 + globals: 16.5.0 2452 + known-css-properties: 0.37.0 2453 + postcss: 8.5.16 2454 + postcss-load-config: 3.1.4(postcss@8.5.16) 2455 + postcss-safe-parser: 7.0.1(postcss@8.5.16) 2456 + semver: 7.8.5 2457 + svelte-eslint-parser: 1.8.0(svelte@5.56.4(@typescript-eslint/types@8.63.0)) 2458 + optionalDependencies: 2459 + svelte: 5.56.4(@typescript-eslint/types@8.63.0) 2460 + transitivePeerDependencies: 2461 + - ts-node 2462 + 2463 + eslint-scope@8.4.0: 2464 + dependencies: 2465 + esrecurse: 4.3.0 2466 + estraverse: 5.3.0 2467 + 2468 + eslint-scope@9.1.2: 2469 + dependencies: 2470 + '@types/esrecurse': 4.3.1 2471 + '@types/estree': 1.0.9 2472 + esrecurse: 4.3.0 2473 + estraverse: 5.3.0 2474 + 2475 + eslint-visitor-keys@3.4.3: {} 2476 + 2477 + eslint-visitor-keys@4.2.1: {} 2478 + 2479 + eslint-visitor-keys@5.0.1: {} 2480 + 2481 + eslint@10.6.0(jiti@2.7.0): 2482 + dependencies: 2483 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) 2484 + '@eslint-community/regexpp': 4.12.2 2485 + '@eslint/config-array': 0.23.5 2486 + '@eslint/config-helpers': 0.6.0 2487 + '@eslint/core': 1.2.1 2488 + '@eslint/plugin-kit': 0.7.2 2489 + '@humanfs/node': 0.16.8 2490 + '@humanwhocodes/module-importer': 1.0.1 2491 + '@humanwhocodes/retry': 0.4.3 2492 + '@types/estree': 1.0.9 2493 + ajv: 6.15.0 2494 + cross-spawn: 7.0.6 2495 + debug: 4.4.3 2496 + escape-string-regexp: 4.0.0 2497 + eslint-scope: 9.1.2 2498 + eslint-visitor-keys: 5.0.1 2499 + espree: 11.2.0 2500 + esquery: 1.7.0 2501 + esutils: 2.0.3 2502 + fast-deep-equal: 3.1.3 2503 + file-entry-cache: 8.0.0 2504 + find-up: 5.0.0 2505 + glob-parent: 6.0.2 2506 + ignore: 5.3.2 2507 + imurmurhash: 0.1.4 2508 + is-glob: 4.0.3 2509 + json-stable-stringify-without-jsonify: 1.0.1 2510 + minimatch: 10.2.5 2511 + natural-compare: 1.4.0 2512 + optionator: 0.9.4 2513 + optionalDependencies: 2514 + jiti: 2.7.0 2515 + transitivePeerDependencies: 2516 + - supports-color 2517 + 2518 + esm-env@1.2.2: {} 2519 + 2520 + espree@10.4.0: 2521 + dependencies: 2522 + acorn: 8.17.0 2523 + acorn-jsx: 5.3.2(acorn@8.17.0) 2524 + eslint-visitor-keys: 4.2.1 2525 + 2526 + espree@11.2.0: 2527 + dependencies: 2528 + acorn: 8.17.0 2529 + acorn-jsx: 5.3.2(acorn@8.17.0) 2530 + eslint-visitor-keys: 5.0.1 2531 + 2532 + esquery@1.7.0: 2533 + dependencies: 2534 + estraverse: 5.3.0 2535 + 2536 + esrap@2.2.13(@typescript-eslint/types@8.63.0): 2537 + dependencies: 2538 + '@jridgewell/sourcemap-codec': 1.5.5 2539 + optionalDependencies: 2540 + '@typescript-eslint/types': 8.63.0 2541 + 2542 + esrecurse@4.3.0: 2543 + dependencies: 2544 + estraverse: 5.3.0 2545 + 2546 + estraverse@5.3.0: {} 2547 + 2548 + estree-walker@2.0.2: {} 2549 + 2550 + estree-walker@3.0.3: 2551 + dependencies: 2552 + '@types/estree': 1.0.9 2553 + 2554 + esutils@2.0.3: {} 2555 + 2556 + expect-type@1.4.0: {} 2557 + 2558 + exsolve@1.1.0: {} 2559 + 2560 + fast-deep-equal@3.1.3: {} 2561 + 2562 + fast-json-stable-stringify@2.1.0: {} 2563 + 2564 + fast-levenshtein@2.0.6: {} 2565 + 2566 + fdir@6.5.0(picomatch@4.0.5): 2567 + optionalDependencies: 2568 + picomatch: 4.0.5 2569 + 2570 + file-entry-cache@8.0.0: 2571 + dependencies: 2572 + flat-cache: 4.0.1 2573 + 2574 + find-up@5.0.0: 2575 + dependencies: 2576 + locate-path: 6.0.0 2577 + path-exists: 4.0.0 2578 + 2579 + flat-cache@4.0.1: 2580 + dependencies: 2581 + flatted: 3.4.2 2582 + keyv: 4.5.4 2583 + 2584 + flatted@3.4.2: {} 2585 + 2586 + fsevents@2.3.2: 2587 + optional: true 2588 + 2589 + fsevents@2.3.3: 2590 + optional: true 2591 + 2592 + function-bind@1.1.2: {} 2593 + 2594 + glob-parent@6.0.2: 2595 + dependencies: 2596 + is-glob: 4.0.3 2597 + 2598 + globals@16.5.0: {} 2599 + 2600 + globals@17.7.0: {} 2601 + 2602 + graceful-fs@4.2.11: {} 2603 + 2604 + hasown@2.0.4: 2605 + dependencies: 2606 + function-bind: 1.1.2 2607 + 2608 + ignore@5.3.2: {} 2609 + 2610 + ignore@7.0.5: {} 2611 + 2612 + import-meta-resolve@4.2.0: {} 2613 + 2614 + imurmurhash@0.1.4: {} 2615 + 2616 + is-core-module@2.16.2: 2617 + dependencies: 2618 + hasown: 2.0.4 2619 + 2620 + is-extglob@2.1.1: {} 2621 + 2622 + is-glob@4.0.3: 2623 + dependencies: 2624 + is-extglob: 2.1.1 2625 + 2626 + is-module@1.0.0: {} 2627 + 2628 + is-reference@1.2.1: 2629 + dependencies: 2630 + '@types/estree': 1.0.9 2631 + 2632 + is-reference@3.0.3: 2633 + dependencies: 2634 + '@types/estree': 1.0.9 2635 + 2636 + isexe@2.0.0: {} 2637 + 2638 + jiti@2.7.0: {} 2639 + 2640 + json-buffer@3.0.1: {} 2641 + 2642 + json-schema-traverse@0.4.1: {} 2643 + 2644 + json-stable-stringify-without-jsonify@1.0.1: {} 2645 + 2646 + keyv@4.5.4: 2647 + dependencies: 2648 + json-buffer: 3.0.1 2649 + 2650 + kleur@4.1.5: {} 2651 + 2652 + known-css-properties@0.37.0: {} 2653 + 2654 + levn@0.4.1: 2655 + dependencies: 2656 + prelude-ls: 1.2.1 2657 + type-check: 0.4.0 2658 + 2659 + lightningcss-android-arm64@1.32.0: 2660 + optional: true 2661 + 2662 + lightningcss-darwin-arm64@1.32.0: 2663 + optional: true 2664 + 2665 + lightningcss-darwin-x64@1.32.0: 2666 + optional: true 2667 + 2668 + lightningcss-freebsd-x64@1.32.0: 2669 + optional: true 2670 + 2671 + lightningcss-linux-arm-gnueabihf@1.32.0: 2672 + optional: true 2673 + 2674 + lightningcss-linux-arm64-gnu@1.32.0: 2675 + optional: true 2676 + 2677 + lightningcss-linux-arm64-musl@1.32.0: 2678 + optional: true 2679 + 2680 + lightningcss-linux-x64-gnu@1.32.0: 2681 + optional: true 2682 + 2683 + lightningcss-linux-x64-musl@1.32.0: 2684 + optional: true 2685 + 2686 + lightningcss-win32-arm64-msvc@1.32.0: 2687 + optional: true 2688 + 2689 + lightningcss-win32-x64-msvc@1.32.0: 2690 + optional: true 2691 + 2692 + lightningcss@1.32.0: 2693 + dependencies: 2694 + detect-libc: 2.1.2 2695 + optionalDependencies: 2696 + lightningcss-android-arm64: 1.32.0 2697 + lightningcss-darwin-arm64: 1.32.0 2698 + lightningcss-darwin-x64: 1.32.0 2699 + lightningcss-freebsd-x64: 1.32.0 2700 + lightningcss-linux-arm-gnueabihf: 1.32.0 2701 + lightningcss-linux-arm64-gnu: 1.32.0 2702 + lightningcss-linux-arm64-musl: 1.32.0 2703 + lightningcss-linux-x64-gnu: 1.32.0 2704 + lightningcss-linux-x64-musl: 1.32.0 2705 + lightningcss-win32-arm64-msvc: 1.32.0 2706 + lightningcss-win32-x64-msvc: 1.32.0 2707 + 2708 + lilconfig@2.1.0: {} 2709 + 2710 + local-pkg@1.2.1: 2711 + dependencies: 2712 + mlly: 1.8.2 2713 + pkg-types: 2.3.1 2714 + quansync: 0.2.11 2715 + 2716 + locate-character@3.0.0: {} 2717 + 2718 + locate-path@6.0.0: 2719 + dependencies: 2720 + p-locate: 5.0.0 2721 + 2722 + magic-string@0.30.21: 2723 + dependencies: 2724 + '@jridgewell/sourcemap-codec': 1.5.5 2725 + 2726 + minimatch@10.2.5: 2727 + dependencies: 2728 + brace-expansion: 5.0.7 2729 + 2730 + mlly@1.8.2: 2731 + dependencies: 2732 + acorn: 8.17.0 2733 + pathe: 2.0.3 2734 + pkg-types: 1.3.1 2735 + ufo: 1.6.4 2736 + 2737 + mri@1.2.0: {} 2738 + 2739 + mrmime@2.0.1: {} 2740 + 2741 + ms@2.1.3: {} 2742 + 2743 + nanoid@3.3.15: {} 2744 + 2745 + nanoid@5.1.16: {} 2746 + 2747 + natural-compare@1.4.0: {} 2748 + 2749 + obug@2.1.3: {} 2750 + 2751 + optionator@0.9.4: 2752 + dependencies: 2753 + deep-is: 0.1.4 2754 + fast-levenshtein: 2.0.6 2755 + levn: 0.4.1 2756 + prelude-ls: 1.2.1 2757 + type-check: 0.4.0 2758 + word-wrap: 1.2.5 2759 + 2760 + p-limit@3.1.0: 2761 + dependencies: 2762 + yocto-queue: 0.1.0 2763 + 2764 + p-locate@5.0.0: 2765 + dependencies: 2766 + p-limit: 3.1.0 2767 + 2768 + package-manager-detector@1.7.0: {} 2769 + 2770 + path-exists@4.0.0: {} 2771 + 2772 + path-key@3.1.1: {} 2773 + 2774 + path-parse@1.0.7: {} 2775 + 2776 + pathe@2.0.3: {} 2777 + 2778 + picocolors@1.1.1: {} 2779 + 2780 + picomatch@4.0.5: {} 2781 + 2782 + pkg-types@1.3.1: 2783 + dependencies: 2784 + confbox: 0.1.8 2785 + mlly: 1.8.2 2786 + pathe: 2.0.3 2787 + 2788 + pkg-types@2.3.1: 2789 + dependencies: 2790 + confbox: 0.2.4 2791 + exsolve: 1.1.0 2792 + pathe: 2.0.3 2793 + 2794 + playwright-core@1.61.1: {} 2795 + 2796 + playwright@1.61.1: 2797 + dependencies: 2798 + playwright-core: 1.61.1 2799 + optionalDependencies: 2800 + fsevents: 2.3.2 2801 + 2802 + postcss-load-config@3.1.4(postcss@8.5.16): 2803 + dependencies: 2804 + lilconfig: 2.1.0 2805 + yaml: 1.10.3 2806 + optionalDependencies: 2807 + postcss: 8.5.16 2808 + 2809 + postcss-safe-parser@7.0.1(postcss@8.5.16): 2810 + dependencies: 2811 + postcss: 8.5.16 2812 + 2813 + postcss-scss@4.0.9(postcss@8.5.16): 2814 + dependencies: 2815 + postcss: 8.5.16 2816 + 2817 + postcss-selector-parser@7.1.4: 2818 + dependencies: 2819 + cssesc: 3.0.0 2820 + util-deprecate: 1.0.2 2821 + 2822 + postcss@8.5.16: 2823 + dependencies: 2824 + nanoid: 3.3.15 2825 + picocolors: 1.1.1 2826 + source-map-js: 1.2.1 2827 + 2828 + prelude-ls@1.2.1: {} 2829 + 2830 + prettier-plugin-svelte@4.1.1(prettier@3.9.4)(svelte@5.56.4(@typescript-eslint/types@8.63.0)): 2831 + dependencies: 2832 + prettier: 3.9.4 2833 + svelte: 5.56.4(@typescript-eslint/types@8.63.0) 2834 + 2835 + prettier-plugin-tailwindcss@0.8.0(prettier-plugin-svelte@4.1.1(prettier@3.9.4)(svelte@5.56.4(@typescript-eslint/types@8.63.0)))(prettier@3.9.4): 2836 + dependencies: 2837 + prettier: 3.9.4 2838 + optionalDependencies: 2839 + prettier-plugin-svelte: 4.1.1(prettier@3.9.4)(svelte@5.56.4(@typescript-eslint/types@8.63.0)) 2840 + 2841 + prettier@3.9.4: {} 2842 + 2843 + punycode@2.3.1: {} 2844 + 2845 + quansync@0.2.11: {} 2846 + 2847 + readdirp@4.1.2: {} 2848 + 2849 + resolve@1.22.12: 2850 + dependencies: 2851 + es-errors: 1.3.0 2852 + is-core-module: 2.16.2 2853 + path-parse: 1.0.7 2854 + supports-preserve-symlinks-flag: 1.0.0 2855 + 2856 + rolldown@1.1.4: 2857 + dependencies: 2858 + '@oxc-project/types': 0.138.0 2859 + '@rolldown/pluginutils': 1.0.1 2860 + optionalDependencies: 2861 + '@rolldown/binding-android-arm64': 1.1.4 2862 + '@rolldown/binding-darwin-arm64': 1.1.4 2863 + '@rolldown/binding-darwin-x64': 1.1.4 2864 + '@rolldown/binding-freebsd-x64': 1.1.4 2865 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.4 2866 + '@rolldown/binding-linux-arm64-gnu': 1.1.4 2867 + '@rolldown/binding-linux-arm64-musl': 1.1.4 2868 + '@rolldown/binding-linux-ppc64-gnu': 1.1.4 2869 + '@rolldown/binding-linux-s390x-gnu': 1.1.4 2870 + '@rolldown/binding-linux-x64-gnu': 1.1.4 2871 + '@rolldown/binding-linux-x64-musl': 1.1.4 2872 + '@rolldown/binding-openharmony-arm64': 1.1.4 2873 + '@rolldown/binding-wasm32-wasi': 1.1.4 2874 + '@rolldown/binding-win32-arm64-msvc': 1.1.4 2875 + '@rolldown/binding-win32-x64-msvc': 1.1.4 2876 + 2877 + rollup@4.62.2: 2878 + dependencies: 2879 + '@types/estree': 1.0.9 2880 + optionalDependencies: 2881 + '@rollup/rollup-android-arm-eabi': 4.62.2 2882 + '@rollup/rollup-android-arm64': 4.62.2 2883 + '@rollup/rollup-darwin-arm64': 4.62.2 2884 + '@rollup/rollup-darwin-x64': 4.62.2 2885 + '@rollup/rollup-freebsd-arm64': 4.62.2 2886 + '@rollup/rollup-freebsd-x64': 4.62.2 2887 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.2 2888 + '@rollup/rollup-linux-arm-musleabihf': 4.62.2 2889 + '@rollup/rollup-linux-arm64-gnu': 4.62.2 2890 + '@rollup/rollup-linux-arm64-musl': 4.62.2 2891 + '@rollup/rollup-linux-loong64-gnu': 4.62.2 2892 + '@rollup/rollup-linux-loong64-musl': 4.62.2 2893 + '@rollup/rollup-linux-ppc64-gnu': 4.62.2 2894 + '@rollup/rollup-linux-ppc64-musl': 4.62.2 2895 + '@rollup/rollup-linux-riscv64-gnu': 4.62.2 2896 + '@rollup/rollup-linux-riscv64-musl': 4.62.2 2897 + '@rollup/rollup-linux-s390x-gnu': 4.62.2 2898 + '@rollup/rollup-linux-x64-gnu': 4.62.2 2899 + '@rollup/rollup-linux-x64-musl': 4.62.2 2900 + '@rollup/rollup-openbsd-x64': 4.62.2 2901 + '@rollup/rollup-openharmony-arm64': 4.62.2 2902 + '@rollup/rollup-win32-arm64-msvc': 4.62.2 2903 + '@rollup/rollup-win32-ia32-msvc': 4.62.2 2904 + '@rollup/rollup-win32-x64-gnu': 4.62.2 2905 + '@rollup/rollup-win32-x64-msvc': 4.62.2 2906 + fsevents: 2.3.3 2907 + 2908 + sade@1.8.1: 2909 + dependencies: 2910 + mri: 1.2.0 2911 + 2912 + semver@7.8.5: {} 2913 + 2914 + set-cookie-parser@3.1.1: {} 2915 + 2916 + shebang-command@2.0.0: 2917 + dependencies: 2918 + shebang-regex: 3.0.0 2919 + 2920 + shebang-regex@3.0.0: {} 2921 + 2922 + siginfo@2.0.0: {} 2923 + 2924 + sirv@3.0.2: 2925 + dependencies: 2926 + '@polka/url': 1.0.0-next.29 2927 + mrmime: 2.0.1 2928 + totalist: 3.0.1 2929 + 2930 + source-map-js@1.2.1: {} 2931 + 2932 + stackback@0.0.2: {} 2933 + 2934 + std-env@4.1.0: {} 2935 + 2936 + supports-preserve-symlinks-flag@1.0.0: {} 2937 + 2938 + svelte-check@4.7.1(picomatch@4.0.5)(svelte@5.56.4(@typescript-eslint/types@8.63.0))(typescript@6.0.3): 2939 + dependencies: 2940 + '@jridgewell/trace-mapping': 0.3.31 2941 + '@sveltejs/load-config': 0.2.0 2942 + chokidar: 4.0.3 2943 + fdir: 6.5.0(picomatch@4.0.5) 2944 + picocolors: 1.1.1 2945 + sade: 1.8.1 2946 + svelte: 5.56.4(@typescript-eslint/types@8.63.0) 2947 + typescript: 6.0.3 2948 + transitivePeerDependencies: 2949 + - picomatch 2950 + 2951 + svelte-eslint-parser@1.8.0(svelte@5.56.4(@typescript-eslint/types@8.63.0)): 2952 + dependencies: 2953 + eslint-scope: 8.4.0 2954 + eslint-visitor-keys: 4.2.1 2955 + espree: 10.4.0 2956 + postcss: 8.5.16 2957 + postcss-scss: 4.0.9(postcss@8.5.16) 2958 + postcss-selector-parser: 7.1.4 2959 + semver: 7.8.5 2960 + optionalDependencies: 2961 + svelte: 5.56.4(@typescript-eslint/types@8.63.0) 2962 + 2963 + svelte@5.56.4(@typescript-eslint/types@8.63.0): 2964 + dependencies: 2965 + '@jridgewell/remapping': 2.3.5 2966 + '@jridgewell/sourcemap-codec': 1.5.5 2967 + '@sveltejs/acorn-typescript': 1.0.10(acorn@8.17.0) 2968 + '@types/estree': 1.0.9 2969 + '@types/trusted-types': 2.0.7 2970 + acorn: 8.17.0 2971 + aria-query: 5.3.1 2972 + axobject-query: 4.1.0 2973 + clsx: 2.1.1 2974 + devalue: 5.8.1 2975 + esm-env: 1.2.2 2976 + esrap: 2.2.13(@typescript-eslint/types@8.63.0) 2977 + is-reference: 3.0.3 2978 + locate-character: 3.0.0 2979 + magic-string: 0.30.21 2980 + zimmerframe: 1.1.4 2981 + transitivePeerDependencies: 2982 + - '@typescript-eslint/types' 2983 + 2984 + tailwindcss@4.3.2: {} 2985 + 2986 + tapable@2.3.3: {} 2987 + 2988 + tinybench@2.9.0: {} 2989 + 2990 + tinyexec@1.2.4: {} 2991 + 2992 + tinyglobby@0.2.17: 2993 + dependencies: 2994 + fdir: 6.5.0(picomatch@4.0.5) 2995 + picomatch: 4.0.5 2996 + 2997 + tinyrainbow@3.1.0: {} 2998 + 2999 + totalist@3.0.1: {} 3000 + 3001 + ts-api-utils@2.5.0(typescript@6.0.3): 3002 + dependencies: 3003 + typescript: 6.0.3 3004 + 3005 + tslib@2.8.1: 3006 + optional: true 3007 + 3008 + type-check@0.4.0: 3009 + dependencies: 3010 + prelude-ls: 1.2.1 3011 + 3012 + typescript-eslint@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3): 3013 + dependencies: 3014 + '@typescript-eslint/eslint-plugin': 8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) 3015 + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) 3016 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) 3017 + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) 3018 + eslint: 10.6.0(jiti@2.7.0) 3019 + typescript: 6.0.3 3020 + transitivePeerDependencies: 3021 + - supports-color 3022 + 3023 + typescript@6.0.3: {} 3024 + 3025 + ufo@1.6.4: {} 3026 + 3027 + undici-types@7.18.2: {} 3028 + 3029 + unicode-segmenter@0.14.5: {} 3030 + 3031 + unplugin-icons@23.0.1(svelte@5.56.4(@typescript-eslint/types@8.63.0)): 3032 + dependencies: 3033 + '@antfu/install-pkg': 1.1.0 3034 + '@iconify/utils': 3.1.4 3035 + local-pkg: 1.2.1 3036 + obug: 2.1.3 3037 + unplugin: 2.3.11 3038 + optionalDependencies: 3039 + svelte: 5.56.4(@typescript-eslint/types@8.63.0) 3040 + 3041 + unplugin@2.3.11: 3042 + dependencies: 3043 + '@jridgewell/remapping': 2.3.5 3044 + acorn: 8.17.0 3045 + picomatch: 4.0.5 3046 + webpack-virtual-modules: 0.6.2 3047 + 3048 + uri-js@4.4.1: 3049 + dependencies: 3050 + punycode: 2.3.1 3051 + 3052 + util-deprecate@1.0.2: {} 3053 + 3054 + valibot@1.4.2(typescript@6.0.3): 3055 + optionalDependencies: 3056 + typescript: 6.0.3 3057 + 3058 + vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0): 3059 + dependencies: 3060 + lightningcss: 1.32.0 3061 + picomatch: 4.0.5 3062 + postcss: 8.5.16 3063 + rolldown: 1.1.4 3064 + tinyglobby: 0.2.17 3065 + optionalDependencies: 3066 + '@types/node': 24.13.2 3067 + fsevents: 2.3.3 3068 + jiti: 2.7.0 3069 + yaml: 2.9.0 3070 + 3071 + vitefu@1.1.3(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)): 3072 + optionalDependencies: 3073 + vite: 8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) 3074 + 3075 + vitest@4.1.10(@types/node@24.13.2)(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)): 3076 + dependencies: 3077 + '@vitest/expect': 4.1.10 3078 + '@vitest/mocker': 4.1.10(vite@8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0)) 3079 + '@vitest/pretty-format': 4.1.10 3080 + '@vitest/runner': 4.1.10 3081 + '@vitest/snapshot': 4.1.10 3082 + '@vitest/spy': 4.1.10 3083 + '@vitest/utils': 4.1.10 3084 + es-module-lexer: 2.3.0 3085 + expect-type: 1.4.0 3086 + magic-string: 0.30.21 3087 + obug: 2.1.3 3088 + pathe: 2.0.3 3089 + picomatch: 4.0.5 3090 + std-env: 4.1.0 3091 + tinybench: 2.9.0 3092 + tinyexec: 1.2.4 3093 + tinyglobby: 0.2.17 3094 + tinyrainbow: 3.1.0 3095 + vite: 8.1.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) 3096 + why-is-node-running: 2.3.0 3097 + optionalDependencies: 3098 + '@types/node': 24.13.2 3099 + transitivePeerDependencies: 3100 + - msw 3101 + 3102 + webpack-virtual-modules@0.6.2: {} 3103 + 3104 + which@2.0.2: 3105 + dependencies: 3106 + isexe: 2.0.0 3107 + 3108 + why-is-node-running@2.3.0: 3109 + dependencies: 3110 + siginfo: 2.0.0 3111 + stackback: 0.0.2 3112 + 3113 + word-wrap@1.2.5: {} 3114 + 3115 + yaml@1.10.3: {} 3116 + 3117 + yaml@2.9.0: 3118 + optional: true 3119 + 3120 + yocto-queue@0.1.0: {} 3121 + 3122 + zimmerframe@1.1.4: {}
+12
web/prettier.config.js
··· 1 + /** @type {import("prettier").Config} */ 2 + const config = { 3 + useTabs: true, 4 + singleQuote: true, 5 + trailingComma: 'none', 6 + printWidth: 100, 7 + plugins: ['prettier-plugin-svelte', 'prettier-plugin-tailwindcss'], 8 + overrides: [{ files: '*.svelte', options: { parser: 'svelte' } }], 9 + tailwindStylesheet: './src/app.css' 10 + }; 11 + 12 + export default config;
+153
web/src/app.css
··· 1 + @import 'tailwindcss'; 2 + 3 + @theme { 4 + --font-sans: 'InterVariable', 'system-ui', sans-serif, ui-sans-serif; 5 + --font-mono: 6 + 'IBMPlexMono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 7 + 'Courier New', monospace; 8 + --color-bg: #f1f5f9; 9 + --color-bg-auth: #ffffff; 10 + --color-surface: #ffffff; 11 + --color-surface-hover: #f9fafb; 12 + --color-surface-muted: #f3f4f6; 13 + --color-fg: #111827; 14 + --color-fg-strong: #030712; 15 + --color-fg-muted: #4b5563; 16 + --color-fg-subtle: #6b7280; 17 + --color-fg-faint: #9ca3af; 18 + --color-border: #e5e7eb; 19 + --color-border-subtle: #f3f4f6; 20 + --color-border-strong: #d1d5db; 21 + --color-ring: #d1d5db; 22 + --color-raised-depth: #e5e7eb; 23 + --color-raised-accent-depth: rgb(17 24 39 / 0.25); 24 + --color-raised-accent-depth-active: rgb(17 24 39 / 0.5); 25 + --color-raised-depth-hover: #d1d5db; 26 + --color-success: #16a34a; 27 + --color-success-hover: #15803d; 28 + --color-success-border: #15803d; 29 + --color-success-fg: #ffffff; 30 + --color-primary: #4f46e5; 31 + --color-primary-hover: #4338ca; 32 + --color-primary-border: #4338ca; 33 + --color-primary-fg: #ffffff; 34 + --color-info: #3b82f6; 35 + --color-info-soft: #dbeafe; 36 + --color-danger: #dc2626; 37 + --color-danger-hover: #b91c1c; 38 + --color-danger-border: #b91c1c; 39 + --color-danger-fg: #ffffff; 40 + --color-danger-soft: #fef2f2; 41 + --shadow-menu: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); 42 + } 43 + 44 + @layer base { 45 + @font-face { 46 + font-family: 'InterVariable'; 47 + src: url('/fonts/InterVariable.woff2') format('woff2-variations'); 48 + font-weight: 100 600; 49 + font-style: normal; 50 + font-display: swap; 51 + } 52 + 53 + @font-face { 54 + font-family: 'InterVariable'; 55 + src: url('/fonts/InterVariable-Italic.woff2') format('woff2-variations'); 56 + font-weight: 100 600; 57 + font-style: italic; 58 + font-display: swap; 59 + } 60 + 61 + @font-face { 62 + font-family: 'InterVariable'; 63 + src: url('/fonts/InterDisplay-Bold.woff2') format('woff2'); 64 + font-weight: bold; 65 + font-style: normal; 66 + font-display: swap; 67 + } 68 + 69 + @font-face { 70 + font-family: 'InterVariable'; 71 + src: url('/fonts/InterDisplay-BoldItalic.woff2') format('woff2'); 72 + font-weight: bold; 73 + font-style: italic; 74 + font-display: swap; 75 + } 76 + 77 + @font-face { 78 + font-family: 'IBMPlexMono'; 79 + src: url('/fonts/IBMPlexMono-Regular.woff2') format('woff2'); 80 + font-weight: normal; 81 + font-style: normal; 82 + font-display: swap; 83 + } 84 + 85 + @font-face { 86 + font-family: 'IBMPlexMono'; 87 + src: url('/fonts/IBMPlexMono-Italic.woff2') format('woff2'); 88 + font-weight: normal; 89 + font-style: italic; 90 + font-display: swap; 91 + } 92 + 93 + @font-face { 94 + font-family: 'IBMPlexMono'; 95 + src: url('/fonts/IBMPlexMono-Bold.woff2') format('woff2'); 96 + font-weight: bold; 97 + font-style: normal; 98 + font-display: swap; 99 + } 100 + 101 + @font-face { 102 + font-family: 'IBMPlexMono'; 103 + src: url('/fonts/IBMPlexMono-BoldItalic.woff2') format('woff2'); 104 + font-weight: bold; 105 + font-style: italic; 106 + font-display: swap; 107 + } 108 + 109 + html { 110 + font-size: 14px; 111 + scrollbar-gutter: stable; 112 + } 113 + 114 + @media (prefers-color-scheme: dark) { 115 + :root { 116 + --color-bg: #111827; 117 + --color-bg-auth: #111827; 118 + --color-surface: #1f2937; 119 + --color-surface-hover: #374151; 120 + --color-surface-muted: #374151; 121 + --color-fg: #f3f4f6; 122 + --color-fg-strong: #ffffff; 123 + --color-fg-muted: #d1d5db; 124 + --color-fg-subtle: #9ca3af; 125 + --color-border: #374151; 126 + --color-border-subtle: #374151; 127 + --color-border-strong: #4b5563; 128 + --color-ring: #4b5563; 129 + --color-raised-depth: #111827; 130 + --color-raised-depth-hover: #1f2937; 131 + --color-success: #15803d; 132 + --color-success-hover: #166534; 133 + --color-success-border: #16a34a; 134 + --color-primary: #6366f1; 135 + --color-primary-hover: #4f46e5; 136 + --color-primary-border: #4f46e5; 137 + --color-info: #60a5fa; 138 + --color-info-soft: rgb(30 58 138 / 0.3); 139 + --color-danger: #b91c1c; 140 + --color-danger-hover: #991b1b; 141 + --color-danger-border: #dc2626; 142 + --color-danger-soft: rgb(153 27 27 / 0.2); 143 + } 144 + } 145 + 146 + body { 147 + @apply flex min-h-screen flex-col bg-bg text-fg transition-colors duration-200; 148 + } 149 + 150 + a { 151 + @apply text-fg no-underline hover:text-fg-muted; 152 + } 153 + }
+14
web/src/app.d.ts
··· 1 + declare global { 2 + namespace App { 3 + interface PageData { 4 + publicConfig?: { 5 + bobbinUrl: string; 6 + apiUrl: string; 7 + knotResolverUrl: string; 8 + camoUrl: string; 9 + }; 10 + } 11 + } 12 + } 13 + 14 + export {};
+27
web/src/app.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, viewport-fit=cover" /> 6 + <meta name="description" content="The next-generation social coding platform." /> 7 + <meta property="og:site_name" content="Tangled" /> 8 + <meta property="og:type" content="website" /> 9 + <meta property="og:locale" content="en_US" /> 10 + <meta 11 + name="keywords" 12 + content="git, code collaboration, AT Protocol, open source, version control, social coding, code hosting" 13 + /> 14 + <meta name="author" content="Tangled" /> 15 + <meta name="robots" content="index, follow" /> 16 + <link rel="icon" href="/logos/dolly.ico" sizes="48x48" /> 17 + <link rel="icon" href="/logos/dolly.svg" sizes="any" type="image/svg+xml" /> 18 + <link rel="apple-touch-icon" href="/logos/dolly.png" /> 19 + <link rel="preconnect" href="https://avatar.tangled.sh" /> 20 + <link rel="preconnect" href="https://camo.tangled.sh" /> 21 + <link rel="preload" href="/fonts/InterVariable.woff2" as="font" type="font/woff2" crossorigin /> 22 + %sveltekit.head% 23 + </head> 24 + <body data-sveltekit-preload-data="hover" class="flex min-h-screen flex-col gap-4"> 25 + <div style="display: contents">%sveltekit.body%</div> 26 + </body> 27 + </html>
+11
web/src/icon.d.ts
··· 1 + // `$icon/<name>` is a vite alias for unplugin-icons' `~icons/lucide/<name>` 2 + // virtual module (see vite.config.ts). mirror its ambient type here so tsc / 3 + // svelte-check resolve the aliased imports. must stay a global .d.ts (no export) 4 + declare module '$icon/*' { 5 + import type { Component } from 'svelte'; 6 + import type { SvelteHTMLElements } from 'svelte/elements'; 7 + 8 + const component: Component<SvelteHTMLElements['svg']>; 9 + 10 + export default component; 11 + }
+1
web/src/lib/assets/favicon.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" width="107" height="128" viewBox="0 0 107 128"><title>svelte-logo</title><path d="M94.157 22.819c-10.4-14.885-30.94-19.297-45.792-9.835L22.282 29.608A29.92 29.92 0 0 0 8.764 49.65a31.5 31.5 0 0 0 3.108 20.231 30 30 0 0 0-4.477 11.183 31.9 31.9 0 0 0 5.448 24.116c10.402 14.887 30.942 19.297 45.791 9.835l26.083-16.624A29.92 29.92 0 0 0 98.235 78.35a31.53 31.53 0 0 0-3.105-20.232 30 30 0 0 0 4.474-11.182 31.88 31.88 0 0 0-5.447-24.116" style="fill:#ff3e00"/><path d="M45.817 106.582a20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.503 18 18 0 0 1 .624-2.435l.49-1.498 1.337.981a33.6 33.6 0 0 0 10.203 5.098l.97.294-.09.968a5.85 5.85 0 0 0 1.052 3.878 6.24 6.24 0 0 0 6.695 2.485 5.8 5.8 0 0 0 1.603-.704L69.27 76.28a5.43 5.43 0 0 0 2.45-3.631 5.8 5.8 0 0 0-.987-4.371 6.24 6.24 0 0 0-6.698-2.487 5.7 5.7 0 0 0-1.6.704l-9.953 6.345a19 19 0 0 1-5.296 2.326 20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.502 17.99 17.99 0 0 1 8.13-12.052l26.081-16.623a19 19 0 0 1 5.3-2.329 20.72 20.72 0 0 1 22.237 8.243 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-.624 2.435l-.49 1.498-1.337-.98a33.6 33.6 0 0 0-10.203-5.1l-.97-.294.09-.968a5.86 5.86 0 0 0-1.052-3.878 6.24 6.24 0 0 0-6.696-2.485 5.8 5.8 0 0 0-1.602.704L37.73 51.72a5.42 5.42 0 0 0-2.449 3.63 5.79 5.79 0 0 0 .986 4.372 6.24 6.24 0 0 0 6.698 2.486 5.8 5.8 0 0 0 1.602-.704l9.952-6.342a19 19 0 0 1 5.295-2.328 20.72 20.72 0 0 1 22.237 8.242 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-8.13 12.053l-26.081 16.622a19 19 0 0 1-5.3 2.328" style="fill:#fff"/></svg>
+331
web/src/lib/auth.svelte.ts
··· 1 + import { browser } from '$app/environment'; 2 + import { 3 + CompositeDidDocumentResolver, 4 + LocalActorResolver, 5 + PlcDidDocumentResolver, 6 + WebDidDocumentResolver, 7 + XrpcHandleResolver 8 + } from '@atcute/identity-resolver'; 9 + import type { ActorIdentifier, Did } from '@atcute/lexicons/syntax'; 10 + import { 11 + OAuthUserAgent, 12 + configureOAuth, 13 + createAuthorizationUrl, 14 + deleteStoredSession, 15 + finalizeAuthorization, 16 + getSession, 17 + listStoredSessions 18 + } from '@atcute/oauth-browser-client'; 19 + import { getContext } from 'svelte'; 20 + import { SvelteURL, SvelteURLSearchParams } from 'svelte/reactivity'; 21 + import oauthMetadata from '../../static/oauth-client-metadata.json'; 22 + 23 + export const AUTH_KEY = Symbol('auth'); 24 + const CURRENT_DID_KEY = 'tangled.currentDid'; 25 + const CURRENT_HANDLE_KEY = 'tangled.currentHandle'; 26 + const DEFAULT_APPVIEW_SERVICE = 'https://bobbin.klbr.net'; 27 + const DEV_REDIRECT_URI = 'http://127.0.0.1:5173/oauth/callback'; 28 + const DEV_CLIENT_ID = `http://localhost?redirect_uri=${encodeURIComponent(DEV_REDIRECT_URI)}&scope=${encodeURIComponent(oauthMetadata.scope)}`; 29 + 30 + const identityResolver = new LocalActorResolver({ 31 + handleResolver: new XrpcHandleResolver({ 32 + serviceUrl: 'https://public.api.bsky.app' 33 + }), 34 + didDocumentResolver: new CompositeDidDocumentResolver({ 35 + methods: { 36 + plc: new PlcDidDocumentResolver(), 37 + web: new WebDidDocumentResolver() 38 + } 39 + }) 40 + }); 41 + 42 + let configured = false; 43 + 44 + export interface AuthProfile { 45 + did: Did; 46 + handle: string; 47 + avatar?: string; 48 + } 49 + 50 + export interface CurrentUser { 51 + did: Did; 52 + handle: string; 53 + avatar?: string; 54 + } 55 + 56 + export interface Auth { 57 + readonly agent: OAuthUserAgent | null; 58 + readonly currentDid: Did | null; 59 + readonly profile: AuthProfile | null; 60 + readonly error: string | null; 61 + readonly profileLoading: boolean; 62 + readonly authenticating: boolean; 63 + readonly currentUser: CurrentUser | null; 64 + refresh(): Promise<void>; 65 + signIn(identifier: string, returnTo?: string): Promise<void>; 66 + completeSignIn(): Promise<string>; 67 + signOut(): Promise<void>; 68 + } 69 + 70 + type MiniDoc = { 71 + did: Did; 72 + handle: string; 73 + pds?: string; 74 + avatar?: string; 75 + }; 76 + 77 + type OAuthSession = ConstructorParameters<typeof OAuthUserAgent>[0]; 78 + 79 + const ENV_OAUTH_REDIRECT_URI = import.meta.env.VITE_OAUTH_REDIRECT_URI as string | undefined; 80 + const HAS_LOCALHOST_REDIRECT = ENV_OAUTH_REDIRECT_URI?.includes('://localhost') ?? false; 81 + const OAUTH_CLIENT_ID = HAS_LOCALHOST_REDIRECT 82 + ? DEV_CLIENT_ID 83 + : ((import.meta.env.VITE_OAUTH_CLIENT_ID as string | undefined) ?? DEV_CLIENT_ID); 84 + const OAUTH_REDIRECT_URI = HAS_LOCALHOST_REDIRECT 85 + ? DEV_REDIRECT_URI 86 + : (ENV_OAUTH_REDIRECT_URI ?? DEV_REDIRECT_URI); 87 + const OAUTH_SCOPE = (import.meta.env.VITE_OAUTH_SCOPE as string | undefined) ?? oauthMetadata.scope; 88 + const APPVIEW_SERVICE = 89 + (import.meta.env.VITE_TANGLED_APPVIEW_SERVICE as string | undefined)?.replace(/\/+$/, '') ?? 90 + DEFAULT_APPVIEW_SERVICE; 91 + 92 + const configure = () => { 93 + if (!browser || configured) return; 94 + 95 + configureOAuth({ 96 + metadata: { 97 + client_id: OAUTH_CLIENT_ID, 98 + redirect_uri: OAUTH_REDIRECT_URI 99 + }, 100 + identityResolver 101 + }); 102 + 103 + configured = true; 104 + }; 105 + 106 + const readStoredDid = (): Did | null => { 107 + if (!browser) return null; 108 + const value = localStorage.getItem(CURRENT_DID_KEY); 109 + return value?.startsWith('did:') ? (value as Did) : null; 110 + }; 111 + 112 + const persistAuth = (did: string, handle: string) => { 113 + if (!browser) return; 114 + localStorage.setItem(CURRENT_DID_KEY, did); 115 + localStorage.setItem(CURRENT_HANDLE_KEY, handle); 116 + const secure = location.protocol === 'https:' ? '; secure' : ''; 117 + const attrs = `; path=/; max-age=31536000; samesite=lax${secure}`; 118 + document.cookie = `${CURRENT_DID_KEY}=${encodeURIComponent(did)}${attrs}`; 119 + document.cookie = `${CURRENT_HANDLE_KEY}=${encodeURIComponent(handle)}${attrs}`; 120 + }; 121 + 122 + const clearAuth = () => { 123 + if (!browser) return; 124 + localStorage.removeItem(CURRENT_DID_KEY); 125 + localStorage.removeItem(CURRENT_HANDLE_KEY); 126 + document.cookie = `${CURRENT_DID_KEY}=; path=/; max-age=0; samesite=lax`; 127 + document.cookie = `${CURRENT_HANDLE_KEY}=; path=/; max-age=0; samesite=lax`; 128 + }; 129 + 130 + const errorMessage = (cause: unknown) => { 131 + const message = cause instanceof Error ? cause.message : String(cause); 132 + return message.toLowerCase().includes('unknown state') 133 + ? 'Could not resume OAuth state. In local development, start login from http://127.0.0.1:5173 instead of localhost.' 134 + : message; 135 + }; 136 + 137 + const resolveProfile = async (identifier: string): Promise<AuthProfile | null> => { 138 + try { 139 + const url = new URL('/xrpc/com.bad-example.identity.resolveMiniDoc', APPVIEW_SERVICE); 140 + url.searchParams.set('identifier', identifier); 141 + const response = await fetch(url, { headers: { accept: 'application/json' } }); 142 + if (response.ok) { 143 + const profile = (await response.json()) as MiniDoc; 144 + return { 145 + did: profile.did, 146 + handle: profile.handle, 147 + avatar: profile.avatar 148 + }; 149 + } 150 + } catch { 151 + // fall through to local resolution 152 + } 153 + 154 + try { 155 + const identity = await identityResolver.resolve(identifier as ActorIdentifier); 156 + return { 157 + did: identity.did as Did, 158 + handle: identity.handle 159 + }; 160 + } catch { 161 + return null; 162 + } 163 + }; 164 + 165 + export const createAuth = (initial?: { did: string; handle: string } | null): Auth => { 166 + const seed = initial ?? null; 167 + let agent = $state<OAuthUserAgent | null>(null); 168 + let currentDid = $state<Did | null>((seed?.did as Did | undefined) ?? null); 169 + let profile = $state<AuthProfile | null>( 170 + seed ? { did: seed.did as Did, handle: seed.handle } : null 171 + ); 172 + let error = $state<string | null>(null); 173 + let authenticating = $state(false); 174 + 175 + const hydrateProfile = async (did: Did) => { 176 + const resolved = await resolveProfile(did); 177 + profile = resolved ?? { did, handle: did }; 178 + persistAuth(did, profile.handle); 179 + }; 180 + 181 + const adoptSession = (session: OAuthSession) => { 182 + const nextAgent = new OAuthUserAgent(session); 183 + agent = nextAgent; 184 + const did = nextAgent.sub as Did; 185 + currentDid = did; 186 + if (browser) localStorage.setItem(CURRENT_DID_KEY, did); 187 + void hydrateProfile(did); 188 + }; 189 + 190 + const refresh = async () => { 191 + if (!browser) return; 192 + configure(); 193 + error = null; 194 + 195 + const preferred = readStoredDid() ?? currentDid ?? listStoredSessions()[0] ?? null; 196 + if (!preferred) { 197 + agent = null; 198 + currentDid = null; 199 + profile = null; 200 + clearAuth(); 201 + return; 202 + } 203 + 204 + try { 205 + const session = await getSession(preferred, { allowStale: true }); 206 + adoptSession(session); 207 + } catch (cause) { 208 + deleteStoredSession(preferred); 209 + clearAuth(); 210 + agent = null; 211 + currentDid = null; 212 + profile = null; 213 + error = errorMessage(cause); 214 + } 215 + }; 216 + 217 + const signIn = async (identifier: string, returnTo = '/') => { 218 + if (!browser) return; 219 + configure(); 220 + error = null; 221 + 222 + const trimmed = identifier.trim(); 223 + if (!trimmed) { 224 + error = 'Handle or DID required'; 225 + return; 226 + } 227 + 228 + if (location.hostname === 'localhost') { 229 + const url = new SvelteURL(location.href); 230 + url.hostname = '127.0.0.1'; 231 + url.searchParams.set('identifier', trimmed); 232 + url.searchParams.set('return_url', returnTo); 233 + location.replace(url); 234 + return; 235 + } 236 + 237 + try { 238 + const url = await createAuthorizationUrl({ 239 + target: { 240 + type: 'account', 241 + identifier: trimmed as ActorIdentifier 242 + }, 243 + scope: OAUTH_SCOPE, 244 + state: { returnTo } 245 + }); 246 + 247 + window.location.assign(url.toString()); 248 + } catch (cause) { 249 + error = errorMessage(cause); 250 + throw cause; 251 + } 252 + }; 253 + 254 + const completeSignIn = async () => { 255 + if (!browser) return '/'; 256 + configure(); 257 + error = null; 258 + authenticating = true; 259 + 260 + try { 261 + const params = new SvelteURLSearchParams(location.hash.slice(1)); 262 + history.replaceState(null, '', location.pathname + location.search); 263 + 264 + const { session, state } = await finalizeAuthorization(params); 265 + adoptSession(session); 266 + 267 + return typeof (state as { returnTo?: unknown } | null)?.returnTo === 'string' 268 + ? (state as { returnTo: string }).returnTo 269 + : '/'; 270 + } catch (cause) { 271 + error = errorMessage(cause); 272 + throw cause; 273 + } finally { 274 + authenticating = false; 275 + } 276 + }; 277 + 278 + const signOut = async () => { 279 + error = null; 280 + const did = currentDid; 281 + try { 282 + if (agent) { 283 + await agent.signOut(); 284 + } else if (did) { 285 + deleteStoredSession(did); 286 + } 287 + } catch { 288 + if (did) deleteStoredSession(did); 289 + } finally { 290 + clearAuth(); 291 + agent = null; 292 + currentDid = null; 293 + profile = null; 294 + } 295 + }; 296 + 297 + return { 298 + get agent() { 299 + return agent; 300 + }, 301 + get currentDid() { 302 + return currentDid; 303 + }, 304 + get profile() { 305 + return profile; 306 + }, 307 + get error() { 308 + return error; 309 + }, 310 + get profileLoading() { 311 + return currentDid !== null && profile === null; 312 + }, 313 + get authenticating() { 314 + return authenticating; 315 + }, 316 + get currentUser() { 317 + if (!currentDid) return null; 318 + return { 319 + did: currentDid, 320 + handle: profile?.handle ?? currentDid, 321 + avatar: profile?.avatar 322 + }; 323 + }, 324 + refresh, 325 + signIn, 326 + completeSignIn, 327 + signOut 328 + }; 329 + }; 330 + 331 + export const getAuth = () => getContext<Auth>(AUTH_KEY);
+117
web/src/lib/components/home/MarketingHome.svelte
··· 1 + <script lang="ts"> 2 + import ArrowRight from '$icon/arrow-right'; 3 + 4 + const activityCards = [ 5 + { left: 'created', right: 'new-knot', x: 'left-[8%]', y: 'top-[28%]', width: 'w-48' }, 6 + { left: 'starred', right: 'tiny-compiler', x: 'left-[22%]', y: 'top-[62%]', width: 'w-72' }, 7 + { left: 'opened', right: 'stacked-prs', x: 'left-[48%]', y: 'top-[45%]', width: 'w-80' }, 8 + { left: 'merged', right: 'microvm-ci', x: 'left-[66%]', y: 'top-[20%]', width: 'w-72' }, 9 + { left: 'followed', right: 'self-hosted', x: 'left-[75%]', y: 'top-[58%]', width: 'w-64' } 10 + ]; 11 + 12 + const ticks = Array.from({ length: 160 }, (_, index) => index); 13 + </script> 14 + 15 + {#snippet marketingButton(label: string, showArrow: boolean, className: string)} 16 + <button 17 + class="inline-flex cursor-pointer items-center justify-center gap-2 rounded border border-success-border bg-success px-4 py-2 text-base font-medium text-success-fg hover:bg-success-hover {className}" 18 + type="submit" 19 + > 20 + {label} 21 + {#if showArrow} 22 + <ArrowRight class="size-4" aria-hidden="true" /> 23 + {/if} 24 + </button> 25 + {/snippet} 26 + 27 + {#snippet signupForm( 28 + id: string, 29 + label: string, 30 + showArrow: boolean, 31 + formClass: string, 32 + buttonClass: string 33 + )} 34 + <form class={formClass} method="get" action="/signup"> 35 + <label class="sr-only" for={id}>Email</label> 36 + <input 37 + {id} 38 + type="email" 39 + name="id" 40 + required 41 + placeholder="Enter your email" 42 + class="min-w-0 flex-1 rounded border border-border-strong bg-surface px-3 py-2 text-base text-fg placeholder:text-fg-faint focus:border-fg-subtle focus:outline-none" 43 + /> 44 + {@render marketingButton(label, showArrow, buttonClass)} 45 + </form> 46 + {/snippet} 47 + 48 + <section class="overflow-hidden px-6 pb-24 pt-28 md:pb-32 md:pt-36"> 49 + <div class="mx-auto grid max-w-screen-xl grid-cols-1 items-center gap-14 md:grid-cols-2"> 50 + <h1 51 + class="text-6xl font-bold leading-[0.98] tracking-[-0.05em] text-fg-strong md:text-7xl lg:text-8xl" 52 + > 53 + tightly-knit<br />social coding. 54 + </h1> 55 + 56 + <div class="max-w-2xl space-y-6 text-xl leading-8 text-fg"> 57 + <p>The next-generation social coding platform.</p> 58 + <p> 59 + We envision a place where developers have ownership of their code, communities can freely 60 + self-govern and most importantly, coding can be social and fun again. 61 + </p> 62 + {@render signupForm('hero-email', 'Join now', true, 'flex max-w-lg gap-2', '')} 63 + </div> 64 + </div> 65 + 66 + <div class="relative mx-auto mt-28 hidden h-72 max-w-screen-xl md:block" aria-hidden="true"> 67 + <div class="absolute inset-x-0 bottom-10 flex items-end gap-[5px] opacity-35"> 68 + {#each ticks as tick (tick)} 69 + <span class="h-4 w-px bg-border-strong" class:h-7={tick % 24 === 0}></span> 70 + {/each} 71 + </div> 72 + <div class="absolute inset-x-0 bottom-14 h-px bg-border"></div> 73 + {#each activityCards as card, index (card.right)} 74 + <div 75 + class={`activity-card absolute ${card.x} ${card.y} ${card.width} overflow-hidden rounded border border-border-strong bg-surface/95 text-sm text-fg-muted shadow-2xl`} 76 + > 77 + <div class="flex items-center gap-2 border-l border-border-strong px-4 py-3"> 78 + <span class="size-5 rounded-full bg-orange-300/90"></span> 79 + <span class="text-fg-subtle">{card.left}</span> 80 + <span class="font-medium text-fg">{card.right}</span> 81 + </div> 82 + <div class="mx-auto h-20 w-px bg-border" class:hidden={index === 0}></div> 83 + </div> 84 + {/each} 85 + </div> 86 + </section> 87 + 88 + <section class="px-6 py-28 md:py-40"> 89 + <div class="mx-auto flex max-w-3xl flex-col items-center text-center"> 90 + <h2 class="text-5xl font-bold tracking-[-0.04em] text-fg-strong md:text-6xl"> 91 + Stay in the loop 92 + </h2> 93 + <p class="mt-6 max-w-2xl text-xl leading-8 text-fg-muted"> 94 + We've got a newsletter. Punch in your email to stay updated on what we're shipping at Tangled. 95 + </p> 96 + {@render signupForm( 97 + 'newsletter-email', 98 + 'Subscribe', 99 + false, 100 + 'mt-8 flex w-full max-w-lg rounded border border-border-strong bg-surface p-2', 101 + 'ml-2' 102 + )} 103 + </div> 104 + </section> 105 + 106 + <style> 107 + .activity-card { 108 + --marketing-card-shadow: rgb(229 231 235 / 0.6); 109 + --tw-shadow-color: var(--marketing-card-shadow); 110 + } 111 + 112 + @media (prefers-color-scheme: dark) { 113 + .activity-card { 114 + --marketing-card-shadow: rgb(3 7 18 / 0.3); 115 + } 116 + } 117 + </style>
+445
web/src/lib/components/shell/Footer.svelte
··· 1 + <script lang="ts"> 2 + import { resolve } from '$app/paths'; 3 + import LogotypeSmall from '../ui/LogotypeSmall.svelte'; 4 + 5 + interface Props { 6 + variant?: 'full' | 'minimal'; 7 + } 8 + 9 + type FooterIcon = 10 + | 'terms' 11 + | 'privacy' 12 + | 'blog' 13 + | 'docs' 14 + | 'source' 15 + | 'brand' 16 + | 'discord' 17 + | 'irc' 18 + | 'bluesky' 19 + | 'twitter' 20 + | 'email' 21 + | 'security'; 22 + type FooterLayout = 'desktop' | 'mobile' | 'minimal'; 23 + 24 + interface FooterLinkAttributes { 25 + target?: '_blank'; 26 + } 27 + 28 + interface FooterLink { 29 + label: string; 30 + href: string; 31 + icon: FooterIcon; 32 + internal?: true; 33 + minimalLabel?: string; 34 + minimalOrder?: number; 35 + attributes?: FooterLinkAttributes; 36 + desktopAttributes?: FooterLinkAttributes; 37 + } 38 + 39 + interface FooterSection { 40 + title: string; 41 + links: FooterLink[]; 42 + } 43 + 44 + let { variant = 'full' }: Props = $props(); 45 + 46 + const appPath = (path: string) => resolve(path as '/'); 47 + const headerStyle = 'text-fg font-bold text-sm tracking-wide mb-1'; 48 + const mobileHeaderStyle = 'text-fg font-bold text-xs tracking-wide mb-1'; 49 + const linkStyle = 'inline-flex items-center gap-1 text-fg-subtle hover:text-fg hover:underline'; 50 + const minimalLinkStyle = 'text-fg-subtle hover:text-fg hover:underline'; 51 + const externalLinkAttributes = { target: '_blank' } as const; 52 + 53 + const footerSections: FooterSection[] = [ 54 + { 55 + title: 'Legal', 56 + links: [ 57 + { 58 + label: 'Terms of service', 59 + minimalLabel: 'Terms', 60 + href: '/terms', 61 + internal: true, 62 + icon: 'terms', 63 + minimalOrder: 8 64 + }, 65 + { 66 + label: 'Privacy policy', 67 + minimalLabel: 'Privacy', 68 + href: '/privacy', 69 + internal: true, 70 + icon: 'privacy', 71 + minimalOrder: 9 72 + } 73 + ] 74 + }, 75 + { 76 + title: 'Resources', 77 + links: [ 78 + { 79 + label: 'Blog', 80 + href: 'https://blog.tangled.org', 81 + icon: 'blog', 82 + minimalOrder: 1, 83 + desktopAttributes: externalLinkAttributes 84 + }, 85 + { 86 + label: 'Docs', 87 + href: 'https://docs.tangled.org', 88 + icon: 'docs', 89 + minimalOrder: 2 90 + }, 91 + { 92 + label: 'Source', 93 + href: 'https://tangled.org/@tangled.org/core', 94 + icon: 'source', 95 + minimalOrder: 3 96 + }, 97 + { 98 + label: 'Brand', 99 + href: 'https://tangled.org/brand', 100 + icon: 'brand', 101 + minimalOrder: 4 102 + } 103 + ] 104 + }, 105 + { 106 + title: 'Social', 107 + links: [ 108 + { 109 + label: 'Discord', 110 + href: 'https://chat.tangled.org', 111 + icon: 'discord', 112 + minimalOrder: 5, 113 + attributes: externalLinkAttributes 114 + }, 115 + { 116 + label: 'IRC', 117 + href: 'https://web.libera.chat/#tangled', 118 + icon: 'irc', 119 + attributes: externalLinkAttributes 120 + }, 121 + { 122 + label: 'Bluesky', 123 + href: 'https://bsky.app/profile/tangled.org', 124 + icon: 'bluesky', 125 + minimalOrder: 6, 126 + attributes: externalLinkAttributes 127 + }, 128 + { 129 + label: 'Twitter (X)', 130 + href: 'https://x.com/tangled_org', 131 + icon: 'twitter', 132 + minimalOrder: 7, 133 + attributes: externalLinkAttributes 134 + } 135 + ] 136 + }, 137 + { 138 + title: 'Contact', 139 + links: [ 140 + { 141 + label: 'team@tangled.org', 142 + href: 'mailto:team@tangled.org', 143 + icon: 'email' 144 + }, 145 + { 146 + label: 'security@tangled.org', 147 + href: 'mailto:security@tangled.org', 148 + icon: 'security' 149 + } 150 + ] 151 + } 152 + ]; 153 + 154 + const minimalFooterLinks = footerSections 155 + .flatMap((section) => section.links) 156 + .filter((link) => typeof link.minimalOrder === 'number') 157 + .sort((a, b) => (a.minimalOrder ?? 0) - (b.minimalOrder ?? 0)); 158 + 159 + const linkAttributes = (link: FooterLink, layout: FooterLayout) => 160 + layout === 'desktop' ? (link.desktopAttributes ?? link.attributes) : link.attributes; 161 + const linkTarget = (link: FooterLink, layout: FooterLayout) => 162 + linkAttributes(link, layout)?.target; 163 + </script> 164 + 165 + {#snippet footerIcon(icon: FooterIcon)} 166 + {#if icon === 'terms'} 167 + <svg 168 + class="size-4 shrink-0" 169 + viewBox="0 0 24 24" 170 + fill="none" 171 + stroke="currentColor" 172 + stroke-width="2" 173 + stroke-linecap="round" 174 + stroke-linejoin="round" 175 + > 176 + <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" /> 177 + <path d="M14 2v4a2 2 0 0 0 2 2h4" /> 178 + <path d="M10 9H8" /> 179 + <path d="M16 13H8" /> 180 + <path d="M16 17H8" /> 181 + </svg> 182 + {:else if icon === 'privacy'} 183 + <svg 184 + class="size-4 shrink-0" 185 + viewBox="0 0 24 24" 186 + fill="none" 187 + stroke="currentColor" 188 + stroke-width="2" 189 + stroke-linecap="round" 190 + stroke-linejoin="round" 191 + > 192 + <path 193 + d="M20 13c0 5-3.5 7.5-7.66 9.7a1 1 0 0 1-.68 0C7.5 20.5 4 18 4 13V6a1 1 0 0 1 .76-.97l8-2a1 1 0 0 1 .48 0l8 2c.47.12.76.54.76.97Z" 194 + /> 195 + </svg> 196 + {:else if icon === 'blog'} 197 + <svg 198 + class="size-4 shrink-0" 199 + viewBox="0 0 24 24" 200 + fill="none" 201 + stroke="currentColor" 202 + stroke-width="2" 203 + stroke-linecap="round" 204 + stroke-linejoin="round" 205 + > 206 + <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" /> 207 + <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" /> 208 + </svg> 209 + {:else if icon === 'docs'} 210 + <svg 211 + class="size-4 shrink-0" 212 + viewBox="0 0 24 24" 213 + fill="none" 214 + stroke="currentColor" 215 + stroke-width="2" 216 + stroke-linecap="round" 217 + stroke-linejoin="round" 218 + > 219 + <path 220 + d="M4 19.5V15a2 2 0 0 1 2-2h2M20 19.5V5a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2z" 221 + /> 222 + </svg> 223 + {:else if icon === 'source'} 224 + <svg 225 + class="size-4 shrink-0" 226 + viewBox="0 0 24 24" 227 + fill="none" 228 + stroke="currentColor" 229 + stroke-width="2" 230 + stroke-linecap="round" 231 + stroke-linejoin="round" 232 + > 233 + <polyline points="16 18 22 12 16 6" /> 234 + <polyline points="8 6 2 12 8 18" /> 235 + </svg> 236 + {:else if icon === 'brand'} 237 + <svg 238 + class="size-4 shrink-0" 239 + viewBox="0 0 24 24" 240 + fill="none" 241 + stroke="currentColor" 242 + stroke-width="2" 243 + stroke-linecap="round" 244 + stroke-linejoin="round" 245 + > 246 + <path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z" /> 247 + <path 248 + d="M7.5 10.5c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5z" 249 + /> 250 + <path 251 + d="M11.5 7.5c.828 0 1.5-.672 1.5-1.5S12.328 4.5 11.5 4.5 10 5.172 10 6s.672 1.5 1.5 1.5z" 252 + /> 253 + <path 254 + d="M16.5 9.5c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5z" 255 + /> 256 + <path d="M6 14c0-2 2-3 4-3 2.5 0 4.5 1.5 4.5 3.5S12.5 18 10 18c-2.5 0-4-2-4-4z" /> 257 + </svg> 258 + {:else if icon === 'discord'} 259 + <svg 260 + class="size-4 shrink-0" 261 + viewBox="0 0 24 24" 262 + fill="none" 263 + stroke="currentColor" 264 + stroke-width="2" 265 + stroke-linecap="round" 266 + stroke-linejoin="round" 267 + > 268 + <path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z" /> 269 + </svg> 270 + {:else if icon === 'irc'} 271 + <svg 272 + class="size-4 shrink-0" 273 + viewBox="0 0 24 24" 274 + fill="none" 275 + stroke="currentColor" 276 + stroke-width="2" 277 + stroke-linecap="round" 278 + stroke-linejoin="round" 279 + > 280 + <line x1="4" y1="9" x2="20" y2="9" /> 281 + <line x1="4" y1="15" x2="20" y2="15" /> 282 + <line x1="10" y1="3" x2="8" y2="21" /> 283 + <line x1="16" y1="3" x2="14" y2="21" /> 284 + </svg> 285 + {:else if icon === 'bluesky'} 286 + <svg 287 + class="size-4 shrink-0" 288 + viewBox="0 0 24 24" 289 + fill="none" 290 + stroke-dasharray="none" 291 + stroke-width="2" 292 + stroke-linecap="round" 293 + stroke-linejoin="round" 294 + > 295 + <path d="M12 21a9 9 0 0 0 9-9 9 9 0 0 0-9-9 9 9 0 0 0-9 9 9 9 0 0 0 9 9Z" /> 296 + <path d="M12 12c2-3 5-3 5 0s-3 3-5 0Zm0 0c-2-3-5-3-5 0s3 3 5 0Z" /> 297 + </svg> 298 + {:else if icon === 'twitter'} 299 + <svg class="size-4 shrink-0" viewBox="0 0 24 24" fill="currentColor"> 300 + <path 301 + d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" 302 + /> 303 + </svg> 304 + {:else if icon === 'email'} 305 + <svg 306 + class="size-4 shrink-0" 307 + viewBox="0 0 24 24" 308 + fill="none" 309 + stroke="currentColor" 310 + stroke-width="2" 311 + stroke-linecap="round" 312 + stroke-linejoin="round" 313 + > 314 + <rect width="20" height="16" x="2" y="4" rx="2" /> 315 + <path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" /> 316 + </svg> 317 + {:else if icon === 'security'} 318 + <svg 319 + class="size-4 shrink-0" 320 + viewBox="0 0 24 24" 321 + fill="none" 322 + stroke="currentColor" 323 + stroke-width="2" 324 + stroke-linecap="round" 325 + stroke-linejoin="round" 326 + > 327 + <path 328 + d="M20 13c0 5-3.5 7.5-7.66 9.7a1 1 0 0 1-.68 0C7.5 20.5 4 18 4 13V6a1 1 0 0 1 .76-.97l8-2a1 1 0 0 1 .48 0l8 2c.47.12.76.54.76.97Z" 329 + /> 330 + <path d="m9 12 2 2 4-4" /> 331 + </svg> 332 + {/if} 333 + {/snippet} 334 + 335 + {#if variant === 'minimal'} 336 + <footer 337 + class="w-full border-t border-border-subtle bg-surface px-6 py-4 pb-[calc(env(safe-area-inset-bottom)+1rem)]" 338 + > 339 + <div 340 + class="mx-auto flex max-w-screen-lg flex-wrap items-center justify-center gap-x-4 gap-y-2 text-sm text-fg-subtle" 341 + > 342 + <div 343 + class="order-last flex w-full items-center justify-center gap-x-2 sm:order-first sm:w-auto" 344 + > 345 + <a href={resolve('/')} class="flex items-center no-underline hover:no-underline"> 346 + <img src="/logos/dolly.svg" alt="tangled" class="size-5 opacity-70" /> 347 + </a> 348 + <span>&copy; 2026 Tangled Labs Oy.</span> 349 + </div> 350 + {#each minimalFooterLinks as link (link.href)} 351 + {#if link.internal} 352 + <a href={appPath(link.href)} class={minimalLinkStyle}>{link.minimalLabel ?? link.label}</a 353 + > 354 + {:else} 355 + <a 356 + href={link.href} 357 + class={minimalLinkStyle} 358 + target={linkTarget(link, 'minimal')} 359 + rel="external noopener noreferrer">{link.minimalLabel ?? link.label}</a 360 + > 361 + {/if} 362 + {/each} 363 + </div> 364 + </footer> 365 + {:else} 366 + <footer class="z-10 pb-[env(safe-area-inset-bottom)] select-none"> 367 + <div class="w-full bg-surface p-8"> 368 + <div class="mx-auto px-4"> 369 + <div class="flex flex-col gap-8 text-fg-subtle"> 370 + <div 371 + class="hidden lg:grid lg:grid-cols-[1fr_minmax(0,1024px)_1fr] lg:items-start lg:gap-8" 372 + > 373 + <div> 374 + <a href={resolve('/')} class="flex gap-2 no-underline hover:no-underline"> 375 + <LogotypeSmall /> 376 + </a> 377 + </div> 378 + 379 + <div class="grid grid-cols-4 gap-2"> 380 + {#each footerSections as section (section.title)} 381 + <div class="flex flex-col gap-1"> 382 + <div class={headerStyle}>{section.title}</div> 383 + {#each section.links as link (link.href)} 384 + {#if link.internal} 385 + <a href={appPath(link.href)} class={linkStyle}> 386 + {@render footerIcon(link.icon)} 387 + <span>{link.label}</span> 388 + </a> 389 + {:else} 390 + <a 391 + href={link.href} 392 + class={linkStyle} 393 + target={linkTarget(link, 'desktop')} 394 + rel="external noopener noreferrer" 395 + > 396 + {@render footerIcon(link.icon)} 397 + <span>{link.label}</span> 398 + </a> 399 + {/if} 400 + {/each} 401 + </div> 402 + {/each} 403 + </div> 404 + 405 + <div class="text-right"> 406 + <div class="text-xs">&copy; 2026 Tangled Labs Oy. All rights reserved.</div> 407 + </div> 408 + </div> 409 + 410 + <div class="flex flex-col gap-8 lg:hidden"> 411 + <div class="mb-4 md:mb-0"> 412 + <a href={resolve('/')} class="flex gap-2 no-underline hover:no-underline"> 413 + <LogotypeSmall /> 414 + </a> 415 + </div> 416 + 417 + <div class="grid grid-cols-1 gap-6 sm:grid-cols-2 md:grid-cols-4 md:gap-2"> 418 + {#each footerSections as section (section.title)} 419 + <div class="flex flex-col gap-1"> 420 + <div class={mobileHeaderStyle}>{section.title}</div> 421 + {#each section.links as link (link.href)} 422 + {#if link.internal} 423 + <a href={appPath(link.href)} class={linkStyle}>{link.label}</a> 424 + {:else} 425 + <a 426 + href={link.href} 427 + class={linkStyle} 428 + target={linkTarget(link, 'mobile')} 429 + rel="external noopener noreferrer">{link.label}</a 430 + > 431 + {/if} 432 + {/each} 433 + </div> 434 + {/each} 435 + </div> 436 + 437 + <div class="text-center"> 438 + <div class="text-xs">&copy; 2026 Tangled Labs Oy. All rights reserved.</div> 439 + </div> 440 + </div> 441 + </div> 442 + </div> 443 + </div> 444 + </footer> 445 + {/if}
+155
web/src/lib/components/shell/Topbar.svelte
··· 1 + <script lang="ts"> 2 + import { resolve } from '$app/paths'; 3 + import Button from '../ui/Button.svelte'; 4 + import Dropdown from '../ui/Dropdown.svelte'; 5 + import DropdownItem from '../ui/DropdownItem.svelte'; 6 + import ArrowRight from '$icon/arrow-right'; 7 + import Bell from '$icon/bell'; 8 + import BookMarked from '$icon/book-marked'; 9 + import BookPlus from '$icon/book-plus'; 10 + import Cog from '$icon/cog'; 11 + import LineSquiggle from '$icon/line-squiggle'; 12 + import LogOut from '$icon/log-out'; 13 + import Plus from '$icon/plus'; 14 + import Search from '$icon/search'; 15 + import User from '$icon/user'; 16 + import UserRound from '$icon/user-round'; 17 + import Spinner from '../ui/Spinner.svelte'; 18 + import LogotypeSmall from '../ui/LogotypeSmall.svelte'; 19 + import TopbarSearch from './TopbarSearch.svelte'; 20 + 21 + interface User { 22 + handle: string; 23 + did: string; 24 + avatar?: string; 25 + } 26 + 27 + interface Props { 28 + variant: 'marketing' | 'app'; 29 + onSignOut?: () => void | Promise<void>; 30 + user: User | null; 31 + loading?: boolean; 32 + } 33 + 34 + let { variant, onSignOut, user, loading = false }: Props = $props(); 35 + 36 + const appPath = (path: string) => resolve(path as '/'); 37 + const navClass = $derived( 38 + variant === 'marketing' 39 + ? 'mx-auto w-full max-w-screen-xl space-x-4 px-4 py-2 sm:px-6' 40 + : 'mx-auto w-full space-x-4 px-6 py-2' 41 + ); 42 + </script> 43 + 44 + <nav class={navClass} aria-label="main"> 45 + <div class="flex items-center justify-between gap-4 p-0"> 46 + <div class="flex shrink-0 items-center gap-2"> 47 + <a 48 + href={resolve('/')} 49 + class="flex shrink-0 items-center gap-2 no-underline hover:no-underline" 50 + > 51 + <span class="hidden sm:inline-flex"> 52 + <LogotypeSmall /> 53 + </span> 54 + <span class="inline-flex sm:hidden"> 55 + <img src="/logos/dolly.svg" alt="tangled" class="size-8" /> 56 + </span> 57 + </a> 58 + </div> 59 + 60 + <div class="flex items-center gap-4"> 61 + {#if variant === 'marketing'} 62 + <a href={appPath('/login')} class="text-fg transition-colors hover:text-fg-muted"> 63 + Login 64 + </a> 65 + <span class="text-fg-subtle">or</span> 66 + <Button variant="success" size="sm" href="/signup" class="!py-0"> 67 + <span>Join now</span> 68 + <ArrowRight class="size-4" aria-hidden="true" /> 69 + </Button> 70 + {:else} 71 + {#if user || loading} 72 + <div class="order-3 flex items-center md:order-1"> 73 + <TopbarSearch /> 74 + </div> 75 + 76 + <div class="order-1 flex items-center md:order-3"> 77 + <Dropdown id="new-menu" group="topbar" variant="button"> 78 + {#snippet trigger()} 79 + <Plus class="size-4" aria-hidden="true" /> 80 + <span class="hidden md:inline">New</span> 81 + {/snippet} 82 + <DropdownItem href="/repo/new" icon={BookPlus}>New repository</DropdownItem> 83 + <DropdownItem href="/strings/new" icon={LineSquiggle}>New string</DropdownItem> 84 + </Dropdown> 85 + </div> 86 + 87 + <div class="order-2 flex items-center md:order-4"> 88 + <a 89 + href={appPath('/notifications')} 90 + class="flex items-center text-fg-subtle transition-colors hover:text-fg" 91 + aria-label="Notifications" 92 + > 93 + <Bell class="size-5" aria-hidden="true" /> 94 + </a> 95 + </div> 96 + 97 + <div class="order-3 md:hidden"> 98 + <a href={appPath('/search')} class="text-fg-subtle" aria-label="Search"> 99 + <Search class="size-5" aria-hidden="true" /> 100 + </a> 101 + </div> 102 + 103 + <div class="hidden h-6 w-px self-center bg-border md:order-2 md:block"></div> 104 + {/if} 105 + 106 + <div class="order-4 flex items-center md:order-5"> 107 + {#if loading} 108 + <div class="flex items-center gap-1" role="status" aria-label="Signing in"> 109 + <span 110 + class="flex size-8 items-center justify-center rounded-full border border-border bg-surface-muted text-fg-faint md:size-6" 111 + > 112 + <Spinner class="size-4" /> 113 + </span> 114 + <span class="hidden h-4 w-24 rounded bg-surface-muted md:block" aria-hidden="true" 115 + ></span> 116 + </div> 117 + {:else if user} 118 + <Dropdown id="profile-menu" group="topbar"> 119 + {#snippet trigger()} 120 + {#if user.avatar} 121 + <img 122 + src={user.avatar} 123 + alt={user.handle} 124 + class="size-8 rounded-full border border-border object-cover md:size-6" 125 + /> 126 + {:else} 127 + <span 128 + class="flex size-8 items-center justify-center rounded-full border border-border bg-surface-muted md:size-6" 129 + > 130 + <UserRound class="size-5 text-fg-faint md:size-4" aria-hidden="true" /> 131 + </span> 132 + {/if} 133 + <span class="hidden max-w-48 truncate md:inline">{user.handle}</span> 134 + {/snippet} 135 + <DropdownItem href={`/${user.handle}`} icon={User}>Profile</DropdownItem> 136 + <DropdownItem href={`/${user.handle}?tab=repos`} icon={BookMarked}> 137 + Repositories 138 + </DropdownItem> 139 + <DropdownItem href={`/${user.handle}?tab=strings`} icon={LineSquiggle}> 140 + Strings 141 + </DropdownItem> 142 + <DropdownItem href="/settings" icon={Cog}>Settings</DropdownItem> 143 + <DropdownItem danger icon={LogOut} onclick={onSignOut}>Logout</DropdownItem> 144 + </Dropdown> 145 + {:else} 146 + <div class="flex items-center gap-2" aria-hidden="true"> 147 + <span class="size-8 rounded-full bg-surface-muted md:size-6"></span> 148 + <span class="hidden h-4 w-24 rounded bg-surface-muted md:block"></span> 149 + </div> 150 + {/if} 151 + </div> 152 + {/if} 153 + </div> 154 + </div> 155 + </nav>
+105
web/src/lib/components/shell/TopbarSearch.svelte
··· 1 + <script lang="ts"> 2 + import { resolve } from '$app/paths'; 3 + import Search from '$icon/search'; 4 + 5 + interface Props { 6 + class?: string; 7 + } 8 + 9 + let { class: className = '' }: Props = $props(); 10 + 11 + const appPath = (path: string) => resolve(path as '/'); 12 + </script> 13 + 14 + <form action={appPath('/search')} method="GET" class={`relative hidden md:block ${className}`}> 15 + <label class="sr-only" for="topbar-search">Search</label> 16 + <div class="search-box"> 17 + <Search class="size-4 shrink-0 text-fg-faint" aria-hidden="true" /> 18 + <input id="topbar-search" name="q" type="search" placeholder="Search..." class="search-input" /> 19 + <kbd class="search-kbd">Ctrl+K</kbd> 20 + </div> 21 + </form> 22 + 23 + <style> 24 + .search-box { 25 + --topbar-search-surface: #ffffff; 26 + --topbar-search-fg: #1f2937; 27 + --topbar-search-placeholder: #9ca3af; 28 + --topbar-search-kbd-fg: #9ca3af; 29 + --topbar-search-kbd-border: #e5e7eb; 30 + position: relative; 31 + display: flex; 32 + max-height: 30px; 33 + width: 20rem; 34 + align-items: center; 35 + gap: 0.5rem; 36 + border: 1px solid var(--color-border); 37 + border-radius: 0.25rem; 38 + background: var(--topbar-search-surface); 39 + padding: 1rem 0.375rem 1rem 0.5rem; 40 + } 41 + 42 + @media (prefers-color-scheme: dark) { 43 + .search-box { 44 + --topbar-search-surface: #111827; 45 + --topbar-search-fg: #e5e7eb; 46 + --topbar-search-placeholder: #4b5563; 47 + --topbar-search-kbd-fg: #6b7280; 48 + --topbar-search-kbd-border: #4b5563; 49 + } 50 + } 51 + 52 + @media (min-width: 1024px) { 53 + .search-box { 54 + width: 24rem; 55 + } 56 + } 57 + 58 + .search-box:focus-within { 59 + z-index: 51; 60 + outline: 2px solid var(--color-ring); 61 + outline-offset: 1px; 62 + } 63 + 64 + .search-input { 65 + min-width: 0; 66 + flex: 1; 67 + border: 0; 68 + border-radius: 0; 69 + background: transparent; 70 + padding: 0; 71 + color: var(--topbar-search-fg); 72 + font-size: 0.875rem; 73 + line-height: 1.25rem; 74 + outline: none; 75 + } 76 + 77 + .search-input:focus { 78 + box-shadow: none; 79 + outline: none; 80 + } 81 + 82 + .search-input::placeholder { 83 + color: var(--topbar-search-placeholder); 84 + } 85 + 86 + .search-kbd { 87 + display: flex; 88 + align-items: center; 89 + border: 1px solid var(--topbar-search-kbd-border); 90 + border-bottom-width: 2px; 91 + border-radius: 0.25rem; 92 + padding: 0 0.25rem; 93 + font-family: var(--font-sans); 94 + color: var(--topbar-search-kbd-fg); 95 + font-size: 0.75rem; 96 + line-height: 1.25rem; 97 + pointer-events: none; 98 + } 99 + 100 + .search-input:focus + .search-kbd, 101 + .search-box:focus-within .search-kbd, 102 + .search-input:not(:placeholder-shown) + .search-kbd { 103 + display: none; 104 + } 105 + </style>
+222
web/src/lib/components/ui/Button.svelte
··· 1 + <script lang="ts"> 2 + import { resolve } from '$app/paths'; 3 + import type { Snippet } from 'svelte'; 4 + import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements'; 5 + import Spinner from './Spinner.svelte'; 6 + 7 + interface Props extends Omit<HTMLAnchorAttributes & HTMLButtonAttributes, 'class' | 'children'> { 8 + variant?: 'default' | 'primary' | 'ghost' | 'danger' | 'success'; 9 + size?: 'sm' | 'md' | 'lg'; 10 + href?: string; 11 + type?: 'button' | 'submit' | 'reset'; 12 + disabled?: boolean; 13 + class?: string; 14 + loading?: boolean; 15 + spinnerClass?: string; 16 + children?: Snippet; 17 + } 18 + 19 + let { 20 + variant = 'default', 21 + size = 'md', 22 + href, 23 + type = 'button', 24 + disabled = false, 25 + class: className = '', 26 + loading = false, 27 + spinnerClass, 28 + children, 29 + ...rest 30 + }: Props = $props(); 31 + 32 + const raised = $derived(variant !== 'ghost'); 33 + const accentRaised = $derived(variant !== 'default' && variant !== 'ghost'); 34 + const spinnerSize = $derived(spinnerClass ?? (size === 'lg' ? 'size-5' : 'size-4')); 35 + </script> 36 + 37 + {#if href} 38 + <a 39 + href={resolve(href as '/')} 40 + class="btn {className}" 41 + data-variant={variant} 42 + data-size={size} 43 + class:raised 44 + class:accentRaised 45 + aria-disabled={disabled || loading ? 'true' : undefined} 46 + tabindex={disabled ? -1 : undefined} 47 + {...rest} 48 + > 49 + {#if loading} 50 + <Spinner class={spinnerSize} /> 51 + {:else if children} 52 + {@render children()} 53 + {/if} 54 + </a> 55 + {:else} 56 + <button 57 + {type} 58 + disabled={disabled || loading} 59 + class="btn {className}" 60 + data-variant={variant} 61 + data-size={size} 62 + class:raised 63 + class:accentRaised 64 + aria-busy={loading} 65 + {...rest} 66 + > 67 + {#if loading} 68 + <Spinner class={spinnerSize} /> 69 + {:else if children} 70 + {@render children()} 71 + {/if} 72 + </button> 73 + {/if} 74 + 75 + <style> 76 + .btn { 77 + display: inline-flex; 78 + cursor: pointer; 79 + align-items: center; 80 + justify-content: center; 81 + overflow: hidden; 82 + border-radius: 0.25rem; 83 + text-decoration: none; 84 + transition: 85 + background-color 150ms cubic-bezier(0.4, 0, 0.2, 1), 86 + border-color 150ms cubic-bezier(0.4, 0, 0.2, 1), 87 + color 150ms cubic-bezier(0.4, 0, 0.2, 1); 88 + user-select: none; 89 + } 90 + 91 + .btn:hover { 92 + text-decoration: none; 93 + } 94 + 95 + .btn:focus-visible { 96 + outline: 2px solid var(--color-ring); 97 + outline-offset: 2px; 98 + } 99 + 100 + .btn:disabled { 101 + pointer-events: none; 102 + opacity: 0.5; 103 + } 104 + 105 + .btn[data-variant='default'] { 106 + background-color: var(--color-surface); 107 + border: 1px solid var(--color-border); 108 + color: var(--color-fg); 109 + } 110 + .btn[data-variant='default']:hover { 111 + background-color: var(--color-surface-hover); 112 + } 113 + .btn[data-variant='default']:focus-visible { 114 + outline-color: var(--color-ring); 115 + } 116 + 117 + .btn[data-variant='primary'] { 118 + background-color: var(--color-primary); 119 + border: 1px solid var(--color-primary-border); 120 + color: var(--color-primary-fg); 121 + } 122 + .btn[data-variant='primary']:hover { 123 + background-color: var(--color-primary-hover); 124 + } 125 + .btn[data-variant='primary']:focus-visible { 126 + outline-color: var(--color-primary); 127 + } 128 + 129 + .btn[data-variant='ghost'] { 130 + color: var(--color-fg-muted); 131 + background-color: transparent; 132 + } 133 + .btn[data-variant='ghost']:hover { 134 + background-color: var(--color-surface-muted); 135 + } 136 + .btn[data-variant='ghost']:focus-visible { 137 + outline-color: var(--color-ring); 138 + } 139 + 140 + .btn[data-variant='danger'] { 141 + background-color: var(--color-danger); 142 + border: 1px solid var(--color-danger-border); 143 + color: var(--color-danger-fg); 144 + } 145 + .btn[data-variant='danger']:hover { 146 + background-color: var(--color-danger-hover); 147 + } 148 + .btn[data-variant='danger']:focus-visible { 149 + outline-color: var(--color-danger); 150 + } 151 + 152 + .btn[data-variant='success'] { 153 + background-color: var(--color-success); 154 + border: 1px solid var(--color-success-border); 155 + color: var(--color-success-fg); 156 + } 157 + .btn[data-variant='success']:hover { 158 + background-color: var(--color-success-hover); 159 + } 160 + .btn[data-variant='success']:focus-visible { 161 + outline-color: var(--color-success); 162 + } 163 + 164 + .btn[data-size='sm'] { 165 + min-height: 2rem; 166 + padding: 0.375rem 0.5rem; 167 + font-size: 0.875rem; 168 + gap: 0.375rem; 169 + } 170 + .btn[data-size='md'] { 171 + min-height: 2.25rem; 172 + padding: 0.5rem 1rem; 173 + font-size: 0.875rem; 174 + gap: 0.5rem; 175 + } 176 + .btn[data-size='lg'] { 177 + min-height: 2.5rem; 178 + padding: 0.5rem 1.5rem; 179 + font-size: 1rem; 180 + gap: 0.625rem; 181 + } 182 + 183 + .raised { 184 + position: relative; 185 + z-index: 0; 186 + } 187 + 188 + .raised::before { 189 + content: ''; 190 + position: absolute; 191 + inset: 0; 192 + z-index: -10; 193 + border-radius: inherit; 194 + box-shadow: inset 0 -2px 0 0 var(--color-raised-depth); 195 + transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); 196 + } 197 + 198 + .raised:hover::before { 199 + box-shadow: inset 0 -2px 0 0 var(--color-raised-depth-hover); 200 + } 201 + 202 + .raised:active { 203 + transform: translateY(0.125rem); 204 + } 205 + 206 + .raised:active::before { 207 + box-shadow: inset 0 2px 2px 0 var(--color-raised-depth); 208 + } 209 + 210 + .accentRaised::before, 211 + .accentRaised:hover::before { 212 + box-shadow: inset 0 -2px 0 0 var(--color-raised-accent-depth); 213 + } 214 + 215 + .accentRaised:active::before { 216 + box-shadow: inset 0 2px 2px 0 var(--color-raised-accent-depth-active); 217 + } 218 + 219 + .raised:disabled:active { 220 + transform: none; 221 + } 222 + </style>
+143
web/src/lib/components/ui/Dropdown.svelte
··· 1 + <script module lang="ts"> 2 + import { SvelteMap, SvelteSet } from 'svelte/reactivity'; 3 + 4 + // global registry so opening one dropdown in a group closes its siblings 5 + const groups = new SvelteMap<string, SvelteSet<() => void>>(); 6 + 7 + function registerDropdown(group: string | undefined, close: () => void) { 8 + if (!group) return () => {}; 9 + let set = groups.get(group); 10 + if (!set) { 11 + set = new SvelteSet(); 12 + groups.set(group, set); 13 + } 14 + set.add(close); 15 + return () => { 16 + set.delete(close); 17 + }; 18 + } 19 + 20 + function closeGroupExcept(group: string | undefined, keep: () => void) { 21 + if (!group) return; 22 + groups.get(group)?.forEach((close) => { 23 + if (close !== keep) close(); 24 + }); 25 + } 26 + </script> 27 + 28 + <script lang="ts"> 29 + import type { Snippet } from 'svelte'; 30 + import { onMount, setContext } from 'svelte'; 31 + import Button from './Button.svelte'; 32 + 33 + interface Props { 34 + id?: string; 35 + group?: string; 36 + variant?: 'plain' | 'button'; 37 + label?: string; 38 + trigger: Snippet; 39 + children: Snippet; 40 + } 41 + 42 + let { id, group, variant = 'plain', label, trigger, children }: Props = $props(); 43 + 44 + let open = $state(false); 45 + let root = $state<HTMLElement>(); 46 + 47 + const close = () => { 48 + open = false; 49 + }; 50 + 51 + const toggle = () => { 52 + open = !open; 53 + if (open) closeGroupExcept(group, close); 54 + }; 55 + 56 + setContext('dropdown-close', close); 57 + 58 + onMount(() => { 59 + const unregister = registerDropdown(group, close); 60 + 61 + const onDocumentClick = (event: MouseEvent) => { 62 + if (open && event.target instanceof Node && root && !root.contains(event.target)) close(); 63 + }; 64 + const onKeydown = (event: KeyboardEvent) => { 65 + if (event.key === 'Escape') close(); 66 + }; 67 + 68 + document.addEventListener('click', onDocumentClick); 69 + document.addEventListener('keydown', onKeydown); 70 + 71 + return () => { 72 + unregister(); 73 + document.removeEventListener('click', onDocumentClick); 74 + document.removeEventListener('keydown', onKeydown); 75 + }; 76 + }); 77 + </script> 78 + 79 + <div bind:this={root} class="dropdown"> 80 + {#if variant === 'button'} 81 + <Button 82 + size="sm" 83 + class="gap-2 !py-0 text-sm" 84 + onclick={toggle} 85 + aria-haspopup="menu" 86 + aria-expanded={open} 87 + aria-label={label} 88 + > 89 + {@render trigger()} 90 + </Button> 91 + {:else} 92 + <button 93 + type="button" 94 + class="plain" 95 + onclick={toggle} 96 + aria-haspopup="menu" 97 + aria-expanded={open} 98 + aria-label={label} 99 + > 100 + {@render trigger()} 101 + </button> 102 + {/if} 103 + 104 + <div {id} class="menu" class:open role="menu"> 105 + {@render children()} 106 + </div> 107 + </div> 108 + 109 + <style> 110 + .dropdown { 111 + position: relative; 112 + display: inline-block; 113 + } 114 + 115 + .plain { 116 + display: flex; 117 + align-items: center; 118 + gap: 0.25rem; 119 + border: 0; 120 + background: transparent; 121 + padding: 0; 122 + color: inherit; 123 + cursor: pointer; 124 + } 125 + 126 + .menu { 127 + position: absolute; 128 + right: 0; 129 + z-index: 50; 130 + margin-top: 0.5rem; 131 + width: 14rem; 132 + overflow: hidden; 133 + border: 1px solid var(--color-border); 134 + border-radius: 0.25rem; 135 + background-color: var(--color-surface); 136 + box-shadow: var(--shadow-menu); 137 + font-size: 0.875rem; 138 + } 139 + 140 + .menu:not(.open) { 141 + display: none; 142 + } 143 + </style>
+77
web/src/lib/components/ui/DropdownItem.svelte
··· 1 + <script lang="ts"> 2 + import { resolve } from '$app/paths'; 3 + import type { Component, Snippet } from 'svelte'; 4 + import type { SvelteHTMLElements } from 'svelte/elements'; 5 + import { getContext } from 'svelte'; 6 + interface Props { 7 + href?: string; 8 + icon?: Component<SvelteHTMLElements['svg']>; 9 + danger?: boolean; 10 + onclick?: (event: MouseEvent) => void; 11 + children: Snippet; 12 + } 13 + 14 + let { href, icon, danger = false, onclick, children }: Props = $props(); 15 + 16 + const closeDropdown = getContext<(() => void) | undefined>('dropdown-close'); 17 + 18 + const handleClick = (event: MouseEvent) => { 19 + closeDropdown?.(); 20 + onclick?.(event); 21 + }; 22 + </script> 23 + 24 + {#if href} 25 + <a href={resolve(href as '/')} class="item" class:danger onclick={handleClick}> 26 + {#if icon} 27 + {@const Glyph = icon} 28 + <Glyph class="size-4" aria-hidden="true" /> 29 + {/if} 30 + {@render children()} 31 + </a> 32 + {:else} 33 + <button type="button" class="item" class:danger onclick={handleClick}> 34 + {#if icon} 35 + {@const Glyph = icon} 36 + <Glyph class="size-4" aria-hidden="true" /> 37 + {/if} 38 + {@render children()} 39 + </button> 40 + {/if} 41 + 42 + <style> 43 + .item { 44 + --dropdown-item-hover-bg: #f9fafb; 45 + display: flex; 46 + width: 100%; 47 + align-items: center; 48 + gap: 0.5rem; 49 + padding: 0.55rem 0.7rem; 50 + border: 0; 51 + background: transparent; 52 + text-align: left; 53 + text-decoration: none; 54 + color: inherit; 55 + cursor: pointer; 56 + transition: background-color 150ms; 57 + } 58 + 59 + .item:hover { 60 + background-color: var(--dropdown-item-hover-bg); 61 + text-decoration: none; 62 + } 63 + 64 + @media (prefers-color-scheme: dark) { 65 + .item { 66 + --dropdown-item-hover-bg: rgb(55 65 81 / 0.5); 67 + } 68 + } 69 + 70 + .danger { 71 + color: var(--color-danger); 72 + } 73 + 74 + .danger:hover { 75 + background-color: var(--color-danger-soft); 76 + } 77 + </style>
+4
web/src/lib/components/ui/LogotypeSmall.svelte
··· 1 + <span class="inline-flex items-center gap-2 select-none"> 2 + <img src="/logos/logotype.svg" alt="tangled" class="h-8 dark:invert" /> 3 + <span class="rounded bg-surface-muted px-1 text-xs font-normal not-italic"> alpha </span> 4 + </span>
+11
web/src/lib/components/ui/Spinner.svelte
··· 1 + <script lang="ts"> 2 + import LoaderCircle from '$icon/loader-circle'; 3 + 4 + interface Props { 5 + class?: string; 6 + } 7 + 8 + let { class: className = 'size-4' }: Props = $props(); 9 + </script> 10 + 11 + <LoaderCircle class={`${className} animate-spin`} aria-hidden="true" />
web/src/lib/index.ts

This is a binary file and will not be displayed.

+37
web/src/lib/server/config.ts
··· 1 + import { env } from '$env/dynamic/private'; 2 + 3 + const cleanUrl = (value: string | undefined, fallback: string) => { 4 + const raw = value?.trim() || fallback; 5 + return raw.replace(/\/+$/, ''); 6 + }; 7 + 8 + export type WebConfig = { 9 + bobbinUrl: string; 10 + apiUrl: string; 11 + knotResolverUrl: string; 12 + camoUrl: string; 13 + }; 14 + 15 + export type PublicWebConfig = Pick< 16 + WebConfig, 17 + 'bobbinUrl' | 'apiUrl' | 'knotResolverUrl' | 'camoUrl' 18 + >; 19 + 20 + type WebConfigEnv = { 21 + BOBBIN_URL?: string; 22 + TANGLED_API_URL?: string; 23 + API_URL?: string; 24 + KNOT_RESOLVER_URL?: string; 25 + CAMO_URL?: string; 26 + }; 27 + 28 + export const resolveConfig = (values: WebConfigEnv): WebConfig => ({ 29 + bobbinUrl: cleanUrl(values.BOBBIN_URL, 'http://127.0.0.1:8090'), 30 + apiUrl: cleanUrl(values.TANGLED_API_URL ?? values.API_URL, 'http://127.0.0.1:8080'), 31 + knotResolverUrl: cleanUrl(values.KNOT_RESOLVER_URL, 'https://knot1.tangled.sh'), 32 + camoUrl: cleanUrl(values.CAMO_URL, 'https://camo.tangled.sh') 33 + }); 34 + 35 + export const getConfig = (): WebConfig => resolveConfig(env as WebConfigEnv); 36 + 37 + export const getPublicConfig = (): PublicWebConfig => getConfig();
+63
web/src/routes/+error.svelte
··· 1 + <script lang="ts"> 2 + import { page } from '$app/state'; 3 + import Button from '$lib/components/ui/Button.svelte'; 4 + 5 + const copy = $derived.by(() => { 6 + switch (page.status) { 7 + case 404: 8 + return { 9 + status: '404', 10 + title: 'Page not found', 11 + message: 12 + "The page you're looking for doesn't exist. It may have been moved, deleted, or you have the wrong URL.", 13 + mark: '?', 14 + tone: 'bg-surface-muted text-fg-subtle' 15 + }; 16 + case 503: 17 + return { 18 + status: '503', 19 + title: 'Service unavailable', 20 + message: 21 + 'We were unable to reach the service backing this page. It may be temporarily unavailable.', 22 + mark: '503', 23 + tone: 'bg-info-soft text-info' 24 + }; 25 + default: 26 + return { 27 + status: '500', 28 + title: 'Internal server error', 29 + message: 30 + page.error?.message ?? 31 + 'We encountered an error while processing your request. Please try again later.', 32 + mark: '!', 33 + tone: 'bg-danger-soft text-danger' 34 + }; 35 + } 36 + }); 37 + </script> 38 + 39 + <svelte:head> 40 + <title>{copy.status} &middot; Tangled</title> 41 + </svelte:head> 42 + 43 + <section class="flex min-h-[60vh] flex-col items-center justify-center text-center"> 44 + <div class="mx-auto max-w-lg rounded-lg bg-surface p-8 shadow-sm"> 45 + <div class="mb-6"> 46 + <div 47 + class={`mx-auto mb-4 flex size-16 items-center justify-center rounded-full ${copy.tone}`} 48 + > 49 + <span class="font-mono text-xl font-bold" aria-hidden="true">{copy.mark}</span> 50 + </div> 51 + </div> 52 + 53 + <div class="space-y-4"> 54 + <h1 class="text-2xl font-bold text-fg-strong sm:text-3xl"> 55 + {copy.status} &mdash; {copy.title} 56 + </h1> 57 + <p class="text-fg-muted">{copy.message}</p> 58 + <div class="mt-6 flex flex-col items-center justify-center gap-3 sm:flex-row"> 59 + <Button href="/" variant="default">Back to home</Button> 60 + </div> 61 + </div> 62 + </div> 63 + </section>
+12
web/src/routes/+layout.server.ts
··· 1 + import { getPublicConfig } from '$lib/server/config'; 2 + import type { LayoutServerLoad } from './$types'; 3 + 4 + export const load: LayoutServerLoad = ({ cookies }) => { 5 + const did = cookies.get('tangled.currentDid'); 6 + const handle = cookies.get('tangled.currentHandle'); 7 + 8 + return { 9 + publicConfig: getPublicConfig(), 10 + auth: did ? { did, handle: handle ?? did } : null 11 + }; 12 + };
+59
web/src/routes/+layout.svelte
··· 1 + <script lang="ts"> 2 + import { page } from '$app/state'; 3 + import { createAuth, AUTH_KEY } from '$lib/auth.svelte'; 4 + import Footer from '$lib/components/shell/Footer.svelte'; 5 + import Topbar from '$lib/components/shell/Topbar.svelte'; 6 + import { onMount, setContext, untrack } from 'svelte'; 7 + import '../app.css'; 8 + 9 + let { children, data } = $props(); 10 + 11 + const auth = createAuth(untrack(() => data.auth)); 12 + setContext(AUTH_KEY, auth); 13 + 14 + onMount(() => { 15 + if (page.url.pathname !== '/oauth/callback') void auth.refresh(); 16 + }); 17 + 18 + const signedIn = $derived(Boolean(auth.currentUser)); 19 + const isAuthShell = $derived(page.url.pathname === '/login'); 20 + const isMarketingShell = $derived( 21 + !signedIn && (page.url.pathname === '/about' || page.url.pathname === '/') 22 + ); 23 + const topbarVariant = $derived(isMarketingShell ? 'marketing' : 'app'); 24 + </script> 25 + 26 + <svelte:head> 27 + <title>Tangled</title> 28 + </svelte:head> 29 + 30 + <div 31 + class={isAuthShell 32 + ? 'flex min-h-screen flex-col bg-bg-auth text-fg' 33 + : isMarketingShell 34 + ? 'flex min-h-screen flex-col bg-gradient-to-b from-bg-auth to-bg text-fg' 35 + : 'flex min-h-screen flex-col bg-bg text-fg'} 36 + > 37 + {#if !isAuthShell} 38 + <header 39 + class={isMarketingShell 40 + ? 'z-20 w-full bg-transparent pt-[env(safe-area-inset-top)]' 41 + : 'sticky top-0 z-20 w-full bg-surface pt-[env(safe-area-inset-top)] shadow-sm'} 42 + > 43 + <Topbar 44 + user={auth.currentUser} 45 + variant={topbarVariant} 46 + loading={auth.authenticating || auth.profileLoading} 47 + onSignOut={auth.signOut} 48 + /> 49 + </header> 50 + {/if} 51 + 52 + <main class={isAuthShell ? 'flex flex-grow items-center justify-center px-7' : 'flex-grow'}> 53 + {@render children()} 54 + </main> 55 + 56 + {#if !isAuthShell} 57 + <Footer variant={isMarketingShell ? 'full' : 'minimal'} /> 58 + {/if} 59 + </div>
+22
web/src/routes/+page.svelte
··· 1 + <script lang="ts"> 2 + import { getAuth } from '$lib/auth.svelte'; 3 + import MarketingHome from '$lib/components/home/MarketingHome.svelte'; 4 + 5 + const auth = getAuth(); 6 + </script> 7 + 8 + <svelte:head> 9 + <title>Tangled &middot; The next-generation social coding platform</title> 10 + <meta 11 + name="description" 12 + content="The next-generation social coding platform. Host repositories on your infrastructure with knots, use stacked pull requests, and run CI with spindles." 13 + /> 14 + </svelte:head> 15 + 16 + {#if auth.currentUser} 17 + <section class="mx-auto flex w-full max-w-screen-lg flex-col gap-2 px-6 py-8"> 18 + <h1 class="text-2xl font-semibold">Home</h1> 19 + </section> 20 + {:else} 21 + <MarketingHome /> 22 + {/if}
+13
web/src/routes/about/+page.svelte
··· 1 + <script lang="ts"> 2 + import MarketingHome from '$lib/components/home/MarketingHome.svelte'; 3 + </script> 4 + 5 + <svelte:head> 6 + <title>About &middot; Tangled</title> 7 + <meta 8 + name="description" 9 + content="The next-generation social coding platform. Host repositories on your infrastructure with knots, use stacked pull requests, and run CI with spindles." 10 + /> 11 + </svelte:head> 12 + 13 + <MarketingHome />
+106
web/src/routes/login/+page.svelte
··· 1 + <script lang="ts"> 2 + import { browser } from '$app/environment'; 3 + import { resolve } from '$app/paths'; 4 + import { page } from '$app/state'; 5 + import { getAuth } from '$lib/auth.svelte'; 6 + import Button from '$lib/components/ui/Button.svelte'; 7 + import CircleAlert from '$icon/circle-alert'; 8 + import { onMount } from 'svelte'; 9 + import { SvelteURL } from 'svelte/reactivity'; 10 + 11 + const appPath = (path: string) => resolve(path as '/'); 12 + const auth = getAuth(); 13 + const returnTo = $derived(page.url.searchParams.get('return_url') ?? '/'); 14 + 15 + let identifier = $state(page.url.searchParams.get('identifier') ?? ''); 16 + let isSubmitting = $state(false); 17 + 18 + onMount(() => { 19 + if (browser && location.hostname === 'localhost') { 20 + const url = new SvelteURL(location.href); 21 + url.hostname = '127.0.0.1'; 22 + location.replace(url); 23 + } 24 + }); 25 + 26 + const submit = async (event: SubmitEvent) => { 27 + event.preventDefault(); 28 + isSubmitting = true; 29 + try { 30 + await auth.signIn(identifier, returnTo); 31 + } finally { 32 + isSubmitting = false; 33 + } 34 + }; 35 + </script> 36 + 37 + <svelte:head> 38 + <title>Login &middot; Tangled</title> 39 + </svelte:head> 40 + 41 + <section class="w-full max-w-md"> 42 + <div class="mb-4 flex flex-col items-center"> 43 + <a href={appPath('/')} class="flex items-center gap-2 no-underline hover:no-underline"> 44 + <img src="/logos/logotype.svg" alt="tangled" class="h-24 w-48 dark:invert" /> 45 + </a> 46 + <p class="text-center text-xl italic text-fg-strong">tightly-knit social coding.</p> 47 + </div> 48 + 49 + <form class="mt-4" onsubmit={submit}> 50 + <div class="flex flex-col"> 51 + <label for="identifier" class="py-2 text-sm text-fg">Handle</label> 52 + <input 53 + id="identifier" 54 + bind:value={identifier} 55 + disabled={isSubmitting} 56 + type="text" 57 + autocomplete="username" 58 + autocapitalize="none" 59 + spellcheck="false" 60 + inputmode="url" 61 + required 62 + placeholder="akshay.tngl.sh" 63 + class="w-full rounded border border-border bg-surface p-3 text-lg text-fg placeholder:text-fg-faint focus:outline-none focus:ring-1 focus:ring-border-strong md:text-base" 64 + /> 65 + <p class="mt-1 text-sm text-fg-subtle"> 66 + Use your <span class="text-fg">AT Protocol</span> handle to log in. If you're unsure, this 67 + is likely your Tangled 68 + <code class="rounded bg-surface-muted px-1 font-mono text-xs text-fg">(.tngl.sh)</code> 69 + or Bluesky 70 + <code class="rounded bg-surface-muted px-1 font-mono text-xs text-fg">(.bsky.social)</code> 71 + account. 72 + </p> 73 + </div> 74 + 75 + <Button 76 + type="submit" 77 + size="sm" 78 + disabled={isSubmitting} 79 + loading={isSubmitting} 80 + spinnerClass="size-4" 81 + aria-label={isSubmitting ? 'Logging in' : undefined} 82 + class="my-2 mt-6 w-full text-base disabled:opacity-100" 83 + > 84 + Login 85 + </Button> 86 + </form> 87 + 88 + <p class="text-sm text-fg-subtle"> 89 + Don't have an account? <a href={appPath('/signup')} class="text-fg underline" 90 + >Create an account</a 91 + > 92 + on Tangled now! 93 + </p> 94 + 95 + {#if auth.error} 96 + <div 97 + class="my-2 flex gap-2 rounded border border-danger bg-danger-soft px-3 py-2 text-danger drop-shadow-sm" 98 + > 99 + <span class="py-1" aria-hidden="true"><CircleAlert class="size-4" /></span> 100 + <div> 101 + <h5 class="font-medium">Login error</h5> 102 + <p class="text-sm">{auth.error} Please try again.</p> 103 + </div> 104 + </div> 105 + {/if} 106 + </section>
+33
web/src/routes/oauth/callback/+page.svelte
··· 1 + <script lang="ts"> 2 + import { resolve } from '$app/paths'; 3 + import { goto } from '$app/navigation'; 4 + import { getAuth } from '$lib/auth.svelte'; 5 + import { onMount } from 'svelte'; 6 + 7 + const auth = getAuth(); 8 + const appPath = (path: string) => resolve(path as '/'); 9 + 10 + onMount(() => { 11 + void (async () => { 12 + try { 13 + const target = await auth.completeSignIn(); 14 + await goto(appPath(target), { replaceState: true }); 15 + } catch (e) { 16 + console.error(e); 17 + } 18 + })(); 19 + }); 20 + </script> 21 + 22 + <svelte:head> 23 + <title>Signing in &middot; Tangled</title> 24 + </svelte:head> 25 + 26 + {#if auth.error} 27 + <section class="mx-auto flex max-w-md flex-col items-center gap-4 px-7 py-16 text-center"> 28 + <p class="text-base text-danger">{auth.error}</p> 29 + <a href={appPath('/login')} class="inline-flex underline">Try again</a> 30 + </section> 31 + {:else} 32 + <p class="sr-only" role="status">Signing you in&hellip;</p> 33 + {/if}
+4
web/static/.gitignore
··· 1 + * 2 + !.gitignore 3 + !oauth-client-metadata.json 4 + !robots.txt
web/static/fonts/IBMPlexMono-Bold.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-BoldItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-ExtraLight.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-ExtraLightItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-Italic.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-Light.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-LightItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-Medium.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-MediumItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-Regular.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-SemiBold.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-SemiBoldItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-Text.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-TextItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-Thin.woff2

This is a binary file and will not be displayed.

web/static/fonts/IBMPlexMono-ThinItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-Black.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-BlackItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-Bold.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-BoldItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-ExtraBold.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-ExtraBoldItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-ExtraLight.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-ExtraLightItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-Italic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-Light.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-LightItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-Medium.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-MediumItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-Regular.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-SemiBold.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-SemiBoldItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-Thin.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterDisplay-ThinItalic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterVariable-Italic.woff2

This is a binary file and will not be displayed.

web/static/fonts/InterVariable.woff2

This is a binary file and will not be displayed.

web/static/logos/dolly.ico

This is a binary file and will not be displayed.

web/static/logos/dolly.png

This is a binary file and will not be displayed.

+21
web/static/logos/dolly.svg
··· 1 + 2 + <svg 3 + class="" 4 + viewBox="0 0 32 32" 5 + fill="currentColor" 6 + xmlns="http://www.w3.org/2000/svg"> 7 + 8 + <style> 9 + :root { 10 + color: #000000; 11 + } 12 + 13 + @media (prefers-color-scheme: dark) { 14 + :root { 15 + color: #ffffff; 16 + } 17 + } 18 + </style> 19 + 20 + <path d="M21.0971 30.866C20.0566 30.8575 19.2628 30.5542 18.4016 30.0269C17.1668 29.3753 16.2237 28.2808 15.5497 27.0739C14.4789 28.4065 13.0476 29.215 11.4453 29.6718C10.763 29.8705 9.56809 30.0721 7.58737 29.3523C4.73277 28.3905 2.65342 25.4114 2.88973 22.3758C2.8465 21.1175 3.30392 19.8825 3.95228 18.8208C2.22264 17.8897 0.81225 16.3266 0.272148 14.4098C-0.0560731 13.3604 -0.042271 12.2299 0.0787626 11.1512C0.512215 8.60429 2.41697 6.38956 4.86912 5.59294C5.8479 3.35574 7.98378 1.68743 10.4037 1.34778C12.0104 1.12338 13.6735 1.46075 15.0792 2.27979C17.1272 0.00158595 20.6952 -0.671697 23.4195 0.727793C25.4978 1.72322 26.9839 3.80003 27.3447 6.06471C29.3222 6.85928 30.9877 8.47971 31.6413 10.5368C32.0784 11.8104 32.0928 13.2132 31.8098 14.5209C31.3041 16.5615 29.8679 18.2987 28.009 19.2482C28.0135 19.6113 29.2037 22.2296 29.0047 24.2056C28.9612 26.676 27.399 29.0172 25.2325 30.1544C23.9683 30.8945 22.4702 30.8805 21.0971 30.866ZM15.1733 23.755C16.9256 23.5593 18.0743 22.0269 18.9665 20.6469C19.3883 20.0182 19.7105 19.3146 20.0306 18.6454C20.4458 19.0271 20.7975 19.7461 21.4541 19.9173C22.1457 20.1333 22.9566 19.9579 23.38 19.3277C24.1902 17.8118 23.7908 15.9827 23.319 14.4119C23.0284 13.5097 22.6472 12.5841 21.9218 11.9446C22.0765 10.85 21.4299 9.73834 20.5106 9.16542C19.7272 9.79198 18.5352 9.78821 17.7794 9.11795C16.3309 10.5997 15.0034 10.5505 13.7212 9.37618C13.4331 9.11226 12.8832 10.9871 10.9535 9.92506C9.84488 10.8567 8.98526 11.753 8.22356 13.0435C7.48342 14.4347 6.70829 15.6703 6.64151 17.1811C6.6094 18.0641 7.29731 18.9892 8.22942 18.9174C9.16105 19.0009 9.7952 18.0813 10.5006 17.6993C10.6058 18.9316 10.7243 20.2556 11.1395 21.4587C11.6161 23.0155 13.2947 24.005 14.8835 23.7784C14.9959 23.7696 15.1733 23.7549 15.1733 23.755ZM16.0828 19.1062C15.2306 18.5823 15.6407 17.4452 15.6066 16.6193C15.6914 15.6227 15.7594 14.575 16.2061 13.667C16.6788 13.0197 17.8318 13.2694 17.8827 14.0999C17.8488 14.9353 17.4664 15.767 17.5121 16.633C17.4129 17.3561 17.5839 18.1684 17.265 18.8293C17.0033 19.195 16.4703 19.3013 16.0828 19.1062ZM12.3606 18.6302C11.5578 18.1933 11.8129 17.0941 11.687 16.3298C11.7914 15.445 11.7045 14.3226 12.4431 13.7021C13.1653 13.1969 14.1485 14.0621 13.8069 14.8564C13.4426 15.8602 13.6814 16.957 13.6891 17.9748C13.5512 18.5752 12.911 18.894 12.3606 18.6302Z" fill="currentColor"/> 21 + </svg>
+12
web/static/oauth-client-metadata.json
··· 1 + { 2 + "client_id": "https://tangled.org/oauth-client-metadata.json", 3 + "client_name": "Tangled", 4 + "client_uri": "https://tangled.org", 5 + "redirect_uris": ["https://tangled.org/oauth/callback"], 6 + "scope": "atproto repo:sh.tangled.actor.profile repo:sh.tangled.feed.comment repo:sh.tangled.feed.reaction repo:sh.tangled.feed.star repo:sh.tangled.graph.follow repo:sh.tangled.graph.vouch repo:sh.tangled.knot repo:sh.tangled.knot.member repo:sh.tangled.label.definition repo:sh.tangled.label.op repo:sh.tangled.publicKey repo:sh.tangled.repo repo:sh.tangled.repo.artifact repo:sh.tangled.repo.collaborator repo:sh.tangled.repo.issue repo:sh.tangled.repo.issue.comment repo:sh.tangled.repo.issue.state repo:sh.tangled.repo.pull repo:sh.tangled.repo.pull.comment repo:sh.tangled.repo.pull.status repo:sh.tangled.spindle repo:sh.tangled.spindle.member repo:sh.tangled.string blob:*/* rpc:sh.tangled.knot.addMember?aud=* rpc:sh.tangled.knot.removeMember?aud=* rpc:sh.tangled.ci.triggerPipeline?aud=* rpc:sh.tangled.ci.cancelPipeline?aud=* rpc:sh.tangled.repo.addCollaborator?aud=* rpc:sh.tangled.repo.addSecret?aud=* rpc:sh.tangled.repo.create?aud=* rpc:sh.tangled.repo.delete?aud=* rpc:sh.tangled.repo.deleteBranch?aud=* rpc:sh.tangled.repo.forkStatus?aud=* rpc:sh.tangled.repo.forkSync?aud=* rpc:sh.tangled.repo.hiddenRef?aud=* rpc:sh.tangled.repo.listSecrets?aud=* rpc:sh.tangled.repo.merge?aud=* rpc:sh.tangled.repo.mergeCheck?aud=* rpc:sh.tangled.repo.removeCollaborator?aud=* rpc:sh.tangled.repo.removeSecret?aud=* rpc:sh.tangled.repo.setDefaultBranch?aud=*", 7 + "grant_types": ["authorization_code", "refresh_token"], 8 + "response_types": ["code"], 9 + "token_endpoint_auth_method": "none", 10 + "application_type": "web", 11 + "dpop_bound_access_tokens": true 12 + }
+3
web/static/robots.txt
··· 1 + # allow crawling everything by default 2 + User-agent: * 3 + Disallow:
+14
web/svelte.config.js
··· 1 + import adapter from '@sveltejs/adapter-node'; 2 + import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 + 4 + const config = { 5 + preprocess: vitePreprocess(), 6 + compilerOptions: { 7 + runes: ({ filename }) => (filename.split(/[/\\]/).includes('node_modules') ? undefined : true) 8 + }, 9 + kit: { 10 + adapter: adapter() 11 + } 12 + }; 13 + 14 + export default config;
+20
web/tsconfig.json
··· 1 + { 2 + "extends": "./.svelte-kit/tsconfig.json", 3 + "compilerOptions": { 4 + "rewriteRelativeImportExtensions": true, 5 + "allowJs": true, 6 + "checkJs": true, 7 + "esModuleInterop": true, 8 + "forceConsistentCasingInFileNames": true, 9 + "resolveJsonModule": true, 10 + "skipLibCheck": true, 11 + "sourceMap": true, 12 + "strict": true, 13 + "moduleResolution": "bundler" 14 + } 15 + // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias 16 + // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files 17 + // 18 + // To make changes to top-level options such as include and exclude, we recommend extending 19 + // the generated config; see https://svelte.dev/docs/kit/configuration#typescript 20 + }
+53
web/vite.config.ts
··· 1 + import tailwindcss from '@tailwindcss/vite'; 2 + import { sveltekit } from '@sveltejs/kit/vite'; 3 + import Icons from 'unplugin-icons/vite'; 4 + import { defineConfig } from 'vitest/config'; 5 + import oauthMetadata from './static/oauth-client-metadata.json'; 6 + 7 + const devHost = '127.0.0.1'; 8 + const devPort = 5173; 9 + const devRedirectUri = `http://${devHost}:${devPort}/oauth/callback`; 10 + const devClientId = `http://localhost?redirect_uri=${encodeURIComponent(devRedirectUri)}&scope=${encodeURIComponent(oauthMetadata.scope)}`; 11 + 12 + export default defineConfig({ 13 + plugins: [ 14 + { 15 + name: 'oauth-env', 16 + config(_config, { command }) { 17 + process.env.VITE_OAUTH_CLIENT_ID ??= 18 + command === 'serve' ? devClientId : oauthMetadata.client_id; 19 + process.env.VITE_OAUTH_REDIRECT_URI ??= 20 + command === 'serve' ? devRedirectUri : oauthMetadata.redirect_uris[0]; 21 + process.env.VITE_OAUTH_SCOPE ??= oauthMetadata.scope; 22 + process.env.VITE_TANGLED_APPVIEW_SERVICE ??= 'https://bobbin.klbr.net'; 23 + } 24 + }, 25 + tailwindcss(), 26 + Icons({ compiler: 'svelte' }), 27 + sveltekit() 28 + ], 29 + resolve: { 30 + alias: { 31 + '$icon/': '~icons/lucide/' 32 + } 33 + }, 34 + server: { 35 + host: devHost, 36 + port: devPort, 37 + strictPort: true 38 + }, 39 + test: { 40 + expect: { requireAssertions: true }, 41 + projects: [ 42 + { 43 + extends: './vite.config.ts', 44 + test: { 45 + name: 'server', 46 + environment: 'node', 47 + include: ['src/**/*.{test,spec}.{js,ts}'], 48 + exclude: ['src/**/*.svelte.{test,spec}.{js,ts}'] 49 + } 50 + } 51 + ] 52 + } 53 + });