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 13, 2026, 3:58 PM +0300) 1625ce79 707d3291

+5694
+47
.tangled/workflows/web.yml
··· 1 + when: 2 + - event: ["push", "pull_request"] 3 + branch: master 4 + paths: 5 + - web/** 6 + - flake.nix 7 + - flake.lock 8 + - nix/pkgs/web-static-files.nix 9 + 10 + engine: microvm 11 + image: nixos 12 + 13 + dependencies: 14 + - nodejs 15 + 16 + steps: 17 + - name: install web deps 18 + command: | 19 + cd web 20 + corepack pnpm install --frozen-lockfile 21 + 22 + - name: lint web 23 + command: | 24 + cd web 25 + corepack pnpm run lint 26 + 27 + - name: typecheck web 28 + command: | 29 + cd web 30 + corepack pnpm run check 31 + 32 + - name: test web 33 + command: | 34 + cd web 35 + corepack pnpm run test:unit -- --run 36 + 37 + - name: sync web static assets 38 + command: | 39 + out=$(nix build .#web-static-files --no-link --print-out-paths) 40 + mkdir -p web/static 41 + rm -rf web/static/fonts web/static/logos 42 + cp -fr --no-preserve=ownership,mode "$out"/* web/static 43 + 44 + - name: build web 45 + command: | 46 + cd web 47 + 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
+7
web/.prettierignore
··· 1 + package-lock.json 2 + pnpm-lock.yaml 3 + yarn.lock 4 + bun.lock 5 + bun.lockb 6 + 7 + /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.
+38
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 owns undefined-name checks. 22 + 'no-undef': 'off' 23 + } 24 + }, 25 + { 26 + files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'], 27 + languageOptions: { 28 + parserOptions: { 29 + projectService: true, 30 + extraFileExtensions: ['.svelte'], 31 + parser: ts.parser 32 + } 33 + } 34 + }, 35 + { 36 + rules: {} 37 + } 38 + );
+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;
+154
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: 16px; 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 + font-size: 14px; 149 + } 150 + 151 + a { 152 + @apply text-fg no-underline hover:text-fg-muted; 153 + } 154 + }
+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 + // 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
+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 + });