A fork of pds-dash for selfhosted.social

Move to SvelteKit and serverside caching

+4
.dockerignore
··· 1 + .idea 2 + node_modules 3 + build 4 + .svelte-kit
+19
.env.example
··· 1 + # The base URL of the PDS (Personal Data Server) 2 + PUBLIC_PDS_URL=https://selfhosted.social 3 + 4 + # Theme to be used (must match a folder in the themes/ directory) 5 + VITE_THEME=dark 6 + 7 + # The base URL of the frontend service for linking to replies/quotes/accounts etc. 8 + PUBLIC_FRONTEND_URL=https://bsky.app 9 + 10 + # Maximum number of posts to fetch from the PDS per request 11 + # Should be around 20 for about 10 users on the PDS 12 + # The more users you have, the lower the number should be 13 + PUBLIC_MAX_POSTS=10 14 + 15 + # Footer text for the dashboard. Supports HTML. 16 + PUBLIC_FOOTER_TEXT= 17 + 18 + # Whether to show posts with timestamps that are in the future 19 + PUBLIC_SHOW_FUTURE_POSTS=false
+6 -2
.gitignore
··· 151 151 .yarn/install-state.gz 152 152 .pnp.* 153 153 154 - # Config files 155 - config.ts 154 + # SvelteKit 155 + .svelte-kit 156 + build 157 + cache.db 158 + 159 + CLAUDE.md
+18
Dockerfile
··· 1 + FROM node:24-slim as builder 2 + ENV PNPM_HOME="/pnpm" 3 + ENV PATH="$PNPM_HOME:$PATH" 4 + RUN corepack enable 5 + WORKDIR /app 6 + 7 + COPY . /app 8 + RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile 9 + RUN pnpm run build 10 + 11 + FROM node:24-alpine3.22 as web-ui 12 + WORKDIR /app 13 + 14 + COPY --from=builder /app/build /app/build 15 + COPY --from=builder /app/package*.json /app/ 16 + RUN npm install --omit=dev 17 + 18 + CMD ["node", "build"]
+1 -1
README.md
··· 8 8 9 9 This fork is much the same but a few differences: 10 10 11 - - [New theme](/themes/dark/theme.css) 11 + - [New theme](/src/lib/assets/theme.css) 12 12 - Uses the CDN for loading images and videos instead of 13 13 `com.atproto.sync.getBlob` 14 14 - Caches a couple of things like did -> handle and PDS user profile lexicon
-44
config.ts.example
··· 1 - /** 2 - * Configuration module for the PDS Dashboard 3 - */ 4 - export class Config { 5 - /** 6 - * The base URL of the PDS (Personal Data Server). 7 - * @default none 8 - */ 9 - static readonly PDS_URL: string = ""; 10 - 11 - /** 12 - * Theme to be used 13 - * @default "default" 14 - */ 15 - static readonly THEME: string = "default"; 16 - 17 - /** 18 - * The base URL of the frontend service for linking to replies/quotes/accounts etc. 19 - * @default "https://deer.social" // or https://bsky.app if you're boring 20 - */ 21 - static readonly FRONTEND_URL: string = "https://deer.social"; 22 - 23 - /** 24 - * Maximum number of posts to fetch from the PDS per request 25 - * Should be around 20 for about 10 users on the pds 26 - * The more users you have, the lower the number should be 27 - * since sorting is slow and is done on the frontend 28 - * @default 20 29 - */ 30 - static readonly MAX_POSTS: number = 20; 31 - 32 - /** 33 - * Footer text for the dashboard, you probably want to change this. Supports HTML. 34 - * @default "<a href='https://git.witchcraft.systems/scientific-witchery/pds-dash' target='_blank'>Source</a> (<a href='https://github.com/witchcraft-systems/pds-dash/' target='_blank'>github mirror</a>)" 35 - */ 36 - static readonly FOOTER_TEXT: string = 37 - "<a href='https://git.witchcraft.systems/scientific-witchery/pds-dash' target='_blank'>Source</a> (<a href='https://github.com/witchcraft-systems/pds-dash/' target='_blank'>github mirror</a>)"; 38 - 39 - /** 40 - * Whether to show the posts with timestamps that are in the future. 41 - * @default false 42 - */ 43 - static readonly SHOW_FUTURE_POSTS: boolean = false; 44 - }
-679
deno.lock
··· 1 - { 2 - "version": "5", 3 - "specifiers": { 4 - "npm:@atcute/bluesky@^2.0.2": "2.0.2_@atcute+client@3.0.1", 5 - "npm:@atcute/client@^3.0.1": "3.0.1", 6 - "npm:@atcute/identity-resolver@~0.1.2": "0.1.2_@atcute+identity@0.1.3", 7 - "npm:@atproto/api@~0.16.9": "0.16.9", 8 - "npm:@sveltejs/vite-plugin-svelte@^5.0.3": "5.0.3_svelte@5.28.1__acorn@8.14.1_vite@6.3.2__picomatch@4.0.2", 9 - "npm:@tsconfig/svelte@^5.0.4": "5.0.4", 10 - "npm:hls.js@^1.6.12": "1.6.12", 11 - "npm:moment@^2.30.1": "2.30.1", 12 - "npm:mutex-ts@^1.2.1": "1.2.1", 13 - "npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3", 14 - "npm:svelte-infinite-loading@^1.4.0": "1.4.0", 15 - "npm:svelte@^5.23.1": "5.28.1_acorn@8.14.1", 16 - "npm:typescript@~5.7.2": "5.7.3", 17 - "npm:vite@^6.3.1": "6.3.2_picomatch@4.0.2" 18 - }, 19 - "npm": { 20 - "@ampproject/remapping@2.3.0": { 21 - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", 22 - "dependencies": [ 23 - "@jridgewell/gen-mapping", 24 - "@jridgewell/trace-mapping" 25 - ] 26 - }, 27 - "@atcute/bluesky@2.0.2_@atcute+client@3.0.1": { 28 - "integrity": "sha512-xU+9Rp8bzc9AOnWSc11M1urRppDt3BiWR7v2QrLt3Qoysa5jvL8j2p2w4iRT8vLByz8Q+Xgk5Kz4zWVx1zCiug==", 29 - "dependencies": [ 30 - "@atcute/client" 31 - ] 32 - }, 33 - "@atcute/client@3.0.1": { 34 - "integrity": "sha512-j51SuQYQj5jeKrx1DCXx+Q3fpVvO0JYGnKnJAdDSlesSLjPXjvnx1abC+hkuro58KRHHJvRA6P1MC0pmJsWfcg==" 35 - }, 36 - "@atcute/identity-resolver@0.1.2_@atcute+identity@0.1.3": { 37 - "integrity": "sha512-fP2VbHD04kVcCdNi/Kszo6jFzqM7Pg3p33oGhfp2zVkwFKaVBlwCaFRWEga/Xvu/IDLwNdASGWnLqoA34SFeSg==", 38 - "dependencies": [ 39 - "@atcute/identity", 40 - "@atcute/util-fetch", 41 - "@badrap/valita" 42 - ] 43 - }, 44 - "@atcute/identity@0.1.3": { 45 - "integrity": "sha512-ndlD8nypHt8G00wixbozKdSNL0O8HTzBjFGEXeAcBUCXSZPBjRWbqtgyJxhgUWnr7swgxgw1mSbZwRB5b7xCiQ==", 46 - "dependencies": [ 47 - "@badrap/valita" 48 - ] 49 - }, 50 - "@atcute/util-fetch@1.0.1": { 51 - "integrity": "sha512-Clc0E/5ufyGBVfYBUwWNlHONlZCoblSr4Ho50l1LhmRPGB1Wu/AQ9Sz+rsBg7fdaW/auve8ulmwhRhnX2cGRow==", 52 - "dependencies": [ 53 - "@badrap/valita" 54 - ] 55 - }, 56 - "@atproto/api@0.16.9": { 57 - "integrity": "sha512-hXbnBIDEIwXxxyduxxZsf0aP8Z+JKyfG7L47FZqAYOI6uNm8oBTLLrHQ2RmJZZeyMIMM17gvxNtPDoULKQfupw==", 58 - "dependencies": [ 59 - "@atproto/common-web", 60 - "@atproto/lexicon", 61 - "@atproto/syntax", 62 - "@atproto/xrpc", 63 - "await-lock", 64 - "multiformats", 65 - "tlds", 66 - "zod" 67 - ] 68 - }, 69 - "@atproto/common-web@0.4.3": { 70 - "integrity": "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg==", 71 - "dependencies": [ 72 - "graphemer", 73 - "multiformats", 74 - "uint8arrays", 75 - "zod" 76 - ] 77 - }, 78 - "@atproto/lexicon@0.5.1": { 79 - "integrity": "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A==", 80 - "dependencies": [ 81 - "@atproto/common-web", 82 - "@atproto/syntax", 83 - "iso-datestring-validator", 84 - "multiformats", 85 - "zod" 86 - ] 87 - }, 88 - "@atproto/syntax@0.4.1": { 89 - "integrity": "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw==" 90 - }, 91 - "@atproto/xrpc@0.7.5": { 92 - "integrity": "sha512-MUYNn5d2hv8yVegRL0ccHvTHAVj5JSnW07bkbiaz96UH45lvYNRVwt44z+yYVnb0/mvBzyD3/ZQ55TRGt7fHkA==", 93 - "dependencies": [ 94 - "@atproto/lexicon", 95 - "zod" 96 - ] 97 - }, 98 - "@badrap/valita@0.4.4": { 99 - "integrity": "sha512-GEhUCk9c4XbNxi+0YZHZsV4fYNd6HejfWuN4Ti4c02DauX+LyX5WY1Y3WfyZ8Pxxl0zqhs+MLtW98cMh86vv6g==" 100 - }, 101 - "@esbuild/aix-ppc64@0.25.2": { 102 - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", 103 - "os": ["aix"], 104 - "cpu": ["ppc64"] 105 - }, 106 - "@esbuild/android-arm64@0.25.2": { 107 - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", 108 - "os": ["android"], 109 - "cpu": ["arm64"] 110 - }, 111 - "@esbuild/android-arm@0.25.2": { 112 - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", 113 - "os": ["android"], 114 - "cpu": ["arm"] 115 - }, 116 - "@esbuild/android-x64@0.25.2": { 117 - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", 118 - "os": ["android"], 119 - "cpu": ["x64"] 120 - }, 121 - "@esbuild/darwin-arm64@0.25.2": { 122 - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", 123 - "os": ["darwin"], 124 - "cpu": ["arm64"] 125 - }, 126 - "@esbuild/darwin-x64@0.25.2": { 127 - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", 128 - "os": ["darwin"], 129 - "cpu": ["x64"] 130 - }, 131 - "@esbuild/freebsd-arm64@0.25.2": { 132 - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", 133 - "os": ["freebsd"], 134 - "cpu": ["arm64"] 135 - }, 136 - "@esbuild/freebsd-x64@0.25.2": { 137 - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", 138 - "os": ["freebsd"], 139 - "cpu": ["x64"] 140 - }, 141 - "@esbuild/linux-arm64@0.25.2": { 142 - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", 143 - "os": ["linux"], 144 - "cpu": ["arm64"] 145 - }, 146 - "@esbuild/linux-arm@0.25.2": { 147 - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", 148 - "os": ["linux"], 149 - "cpu": ["arm"] 150 - }, 151 - "@esbuild/linux-ia32@0.25.2": { 152 - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", 153 - "os": ["linux"], 154 - "cpu": ["ia32"] 155 - }, 156 - "@esbuild/linux-loong64@0.25.2": { 157 - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", 158 - "os": ["linux"], 159 - "cpu": ["loong64"] 160 - }, 161 - "@esbuild/linux-mips64el@0.25.2": { 162 - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", 163 - "os": ["linux"], 164 - "cpu": ["mips64el"] 165 - }, 166 - "@esbuild/linux-ppc64@0.25.2": { 167 - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", 168 - "os": ["linux"], 169 - "cpu": ["ppc64"] 170 - }, 171 - "@esbuild/linux-riscv64@0.25.2": { 172 - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", 173 - "os": ["linux"], 174 - "cpu": ["riscv64"] 175 - }, 176 - "@esbuild/linux-s390x@0.25.2": { 177 - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", 178 - "os": ["linux"], 179 - "cpu": ["s390x"] 180 - }, 181 - "@esbuild/linux-x64@0.25.2": { 182 - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", 183 - "os": ["linux"], 184 - "cpu": ["x64"] 185 - }, 186 - "@esbuild/netbsd-arm64@0.25.2": { 187 - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", 188 - "os": ["netbsd"], 189 - "cpu": ["arm64"] 190 - }, 191 - "@esbuild/netbsd-x64@0.25.2": { 192 - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", 193 - "os": ["netbsd"], 194 - "cpu": ["x64"] 195 - }, 196 - "@esbuild/openbsd-arm64@0.25.2": { 197 - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", 198 - "os": ["openbsd"], 199 - "cpu": ["arm64"] 200 - }, 201 - "@esbuild/openbsd-x64@0.25.2": { 202 - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", 203 - "os": ["openbsd"], 204 - "cpu": ["x64"] 205 - }, 206 - "@esbuild/sunos-x64@0.25.2": { 207 - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", 208 - "os": ["sunos"], 209 - "cpu": ["x64"] 210 - }, 211 - "@esbuild/win32-arm64@0.25.2": { 212 - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", 213 - "os": ["win32"], 214 - "cpu": ["arm64"] 215 - }, 216 - "@esbuild/win32-ia32@0.25.2": { 217 - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", 218 - "os": ["win32"], 219 - "cpu": ["ia32"] 220 - }, 221 - "@esbuild/win32-x64@0.25.2": { 222 - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", 223 - "os": ["win32"], 224 - "cpu": ["x64"] 225 - }, 226 - "@jridgewell/gen-mapping@0.3.8": { 227 - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", 228 - "dependencies": [ 229 - "@jridgewell/set-array", 230 - "@jridgewell/sourcemap-codec", 231 - "@jridgewell/trace-mapping" 232 - ] 233 - }, 234 - "@jridgewell/resolve-uri@3.1.2": { 235 - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" 236 - }, 237 - "@jridgewell/set-array@1.2.1": { 238 - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" 239 - }, 240 - "@jridgewell/sourcemap-codec@1.5.0": { 241 - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" 242 - }, 243 - "@jridgewell/trace-mapping@0.3.25": { 244 - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", 245 - "dependencies": [ 246 - "@jridgewell/resolve-uri", 247 - "@jridgewell/sourcemap-codec" 248 - ] 249 - }, 250 - "@rollup/rollup-android-arm-eabi@4.40.0": { 251 - "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", 252 - "os": ["android"], 253 - "cpu": ["arm"] 254 - }, 255 - "@rollup/rollup-android-arm64@4.40.0": { 256 - "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", 257 - "os": ["android"], 258 - "cpu": ["arm64"] 259 - }, 260 - "@rollup/rollup-darwin-arm64@4.40.0": { 261 - "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", 262 - "os": ["darwin"], 263 - "cpu": ["arm64"] 264 - }, 265 - "@rollup/rollup-darwin-x64@4.40.0": { 266 - "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", 267 - "os": ["darwin"], 268 - "cpu": ["x64"] 269 - }, 270 - "@rollup/rollup-freebsd-arm64@4.40.0": { 271 - "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", 272 - "os": ["freebsd"], 273 - "cpu": ["arm64"] 274 - }, 275 - "@rollup/rollup-freebsd-x64@4.40.0": { 276 - "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", 277 - "os": ["freebsd"], 278 - "cpu": ["x64"] 279 - }, 280 - "@rollup/rollup-linux-arm-gnueabihf@4.40.0": { 281 - "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", 282 - "os": ["linux"], 283 - "cpu": ["arm"] 284 - }, 285 - "@rollup/rollup-linux-arm-musleabihf@4.40.0": { 286 - "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", 287 - "os": ["linux"], 288 - "cpu": ["arm"] 289 - }, 290 - "@rollup/rollup-linux-arm64-gnu@4.40.0": { 291 - "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", 292 - "os": ["linux"], 293 - "cpu": ["arm64"] 294 - }, 295 - "@rollup/rollup-linux-arm64-musl@4.40.0": { 296 - "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", 297 - "os": ["linux"], 298 - "cpu": ["arm64"] 299 - }, 300 - "@rollup/rollup-linux-loongarch64-gnu@4.40.0": { 301 - "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", 302 - "os": ["linux"], 303 - "cpu": ["loong64"] 304 - }, 305 - "@rollup/rollup-linux-powerpc64le-gnu@4.40.0": { 306 - "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", 307 - "os": ["linux"], 308 - "cpu": ["ppc64"] 309 - }, 310 - "@rollup/rollup-linux-riscv64-gnu@4.40.0": { 311 - "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", 312 - "os": ["linux"], 313 - "cpu": ["riscv64"] 314 - }, 315 - "@rollup/rollup-linux-riscv64-musl@4.40.0": { 316 - "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", 317 - "os": ["linux"], 318 - "cpu": ["riscv64"] 319 - }, 320 - "@rollup/rollup-linux-s390x-gnu@4.40.0": { 321 - "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", 322 - "os": ["linux"], 323 - "cpu": ["s390x"] 324 - }, 325 - "@rollup/rollup-linux-x64-gnu@4.40.0": { 326 - "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", 327 - "os": ["linux"], 328 - "cpu": ["x64"] 329 - }, 330 - "@rollup/rollup-linux-x64-musl@4.40.0": { 331 - "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", 332 - "os": ["linux"], 333 - "cpu": ["x64"] 334 - }, 335 - "@rollup/rollup-win32-arm64-msvc@4.40.0": { 336 - "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", 337 - "os": ["win32"], 338 - "cpu": ["arm64"] 339 - }, 340 - "@rollup/rollup-win32-ia32-msvc@4.40.0": { 341 - "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", 342 - "os": ["win32"], 343 - "cpu": ["ia32"] 344 - }, 345 - "@rollup/rollup-win32-x64-msvc@4.40.0": { 346 - "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", 347 - "os": ["win32"], 348 - "cpu": ["x64"] 349 - }, 350 - "@sveltejs/acorn-typescript@1.0.5_acorn@8.14.1": { 351 - "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", 352 - "dependencies": [ 353 - "acorn" 354 - ] 355 - }, 356 - "@sveltejs/vite-plugin-svelte-inspector@4.0.1_@sveltejs+vite-plugin-svelte@5.0.3__svelte@5.28.1___acorn@8.14.1__vite@6.3.2___picomatch@4.0.2_svelte@5.28.1__acorn@8.14.1_vite@6.3.2__picomatch@4.0.2": { 357 - "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", 358 - "dependencies": [ 359 - "@sveltejs/vite-plugin-svelte", 360 - "debug", 361 - "svelte", 362 - "vite" 363 - ] 364 - }, 365 - "@sveltejs/vite-plugin-svelte@5.0.3_svelte@5.28.1__acorn@8.14.1_vite@6.3.2__picomatch@4.0.2": { 366 - "integrity": "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw==", 367 - "dependencies": [ 368 - "@sveltejs/vite-plugin-svelte-inspector", 369 - "debug", 370 - "deepmerge", 371 - "kleur", 372 - "magic-string", 373 - "svelte", 374 - "vite", 375 - "vitefu" 376 - ] 377 - }, 378 - "@tsconfig/svelte@5.0.4": { 379 - "integrity": "sha512-BV9NplVgLmSi4mwKzD8BD/NQ8erOY/nUE/GpgWe2ckx+wIQF5RyRirn/QsSSCPeulVpc3RA/iJt6DpfTIZps0Q==" 380 - }, 381 - "@types/estree@1.0.7": { 382 - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==" 383 - }, 384 - "acorn@8.14.1": { 385 - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", 386 - "bin": true 387 - }, 388 - "aria-query@5.3.2": { 389 - "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==" 390 - }, 391 - "await-lock@2.2.2": { 392 - "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==" 393 - }, 394 - "axobject-query@4.1.0": { 395 - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==" 396 - }, 397 - "chokidar@4.0.3": { 398 - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", 399 - "dependencies": [ 400 - "readdirp" 401 - ] 402 - }, 403 - "clsx@2.1.1": { 404 - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" 405 - }, 406 - "debug@4.4.0": { 407 - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 408 - "dependencies": [ 409 - "ms" 410 - ] 411 - }, 412 - "deepmerge@4.3.1": { 413 - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" 414 - }, 415 - "esbuild@0.25.2": { 416 - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", 417 - "optionalDependencies": [ 418 - "@esbuild/aix-ppc64", 419 - "@esbuild/android-arm", 420 - "@esbuild/android-arm64", 421 - "@esbuild/android-x64", 422 - "@esbuild/darwin-arm64", 423 - "@esbuild/darwin-x64", 424 - "@esbuild/freebsd-arm64", 425 - "@esbuild/freebsd-x64", 426 - "@esbuild/linux-arm", 427 - "@esbuild/linux-arm64", 428 - "@esbuild/linux-ia32", 429 - "@esbuild/linux-loong64", 430 - "@esbuild/linux-mips64el", 431 - "@esbuild/linux-ppc64", 432 - "@esbuild/linux-riscv64", 433 - "@esbuild/linux-s390x", 434 - "@esbuild/linux-x64", 435 - "@esbuild/netbsd-arm64", 436 - "@esbuild/netbsd-x64", 437 - "@esbuild/openbsd-arm64", 438 - "@esbuild/openbsd-x64", 439 - "@esbuild/sunos-x64", 440 - "@esbuild/win32-arm64", 441 - "@esbuild/win32-ia32", 442 - "@esbuild/win32-x64" 443 - ], 444 - "scripts": true, 445 - "bin": true 446 - }, 447 - "esm-env@1.2.2": { 448 - "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==" 449 - }, 450 - "esrap@1.4.6": { 451 - "integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==", 452 - "dependencies": [ 453 - "@jridgewell/sourcemap-codec" 454 - ] 455 - }, 456 - "fdir@6.4.4_picomatch@4.0.2": { 457 - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", 458 - "dependencies": [ 459 - "picomatch" 460 - ], 461 - "optionalPeers": [ 462 - "picomatch" 463 - ] 464 - }, 465 - "fsevents@2.3.3": { 466 - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 467 - "os": ["darwin"], 468 - "scripts": true 469 - }, 470 - "graphemer@1.4.0": { 471 - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" 472 - }, 473 - "hls.js@1.6.12": { 474 - "integrity": "sha512-Pz+7IzvkbAht/zXvwLzA/stUHNqztqKvlLbfpq6ZYU68+gZ+CZMlsbQBPUviRap+3IQ41E39ke7Ia+yvhsehEQ==" 475 - }, 476 - "is-reference@3.0.3": { 477 - "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", 478 - "dependencies": [ 479 - "@types/estree" 480 - ] 481 - }, 482 - "iso-datestring-validator@2.2.2": { 483 - "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==" 484 - }, 485 - "kleur@4.1.5": { 486 - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" 487 - }, 488 - "locate-character@3.0.0": { 489 - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" 490 - }, 491 - "magic-string@0.30.17": { 492 - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", 493 - "dependencies": [ 494 - "@jridgewell/sourcemap-codec" 495 - ] 496 - }, 497 - "moment@2.30.1": { 498 - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" 499 - }, 500 - "mri@1.2.0": { 501 - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" 502 - }, 503 - "ms@2.1.3": { 504 - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 505 - }, 506 - "multiformats@9.9.0": { 507 - "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" 508 - }, 509 - "mutex-ts@1.2.1": { 510 - "integrity": "sha512-OkcXgf0viuCgYdnm48kiNQ9PzC5OzISQ261svHr/Ybc2vBYC/5xfLXn44hQ+dYRX74v7MCSqV/LKPEbpYdDybw==" 511 - }, 512 - "nanoid@3.3.11": { 513 - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", 514 - "bin": true 515 - }, 516 - "picocolors@1.1.1": { 517 - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" 518 - }, 519 - "picomatch@4.0.2": { 520 - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==" 521 - }, 522 - "postcss@8.5.3": { 523 - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", 524 - "dependencies": [ 525 - "nanoid", 526 - "picocolors", 527 - "source-map-js" 528 - ] 529 - }, 530 - "readdirp@4.1.2": { 531 - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==" 532 - }, 533 - "rollup@4.40.0": { 534 - "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", 535 - "dependencies": [ 536 - "@types/estree" 537 - ], 538 - "optionalDependencies": [ 539 - "@rollup/rollup-android-arm-eabi", 540 - "@rollup/rollup-android-arm64", 541 - "@rollup/rollup-darwin-arm64", 542 - "@rollup/rollup-darwin-x64", 543 - "@rollup/rollup-freebsd-arm64", 544 - "@rollup/rollup-freebsd-x64", 545 - "@rollup/rollup-linux-arm-gnueabihf", 546 - "@rollup/rollup-linux-arm-musleabihf", 547 - "@rollup/rollup-linux-arm64-gnu", 548 - "@rollup/rollup-linux-arm64-musl", 549 - "@rollup/rollup-linux-loongarch64-gnu", 550 - "@rollup/rollup-linux-powerpc64le-gnu", 551 - "@rollup/rollup-linux-riscv64-gnu", 552 - "@rollup/rollup-linux-riscv64-musl", 553 - "@rollup/rollup-linux-s390x-gnu", 554 - "@rollup/rollup-linux-x64-gnu", 555 - "@rollup/rollup-linux-x64-musl", 556 - "@rollup/rollup-win32-arm64-msvc", 557 - "@rollup/rollup-win32-ia32-msvc", 558 - "@rollup/rollup-win32-x64-msvc", 559 - "fsevents" 560 - ], 561 - "bin": true 562 - }, 563 - "sade@1.8.1": { 564 - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", 565 - "dependencies": [ 566 - "mri" 567 - ] 568 - }, 569 - "source-map-js@1.2.1": { 570 - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" 571 - }, 572 - "svelte-check@4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3": { 573 - "integrity": "sha512-P7w/6tdSfk3zEVvfsgrp3h3DFC75jCdZjTQvgGJtjPORs1n7/v2VMPIoty3PWv7jnfEm3x0G/p9wH4pecTb0Wg==", 574 - "dependencies": [ 575 - "@jridgewell/trace-mapping", 576 - "chokidar", 577 - "fdir", 578 - "picocolors", 579 - "sade", 580 - "svelte", 581 - "typescript" 582 - ], 583 - "bin": true 584 - }, 585 - "svelte-infinite-loading@1.4.0": { 586 - "integrity": "sha512-Jo+f/yr/HmZQuIiiKKzAHVFXdAUWHW2RBbrcQTil8JVk1sCm/riy7KTJVzjBgQvHasrFQYKF84zvtc9/Y4lFYg==" 587 - }, 588 - "svelte@5.28.1_acorn@8.14.1": { 589 - "integrity": "sha512-iOa9WmfNG95lSOSJdMhdjJ4Afok7IRAQYXpbnxhd5EINnXseG0GVa9j6WPght4eX78XfFez45Fi+uRglGKPV/Q==", 590 - "dependencies": [ 591 - "@ampproject/remapping", 592 - "@jridgewell/sourcemap-codec", 593 - "@sveltejs/acorn-typescript", 594 - "@types/estree", 595 - "acorn", 596 - "aria-query", 597 - "axobject-query", 598 - "clsx", 599 - "esm-env", 600 - "esrap", 601 - "is-reference", 602 - "locate-character", 603 - "magic-string", 604 - "zimmerframe" 605 - ] 606 - }, 607 - "tinyglobby@0.2.13_picomatch@4.0.2": { 608 - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", 609 - "dependencies": [ 610 - "fdir", 611 - "picomatch" 612 - ] 613 - }, 614 - "tlds@1.260.0": { 615 - "integrity": "sha512-78+28EWBhCEE7qlyaHA9OR3IPvbCLiDh3Ckla593TksfFc9vfTsgvH7eS+dr3o9qr31gwGbogcI16yN91PoRjQ==", 616 - "bin": true 617 - }, 618 - "typescript@5.7.3": { 619 - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", 620 - "bin": true 621 - }, 622 - "uint8arrays@3.0.0": { 623 - "integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==", 624 - "dependencies": [ 625 - "multiformats" 626 - ] 627 - }, 628 - "vite@6.3.2_picomatch@4.0.2": { 629 - "integrity": "sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==", 630 - "dependencies": [ 631 - "esbuild", 632 - "fdir", 633 - "picomatch", 634 - "postcss", 635 - "rollup", 636 - "tinyglobby" 637 - ], 638 - "optionalDependencies": [ 639 - "fsevents" 640 - ], 641 - "bin": true 642 - }, 643 - "vitefu@1.0.6_vite@6.3.2__picomatch@4.0.2": { 644 - "integrity": "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==", 645 - "dependencies": [ 646 - "vite" 647 - ], 648 - "optionalPeers": [ 649 - "vite" 650 - ] 651 - }, 652 - "zimmerframe@1.1.2": { 653 - "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==" 654 - }, 655 - "zod@3.25.76": { 656 - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==" 657 - } 658 - }, 659 - "workspace": { 660 - "packageJson": { 661 - "dependencies": [ 662 - "npm:@atcute/bluesky@^2.0.2", 663 - "npm:@atcute/client@^3.0.1", 664 - "npm:@atcute/identity-resolver@~0.1.2", 665 - "npm:@atproto/api@~0.16.9", 666 - "npm:@sveltejs/vite-plugin-svelte@^5.0.3", 667 - "npm:@tsconfig/svelte@^5.0.4", 668 - "npm:hls.js@^1.6.12", 669 - "npm:moment@^2.30.1", 670 - "npm:mutex-ts@^1.2.1", 671 - "npm:svelte-check@^4.1.5", 672 - "npm:svelte-infinite-loading@^1.4.0", 673 - "npm:svelte@^5.23.1", 674 - "npm:typescript@~5.7.2", 675 - "npm:vite@^6.3.1" 676 - ] 677 - } 678 - } 679 - }
+11
docker-compose.yml
··· 1 + services: 2 + pds-dash: 3 + build: . 4 + environment: 5 + - PORT=8081 6 + - PUBLIC_PDS_URL=https://selfhosted.social 7 + - PUBLIC_FRONTEND_URL=https://bsky.app 8 + - PUBLIC_MAX_POSTS=10 9 + - PUBLIC_SHOW_FUTURE_POSTS=false 10 + ports: 11 + - "8081:8081"
+44
eslint.config.js
··· 1 + 2 + import {fileURLToPath} from 'node:url'; 3 + import {includeIgnoreFile} from '@eslint/compat'; 4 + import js from '@eslint/js'; 5 + import svelte from 'eslint-plugin-svelte'; 6 + import {defineConfig} from 'eslint/config'; 7 + import globals from 'globals'; 8 + import ts from 'typescript-eslint'; 9 + import svelteConfig from './svelte.config.js'; 10 + 11 + const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url)); 12 + 13 + export default defineConfig( 14 + includeIgnoreFile(gitignorePath), 15 + js.configs.recommended, 16 + ...ts.configs.recommended, 17 + ...svelte.configs.recommended, 18 + { 19 + languageOptions: { 20 + globals: {...globals.browser, ...globals.node} 21 + }, 22 + rules: { // typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects. 23 + // see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors 24 + 'no-undef': 'off', 25 + 'quotes': ['error', 'single'], 26 + 27 + } 28 + }, 29 + { 30 + files: [ 31 + '**/*.svelte', 32 + '**/*.svelte.ts', 33 + '**/*.svelte.js' 34 + ], 35 + languageOptions: { 36 + parserOptions: { 37 + projectService: true, 38 + extraFileExtensions: ['.svelte'], 39 + parser: ts.parser, 40 + svelteConfig 41 + } 42 + } 43 + } 44 + );
+6
justfile
··· 1 + release: 2 + #Web 3 + docker buildx build \ 4 + --platform linux/arm64,linux/amd64 \ 5 + --tag fatfingers23/selfhosted-dash:latest \ 6 + --push .
+13 -3
package.json
··· 4 4 "version": "0.0.0", 5 5 "type": "module", 6 6 "scripts": { 7 - "dev": "vite", 7 + "dev": "vite dev", 8 8 "build": "vite build", 9 9 "preview": "vite preview", 10 - "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json" 10 + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.app.json" 11 11 }, 12 12 "dependencies": { 13 13 "@atcute/bluesky": "^2.0.2", 14 14 "@atcute/client": "^3.0.1", 15 15 "@atcute/identity-resolver": "^0.1.2", 16 16 "@atproto/api": "^0.16.9", 17 + "@eslint/compat": "^2.0.0", 18 + "@eslint/js": "^9.39.1", 19 + "@sinclair/typebox": "^0.34.41", 20 + "globals": "^16.5.0", 17 21 "hls.js": "^1.6.12", 18 22 "moment": "^2.30.1", 19 23 "mutex-ts": "^1.2.1", 20 - "svelte-infinite-loading": "^1.4.0" 24 + "sqlite-cache": "^0.0.2", 25 + "svelte-infinite-loading": "^1.4.0", 26 + "typescript-eslint": "^8.48.0" 21 27 }, 22 28 "devDependencies": { 29 + "@sveltejs/adapter-node": "^5.4.0", 30 + "@sveltejs/kit": "^2.49.0", 23 31 "@sveltejs/vite-plugin-svelte": "^5.0.3", 24 32 "@tsconfig/svelte": "^5.0.4", 33 + "eslint": "^9.36.0", 34 + "eslint-plugin-svelte": "^3.12.4", 25 35 "svelte": "^5.23.1", 26 36 "svelte-check": "^4.1.5", 27 37 "typescript": "~5.7.2",
+2458
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/bluesky': 12 + specifier: ^2.0.2 13 + version: 2.1.1(@atcute/client@3.1.0) 14 + '@atcute/client': 15 + specifier: ^3.0.1 16 + version: 3.1.0 17 + '@atcute/identity-resolver': 18 + specifier: ^0.1.2 19 + version: 0.1.2(@atcute/identity@1.1.3) 20 + '@atproto/api': 21 + specifier: ^0.16.9 22 + version: 0.16.11 23 + '@eslint/compat': 24 + specifier: ^2.0.0 25 + version: 2.0.0(eslint@9.39.1) 26 + '@eslint/js': 27 + specifier: ^9.39.1 28 + version: 9.39.1 29 + '@sinclair/typebox': 30 + specifier: ^0.34.41 31 + version: 0.34.41 32 + globals: 33 + specifier: ^16.5.0 34 + version: 16.5.0 35 + hls.js: 36 + specifier: ^1.6.12 37 + version: 1.6.15 38 + moment: 39 + specifier: ^2.30.1 40 + version: 2.30.1 41 + mutex-ts: 42 + specifier: ^1.2.1 43 + version: 1.2.1 44 + sqlite-cache: 45 + specifier: ^0.0.2 46 + version: 0.0.2 47 + svelte-infinite-loading: 48 + specifier: ^1.4.0 49 + version: 1.4.0 50 + typescript-eslint: 51 + specifier: ^8.48.0 52 + version: 8.48.0(eslint@9.39.1)(typescript@5.7.3) 53 + devDependencies: 54 + '@sveltejs/adapter-node': 55 + specifier: ^5.4.0 56 + version: 5.4.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.2)(vite@6.4.1))(svelte@5.45.2)(vite@6.4.1)) 57 + '@sveltejs/kit': 58 + specifier: ^2.49.0 59 + version: 2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.2)(vite@6.4.1))(svelte@5.45.2)(vite@6.4.1) 60 + '@sveltejs/vite-plugin-svelte': 61 + specifier: ^5.0.3 62 + version: 5.1.1(svelte@5.45.2)(vite@6.4.1) 63 + '@tsconfig/svelte': 64 + specifier: ^5.0.4 65 + version: 5.0.6 66 + eslint: 67 + specifier: ^9.36.0 68 + version: 9.39.1 69 + eslint-plugin-svelte: 70 + specifier: ^3.12.4 71 + version: 3.13.0(eslint@9.39.1)(svelte@5.45.2) 72 + svelte: 73 + specifier: ^5.23.1 74 + version: 5.45.2 75 + svelte-check: 76 + specifier: ^4.1.5 77 + version: 4.3.4(picomatch@4.0.3)(svelte@5.45.2)(typescript@5.7.3) 78 + typescript: 79 + specifier: ~5.7.2 80 + version: 5.7.3 81 + vite: 82 + specifier: ^6.3.1 83 + version: 6.4.1 84 + 85 + packages: 86 + 87 + '@atcute/bluesky@2.1.1': 88 + resolution: {integrity: sha512-wEZfFW58J6yC1SqHcVJOn4qbHENTTzjeCEWthRT5HvKovADLqk54HSMSAuXDMBUbintSTBr0khQNZQ3ZdgzDdQ==} 89 + peerDependencies: 90 + '@atcute/client': ^3.0.0 91 + 92 + '@atcute/client@3.1.0': 93 + resolution: {integrity: sha512-+rQPsHXSf0DUm8XoHoaH7Y2E8tIpbsW84djyPj7dqAyrFIjvGuJ1X1DvMufwbTIcmLerdy+dzl34iZcz/h3Vhg==} 94 + 95 + '@atcute/identity-resolver@0.1.2': 96 + resolution: {integrity: sha512-fP2VbHD04kVcCdNi/Kszo6jFzqM7Pg3p33oGhfp2zVkwFKaVBlwCaFRWEga/Xvu/IDLwNdASGWnLqoA34SFeSg==} 97 + peerDependencies: 98 + '@atcute/identity': ^0.1.0 99 + 100 + '@atcute/identity@1.1.3': 101 + resolution: {integrity: sha512-oIqPoI8TwWeQxvcLmFEZLdN2XdWcaLVtlm8pNk0E72As9HNzzD9pwKPrLr3rmTLRIoULPPFmq9iFNsTeCIU9ng==} 102 + 103 + '@atcute/lexicons@1.2.5': 104 + resolution: {integrity: sha512-9yO9WdgxW8jZ7SbzUycH710z+JmsQ9W9n5S6i6eghYju32kkluFmgBeS47r8e8p2+Dv4DemS7o/3SUGsX9FR5Q==} 105 + 106 + '@atcute/util-fetch@1.0.4': 107 + resolution: {integrity: sha512-sIU9Qk0dE8PLEXSfhy+gIJV+HpiiknMytCI2SqLlqd0vgZUtEKI/EQfP+23LHWvP+CLCzVDOa6cpH045OlmNBg==} 108 + 109 + '@atproto/api@0.16.11': 110 + resolution: {integrity: sha512-1dhfQNHiclb102RW+Ea8Nft5olfqU0Ev/vlQaSX6mWNo1aP5zT+sPODJ8+BTUOYk3vcuvL7QMkqA/rLYy2PMyw==} 111 + 112 + '@atproto/common-web@0.4.5': 113 + resolution: {integrity: sha512-Tx0xUafLm3vRvOQpbBl5eb9V8xlC7TaRXs6dAulHRkDG3Kb+P9qn3pkDteq+aeMshbVXbVa1rm3Ok4vFyuoyYA==} 114 + 115 + '@atproto/lex-data@0.0.1': 116 + resolution: {integrity: sha512-DrS/8cQcQs3s5t9ELAFNtyDZ8/PdiCx47ALtFEP2GnX2uCBHZRkqWG7xmu6ehjc787nsFzZBvlnz3T/gov5fGA==} 117 + 118 + '@atproto/lex-json@0.0.1': 119 + resolution: {integrity: sha512-ivcF7+pDRuD/P97IEKQ/9TruunXj0w58Khvwk3M6psaI5eZT6LRsRZ4cWcKaXiFX4SHnjy+x43g0f7pPtIsERg==} 120 + 121 + '@atproto/lexicon@0.5.2': 122 + resolution: {integrity: sha512-lRmJgMA8f5j7VB5Iu5cp188ald5FuI4FlmZ7nn6EBrk1dgOstWVrI5Ft6K3z2vjyLZRG6nzknlsw+tDP63p7bQ==} 123 + 124 + '@atproto/syntax@0.4.1': 125 + resolution: {integrity: sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw==} 126 + 127 + '@atproto/xrpc@0.7.6': 128 + resolution: {integrity: sha512-RvCf4j0JnKYWuz3QzsYCntJi3VuiAAybQsMIUw2wLWcHhchO9F7UaBZINLL2z0qc/cYWPv5NSwcVydMseoCZLA==} 129 + 130 + '@badrap/valita@0.4.6': 131 + resolution: {integrity: sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==} 132 + engines: {node: '>= 18'} 133 + 134 + '@esbuild/aix-ppc64@0.25.12': 135 + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} 136 + engines: {node: '>=18'} 137 + cpu: [ppc64] 138 + os: [aix] 139 + 140 + '@esbuild/android-arm64@0.25.12': 141 + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} 142 + engines: {node: '>=18'} 143 + cpu: [arm64] 144 + os: [android] 145 + 146 + '@esbuild/android-arm@0.25.12': 147 + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} 148 + engines: {node: '>=18'} 149 + cpu: [arm] 150 + os: [android] 151 + 152 + '@esbuild/android-x64@0.25.12': 153 + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} 154 + engines: {node: '>=18'} 155 + cpu: [x64] 156 + os: [android] 157 + 158 + '@esbuild/darwin-arm64@0.25.12': 159 + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} 160 + engines: {node: '>=18'} 161 + cpu: [arm64] 162 + os: [darwin] 163 + 164 + '@esbuild/darwin-x64@0.25.12': 165 + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} 166 + engines: {node: '>=18'} 167 + cpu: [x64] 168 + os: [darwin] 169 + 170 + '@esbuild/freebsd-arm64@0.25.12': 171 + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} 172 + engines: {node: '>=18'} 173 + cpu: [arm64] 174 + os: [freebsd] 175 + 176 + '@esbuild/freebsd-x64@0.25.12': 177 + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} 178 + engines: {node: '>=18'} 179 + cpu: [x64] 180 + os: [freebsd] 181 + 182 + '@esbuild/linux-arm64@0.25.12': 183 + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} 184 + engines: {node: '>=18'} 185 + cpu: [arm64] 186 + os: [linux] 187 + 188 + '@esbuild/linux-arm@0.25.12': 189 + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} 190 + engines: {node: '>=18'} 191 + cpu: [arm] 192 + os: [linux] 193 + 194 + '@esbuild/linux-ia32@0.25.12': 195 + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} 196 + engines: {node: '>=18'} 197 + cpu: [ia32] 198 + os: [linux] 199 + 200 + '@esbuild/linux-loong64@0.25.12': 201 + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} 202 + engines: {node: '>=18'} 203 + cpu: [loong64] 204 + os: [linux] 205 + 206 + '@esbuild/linux-mips64el@0.25.12': 207 + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} 208 + engines: {node: '>=18'} 209 + cpu: [mips64el] 210 + os: [linux] 211 + 212 + '@esbuild/linux-ppc64@0.25.12': 213 + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} 214 + engines: {node: '>=18'} 215 + cpu: [ppc64] 216 + os: [linux] 217 + 218 + '@esbuild/linux-riscv64@0.25.12': 219 + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} 220 + engines: {node: '>=18'} 221 + cpu: [riscv64] 222 + os: [linux] 223 + 224 + '@esbuild/linux-s390x@0.25.12': 225 + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} 226 + engines: {node: '>=18'} 227 + cpu: [s390x] 228 + os: [linux] 229 + 230 + '@esbuild/linux-x64@0.25.12': 231 + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} 232 + engines: {node: '>=18'} 233 + cpu: [x64] 234 + os: [linux] 235 + 236 + '@esbuild/netbsd-arm64@0.25.12': 237 + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} 238 + engines: {node: '>=18'} 239 + cpu: [arm64] 240 + os: [netbsd] 241 + 242 + '@esbuild/netbsd-x64@0.25.12': 243 + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} 244 + engines: {node: '>=18'} 245 + cpu: [x64] 246 + os: [netbsd] 247 + 248 + '@esbuild/openbsd-arm64@0.25.12': 249 + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} 250 + engines: {node: '>=18'} 251 + cpu: [arm64] 252 + os: [openbsd] 253 + 254 + '@esbuild/openbsd-x64@0.25.12': 255 + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} 256 + engines: {node: '>=18'} 257 + cpu: [x64] 258 + os: [openbsd] 259 + 260 + '@esbuild/openharmony-arm64@0.25.12': 261 + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} 262 + engines: {node: '>=18'} 263 + cpu: [arm64] 264 + os: [openharmony] 265 + 266 + '@esbuild/sunos-x64@0.25.12': 267 + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} 268 + engines: {node: '>=18'} 269 + cpu: [x64] 270 + os: [sunos] 271 + 272 + '@esbuild/win32-arm64@0.25.12': 273 + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} 274 + engines: {node: '>=18'} 275 + cpu: [arm64] 276 + os: [win32] 277 + 278 + '@esbuild/win32-ia32@0.25.12': 279 + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} 280 + engines: {node: '>=18'} 281 + cpu: [ia32] 282 + os: [win32] 283 + 284 + '@esbuild/win32-x64@0.25.12': 285 + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} 286 + engines: {node: '>=18'} 287 + cpu: [x64] 288 + os: [win32] 289 + 290 + '@eslint-community/eslint-utils@4.9.0': 291 + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} 292 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 293 + peerDependencies: 294 + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 295 + 296 + '@eslint-community/regexpp@4.12.2': 297 + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} 298 + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 299 + 300 + '@eslint/compat@2.0.0': 301 + resolution: {integrity: sha512-T9AfE1G1uv4wwq94ozgTGio5EUQBqAVe1X9qsQtSNVEYW6j3hvtZVm8Smr4qL1qDPFg+lOB2cL5RxTRMzq4CTA==} 302 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 303 + peerDependencies: 304 + eslint: ^8.40 || 9 305 + peerDependenciesMeta: 306 + eslint: 307 + optional: true 308 + 309 + '@eslint/config-array@0.21.1': 310 + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} 311 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 312 + 313 + '@eslint/config-helpers@0.4.2': 314 + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} 315 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 316 + 317 + '@eslint/core@0.17.0': 318 + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} 319 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 320 + 321 + '@eslint/core@1.0.0': 322 + resolution: {integrity: sha512-PRfWP+8FOldvbApr6xL7mNCw4cJcSTq4GA7tYbgq15mRb0kWKO/wEB2jr+uwjFH3sZvEZneZyCUGTxsv4Sahyw==} 323 + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 324 + 325 + '@eslint/eslintrc@3.3.3': 326 + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} 327 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 328 + 329 + '@eslint/js@9.39.1': 330 + resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} 331 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 332 + 333 + '@eslint/object-schema@2.1.7': 334 + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} 335 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 336 + 337 + '@eslint/plugin-kit@0.4.1': 338 + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} 339 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 340 + 341 + '@fastify/merge-json-schemas@0.2.1': 342 + resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==} 343 + 344 + '@humanfs/core@0.19.1': 345 + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} 346 + engines: {node: '>=18.18.0'} 347 + 348 + '@humanfs/node@0.16.7': 349 + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} 350 + engines: {node: '>=18.18.0'} 351 + 352 + '@humanwhocodes/module-importer@1.0.1': 353 + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 354 + engines: {node: '>=12.22'} 355 + 356 + '@humanwhocodes/retry@0.4.3': 357 + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} 358 + engines: {node: '>=18.18'} 359 + 360 + '@jridgewell/gen-mapping@0.3.13': 361 + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} 362 + 363 + '@jridgewell/remapping@2.3.5': 364 + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} 365 + 366 + '@jridgewell/resolve-uri@3.1.2': 367 + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 368 + engines: {node: '>=6.0.0'} 369 + 370 + '@jridgewell/sourcemap-codec@1.5.5': 371 + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} 372 + 373 + '@jridgewell/trace-mapping@0.3.31': 374 + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} 375 + 376 + '@polka/url@1.0.0-next.29': 377 + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} 378 + 379 + '@rollup/plugin-commonjs@28.0.9': 380 + resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==} 381 + engines: {node: '>=16.0.0 || 14 >= 14.17'} 382 + peerDependencies: 383 + rollup: ^2.68.0||^3.0.0||^4.0.0 384 + peerDependenciesMeta: 385 + rollup: 386 + optional: true 387 + 388 + '@rollup/plugin-json@6.1.0': 389 + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} 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/plugin-node-resolve@16.0.3': 398 + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} 399 + engines: {node: '>=14.0.0'} 400 + peerDependencies: 401 + rollup: ^2.78.0||^3.0.0||^4.0.0 402 + peerDependenciesMeta: 403 + rollup: 404 + optional: true 405 + 406 + '@rollup/pluginutils@5.3.0': 407 + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} 408 + engines: {node: '>=14.0.0'} 409 + peerDependencies: 410 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 411 + peerDependenciesMeta: 412 + rollup: 413 + optional: true 414 + 415 + '@rollup/rollup-android-arm-eabi@4.53.3': 416 + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} 417 + cpu: [arm] 418 + os: [android] 419 + 420 + '@rollup/rollup-android-arm64@4.53.3': 421 + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} 422 + cpu: [arm64] 423 + os: [android] 424 + 425 + '@rollup/rollup-darwin-arm64@4.53.3': 426 + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} 427 + cpu: [arm64] 428 + os: [darwin] 429 + 430 + '@rollup/rollup-darwin-x64@4.53.3': 431 + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} 432 + cpu: [x64] 433 + os: [darwin] 434 + 435 + '@rollup/rollup-freebsd-arm64@4.53.3': 436 + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} 437 + cpu: [arm64] 438 + os: [freebsd] 439 + 440 + '@rollup/rollup-freebsd-x64@4.53.3': 441 + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} 442 + cpu: [x64] 443 + os: [freebsd] 444 + 445 + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': 446 + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} 447 + cpu: [arm] 448 + os: [linux] 449 + 450 + '@rollup/rollup-linux-arm-musleabihf@4.53.3': 451 + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} 452 + cpu: [arm] 453 + os: [linux] 454 + 455 + '@rollup/rollup-linux-arm64-gnu@4.53.3': 456 + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} 457 + cpu: [arm64] 458 + os: [linux] 459 + 460 + '@rollup/rollup-linux-arm64-musl@4.53.3': 461 + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} 462 + cpu: [arm64] 463 + os: [linux] 464 + 465 + '@rollup/rollup-linux-loong64-gnu@4.53.3': 466 + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} 467 + cpu: [loong64] 468 + os: [linux] 469 + 470 + '@rollup/rollup-linux-ppc64-gnu@4.53.3': 471 + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} 472 + cpu: [ppc64] 473 + os: [linux] 474 + 475 + '@rollup/rollup-linux-riscv64-gnu@4.53.3': 476 + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} 477 + cpu: [riscv64] 478 + os: [linux] 479 + 480 + '@rollup/rollup-linux-riscv64-musl@4.53.3': 481 + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} 482 + cpu: [riscv64] 483 + os: [linux] 484 + 485 + '@rollup/rollup-linux-s390x-gnu@4.53.3': 486 + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} 487 + cpu: [s390x] 488 + os: [linux] 489 + 490 + '@rollup/rollup-linux-x64-gnu@4.53.3': 491 + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} 492 + cpu: [x64] 493 + os: [linux] 494 + 495 + '@rollup/rollup-linux-x64-musl@4.53.3': 496 + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} 497 + cpu: [x64] 498 + os: [linux] 499 + 500 + '@rollup/rollup-openharmony-arm64@4.53.3': 501 + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} 502 + cpu: [arm64] 503 + os: [openharmony] 504 + 505 + '@rollup/rollup-win32-arm64-msvc@4.53.3': 506 + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} 507 + cpu: [arm64] 508 + os: [win32] 509 + 510 + '@rollup/rollup-win32-ia32-msvc@4.53.3': 511 + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} 512 + cpu: [ia32] 513 + os: [win32] 514 + 515 + '@rollup/rollup-win32-x64-gnu@4.53.3': 516 + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} 517 + cpu: [x64] 518 + os: [win32] 519 + 520 + '@rollup/rollup-win32-x64-msvc@4.53.3': 521 + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} 522 + cpu: [x64] 523 + os: [win32] 524 + 525 + '@sinclair/typebox@0.34.41': 526 + resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==} 527 + 528 + '@standard-schema/spec@1.0.0': 529 + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} 530 + 531 + '@sveltejs/acorn-typescript@1.0.8': 532 + resolution: {integrity: sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==} 533 + peerDependencies: 534 + acorn: ^8.9.0 535 + 536 + '@sveltejs/adapter-node@5.4.0': 537 + resolution: {integrity: sha512-NMsrwGVPEn+J73zH83Uhss/hYYZN6zT3u31R3IHAn3MiKC3h8fjmIAhLfTSOeNHr5wPYfjjMg8E+1gyFgyrEcQ==} 538 + peerDependencies: 539 + '@sveltejs/kit': ^2.4.0 540 + 541 + '@sveltejs/kit@2.49.0': 542 + resolution: {integrity: sha512-oH8tXw7EZnie8FdOWYrF7Yn4IKrqTFHhXvl8YxXxbKwTMcD/5NNCryUSEXRk2ZR4ojnub0P8rNrsVGHXWqIDtA==} 543 + engines: {node: '>=18.13'} 544 + hasBin: true 545 + peerDependencies: 546 + '@opentelemetry/api': ^1.0.0 547 + '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 548 + svelte: ^4.0.0 || ^5.0.0-next.0 549 + vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 550 + peerDependenciesMeta: 551 + '@opentelemetry/api': 552 + optional: true 553 + 554 + '@sveltejs/vite-plugin-svelte-inspector@4.0.1': 555 + resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==} 556 + engines: {node: ^18.0.0 || ^20.0.0 || >=22} 557 + peerDependencies: 558 + '@sveltejs/vite-plugin-svelte': ^5.0.0 559 + svelte: ^5.0.0 560 + vite: ^6.0.0 561 + 562 + '@sveltejs/vite-plugin-svelte@5.1.1': 563 + resolution: {integrity: sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==} 564 + engines: {node: ^18.0.0 || ^20.0.0 || >=22} 565 + peerDependencies: 566 + svelte: ^5.0.0 567 + vite: ^6.0.0 568 + 569 + '@tsconfig/svelte@5.0.6': 570 + resolution: {integrity: sha512-yGxYL0I9eETH1/DR9qVJey4DAsCdeau4a9wYPKuXfEhm8lFO8wg+LLYJjIpAm6Fw7HSlhepPhYPDop75485yWQ==} 571 + 572 + '@types/cookie@0.6.0': 573 + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} 574 + 575 + '@types/estree@1.0.8': 576 + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 577 + 578 + '@types/json-schema@7.0.15': 579 + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 580 + 581 + '@types/resolve@1.20.2': 582 + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} 583 + 584 + '@typescript-eslint/eslint-plugin@8.48.0': 585 + resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==} 586 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 587 + peerDependencies: 588 + '@typescript-eslint/parser': ^8.48.0 589 + eslint: ^8.57.0 || ^9.0.0 590 + typescript: '>=4.8.4 <6.0.0' 591 + 592 + '@typescript-eslint/parser@8.48.0': 593 + resolution: {integrity: sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==} 594 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 595 + peerDependencies: 596 + eslint: ^8.57.0 || ^9.0.0 597 + typescript: '>=4.8.4 <6.0.0' 598 + 599 + '@typescript-eslint/project-service@8.48.0': 600 + resolution: {integrity: sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==} 601 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 602 + peerDependencies: 603 + typescript: '>=4.8.4 <6.0.0' 604 + 605 + '@typescript-eslint/scope-manager@8.48.0': 606 + resolution: {integrity: sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==} 607 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 608 + 609 + '@typescript-eslint/tsconfig-utils@8.48.0': 610 + resolution: {integrity: sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==} 611 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 612 + peerDependencies: 613 + typescript: '>=4.8.4 <6.0.0' 614 + 615 + '@typescript-eslint/type-utils@8.48.0': 616 + resolution: {integrity: sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==} 617 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 618 + peerDependencies: 619 + eslint: ^8.57.0 || ^9.0.0 620 + typescript: '>=4.8.4 <6.0.0' 621 + 622 + '@typescript-eslint/types@8.48.0': 623 + resolution: {integrity: sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==} 624 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 625 + 626 + '@typescript-eslint/typescript-estree@8.48.0': 627 + resolution: {integrity: sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==} 628 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 629 + peerDependencies: 630 + typescript: '>=4.8.4 <6.0.0' 631 + 632 + '@typescript-eslint/utils@8.48.0': 633 + resolution: {integrity: sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==} 634 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 635 + peerDependencies: 636 + eslint: ^8.57.0 || ^9.0.0 637 + typescript: '>=4.8.4 <6.0.0' 638 + 639 + '@typescript-eslint/visitor-keys@8.48.0': 640 + resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==} 641 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 642 + 643 + acorn-jsx@5.3.2: 644 + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 645 + peerDependencies: 646 + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 647 + 648 + acorn@8.15.0: 649 + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} 650 + engines: {node: '>=0.4.0'} 651 + hasBin: true 652 + 653 + ajv-formats@3.0.1: 654 + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} 655 + peerDependencies: 656 + ajv: ^8.0.0 657 + peerDependenciesMeta: 658 + ajv: 659 + optional: true 660 + 661 + ajv@6.12.6: 662 + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 663 + 664 + ajv@8.17.1: 665 + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} 666 + 667 + ansi-styles@4.3.0: 668 + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 669 + engines: {node: '>=8'} 670 + 671 + argparse@2.0.1: 672 + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 673 + 674 + aria-query@5.3.2: 675 + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} 676 + engines: {node: '>= 0.4'} 677 + 678 + await-lock@2.2.2: 679 + resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==} 680 + 681 + axobject-query@4.1.0: 682 + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} 683 + engines: {node: '>= 0.4'} 684 + 685 + balanced-match@1.0.2: 686 + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 687 + 688 + brace-expansion@1.1.12: 689 + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} 690 + 691 + brace-expansion@2.0.2: 692 + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} 693 + 694 + callsites@3.1.0: 695 + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 696 + engines: {node: '>=6'} 697 + 698 + chalk@4.1.2: 699 + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 700 + engines: {node: '>=10'} 701 + 702 + chokidar@4.0.3: 703 + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 704 + engines: {node: '>= 14.16.0'} 705 + 706 + clsx@2.1.1: 707 + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} 708 + engines: {node: '>=6'} 709 + 710 + color-convert@2.0.1: 711 + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 712 + engines: {node: '>=7.0.0'} 713 + 714 + color-name@1.1.4: 715 + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 716 + 717 + colorette@2.0.20: 718 + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} 719 + 720 + commondir@1.0.1: 721 + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} 722 + 723 + concat-map@0.0.1: 724 + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 725 + 726 + cookie@0.6.0: 727 + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} 728 + engines: {node: '>= 0.6'} 729 + 730 + cross-spawn@7.0.6: 731 + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 732 + engines: {node: '>= 8'} 733 + 734 + cssesc@3.0.0: 735 + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 736 + engines: {node: '>=4'} 737 + hasBin: true 738 + 739 + debug@4.4.3: 740 + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} 741 + engines: {node: '>=6.0'} 742 + peerDependencies: 743 + supports-color: '*' 744 + peerDependenciesMeta: 745 + supports-color: 746 + optional: true 747 + 748 + deep-is@0.1.4: 749 + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 750 + 751 + deepmerge@4.3.1: 752 + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 753 + engines: {node: '>=0.10.0'} 754 + 755 + dequal@2.0.3: 756 + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} 757 + engines: {node: '>=6'} 758 + 759 + devalue@5.5.0: 760 + resolution: {integrity: sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==} 761 + 762 + esbuild@0.25.12: 763 + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} 764 + engines: {node: '>=18'} 765 + hasBin: true 766 + 767 + escape-string-regexp@4.0.0: 768 + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 769 + engines: {node: '>=10'} 770 + 771 + eslint-plugin-svelte@3.13.0: 772 + resolution: {integrity: sha512-2ohCCQJJTNbIpQCSDSTWj+FN0OVfPmSO03lmSNT7ytqMaWF6kpT86LdzDqtm4sh7TVPl/OEWJ/d7R87bXP2Vjg==} 773 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 774 + peerDependencies: 775 + eslint: ^8.57.1 || ^9.0.0 776 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 777 + peerDependenciesMeta: 778 + svelte: 779 + optional: true 780 + 781 + eslint-scope@8.4.0: 782 + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} 783 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 784 + 785 + eslint-visitor-keys@3.4.3: 786 + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 787 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 788 + 789 + eslint-visitor-keys@4.2.1: 790 + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} 791 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 792 + 793 + eslint@9.39.1: 794 + resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} 795 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 796 + hasBin: true 797 + peerDependencies: 798 + jiti: '*' 799 + peerDependenciesMeta: 800 + jiti: 801 + optional: true 802 + 803 + esm-env@1.2.2: 804 + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} 805 + 806 + espree@10.4.0: 807 + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} 808 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 809 + 810 + esquery@1.6.0: 811 + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} 812 + engines: {node: '>=0.10'} 813 + 814 + esrap@2.2.0: 815 + resolution: {integrity: sha512-WBmtxe7R9C5mvL4n2le8nMUe4mD5V9oiK2vJpQ9I3y20ENPUomPcphBXE8D1x/Bm84oN1V+lOfgXxtqmxTp3Xg==} 816 + 817 + esrecurse@4.3.0: 818 + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 819 + engines: {node: '>=4.0'} 820 + 821 + estraverse@5.3.0: 822 + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 823 + engines: {node: '>=4.0'} 824 + 825 + estree-walker@2.0.2: 826 + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 827 + 828 + esutils@2.0.3: 829 + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 830 + engines: {node: '>=0.10.0'} 831 + 832 + fast-deep-equal@3.1.3: 833 + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 834 + 835 + fast-json-stable-stringify@2.1.0: 836 + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 837 + 838 + fast-json-stringify@6.1.1: 839 + resolution: {integrity: sha512-DbgptncYEXZqDUOEl4krff4mUiVrTZZVI7BBrQR/T3BqMj/eM1flTC1Uk2uUoLcWCxjT95xKulV/Lc6hhOZsBQ==} 840 + 841 + fast-levenshtein@2.0.6: 842 + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 843 + 844 + fast-uri@3.1.0: 845 + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} 846 + 847 + fdir@6.5.0: 848 + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} 849 + engines: {node: '>=12.0.0'} 850 + peerDependencies: 851 + picomatch: ^3 || ^4 852 + peerDependenciesMeta: 853 + picomatch: 854 + optional: true 855 + 856 + file-entry-cache@8.0.0: 857 + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} 858 + engines: {node: '>=16.0.0'} 859 + 860 + find-up@5.0.0: 861 + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 862 + engines: {node: '>=10'} 863 + 864 + flat-cache@4.0.1: 865 + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} 866 + engines: {node: '>=16'} 867 + 868 + flatted@3.3.3: 869 + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} 870 + 871 + fsevents@2.3.3: 872 + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 873 + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 874 + os: [darwin] 875 + 876 + function-bind@1.1.2: 877 + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 878 + 879 + glob-parent@6.0.2: 880 + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 881 + engines: {node: '>=10.13.0'} 882 + 883 + globals@14.0.0: 884 + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} 885 + engines: {node: '>=18'} 886 + 887 + globals@16.5.0: 888 + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} 889 + engines: {node: '>=18'} 890 + 891 + graphemer@1.4.0: 892 + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 893 + 894 + has-flag@4.0.0: 895 + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 896 + engines: {node: '>=8'} 897 + 898 + hasown@2.0.2: 899 + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 900 + engines: {node: '>= 0.4'} 901 + 902 + hls.js@1.6.15: 903 + resolution: {integrity: sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==} 904 + 905 + ignore@5.3.2: 906 + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 907 + engines: {node: '>= 4'} 908 + 909 + ignore@7.0.5: 910 + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} 911 + engines: {node: '>= 4'} 912 + 913 + import-fresh@3.3.1: 914 + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} 915 + engines: {node: '>=6'} 916 + 917 + imurmurhash@0.1.4: 918 + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 919 + engines: {node: '>=0.8.19'} 920 + 921 + is-core-module@2.16.1: 922 + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} 923 + engines: {node: '>= 0.4'} 924 + 925 + is-extglob@2.1.1: 926 + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 927 + engines: {node: '>=0.10.0'} 928 + 929 + is-glob@4.0.3: 930 + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 931 + engines: {node: '>=0.10.0'} 932 + 933 + is-module@1.0.0: 934 + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} 935 + 936 + is-reference@1.2.1: 937 + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} 938 + 939 + is-reference@3.0.3: 940 + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} 941 + 942 + isexe@2.0.0: 943 + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 944 + 945 + iso-datestring-validator@2.2.2: 946 + resolution: {integrity: sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==} 947 + 948 + js-yaml@4.1.1: 949 + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} 950 + hasBin: true 951 + 952 + json-buffer@3.0.1: 953 + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 954 + 955 + json-schema-ref-resolver@3.0.0: 956 + resolution: {integrity: sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==} 957 + 958 + json-schema-traverse@0.4.1: 959 + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 960 + 961 + json-schema-traverse@1.0.0: 962 + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} 963 + 964 + json-stable-stringify-without-jsonify@1.0.1: 965 + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 966 + 967 + keyv@4.5.4: 968 + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 969 + 970 + kleur@4.1.5: 971 + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} 972 + engines: {node: '>=6'} 973 + 974 + known-css-properties@0.37.0: 975 + resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==} 976 + 977 + levn@0.4.1: 978 + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 979 + engines: {node: '>= 0.8.0'} 980 + 981 + lilconfig@2.1.0: 982 + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} 983 + engines: {node: '>=10'} 984 + 985 + locate-character@3.0.0: 986 + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} 987 + 988 + locate-path@6.0.0: 989 + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 990 + engines: {node: '>=10'} 991 + 992 + lodash.merge@4.6.2: 993 + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 994 + 995 + magic-string@0.30.21: 996 + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} 997 + 998 + minimatch@3.1.2: 999 + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1000 + 1001 + minimatch@9.0.5: 1002 + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 1003 + engines: {node: '>=16 || 14 >=14.17'} 1004 + 1005 + moment@2.30.1: 1006 + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} 1007 + 1008 + mri@1.2.0: 1009 + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} 1010 + engines: {node: '>=4'} 1011 + 1012 + mrmime@2.0.1: 1013 + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} 1014 + engines: {node: '>=10'} 1015 + 1016 + ms@2.1.3: 1017 + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1018 + 1019 + multiformats@9.9.0: 1020 + resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} 1021 + 1022 + mutex-ts@1.2.1: 1023 + resolution: {integrity: sha512-OkcXgf0viuCgYdnm48kiNQ9PzC5OzISQ261svHr/Ybc2vBYC/5xfLXn44hQ+dYRX74v7MCSqV/LKPEbpYdDybw==} 1024 + deprecated: deprecated in favor of async-ts 1025 + 1026 + nanoid@3.3.11: 1027 + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 1028 + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1029 + hasBin: true 1030 + 1031 + natural-compare@1.4.0: 1032 + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1033 + 1034 + optionator@0.9.4: 1035 + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} 1036 + engines: {node: '>= 0.8.0'} 1037 + 1038 + p-limit@3.1.0: 1039 + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1040 + engines: {node: '>=10'} 1041 + 1042 + p-locate@5.0.0: 1043 + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1044 + engines: {node: '>=10'} 1045 + 1046 + parent-module@1.0.1: 1047 + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1048 + engines: {node: '>=6'} 1049 + 1050 + path-exists@4.0.0: 1051 + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1052 + engines: {node: '>=8'} 1053 + 1054 + path-key@3.1.1: 1055 + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1056 + engines: {node: '>=8'} 1057 + 1058 + path-parse@1.0.7: 1059 + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 1060 + 1061 + picocolors@1.1.1: 1062 + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 1063 + 1064 + picomatch@4.0.3: 1065 + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} 1066 + engines: {node: '>=12'} 1067 + 1068 + postcss-load-config@3.1.4: 1069 + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} 1070 + engines: {node: '>= 10'} 1071 + peerDependencies: 1072 + postcss: '>=8.0.9' 1073 + ts-node: '>=9.0.0' 1074 + peerDependenciesMeta: 1075 + postcss: 1076 + optional: true 1077 + ts-node: 1078 + optional: true 1079 + 1080 + postcss-safe-parser@7.0.1: 1081 + resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} 1082 + engines: {node: '>=18.0'} 1083 + peerDependencies: 1084 + postcss: ^8.4.31 1085 + 1086 + postcss-scss@4.0.9: 1087 + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} 1088 + engines: {node: '>=12.0'} 1089 + peerDependencies: 1090 + postcss: ^8.4.29 1091 + 1092 + postcss-selector-parser@7.1.1: 1093 + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} 1094 + engines: {node: '>=4'} 1095 + 1096 + postcss@8.5.6: 1097 + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} 1098 + engines: {node: ^10 || ^12 || >=14} 1099 + 1100 + prelude-ls@1.2.1: 1101 + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1102 + engines: {node: '>= 0.8.0'} 1103 + 1104 + punycode@2.3.1: 1105 + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1106 + engines: {node: '>=6'} 1107 + 1108 + readdirp@4.1.2: 1109 + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} 1110 + engines: {node: '>= 14.18.0'} 1111 + 1112 + require-from-string@2.0.2: 1113 + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} 1114 + engines: {node: '>=0.10.0'} 1115 + 1116 + resolve-from@4.0.0: 1117 + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1118 + engines: {node: '>=4'} 1119 + 1120 + resolve@1.22.11: 1121 + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} 1122 + engines: {node: '>= 0.4'} 1123 + hasBin: true 1124 + 1125 + rfdc@1.4.1: 1126 + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} 1127 + 1128 + rollup@4.53.3: 1129 + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} 1130 + engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1131 + hasBin: true 1132 + 1133 + sade@1.8.1: 1134 + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} 1135 + engines: {node: '>=6'} 1136 + 1137 + semver@7.7.3: 1138 + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} 1139 + engines: {node: '>=10'} 1140 + hasBin: true 1141 + 1142 + set-cookie-parser@2.7.2: 1143 + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} 1144 + 1145 + shebang-command@2.0.0: 1146 + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1147 + engines: {node: '>=8'} 1148 + 1149 + shebang-regex@3.0.0: 1150 + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1151 + engines: {node: '>=8'} 1152 + 1153 + sirv@3.0.2: 1154 + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} 1155 + engines: {node: '>=18'} 1156 + 1157 + source-map-js@1.2.1: 1158 + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1159 + engines: {node: '>=0.10.0'} 1160 + 1161 + sqlite-cache@0.0.2: 1162 + resolution: {integrity: sha512-YEAIrCzfoBAnJ4Z92m9LsWbbYXMn1pjgOmEe0hhQOglp8uyQhGgHkuZQ+nCfgktoGTcEXghZy/3Ed1ziqe9LAg==} 1163 + 1164 + strip-json-comments@3.1.1: 1165 + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1166 + engines: {node: '>=8'} 1167 + 1168 + supports-color@7.2.0: 1169 + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1170 + engines: {node: '>=8'} 1171 + 1172 + supports-preserve-symlinks-flag@1.0.0: 1173 + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 1174 + engines: {node: '>= 0.4'} 1175 + 1176 + svelte-check@4.3.4: 1177 + resolution: {integrity: sha512-DVWvxhBrDsd+0hHWKfjP99lsSXASeOhHJYyuKOFYJcP7ThfSCKgjVarE8XfuMWpS5JV3AlDf+iK1YGGo2TACdw==} 1178 + engines: {node: '>= 18.0.0'} 1179 + hasBin: true 1180 + peerDependencies: 1181 + svelte: ^4.0.0 || ^5.0.0-next.0 1182 + typescript: '>=5.0.0' 1183 + 1184 + svelte-eslint-parser@1.4.0: 1185 + resolution: {integrity: sha512-fjPzOfipR5S7gQ/JvI9r2H8y9gMGXO3JtmrylHLLyahEMquXI0lrebcjT+9/hNgDej0H7abTyox5HpHmW1PSWA==} 1186 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: 10.18.3} 1187 + peerDependencies: 1188 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 1189 + peerDependenciesMeta: 1190 + svelte: 1191 + optional: true 1192 + 1193 + svelte-infinite-loading@1.4.0: 1194 + resolution: {integrity: sha512-Jo+f/yr/HmZQuIiiKKzAHVFXdAUWHW2RBbrcQTil8JVk1sCm/riy7KTJVzjBgQvHasrFQYKF84zvtc9/Y4lFYg==} 1195 + 1196 + svelte@5.45.2: 1197 + resolution: {integrity: sha512-yyXdW2u3H0H/zxxWoGwJoQlRgaSJLp+Vhktv12iRw2WRDlKqUPT54Fi0K/PkXqrdkcQ98aBazpy0AH4BCBVfoA==} 1198 + engines: {node: '>=18'} 1199 + 1200 + tinyglobby@0.2.15: 1201 + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} 1202 + engines: {node: '>=12.0.0'} 1203 + 1204 + tlds@1.261.0: 1205 + resolution: {integrity: sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==} 1206 + hasBin: true 1207 + 1208 + totalist@3.0.1: 1209 + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} 1210 + engines: {node: '>=6'} 1211 + 1212 + ts-api-utils@2.1.0: 1213 + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} 1214 + engines: {node: '>=18.12'} 1215 + peerDependencies: 1216 + typescript: '>=4.8.4' 1217 + 1218 + tslib@2.8.1: 1219 + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1220 + 1221 + type-check@0.4.0: 1222 + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 1223 + engines: {node: '>= 0.8.0'} 1224 + 1225 + typescript-eslint@8.48.0: 1226 + resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} 1227 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1228 + peerDependencies: 1229 + eslint: ^8.57.0 || ^9.0.0 1230 + typescript: '>=4.8.4 <6.0.0' 1231 + 1232 + typescript@5.7.3: 1233 + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} 1234 + engines: {node: '>=14.17'} 1235 + hasBin: true 1236 + 1237 + uint8arrays@3.0.0: 1238 + resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==} 1239 + 1240 + unicode-segmenter@0.14.0: 1241 + resolution: {integrity: sha512-AH4lhPCJANUnSLEKnM4byboctePJzltF4xj8b+NbNiYeAkAXGh7px2K/4NANFp7dnr6+zB3e6HLu8Jj8SKyvYg==} 1242 + 1243 + uri-js@4.4.1: 1244 + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1245 + 1246 + util-deprecate@1.0.2: 1247 + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 1248 + 1249 + vite@6.4.1: 1250 + resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} 1251 + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 1252 + hasBin: true 1253 + peerDependencies: 1254 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 1255 + jiti: '>=1.21.0' 1256 + less: '*' 1257 + lightningcss: ^1.21.0 1258 + sass: '*' 1259 + sass-embedded: '*' 1260 + stylus: '*' 1261 + sugarss: '*' 1262 + terser: ^5.16.0 1263 + tsx: ^4.8.1 1264 + yaml: ^2.4.2 1265 + peerDependenciesMeta: 1266 + '@types/node': 1267 + optional: true 1268 + jiti: 1269 + optional: true 1270 + less: 1271 + optional: true 1272 + lightningcss: 1273 + optional: true 1274 + sass: 1275 + optional: true 1276 + sass-embedded: 1277 + optional: true 1278 + stylus: 1279 + optional: true 1280 + sugarss: 1281 + optional: true 1282 + terser: 1283 + optional: true 1284 + tsx: 1285 + optional: true 1286 + yaml: 1287 + optional: true 1288 + 1289 + vitefu@1.1.1: 1290 + resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} 1291 + peerDependencies: 1292 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 1293 + peerDependenciesMeta: 1294 + vite: 1295 + optional: true 1296 + 1297 + which@2.0.2: 1298 + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1299 + engines: {node: '>= 8'} 1300 + hasBin: true 1301 + 1302 + word-wrap@1.2.5: 1303 + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} 1304 + engines: {node: '>=0.10.0'} 1305 + 1306 + yaml@1.10.2: 1307 + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} 1308 + engines: {node: '>= 6'} 1309 + 1310 + yocto-queue@0.1.0: 1311 + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 1312 + engines: {node: '>=10'} 1313 + 1314 + zimmerframe@1.1.4: 1315 + resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} 1316 + 1317 + zod@3.25.76: 1318 + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} 1319 + 1320 + snapshots: 1321 + 1322 + '@atcute/bluesky@2.1.1(@atcute/client@3.1.0)': 1323 + dependencies: 1324 + '@atcute/client': 3.1.0 1325 + 1326 + '@atcute/client@3.1.0': {} 1327 + 1328 + '@atcute/identity-resolver@0.1.2(@atcute/identity@1.1.3)': 1329 + dependencies: 1330 + '@atcute/identity': 1.1.3 1331 + '@atcute/util-fetch': 1.0.4 1332 + '@badrap/valita': 0.4.6 1333 + 1334 + '@atcute/identity@1.1.3': 1335 + dependencies: 1336 + '@atcute/lexicons': 1.2.5 1337 + '@badrap/valita': 0.4.6 1338 + 1339 + '@atcute/lexicons@1.2.5': 1340 + dependencies: 1341 + '@standard-schema/spec': 1.0.0 1342 + esm-env: 1.2.2 1343 + 1344 + '@atcute/util-fetch@1.0.4': 1345 + dependencies: 1346 + '@badrap/valita': 0.4.6 1347 + 1348 + '@atproto/api@0.16.11': 1349 + dependencies: 1350 + '@atproto/common-web': 0.4.5 1351 + '@atproto/lexicon': 0.5.2 1352 + '@atproto/syntax': 0.4.1 1353 + '@atproto/xrpc': 0.7.6 1354 + await-lock: 2.2.2 1355 + multiformats: 9.9.0 1356 + tlds: 1.261.0 1357 + zod: 3.25.76 1358 + 1359 + '@atproto/common-web@0.4.5': 1360 + dependencies: 1361 + '@atproto/lex-data': 0.0.1 1362 + '@atproto/lex-json': 0.0.1 1363 + zod: 3.25.76 1364 + 1365 + '@atproto/lex-data@0.0.1': 1366 + dependencies: 1367 + '@atproto/syntax': 0.4.1 1368 + multiformats: 9.9.0 1369 + tslib: 2.8.1 1370 + uint8arrays: 3.0.0 1371 + unicode-segmenter: 0.14.0 1372 + 1373 + '@atproto/lex-json@0.0.1': 1374 + dependencies: 1375 + '@atproto/lex-data': 0.0.1 1376 + tslib: 2.8.1 1377 + 1378 + '@atproto/lexicon@0.5.2': 1379 + dependencies: 1380 + '@atproto/common-web': 0.4.5 1381 + '@atproto/syntax': 0.4.1 1382 + iso-datestring-validator: 2.2.2 1383 + multiformats: 9.9.0 1384 + zod: 3.25.76 1385 + 1386 + '@atproto/syntax@0.4.1': {} 1387 + 1388 + '@atproto/xrpc@0.7.6': 1389 + dependencies: 1390 + '@atproto/lexicon': 0.5.2 1391 + zod: 3.25.76 1392 + 1393 + '@badrap/valita@0.4.6': {} 1394 + 1395 + '@esbuild/aix-ppc64@0.25.12': 1396 + optional: true 1397 + 1398 + '@esbuild/android-arm64@0.25.12': 1399 + optional: true 1400 + 1401 + '@esbuild/android-arm@0.25.12': 1402 + optional: true 1403 + 1404 + '@esbuild/android-x64@0.25.12': 1405 + optional: true 1406 + 1407 + '@esbuild/darwin-arm64@0.25.12': 1408 + optional: true 1409 + 1410 + '@esbuild/darwin-x64@0.25.12': 1411 + optional: true 1412 + 1413 + '@esbuild/freebsd-arm64@0.25.12': 1414 + optional: true 1415 + 1416 + '@esbuild/freebsd-x64@0.25.12': 1417 + optional: true 1418 + 1419 + '@esbuild/linux-arm64@0.25.12': 1420 + optional: true 1421 + 1422 + '@esbuild/linux-arm@0.25.12': 1423 + optional: true 1424 + 1425 + '@esbuild/linux-ia32@0.25.12': 1426 + optional: true 1427 + 1428 + '@esbuild/linux-loong64@0.25.12': 1429 + optional: true 1430 + 1431 + '@esbuild/linux-mips64el@0.25.12': 1432 + optional: true 1433 + 1434 + '@esbuild/linux-ppc64@0.25.12': 1435 + optional: true 1436 + 1437 + '@esbuild/linux-riscv64@0.25.12': 1438 + optional: true 1439 + 1440 + '@esbuild/linux-s390x@0.25.12': 1441 + optional: true 1442 + 1443 + '@esbuild/linux-x64@0.25.12': 1444 + optional: true 1445 + 1446 + '@esbuild/netbsd-arm64@0.25.12': 1447 + optional: true 1448 + 1449 + '@esbuild/netbsd-x64@0.25.12': 1450 + optional: true 1451 + 1452 + '@esbuild/openbsd-arm64@0.25.12': 1453 + optional: true 1454 + 1455 + '@esbuild/openbsd-x64@0.25.12': 1456 + optional: true 1457 + 1458 + '@esbuild/openharmony-arm64@0.25.12': 1459 + optional: true 1460 + 1461 + '@esbuild/sunos-x64@0.25.12': 1462 + optional: true 1463 + 1464 + '@esbuild/win32-arm64@0.25.12': 1465 + optional: true 1466 + 1467 + '@esbuild/win32-ia32@0.25.12': 1468 + optional: true 1469 + 1470 + '@esbuild/win32-x64@0.25.12': 1471 + optional: true 1472 + 1473 + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)': 1474 + dependencies: 1475 + eslint: 9.39.1 1476 + eslint-visitor-keys: 3.4.3 1477 + 1478 + '@eslint-community/regexpp@4.12.2': {} 1479 + 1480 + '@eslint/compat@2.0.0(eslint@9.39.1)': 1481 + dependencies: 1482 + '@eslint/core': 1.0.0 1483 + optionalDependencies: 1484 + eslint: 9.39.1 1485 + 1486 + '@eslint/config-array@0.21.1': 1487 + dependencies: 1488 + '@eslint/object-schema': 2.1.7 1489 + debug: 4.4.3 1490 + minimatch: 3.1.2 1491 + transitivePeerDependencies: 1492 + - supports-color 1493 + 1494 + '@eslint/config-helpers@0.4.2': 1495 + dependencies: 1496 + '@eslint/core': 0.17.0 1497 + 1498 + '@eslint/core@0.17.0': 1499 + dependencies: 1500 + '@types/json-schema': 7.0.15 1501 + 1502 + '@eslint/core@1.0.0': 1503 + dependencies: 1504 + '@types/json-schema': 7.0.15 1505 + 1506 + '@eslint/eslintrc@3.3.3': 1507 + dependencies: 1508 + ajv: 6.12.6 1509 + debug: 4.4.3 1510 + espree: 10.4.0 1511 + globals: 14.0.0 1512 + ignore: 5.3.2 1513 + import-fresh: 3.3.1 1514 + js-yaml: 4.1.1 1515 + minimatch: 3.1.2 1516 + strip-json-comments: 3.1.1 1517 + transitivePeerDependencies: 1518 + - supports-color 1519 + 1520 + '@eslint/js@9.39.1': {} 1521 + 1522 + '@eslint/object-schema@2.1.7': {} 1523 + 1524 + '@eslint/plugin-kit@0.4.1': 1525 + dependencies: 1526 + '@eslint/core': 0.17.0 1527 + levn: 0.4.1 1528 + 1529 + '@fastify/merge-json-schemas@0.2.1': 1530 + dependencies: 1531 + dequal: 2.0.3 1532 + 1533 + '@humanfs/core@0.19.1': {} 1534 + 1535 + '@humanfs/node@0.16.7': 1536 + dependencies: 1537 + '@humanfs/core': 0.19.1 1538 + '@humanwhocodes/retry': 0.4.3 1539 + 1540 + '@humanwhocodes/module-importer@1.0.1': {} 1541 + 1542 + '@humanwhocodes/retry@0.4.3': {} 1543 + 1544 + '@jridgewell/gen-mapping@0.3.13': 1545 + dependencies: 1546 + '@jridgewell/sourcemap-codec': 1.5.5 1547 + '@jridgewell/trace-mapping': 0.3.31 1548 + 1549 + '@jridgewell/remapping@2.3.5': 1550 + dependencies: 1551 + '@jridgewell/gen-mapping': 0.3.13 1552 + '@jridgewell/trace-mapping': 0.3.31 1553 + 1554 + '@jridgewell/resolve-uri@3.1.2': {} 1555 + 1556 + '@jridgewell/sourcemap-codec@1.5.5': {} 1557 + 1558 + '@jridgewell/trace-mapping@0.3.31': 1559 + dependencies: 1560 + '@jridgewell/resolve-uri': 3.1.2 1561 + '@jridgewell/sourcemap-codec': 1.5.5 1562 + 1563 + '@polka/url@1.0.0-next.29': {} 1564 + 1565 + '@rollup/plugin-commonjs@28.0.9(rollup@4.53.3)': 1566 + dependencies: 1567 + '@rollup/pluginutils': 5.3.0(rollup@4.53.3) 1568 + commondir: 1.0.1 1569 + estree-walker: 2.0.2 1570 + fdir: 6.5.0(picomatch@4.0.3) 1571 + is-reference: 1.2.1 1572 + magic-string: 0.30.21 1573 + picomatch: 4.0.3 1574 + optionalDependencies: 1575 + rollup: 4.53.3 1576 + 1577 + '@rollup/plugin-json@6.1.0(rollup@4.53.3)': 1578 + dependencies: 1579 + '@rollup/pluginutils': 5.3.0(rollup@4.53.3) 1580 + optionalDependencies: 1581 + rollup: 4.53.3 1582 + 1583 + '@rollup/plugin-node-resolve@16.0.3(rollup@4.53.3)': 1584 + dependencies: 1585 + '@rollup/pluginutils': 5.3.0(rollup@4.53.3) 1586 + '@types/resolve': 1.20.2 1587 + deepmerge: 4.3.1 1588 + is-module: 1.0.0 1589 + resolve: 1.22.11 1590 + optionalDependencies: 1591 + rollup: 4.53.3 1592 + 1593 + '@rollup/pluginutils@5.3.0(rollup@4.53.3)': 1594 + dependencies: 1595 + '@types/estree': 1.0.8 1596 + estree-walker: 2.0.2 1597 + picomatch: 4.0.3 1598 + optionalDependencies: 1599 + rollup: 4.53.3 1600 + 1601 + '@rollup/rollup-android-arm-eabi@4.53.3': 1602 + optional: true 1603 + 1604 + '@rollup/rollup-android-arm64@4.53.3': 1605 + optional: true 1606 + 1607 + '@rollup/rollup-darwin-arm64@4.53.3': 1608 + optional: true 1609 + 1610 + '@rollup/rollup-darwin-x64@4.53.3': 1611 + optional: true 1612 + 1613 + '@rollup/rollup-freebsd-arm64@4.53.3': 1614 + optional: true 1615 + 1616 + '@rollup/rollup-freebsd-x64@4.53.3': 1617 + optional: true 1618 + 1619 + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': 1620 + optional: true 1621 + 1622 + '@rollup/rollup-linux-arm-musleabihf@4.53.3': 1623 + optional: true 1624 + 1625 + '@rollup/rollup-linux-arm64-gnu@4.53.3': 1626 + optional: true 1627 + 1628 + '@rollup/rollup-linux-arm64-musl@4.53.3': 1629 + optional: true 1630 + 1631 + '@rollup/rollup-linux-loong64-gnu@4.53.3': 1632 + optional: true 1633 + 1634 + '@rollup/rollup-linux-ppc64-gnu@4.53.3': 1635 + optional: true 1636 + 1637 + '@rollup/rollup-linux-riscv64-gnu@4.53.3': 1638 + optional: true 1639 + 1640 + '@rollup/rollup-linux-riscv64-musl@4.53.3': 1641 + optional: true 1642 + 1643 + '@rollup/rollup-linux-s390x-gnu@4.53.3': 1644 + optional: true 1645 + 1646 + '@rollup/rollup-linux-x64-gnu@4.53.3': 1647 + optional: true 1648 + 1649 + '@rollup/rollup-linux-x64-musl@4.53.3': 1650 + optional: true 1651 + 1652 + '@rollup/rollup-openharmony-arm64@4.53.3': 1653 + optional: true 1654 + 1655 + '@rollup/rollup-win32-arm64-msvc@4.53.3': 1656 + optional: true 1657 + 1658 + '@rollup/rollup-win32-ia32-msvc@4.53.3': 1659 + optional: true 1660 + 1661 + '@rollup/rollup-win32-x64-gnu@4.53.3': 1662 + optional: true 1663 + 1664 + '@rollup/rollup-win32-x64-msvc@4.53.3': 1665 + optional: true 1666 + 1667 + '@sinclair/typebox@0.34.41': {} 1668 + 1669 + '@standard-schema/spec@1.0.0': {} 1670 + 1671 + '@sveltejs/acorn-typescript@1.0.8(acorn@8.15.0)': 1672 + dependencies: 1673 + acorn: 8.15.0 1674 + 1675 + '@sveltejs/adapter-node@5.4.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.2)(vite@6.4.1))(svelte@5.45.2)(vite@6.4.1))': 1676 + dependencies: 1677 + '@rollup/plugin-commonjs': 28.0.9(rollup@4.53.3) 1678 + '@rollup/plugin-json': 6.1.0(rollup@4.53.3) 1679 + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.53.3) 1680 + '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.2)(vite@6.4.1))(svelte@5.45.2)(vite@6.4.1) 1681 + rollup: 4.53.3 1682 + 1683 + '@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.2)(vite@6.4.1))(svelte@5.45.2)(vite@6.4.1)': 1684 + dependencies: 1685 + '@standard-schema/spec': 1.0.0 1686 + '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) 1687 + '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.45.2)(vite@6.4.1) 1688 + '@types/cookie': 0.6.0 1689 + acorn: 8.15.0 1690 + cookie: 0.6.0 1691 + devalue: 5.5.0 1692 + esm-env: 1.2.2 1693 + kleur: 4.1.5 1694 + magic-string: 0.30.21 1695 + mrmime: 2.0.1 1696 + sade: 1.8.1 1697 + set-cookie-parser: 2.7.2 1698 + sirv: 3.0.2 1699 + svelte: 5.45.2 1700 + vite: 6.4.1 1701 + 1702 + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.2)(vite@6.4.1))(svelte@5.45.2)(vite@6.4.1)': 1703 + dependencies: 1704 + '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.45.2)(vite@6.4.1) 1705 + debug: 4.4.3 1706 + svelte: 5.45.2 1707 + vite: 6.4.1 1708 + transitivePeerDependencies: 1709 + - supports-color 1710 + 1711 + '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.2)(vite@6.4.1)': 1712 + dependencies: 1713 + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.2)(vite@6.4.1))(svelte@5.45.2)(vite@6.4.1) 1714 + debug: 4.4.3 1715 + deepmerge: 4.3.1 1716 + kleur: 4.1.5 1717 + magic-string: 0.30.21 1718 + svelte: 5.45.2 1719 + vite: 6.4.1 1720 + vitefu: 1.1.1(vite@6.4.1) 1721 + transitivePeerDependencies: 1722 + - supports-color 1723 + 1724 + '@tsconfig/svelte@5.0.6': {} 1725 + 1726 + '@types/cookie@0.6.0': {} 1727 + 1728 + '@types/estree@1.0.8': {} 1729 + 1730 + '@types/json-schema@7.0.15': {} 1731 + 1732 + '@types/resolve@1.20.2': {} 1733 + 1734 + '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.7.3))(eslint@9.39.1)(typescript@5.7.3)': 1735 + dependencies: 1736 + '@eslint-community/regexpp': 4.12.2 1737 + '@typescript-eslint/parser': 8.48.0(eslint@9.39.1)(typescript@5.7.3) 1738 + '@typescript-eslint/scope-manager': 8.48.0 1739 + '@typescript-eslint/type-utils': 8.48.0(eslint@9.39.1)(typescript@5.7.3) 1740 + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.7.3) 1741 + '@typescript-eslint/visitor-keys': 8.48.0 1742 + eslint: 9.39.1 1743 + graphemer: 1.4.0 1744 + ignore: 7.0.5 1745 + natural-compare: 1.4.0 1746 + ts-api-utils: 2.1.0(typescript@5.7.3) 1747 + typescript: 5.7.3 1748 + transitivePeerDependencies: 1749 + - supports-color 1750 + 1751 + '@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.7.3)': 1752 + dependencies: 1753 + '@typescript-eslint/scope-manager': 8.48.0 1754 + '@typescript-eslint/types': 8.48.0 1755 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.7.3) 1756 + '@typescript-eslint/visitor-keys': 8.48.0 1757 + debug: 4.4.3 1758 + eslint: 9.39.1 1759 + typescript: 5.7.3 1760 + transitivePeerDependencies: 1761 + - supports-color 1762 + 1763 + '@typescript-eslint/project-service@8.48.0(typescript@5.7.3)': 1764 + dependencies: 1765 + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.7.3) 1766 + '@typescript-eslint/types': 8.48.0 1767 + debug: 4.4.3 1768 + typescript: 5.7.3 1769 + transitivePeerDependencies: 1770 + - supports-color 1771 + 1772 + '@typescript-eslint/scope-manager@8.48.0': 1773 + dependencies: 1774 + '@typescript-eslint/types': 8.48.0 1775 + '@typescript-eslint/visitor-keys': 8.48.0 1776 + 1777 + '@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.7.3)': 1778 + dependencies: 1779 + typescript: 5.7.3 1780 + 1781 + '@typescript-eslint/type-utils@8.48.0(eslint@9.39.1)(typescript@5.7.3)': 1782 + dependencies: 1783 + '@typescript-eslint/types': 8.48.0 1784 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.7.3) 1785 + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.7.3) 1786 + debug: 4.4.3 1787 + eslint: 9.39.1 1788 + ts-api-utils: 2.1.0(typescript@5.7.3) 1789 + typescript: 5.7.3 1790 + transitivePeerDependencies: 1791 + - supports-color 1792 + 1793 + '@typescript-eslint/types@8.48.0': {} 1794 + 1795 + '@typescript-eslint/typescript-estree@8.48.0(typescript@5.7.3)': 1796 + dependencies: 1797 + '@typescript-eslint/project-service': 8.48.0(typescript@5.7.3) 1798 + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.7.3) 1799 + '@typescript-eslint/types': 8.48.0 1800 + '@typescript-eslint/visitor-keys': 8.48.0 1801 + debug: 4.4.3 1802 + minimatch: 9.0.5 1803 + semver: 7.7.3 1804 + tinyglobby: 0.2.15 1805 + ts-api-utils: 2.1.0(typescript@5.7.3) 1806 + typescript: 5.7.3 1807 + transitivePeerDependencies: 1808 + - supports-color 1809 + 1810 + '@typescript-eslint/utils@8.48.0(eslint@9.39.1)(typescript@5.7.3)': 1811 + dependencies: 1812 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) 1813 + '@typescript-eslint/scope-manager': 8.48.0 1814 + '@typescript-eslint/types': 8.48.0 1815 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.7.3) 1816 + eslint: 9.39.1 1817 + typescript: 5.7.3 1818 + transitivePeerDependencies: 1819 + - supports-color 1820 + 1821 + '@typescript-eslint/visitor-keys@8.48.0': 1822 + dependencies: 1823 + '@typescript-eslint/types': 8.48.0 1824 + eslint-visitor-keys: 4.2.1 1825 + 1826 + acorn-jsx@5.3.2(acorn@8.15.0): 1827 + dependencies: 1828 + acorn: 8.15.0 1829 + 1830 + acorn@8.15.0: {} 1831 + 1832 + ajv-formats@3.0.1(ajv@8.17.1): 1833 + optionalDependencies: 1834 + ajv: 8.17.1 1835 + 1836 + ajv@6.12.6: 1837 + dependencies: 1838 + fast-deep-equal: 3.1.3 1839 + fast-json-stable-stringify: 2.1.0 1840 + json-schema-traverse: 0.4.1 1841 + uri-js: 4.4.1 1842 + 1843 + ajv@8.17.1: 1844 + dependencies: 1845 + fast-deep-equal: 3.1.3 1846 + fast-uri: 3.1.0 1847 + json-schema-traverse: 1.0.0 1848 + require-from-string: 2.0.2 1849 + 1850 + ansi-styles@4.3.0: 1851 + dependencies: 1852 + color-convert: 2.0.1 1853 + 1854 + argparse@2.0.1: {} 1855 + 1856 + aria-query@5.3.2: {} 1857 + 1858 + await-lock@2.2.2: {} 1859 + 1860 + axobject-query@4.1.0: {} 1861 + 1862 + balanced-match@1.0.2: {} 1863 + 1864 + brace-expansion@1.1.12: 1865 + dependencies: 1866 + balanced-match: 1.0.2 1867 + concat-map: 0.0.1 1868 + 1869 + brace-expansion@2.0.2: 1870 + dependencies: 1871 + balanced-match: 1.0.2 1872 + 1873 + callsites@3.1.0: {} 1874 + 1875 + chalk@4.1.2: 1876 + dependencies: 1877 + ansi-styles: 4.3.0 1878 + supports-color: 7.2.0 1879 + 1880 + chokidar@4.0.3: 1881 + dependencies: 1882 + readdirp: 4.1.2 1883 + 1884 + clsx@2.1.1: {} 1885 + 1886 + color-convert@2.0.1: 1887 + dependencies: 1888 + color-name: 1.1.4 1889 + 1890 + color-name@1.1.4: {} 1891 + 1892 + colorette@2.0.20: {} 1893 + 1894 + commondir@1.0.1: {} 1895 + 1896 + concat-map@0.0.1: {} 1897 + 1898 + cookie@0.6.0: {} 1899 + 1900 + cross-spawn@7.0.6: 1901 + dependencies: 1902 + path-key: 3.1.1 1903 + shebang-command: 2.0.0 1904 + which: 2.0.2 1905 + 1906 + cssesc@3.0.0: {} 1907 + 1908 + debug@4.4.3: 1909 + dependencies: 1910 + ms: 2.1.3 1911 + 1912 + deep-is@0.1.4: {} 1913 + 1914 + deepmerge@4.3.1: {} 1915 + 1916 + dequal@2.0.3: {} 1917 + 1918 + devalue@5.5.0: {} 1919 + 1920 + esbuild@0.25.12: 1921 + optionalDependencies: 1922 + '@esbuild/aix-ppc64': 0.25.12 1923 + '@esbuild/android-arm': 0.25.12 1924 + '@esbuild/android-arm64': 0.25.12 1925 + '@esbuild/android-x64': 0.25.12 1926 + '@esbuild/darwin-arm64': 0.25.12 1927 + '@esbuild/darwin-x64': 0.25.12 1928 + '@esbuild/freebsd-arm64': 0.25.12 1929 + '@esbuild/freebsd-x64': 0.25.12 1930 + '@esbuild/linux-arm': 0.25.12 1931 + '@esbuild/linux-arm64': 0.25.12 1932 + '@esbuild/linux-ia32': 0.25.12 1933 + '@esbuild/linux-loong64': 0.25.12 1934 + '@esbuild/linux-mips64el': 0.25.12 1935 + '@esbuild/linux-ppc64': 0.25.12 1936 + '@esbuild/linux-riscv64': 0.25.12 1937 + '@esbuild/linux-s390x': 0.25.12 1938 + '@esbuild/linux-x64': 0.25.12 1939 + '@esbuild/netbsd-arm64': 0.25.12 1940 + '@esbuild/netbsd-x64': 0.25.12 1941 + '@esbuild/openbsd-arm64': 0.25.12 1942 + '@esbuild/openbsd-x64': 0.25.12 1943 + '@esbuild/openharmony-arm64': 0.25.12 1944 + '@esbuild/sunos-x64': 0.25.12 1945 + '@esbuild/win32-arm64': 0.25.12 1946 + '@esbuild/win32-ia32': 0.25.12 1947 + '@esbuild/win32-x64': 0.25.12 1948 + 1949 + escape-string-regexp@4.0.0: {} 1950 + 1951 + eslint-plugin-svelte@3.13.0(eslint@9.39.1)(svelte@5.45.2): 1952 + dependencies: 1953 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) 1954 + '@jridgewell/sourcemap-codec': 1.5.5 1955 + eslint: 9.39.1 1956 + esutils: 2.0.3 1957 + globals: 16.5.0 1958 + known-css-properties: 0.37.0 1959 + postcss: 8.5.6 1960 + postcss-load-config: 3.1.4(postcss@8.5.6) 1961 + postcss-safe-parser: 7.0.1(postcss@8.5.6) 1962 + semver: 7.7.3 1963 + svelte-eslint-parser: 1.4.0(svelte@5.45.2) 1964 + optionalDependencies: 1965 + svelte: 5.45.2 1966 + transitivePeerDependencies: 1967 + - ts-node 1968 + 1969 + eslint-scope@8.4.0: 1970 + dependencies: 1971 + esrecurse: 4.3.0 1972 + estraverse: 5.3.0 1973 + 1974 + eslint-visitor-keys@3.4.3: {} 1975 + 1976 + eslint-visitor-keys@4.2.1: {} 1977 + 1978 + eslint@9.39.1: 1979 + dependencies: 1980 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) 1981 + '@eslint-community/regexpp': 4.12.2 1982 + '@eslint/config-array': 0.21.1 1983 + '@eslint/config-helpers': 0.4.2 1984 + '@eslint/core': 0.17.0 1985 + '@eslint/eslintrc': 3.3.3 1986 + '@eslint/js': 9.39.1 1987 + '@eslint/plugin-kit': 0.4.1 1988 + '@humanfs/node': 0.16.7 1989 + '@humanwhocodes/module-importer': 1.0.1 1990 + '@humanwhocodes/retry': 0.4.3 1991 + '@types/estree': 1.0.8 1992 + ajv: 6.12.6 1993 + chalk: 4.1.2 1994 + cross-spawn: 7.0.6 1995 + debug: 4.4.3 1996 + escape-string-regexp: 4.0.0 1997 + eslint-scope: 8.4.0 1998 + eslint-visitor-keys: 4.2.1 1999 + espree: 10.4.0 2000 + esquery: 1.6.0 2001 + esutils: 2.0.3 2002 + fast-deep-equal: 3.1.3 2003 + file-entry-cache: 8.0.0 2004 + find-up: 5.0.0 2005 + glob-parent: 6.0.2 2006 + ignore: 5.3.2 2007 + imurmurhash: 0.1.4 2008 + is-glob: 4.0.3 2009 + json-stable-stringify-without-jsonify: 1.0.1 2010 + lodash.merge: 4.6.2 2011 + minimatch: 3.1.2 2012 + natural-compare: 1.4.0 2013 + optionator: 0.9.4 2014 + transitivePeerDependencies: 2015 + - supports-color 2016 + 2017 + esm-env@1.2.2: {} 2018 + 2019 + espree@10.4.0: 2020 + dependencies: 2021 + acorn: 8.15.0 2022 + acorn-jsx: 5.3.2(acorn@8.15.0) 2023 + eslint-visitor-keys: 4.2.1 2024 + 2025 + esquery@1.6.0: 2026 + dependencies: 2027 + estraverse: 5.3.0 2028 + 2029 + esrap@2.2.0: 2030 + dependencies: 2031 + '@jridgewell/sourcemap-codec': 1.5.5 2032 + 2033 + esrecurse@4.3.0: 2034 + dependencies: 2035 + estraverse: 5.3.0 2036 + 2037 + estraverse@5.3.0: {} 2038 + 2039 + estree-walker@2.0.2: {} 2040 + 2041 + esutils@2.0.3: {} 2042 + 2043 + fast-deep-equal@3.1.3: {} 2044 + 2045 + fast-json-stable-stringify@2.1.0: {} 2046 + 2047 + fast-json-stringify@6.1.1: 2048 + dependencies: 2049 + '@fastify/merge-json-schemas': 0.2.1 2050 + ajv: 8.17.1 2051 + ajv-formats: 3.0.1(ajv@8.17.1) 2052 + fast-uri: 3.1.0 2053 + json-schema-ref-resolver: 3.0.0 2054 + rfdc: 1.4.1 2055 + 2056 + fast-levenshtein@2.0.6: {} 2057 + 2058 + fast-uri@3.1.0: {} 2059 + 2060 + fdir@6.5.0(picomatch@4.0.3): 2061 + optionalDependencies: 2062 + picomatch: 4.0.3 2063 + 2064 + file-entry-cache@8.0.0: 2065 + dependencies: 2066 + flat-cache: 4.0.1 2067 + 2068 + find-up@5.0.0: 2069 + dependencies: 2070 + locate-path: 6.0.0 2071 + path-exists: 4.0.0 2072 + 2073 + flat-cache@4.0.1: 2074 + dependencies: 2075 + flatted: 3.3.3 2076 + keyv: 4.5.4 2077 + 2078 + flatted@3.3.3: {} 2079 + 2080 + fsevents@2.3.3: 2081 + optional: true 2082 + 2083 + function-bind@1.1.2: {} 2084 + 2085 + glob-parent@6.0.2: 2086 + dependencies: 2087 + is-glob: 4.0.3 2088 + 2089 + globals@14.0.0: {} 2090 + 2091 + globals@16.5.0: {} 2092 + 2093 + graphemer@1.4.0: {} 2094 + 2095 + has-flag@4.0.0: {} 2096 + 2097 + hasown@2.0.2: 2098 + dependencies: 2099 + function-bind: 1.1.2 2100 + 2101 + hls.js@1.6.15: {} 2102 + 2103 + ignore@5.3.2: {} 2104 + 2105 + ignore@7.0.5: {} 2106 + 2107 + import-fresh@3.3.1: 2108 + dependencies: 2109 + parent-module: 1.0.1 2110 + resolve-from: 4.0.0 2111 + 2112 + imurmurhash@0.1.4: {} 2113 + 2114 + is-core-module@2.16.1: 2115 + dependencies: 2116 + hasown: 2.0.2 2117 + 2118 + is-extglob@2.1.1: {} 2119 + 2120 + is-glob@4.0.3: 2121 + dependencies: 2122 + is-extglob: 2.1.1 2123 + 2124 + is-module@1.0.0: {} 2125 + 2126 + is-reference@1.2.1: 2127 + dependencies: 2128 + '@types/estree': 1.0.8 2129 + 2130 + is-reference@3.0.3: 2131 + dependencies: 2132 + '@types/estree': 1.0.8 2133 + 2134 + isexe@2.0.0: {} 2135 + 2136 + iso-datestring-validator@2.2.2: {} 2137 + 2138 + js-yaml@4.1.1: 2139 + dependencies: 2140 + argparse: 2.0.1 2141 + 2142 + json-buffer@3.0.1: {} 2143 + 2144 + json-schema-ref-resolver@3.0.0: 2145 + dependencies: 2146 + dequal: 2.0.3 2147 + 2148 + json-schema-traverse@0.4.1: {} 2149 + 2150 + json-schema-traverse@1.0.0: {} 2151 + 2152 + json-stable-stringify-without-jsonify@1.0.1: {} 2153 + 2154 + keyv@4.5.4: 2155 + dependencies: 2156 + json-buffer: 3.0.1 2157 + 2158 + kleur@4.1.5: {} 2159 + 2160 + known-css-properties@0.37.0: {} 2161 + 2162 + levn@0.4.1: 2163 + dependencies: 2164 + prelude-ls: 1.2.1 2165 + type-check: 0.4.0 2166 + 2167 + lilconfig@2.1.0: {} 2168 + 2169 + locate-character@3.0.0: {} 2170 + 2171 + locate-path@6.0.0: 2172 + dependencies: 2173 + p-locate: 5.0.0 2174 + 2175 + lodash.merge@4.6.2: {} 2176 + 2177 + magic-string@0.30.21: 2178 + dependencies: 2179 + '@jridgewell/sourcemap-codec': 1.5.5 2180 + 2181 + minimatch@3.1.2: 2182 + dependencies: 2183 + brace-expansion: 1.1.12 2184 + 2185 + minimatch@9.0.5: 2186 + dependencies: 2187 + brace-expansion: 2.0.2 2188 + 2189 + moment@2.30.1: {} 2190 + 2191 + mri@1.2.0: {} 2192 + 2193 + mrmime@2.0.1: {} 2194 + 2195 + ms@2.1.3: {} 2196 + 2197 + multiformats@9.9.0: {} 2198 + 2199 + mutex-ts@1.2.1: {} 2200 + 2201 + nanoid@3.3.11: {} 2202 + 2203 + natural-compare@1.4.0: {} 2204 + 2205 + optionator@0.9.4: 2206 + dependencies: 2207 + deep-is: 0.1.4 2208 + fast-levenshtein: 2.0.6 2209 + levn: 0.4.1 2210 + prelude-ls: 1.2.1 2211 + type-check: 0.4.0 2212 + word-wrap: 1.2.5 2213 + 2214 + p-limit@3.1.0: 2215 + dependencies: 2216 + yocto-queue: 0.1.0 2217 + 2218 + p-locate@5.0.0: 2219 + dependencies: 2220 + p-limit: 3.1.0 2221 + 2222 + parent-module@1.0.1: 2223 + dependencies: 2224 + callsites: 3.1.0 2225 + 2226 + path-exists@4.0.0: {} 2227 + 2228 + path-key@3.1.1: {} 2229 + 2230 + path-parse@1.0.7: {} 2231 + 2232 + picocolors@1.1.1: {} 2233 + 2234 + picomatch@4.0.3: {} 2235 + 2236 + postcss-load-config@3.1.4(postcss@8.5.6): 2237 + dependencies: 2238 + lilconfig: 2.1.0 2239 + yaml: 1.10.2 2240 + optionalDependencies: 2241 + postcss: 8.5.6 2242 + 2243 + postcss-safe-parser@7.0.1(postcss@8.5.6): 2244 + dependencies: 2245 + postcss: 8.5.6 2246 + 2247 + postcss-scss@4.0.9(postcss@8.5.6): 2248 + dependencies: 2249 + postcss: 8.5.6 2250 + 2251 + postcss-selector-parser@7.1.1: 2252 + dependencies: 2253 + cssesc: 3.0.0 2254 + util-deprecate: 1.0.2 2255 + 2256 + postcss@8.5.6: 2257 + dependencies: 2258 + nanoid: 3.3.11 2259 + picocolors: 1.1.1 2260 + source-map-js: 1.2.1 2261 + 2262 + prelude-ls@1.2.1: {} 2263 + 2264 + punycode@2.3.1: {} 2265 + 2266 + readdirp@4.1.2: {} 2267 + 2268 + require-from-string@2.0.2: {} 2269 + 2270 + resolve-from@4.0.0: {} 2271 + 2272 + resolve@1.22.11: 2273 + dependencies: 2274 + is-core-module: 2.16.1 2275 + path-parse: 1.0.7 2276 + supports-preserve-symlinks-flag: 1.0.0 2277 + 2278 + rfdc@1.4.1: {} 2279 + 2280 + rollup@4.53.3: 2281 + dependencies: 2282 + '@types/estree': 1.0.8 2283 + optionalDependencies: 2284 + '@rollup/rollup-android-arm-eabi': 4.53.3 2285 + '@rollup/rollup-android-arm64': 4.53.3 2286 + '@rollup/rollup-darwin-arm64': 4.53.3 2287 + '@rollup/rollup-darwin-x64': 4.53.3 2288 + '@rollup/rollup-freebsd-arm64': 4.53.3 2289 + '@rollup/rollup-freebsd-x64': 4.53.3 2290 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 2291 + '@rollup/rollup-linux-arm-musleabihf': 4.53.3 2292 + '@rollup/rollup-linux-arm64-gnu': 4.53.3 2293 + '@rollup/rollup-linux-arm64-musl': 4.53.3 2294 + '@rollup/rollup-linux-loong64-gnu': 4.53.3 2295 + '@rollup/rollup-linux-ppc64-gnu': 4.53.3 2296 + '@rollup/rollup-linux-riscv64-gnu': 4.53.3 2297 + '@rollup/rollup-linux-riscv64-musl': 4.53.3 2298 + '@rollup/rollup-linux-s390x-gnu': 4.53.3 2299 + '@rollup/rollup-linux-x64-gnu': 4.53.3 2300 + '@rollup/rollup-linux-x64-musl': 4.53.3 2301 + '@rollup/rollup-openharmony-arm64': 4.53.3 2302 + '@rollup/rollup-win32-arm64-msvc': 4.53.3 2303 + '@rollup/rollup-win32-ia32-msvc': 4.53.3 2304 + '@rollup/rollup-win32-x64-gnu': 4.53.3 2305 + '@rollup/rollup-win32-x64-msvc': 4.53.3 2306 + fsevents: 2.3.3 2307 + 2308 + sade@1.8.1: 2309 + dependencies: 2310 + mri: 1.2.0 2311 + 2312 + semver@7.7.3: {} 2313 + 2314 + set-cookie-parser@2.7.2: {} 2315 + 2316 + shebang-command@2.0.0: 2317 + dependencies: 2318 + shebang-regex: 3.0.0 2319 + 2320 + shebang-regex@3.0.0: {} 2321 + 2322 + sirv@3.0.2: 2323 + dependencies: 2324 + '@polka/url': 1.0.0-next.29 2325 + mrmime: 2.0.1 2326 + totalist: 3.0.1 2327 + 2328 + source-map-js@1.2.1: {} 2329 + 2330 + sqlite-cache@0.0.2: 2331 + dependencies: 2332 + '@sinclair/typebox': 0.34.41 2333 + colorette: 2.0.20 2334 + fast-json-stringify: 6.1.1 2335 + 2336 + strip-json-comments@3.1.1: {} 2337 + 2338 + supports-color@7.2.0: 2339 + dependencies: 2340 + has-flag: 4.0.0 2341 + 2342 + supports-preserve-symlinks-flag@1.0.0: {} 2343 + 2344 + svelte-check@4.3.4(picomatch@4.0.3)(svelte@5.45.2)(typescript@5.7.3): 2345 + dependencies: 2346 + '@jridgewell/trace-mapping': 0.3.31 2347 + chokidar: 4.0.3 2348 + fdir: 6.5.0(picomatch@4.0.3) 2349 + picocolors: 1.1.1 2350 + sade: 1.8.1 2351 + svelte: 5.45.2 2352 + typescript: 5.7.3 2353 + transitivePeerDependencies: 2354 + - picomatch 2355 + 2356 + svelte-eslint-parser@1.4.0(svelte@5.45.2): 2357 + dependencies: 2358 + eslint-scope: 8.4.0 2359 + eslint-visitor-keys: 4.2.1 2360 + espree: 10.4.0 2361 + postcss: 8.5.6 2362 + postcss-scss: 4.0.9(postcss@8.5.6) 2363 + postcss-selector-parser: 7.1.1 2364 + optionalDependencies: 2365 + svelte: 5.45.2 2366 + 2367 + svelte-infinite-loading@1.4.0: {} 2368 + 2369 + svelte@5.45.2: 2370 + dependencies: 2371 + '@jridgewell/remapping': 2.3.5 2372 + '@jridgewell/sourcemap-codec': 1.5.5 2373 + '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) 2374 + '@types/estree': 1.0.8 2375 + acorn: 8.15.0 2376 + aria-query: 5.3.2 2377 + axobject-query: 4.1.0 2378 + clsx: 2.1.1 2379 + devalue: 5.5.0 2380 + esm-env: 1.2.2 2381 + esrap: 2.2.0 2382 + is-reference: 3.0.3 2383 + locate-character: 3.0.0 2384 + magic-string: 0.30.21 2385 + zimmerframe: 1.1.4 2386 + 2387 + tinyglobby@0.2.15: 2388 + dependencies: 2389 + fdir: 6.5.0(picomatch@4.0.3) 2390 + picomatch: 4.0.3 2391 + 2392 + tlds@1.261.0: {} 2393 + 2394 + totalist@3.0.1: {} 2395 + 2396 + ts-api-utils@2.1.0(typescript@5.7.3): 2397 + dependencies: 2398 + typescript: 5.7.3 2399 + 2400 + tslib@2.8.1: {} 2401 + 2402 + type-check@0.4.0: 2403 + dependencies: 2404 + prelude-ls: 1.2.1 2405 + 2406 + typescript-eslint@8.48.0(eslint@9.39.1)(typescript@5.7.3): 2407 + dependencies: 2408 + '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.7.3))(eslint@9.39.1)(typescript@5.7.3) 2409 + '@typescript-eslint/parser': 8.48.0(eslint@9.39.1)(typescript@5.7.3) 2410 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.7.3) 2411 + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.7.3) 2412 + eslint: 9.39.1 2413 + typescript: 5.7.3 2414 + transitivePeerDependencies: 2415 + - supports-color 2416 + 2417 + typescript@5.7.3: {} 2418 + 2419 + uint8arrays@3.0.0: 2420 + dependencies: 2421 + multiformats: 9.9.0 2422 + 2423 + unicode-segmenter@0.14.0: {} 2424 + 2425 + uri-js@4.4.1: 2426 + dependencies: 2427 + punycode: 2.3.1 2428 + 2429 + util-deprecate@1.0.2: {} 2430 + 2431 + vite@6.4.1: 2432 + dependencies: 2433 + esbuild: 0.25.12 2434 + fdir: 6.5.0(picomatch@4.0.3) 2435 + picomatch: 4.0.3 2436 + postcss: 8.5.6 2437 + rollup: 4.53.3 2438 + tinyglobby: 0.2.15 2439 + optionalDependencies: 2440 + fsevents: 2.3.3 2441 + 2442 + vitefu@1.1.1(vite@6.4.1): 2443 + optionalDependencies: 2444 + vite: 6.4.1 2445 + 2446 + which@2.0.2: 2447 + dependencies: 2448 + isexe: 2.0.0 2449 + 2450 + word-wrap@1.2.5: {} 2451 + 2452 + yaml@1.10.2: {} 2453 + 2454 + yocto-queue@0.1.0: {} 2455 + 2456 + zimmerframe@1.1.4: {} 2457 + 2458 + zod@3.25.76: {}
-95
src/App.svelte
··· 1 - <script lang="ts"> 2 - import PostComponent from "./lib/PostComponent.svelte"; 3 - import AccountComponent from "./lib/AccountComponent.svelte"; 4 - import InfiniteLoading from "svelte-infinite-loading"; 5 - import { getNextPosts, Post, getAllMetadataFromPds } from "./lib/pdsfetch"; 6 - import { Config } from "../config"; 7 - const accountsPromise = getAllMetadataFromPds(); 8 - import { onMount } from "svelte"; 9 - 10 - 11 - 12 - let posts: Post[] = []; 13 - 14 - let hue: number = 1; 15 - const cycleColors = async () => { 16 - while (true) { 17 - hue += 1; 18 - if (hue > 360) { 19 - hue = 0; 20 - } 21 - document.documentElement.style.setProperty("--primary-h", hue.toString()); 22 - await new Promise((resolve) => setTimeout(resolve, 10)); 23 - } 24 - } 25 - let clickCounter = 0; 26 - const carameldansenfusion = async () => { 27 - clickCounter++; 28 - if (clickCounter >= 10) { 29 - clickCounter = 0; 30 - cycleColors(); 31 - } 32 - }; 33 - 34 - onMount(() => { 35 - // Fetch initial posts 36 - // TODO I think this was getting called twice? 37 - // getNextPosts().then((initialPosts) => { 38 - // posts = initialPosts; 39 - // }); 40 - }); 41 - // Infinite loading function 42 - const onInfinite = ({ 43 - detail: { loaded, complete }, 44 - }: { 45 - detail: { loaded: () => void; complete: () => void }; 46 - }) => { 47 - getNextPosts().then((newPosts) => { 48 - console.log("Loading next posts..."); 49 - if (newPosts.length > 0) { 50 - posts = [...posts, ...newPosts]; 51 - loaded(); 52 - } else { 53 - complete(); 54 - } 55 - }); 56 - }; 57 - </script> 58 - 59 - <main> 60 - <div id="Content"> 61 - {#await accountsPromise} 62 - <p>Loading...</p> 63 - {:then accountsData} 64 - <div id="Account"> 65 - <h1 onclick={carameldansenfusion} id="Header">ATProto PDS</h1> 66 - <p>Home to {accountsData.length} accounts</p> 67 - <div id="accountsList"> 68 - {#each accountsData as accountObject} 69 - <AccountComponent account={accountObject} /> 70 - {/each} 71 - </div> 72 - <div style="margin: 8px 0 12px;"> 73 - <p>Help support the PDS</p> 74 - <iframe src="https://github.com/sponsors/fatfingers23/button" title="Sponsor fatfingers23" height="32" width="114" style="border: 0; border-radius: 6px;"></iframe> 75 - </div> 76 - <p>{@html Config.FOOTER_TEXT}</p> 77 - </div> 78 - {:catch error} 79 - <p>Error: {error.message}</p> 80 - {/await} 81 - 82 - <div id="Feed"> 83 - <div id="spacer"></div> 84 - {#each posts as postObject} 85 - <PostComponent post={postObject} /> 86 - {/each} 87 - <InfiniteLoading on:infinite={onInfinite} distance={3000} /> 88 - <div id="spacer"></div> 89 - </div> 90 - </div> 91 - </main> 92 - 93 - <style> 94 - 95 - </style>
-4
src/app.css
··· 1 - @import url("./themes/colors.css"); 2 - body { 3 - background-color: red; 4 - }
+16
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" /> 6 + <title>Selfhosted.social</title> 7 + <meta 8 + name="description" 9 + content="Landing page for selfhosted.social, an ATProto PDS" 10 + > 11 + %sveltekit.head% 12 + </head> 13 + <body data-sveltekit-preload-data="hover"> 14 + <div style="display: contents">%sveltekit.body%</div> 15 + </body> 16 + </html>
+3 -3
src/lib/AccountComponent.svelte src/lib/components/landing/AccountComponent.svelte
··· 1 1 <script lang="ts"> 2 - import type { AccountMetadata } from "./pdsfetch"; 3 - import { getTealNowListeningTo, getStatusSphere } from "./pdsfetch"; 2 + import type { AccountMetadata } from '../../pdsfetch'; 3 + import { getTealNowListeningTo, getStatusSphere } from '../../pdsfetch'; 4 4 const { account }: { account: AccountMetadata } = $props(); 5 - import { Config } from "../../config"; 5 + import { Config } from '$lib/config'; 6 6 7 7 let nowListeningTo: string | null = $state(null); 8 8 let statusEmoji: string | null = $state(null);
+48 -38
src/lib/PostComponent.svelte src/lib/components/landing/PostComponent.svelte
··· 1 1 <script lang="ts"> 2 - import { Post } from "./pdsfetch"; 3 - import { Config } from "../../config"; 4 - import { onMount, onDestroy } from "svelte"; 5 - import moment from "moment"; 6 - import { blueskyHandleFromDid } from "./pdsfetch"; 7 - import Hls from "hls.js"; 2 + import { Post } from '../../pdsfetch'; 3 + import { Config } from '$lib/config'; 4 + import { onMount, onDestroy } from 'svelte'; 5 + import moment from 'moment'; 6 + import { blueskyHandleFromDid } from '../../pdsfetch'; 7 + import Hls from 'hls.js'; 8 8 let { post }: { post: Post } = $props(); 9 9 10 10 // State for image carousel ··· 49 49 // Function to preload an image 50 50 function preloadImage(index: number): void { 51 51 if (!post.imagesCid || index < 0 || index >= post.imagesCid.length) return; 52 - 53 52 const img = new Image(); 54 53 img.src = `https://cdn.bsky.app/img/feed_thumbnail/plain/${post.authorDid}/${post.imagesCid[index]}@jpeg`; 55 54 } 56 55 57 56 // Initialize HLS playback when mounted if there's a video 58 57 onMount(() => { 58 + 59 59 // Preload the next image if it exists 60 60 if (post.imagesCid && post.imagesCid.length > 1) { 61 61 if (post.imagesCid.length > 1) { ··· 70 70 hls = new Hls(); 71 71 hls.loadSource(src); 72 72 hls.attachMedia(videoEl); 73 - } else if (videoEl.canPlayType("application/vnd.apple.mpegurl")) { 73 + } else if (videoEl.canPlayType('application/vnd.apple.mpegurl')) { 74 74 // Safari / iOS native HLS 75 75 videoEl.src = src; 76 76 } else { ··· 113 113 id="postLink" 114 114 style="text-decoration: underline;" 115 115 href="{Config.FRONTEND_URL}/profile/{post.authorDid}/post/{post.recordName}" 116 - >{moment(post.timenotstamp).isBefore(moment().subtract(1, "month")) 117 - ? moment(post.timenotstamp).format("MMM D, YYYY") 116 + >{moment(post.timenotstamp).isBefore(moment().subtract(1, 'month')) 117 + ? moment(post.timenotstamp).format('MMM D, YYYY') 118 118 : moment(post.timenotstamp).fromNow()}</a 119 119 > 120 120 </p> ··· 150 150 {/each} 151 151 </div> 152 152 {#if post.imagesCid && post.imagesCid.length > 0} 153 + 154 + 153 155 <div id="carouselContainer"> 154 - <img 155 - id="embedImages" 156 - alt="Post Image {currentImageIndex + 1} of {post.imagesCid.length}" 157 - src="https://cdn.bsky.app/img/feed_thumbnail/plain/{post.authorDid}/{post 158 - .imagesCid[currentImageIndex]}@jpeg" 159 - /> 156 + {#if post.hideMedia} 157 + <img 158 + id="embedImages" 159 + alt="A random cat since the media was marked as hidden" 160 + src="https://cataas.com/cat"/> 161 + {:else} 160 162 161 - {#if post.imagesCid.length > 1} 162 - <div id="carouselControls"> 163 - <button 164 - id="prevBtn" 165 - onclick={prevImage} 166 - disabled={currentImageIndex === 0}>←</button 167 - > 168 - <div id="carouselIndicators"> 169 - {#each post.imagesCid as _, i} 170 - <div 171 - class="indicator {i === currentImageIndex ? 'active' : ''}" 172 - ></div> 173 - {/each} 174 - </div> 175 - <button 176 - id="nextBtn" 177 - onclick={nextImage} 178 - disabled={currentImageIndex === post.imagesCid.length - 1} 179 - >→</button 180 - > 181 - </div> 182 - {/if} 163 + <img 164 + id="embedImages" 165 + alt="Post Image {currentImageIndex + 1} of {post.imagesCid.length}" 166 + src="https://cdn.bsky.app/img/feed_thumbnail/plain/{post.authorDid}/{post 167 + .imagesCid[currentImageIndex]}@jpeg" 168 + /> 169 + 170 + {#if post.imagesCid.length > 1} 171 + <div id="carouselControls"> 172 + <button 173 + id="prevBtn" 174 + onclick={prevImage} 175 + disabled={currentImageIndex === 0}>←</button 176 + > 177 + <div id="carouselIndicators"> 178 + {#each post.imagesCid as cid, i (cid)} 179 + <div 180 + class="indicator {i === currentImageIndex ? 'active' : ''}" 181 + ></div> 182 + {/each} 183 + </div> 184 + <button 185 + id="nextBtn" 186 + onclick={nextImage} 187 + disabled={currentImageIndex === post.imagesCid.length - 1} 188 + >→</button 189 + > 190 + </div> 191 + {/if} 192 + {/if} 183 193 </div> 184 194 {/if} 185 195 {#if post.videosLinkCid}
+211
src/lib/components/Navbar.svelte
··· 1 + <script lang="ts"> 2 + import { page } from '$app/stores'; 3 + 4 + let menuOpen = $state(false); 5 + 6 + function toggleMenu() { 7 + menuOpen = !menuOpen; 8 + } 9 + 10 + function closeMenu() { 11 + menuOpen = false; 12 + } 13 + </script> 14 + 15 + <nav class="navbar"> 16 + <div class="navbar-container"> 17 + <a href="/" class="navbar-brand">selfhosted.social</a> 18 + 19 + <button class="hamburger" onclick={toggleMenu} aria-label="Toggle menu"> 20 + <span class="hamburger-line"></span> 21 + <span class="hamburger-line"></span> 22 + <span class="hamburger-line"></span> 23 + </button> 24 + 25 + <div class="navbar-links" class:open={menuOpen}> 26 + <a href="/info" class:active={$page.url.pathname === '/info'} onclick={closeMenu}>Info</a> 27 + <a href="/legal" class:active={$page.url.pathname === '/legal'} onclick={closeMenu}>Legal</a> 28 + <a href="https://pdsmoover.com/moover/selfhosted.social">Migrate</a> 29 + </div> 30 + </div> 31 + </nav> 32 + 33 + <style> 34 + .navbar { 35 + position: fixed; 36 + top: 0; 37 + left: 0; 38 + right: 0; 39 + width: 100%; 40 + background-color: var(--header-background-color, #ffffff); 41 + border-bottom: 1px solid var(--border-color, #e2e8f0); 42 + padding: 1rem 2rem; 43 + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); 44 + z-index: 1000; 45 + } 46 + 47 + .navbar-container { 48 + max-width: 1400px; 49 + margin: 0 auto; 50 + display: flex; 51 + justify-content: space-between; 52 + align-items: center; 53 + position: relative; 54 + } 55 + 56 + .navbar-brand { 57 + font-size: 1.5rem; 58 + font-weight: bold; 59 + color: var(--text-color, #111827); 60 + text-decoration: none; 61 + transition: opacity 0.2s; 62 + flex-shrink: 0; 63 + } 64 + 65 + .navbar-brand:hover { 66 + opacity: 0.8; 67 + } 68 + 69 + .hamburger { 70 + display: none; 71 + flex-direction: column; 72 + gap: 4px; 73 + background: none; 74 + border: none; 75 + cursor: pointer; 76 + padding: 0.5rem; 77 + z-index: 1001; 78 + } 79 + 80 + .hamburger-line { 81 + width: 25px; 82 + height: 3px; 83 + background-color: var(--text-color, #111827); 84 + transition: all 0.3s ease; 85 + border-radius: 2px; 86 + } 87 + 88 + .navbar-links { 89 + display: flex; 90 + gap: 2rem; 91 + align-items: center; 92 + flex-wrap: wrap; 93 + justify-content: flex-end; 94 + } 95 + 96 + .navbar-links a { 97 + color: var(--text-color, #111827); 98 + text-decoration: none; 99 + font-weight: 500; 100 + transition: opacity 0.2s; 101 + padding: 0.5rem 0; 102 + border-bottom: 2px solid transparent; 103 + white-space: nowrap; 104 + } 105 + 106 + .navbar-links a:hover { 107 + opacity: 0.8; 108 + } 109 + 110 + .navbar-links a.active { 111 + border-bottom-color: var(--link-color, #6366f1); 112 + } 113 + 114 + @media (max-width: 1200px) { 115 + .navbar-links { 116 + gap: 1.5rem; 117 + } 118 + 119 + .navbar-links a { 120 + font-size: 0.95rem; 121 + } 122 + } 123 + 124 + @media (max-width: 1024px) { 125 + .navbar { 126 + padding: 1rem; 127 + } 128 + 129 + .navbar-links { 130 + gap: 1rem; 131 + } 132 + 133 + .navbar-links a { 134 + font-size: 0.9rem; 135 + } 136 + } 137 + 138 + @media (max-width: 768px) { 139 + .navbar { 140 + padding: 0.75rem 1rem; 141 + } 142 + 143 + .navbar-container { 144 + flex-direction: row; 145 + width: 100%; 146 + } 147 + 148 + .navbar-brand { 149 + font-size: 1.25rem; 150 + } 151 + 152 + .hamburger { 153 + display: flex; 154 + } 155 + 156 + .navbar-links { 157 + position: absolute; 158 + top: 100%; 159 + left: 0; 160 + right: 0; 161 + flex-direction: column; 162 + gap: 0; 163 + background-color: var(--header-background-color, #ffffff); 164 + border-bottom: 1px solid var(--border-color, #e2e8f0); 165 + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 166 + max-height: 0; 167 + overflow: hidden; 168 + transition: max-height 0.3s ease; 169 + } 170 + 171 + .navbar-links.open { 172 + max-height: 500px; 173 + } 174 + 175 + .navbar-links a { 176 + width: 100%; 177 + padding: 1rem; 178 + text-align: center; 179 + border-bottom: 1px solid var(--border-color, #e2e8f0); 180 + font-size: 1rem; 181 + } 182 + 183 + .navbar-links a:last-child { 184 + border-bottom: none; 185 + } 186 + 187 + .navbar-links a.active { 188 + border-bottom: 1px solid var(--link-color, #6366f1); 189 + background-color: rgba(99, 102, 241, 0.05); 190 + } 191 + 192 + .navbar-links a.active:last-child { 193 + border-bottom: none; 194 + } 195 + } 196 + 197 + @media (max-width: 480px) { 198 + .navbar { 199 + padding: 0.5rem 0.75rem; 200 + } 201 + 202 + .navbar-brand { 203 + font-size: 1.1rem; 204 + } 205 + 206 + .hamburger-line { 207 + width: 22px; 208 + height: 2.5px; 209 + } 210 + } 211 + </style>
+75
src/lib/components/PDSHeader.svelte
··· 1 + <script lang="ts"> 2 + // Optional props to customize the header 3 + 4 + </script> 5 + 6 + <div class="info-header"> 7 + <h1 class="title">Who are we?</h1> 8 + <p class="description"> 9 + We're hackers, designers, developers, ATProto enthusiasts, scrobblers, tinkerers, friends, and curious minds. Some of us are all these things, some of us are none of these things. 10 + <br><br> 11 + What brings us together isn't a checklist, but a shared space where everyone is welcome to be themselves. This is our slice of the atmosphere. 12 + </p> 13 + </div> 14 + 15 + <style> 16 + .info-header { 17 + text-align: center; 18 + padding: 3rem 1rem; 19 + background: linear-gradient(135deg, rgba(99, 102, 241, 0.05) 0%, rgba(168, 85, 247, 0.05) 100%); 20 + border-radius: 12px; 21 + margin-bottom: 3rem; 22 + } 23 + 24 + .title { 25 + font-size: 3rem; 26 + font-weight: 800; 27 + color: var(--text-color, #111827); 28 + margin: 0 0 1.5rem 0; 29 + letter-spacing: -0.02em; 30 + line-height: 1.2; 31 + } 32 + 33 + .description { 34 + font-size: 1.125rem; 35 + color: var(--text-color, #111827); 36 + opacity: 0.8; 37 + max-width: 750px; 38 + margin: 0 auto; 39 + line-height: 1.7; 40 + } 41 + 42 + .description strong { 43 + font-weight: 700; 44 + opacity: 1; 45 + } 46 + 47 + @media (max-width: 768px) { 48 + .info-header { 49 + padding: 2rem 1rem; 50 + margin-bottom: 2rem; 51 + } 52 + 53 + .title { 54 + font-size: 2rem; 55 + } 56 + 57 + .description { 58 + font-size: 1rem; 59 + } 60 + } 61 + 62 + @media (max-width: 480px) { 63 + .info-header { 64 + padding: 1.5rem 0.75rem; 65 + } 66 + 67 + .title { 68 + font-size: 1.75rem; 69 + } 70 + 71 + .description { 72 + font-size: 0.95rem; 73 + } 74 + } 75 + </style>
+71
src/lib/components/landing/LandingPage.svelte
··· 1 + <script lang="ts"> 2 + import PostComponent from '$lib/components/landing/PostComponent.svelte'; 3 + import AccountComponent from '$lib/components/landing/AccountComponent.svelte'; 4 + import InfiniteLoading from 'svelte-infinite-loading'; 5 + import { getNextPosts, Post, getAllMetadataFromPds } from '$lib/pdsfetch'; 6 + import { onMount } from 'svelte'; 7 + import type { AccountMetadata } from '$lib/pdsfetch'; 8 + 9 + let accountsPromise: Promise<AccountMetadata[]> | null = $state(null); 10 + let posts: Post[] = $state([]); 11 + 12 + onMount(() => { 13 + accountsPromise = getAllMetadataFromPds(); 14 + }); 15 + 16 + // Infinite loading function 17 + const onInfinite = ({ 18 + detail: { loaded, complete }, 19 + }: { 20 + detail: { loaded: () => void; complete: () => void }; 21 + }) => { 22 + getNextPosts().then((newPosts) => { 23 + console.log('Loading next posts...'); 24 + if (newPosts.length > 0) { 25 + posts = [...posts, ...newPosts]; 26 + loaded(); 27 + } else { 28 + complete(); 29 + } 30 + }); 31 + }; 32 + </script> 33 + 34 + 35 + <div id="Content"> 36 + {#if accountsPromise} 37 + {#await accountsPromise} 38 + <p>Loading...</p> 39 + {:then accountsData} 40 + <div id="Account"> 41 + <h1 id="Header">ATProto PDS</h1> 42 + <p>Home to {accountsData.length} accounts</p> 43 + <div id="accountsList"> 44 + {#each accountsData as accountObject (accountObject.did)} 45 + <AccountComponent account={accountObject} /> 46 + {/each} 47 + </div> 48 + <div style="margin: 8px 0 12px;"> 49 + <p>Help support the PDS</p> 50 + <iframe src="https://github.com/sponsors/fatfingers23/button" title="Sponsor fatfingers23" height="32" width="114" style="border: 0; border-radius: 6px;"></iframe> 51 + </div> 52 + <p> 53 + <span>Forked with ❤️ from <a href='https://git.witchcraft.systems/scientific-witchery/pds-dash' target='_blank'>witchcraft.systems</a> (<a href='https://tangled.org/baileytownsend.dev/pds-dash-fork' target='_blank'>fork</a>)</span> 54 + </p> 55 + </div> 56 + {:catch error} 57 + <p>Error: {error.message}</p> 58 + {/await} 59 + {:else} 60 + <p>Loading...</p> 61 + {/if} 62 + 63 + <div id="Feed"> 64 + <div id="spacer"></div> 65 + {#each posts as postObject (postObject.postCid)} 66 + <PostComponent post={postObject} /> 67 + {/each} 68 + <InfiniteLoading on:infinite={onInfinite} distance={3000} /> 69 + <div id="spacer"></div> 70 + </div> 71 + </div>
+33
src/lib/config.ts
··· 1 + /** 2 + * Configuration module for the PDS Dashboard 3 + * Uses SvelteKit environment variables 4 + */ 5 + import { 6 + PUBLIC_PDS_URL, 7 + PUBLIC_FRONTEND_URL, 8 + PUBLIC_MAX_POSTS, 9 + PUBLIC_SHOW_FUTURE_POSTS 10 + } from '$env/static/public'; 11 + 12 + export class Config { 13 + /** 14 + * The base URL of the PDS (Personal Data Server). 15 + */ 16 + static readonly PDS_URL: string = PUBLIC_PDS_URL; 17 + 18 + /** 19 + * The base URL of the frontend service for linking to replies/quotes/accounts etc. 20 + */ 21 + static readonly FRONTEND_URL: string = PUBLIC_FRONTEND_URL; 22 + 23 + /** 24 + * Maximum number of posts to fetch from the PDS per request 25 + */ 26 + static readonly MAX_POSTS: number = parseInt(PUBLIC_MAX_POSTS, 10); 27 + 28 + 29 + /** 30 + * Whether to show the posts with timestamps that are in the future. 31 + */ 32 + static readonly SHOW_FUTURE_POSTS: boolean = PUBLIC_SHOW_FUTURE_POSTS === 'true'; 33 + }
+81 -129
src/lib/pdsfetch.ts
··· 1 - import { simpleFetchHandler, XRPC } from "@atcute/client"; 2 - import "@atcute/bluesky/lexicons"; 1 + import { simpleFetchHandler, XRPC } from '@atcute/client'; 2 + import '@atcute/bluesky/lexicons'; 3 3 import type { 4 4 AppBskyActorProfile, 5 5 AppBskyEmbedImages, 6 6 AppBskyFeedPost, 7 7 At, 8 8 ComAtprotoRepoListRecords, 9 - } from "@atcute/client/lexicons"; 10 - import { 11 - CompositeDidDocumentResolver, 12 - PlcDidDocumentResolver, 13 - WebDidDocumentResolver, 14 - } from "@atcute/identity-resolver"; 15 - import { Config } from "../../config.ts"; 16 - import { Mutex } from "mutex-ts"; 17 - import moment from "moment"; 18 - import { RichText } from "@atproto/api"; 9 + } from '@atcute/client/lexicons'; 10 + import { Config } from '$lib/config'; 11 + import { Mutex } from 'mutex-ts'; 12 + import moment from 'moment'; 13 + import { RichText } from '@atproto/api'; 14 + import type {Repo} from '@atproto/api/dist/client/types/com/atproto/sync/listRepos'; 19 15 20 16 // import { ComAtprotoRepoListRecords.Record } from "@atcute/client/lexicons"; 21 17 // import { AppBskyFeedPost } from "@atcute/client/lexicons"; ··· 51 47 imagesCid: string[] | null; 52 48 videosLinkCid: string | null; 53 49 gifLink: string | null; 50 + hideMedia: boolean; 54 51 richText: RichText; 55 52 56 53 constructor( ··· 58 55 account: AccountMetadata, 59 56 richText: RichText, 60 57 ) { 58 + const post = record.value as AppBskyFeedPost.Record; 59 + const hideLabels = ['!hide', '!no-promote', '!warn', '!no-unauthenticated', 60 + 'dmca-violation', 'doxxing', 'porn', 'sexual', 'nudity', 61 + 'nsfl', 'gore']; 62 + 63 + if (post.labels?.values?.length > 0) { 64 + 65 + const labels = post.labels.values.map(label => label.val); 66 + this.hideMedia = hideLabels.some(label => labels.includes(label)); 67 + } else { 68 + this.hideMedia = false; 69 + } 70 + 61 71 this.richText = richText; 62 72 this.postCid = record.cid; 63 73 this.recordName = processAtUri(record.uri).rkey; ··· 65 75 this.authorAvatarCid = account.avatarCid; 66 76 this.authorHandle = account.handle; 67 77 this.displayName = account.displayName; 68 - const post = record.value as AppBskyFeedPost.Record; 69 78 this.timenotstamp = post.createdAt; 70 79 this.text = post.text; 71 80 this.timestamp = Date.parse(post.createdAt); ··· 79 88 this.videosLinkCid = null; 80 89 this.gifLink = null; 81 90 switch (post.embed?.$type) { 82 - case "app.bsky.embed.images": 91 + case 'app.bsky.embed.images': 83 92 this.imagesCid = post.embed.images.map( 84 93 (imageRecord: AppBskyEmbedImages.Image) => 85 94 imageRecord.image.ref.$link, 86 95 ); 87 96 break; 88 - case "app.bsky.embed.video": 97 + case 'app.bsky.embed.video': 89 98 this.videosLinkCid = post.embed.video.ref.$link; 90 99 break; 91 - case "app.bsky.embed.record": 100 + case 'app.bsky.embed.record': 92 101 this.quotingUri = processAtUri(post.embed.record.uri); 93 102 break; 94 - case "app.bsky.embed.recordWithMedia": 103 + case 'app.bsky.embed.recordWithMedia': 95 104 this.quotingUri = processAtUri(post.embed.record.record.uri); 96 105 switch (post.embed.media.$type) { 97 - case "app.bsky.embed.images": 106 + case 'app.bsky.embed.images': 98 107 this.imagesCid = post.embed.media.images.map( 99 108 (imageRecord) => imageRecord.image.ref.$link, 100 109 ); 101 110 102 111 break; 103 - case "app.bsky.embed.video": 112 + case 'app.bsky.embed.video': 104 113 this.videosLinkCid = post.embed.media.video.ref.$link; 105 114 106 115 break; 107 116 } 108 117 break; 109 - case "app.bsky.embed.external": // assuming that external embeds are gifs for now 110 - if (post.embed.external.uri.includes(".gif")) { 118 + case 'app.bsky.embed.external': // assuming that external embeds are gifs for now 119 + if (post.embed.external.uri.includes('.gif')) { 111 120 this.gifLink = post.embed.external.uri; 112 121 } 113 122 break; ··· 116 125 } 117 126 118 127 const processAtUri = (aturi: string): atUriObject => { 119 - const parts = aturi.split("/"); 128 + const parts = aturi.split('/'); 120 129 return { 121 130 repo: parts[2], 122 131 collection: parts[3], ··· 130 139 }), 131 140 }); 132 141 133 - const getDidsFromPDS = async (): Promise<At.Did[]> => { 134 - const { data } = await rpc.get("com.atproto.sync.listRepos", { 135 - params: { 136 - limit: 1000, 137 - }, 138 - }); 139 - return data.repos.filter((x) => x.active).map((repo: Repo) => repo.did) 140 - .reverse() as At.Did[]; 141 - }; 142 - const getAccountMetadata = async ( 143 - did: `did:${string}:${string}`, 144 - ) => { 145 - const account: AccountMetadata = { 146 - did: did, 147 - handle: "", // Guaranteed to be filled out later 148 - displayName: "", 149 - avatarCid: null, 150 - }; 151 - const localStorageKey = `did-metadata:${did}`; 152 - const cachedResult = cacheGet<AccountMetadata>(localStorageKey); 153 - if (cachedResult) { 154 - return cachedResult; 155 - } 142 + const getAllMetadataFromPds = async (): Promise<AccountMetadata[]> => { 156 143 try { 157 - const { data } = await rpc.get("com.atproto.repo.getRecord", { 158 - params: { 159 - repo: did, 160 - collection: "app.bsky.actor.profile", 161 - rkey: "self", 162 - }, 163 - }); 164 - const value = data.value as AppBskyActorProfile.Record; 165 - account.displayName = value.displayName || ""; 166 - if (value.avatar) { 167 - account.avatarCid = value.avatar.ref["$link"]; 144 + if (accountsMetadata.length > 0) { 145 + return accountsMetadata; 168 146 } 169 - } catch (e) { 170 - console.warn(`Error fetching profile for ${did}:`, e); 171 - } 172 - 173 - try { 174 - account.handle = await blueskyHandleFromDid(did); 175 - } catch (e) { 176 - console.error(`Error fetching handle for ${did}:`, e); 177 - return null; 178 - } 179 - cacheSet<AccountMetadata>(localStorageKey, account); 180 - return account; 181 - }; 182 - 183 - const getAllMetadataFromPds = async (): Promise<AccountMetadata[]> => { 184 - const dids = await getDidsFromPDS(); 185 - const metadata = await Promise.all( 186 - dids.map(async (repo: `did:${string}:${string}`) => { 187 - return await getAccountMetadata(repo); 188 - }), 189 - ); 190 - return metadata.filter((account) => account !== null) as AccountMetadata[]; 191 - }; 192 - 193 - const identityResolve = async (did: At.Did) => { 194 - const resolver = new CompositeDidDocumentResolver({ 195 - methods: { 196 - plc: new PlcDidDocumentResolver(), 197 - web: new WebDidDocumentResolver(), 198 - }, 199 - }); 200 - 201 - if (did.startsWith("did:plc:") || did.startsWith("did:web:")) { 202 - const doc = await resolver.resolve( 203 - did as `did:plc:${string}` | `did:web:${string}`, 204 - ); 205 - return doc; 206 - } else { 207 - throw new Error(`Unsupported DID type: ${did}`); 147 + const response = await fetch('/api/accounts'); 148 + if (!response.ok) { 149 + throw new Error(`Failed to fetch metadata: ${response.statusText}`); 150 + } 151 + const metadata = await response.json(); 152 + // Populate the module-level accountsMetadata to prevent duplicate fetches 153 + accountsMetadata = metadata; 154 + return metadata; 155 + } catch (error) { 156 + console.error('Error fetching all accounts:', error); 157 + return []; 208 158 } 209 159 }; 210 160 211 161 const blueskyHandleFromDid = async (did: At.Did) => { 212 - const localStorageKey = `did-handle:${did}`; 213 - const cachedResult = cacheGet<string>(localStorageKey); 214 - if (cachedResult) { 215 - return cachedResult; 216 - } 217 - const doc = await identityResolve(did); 218 - if (doc.alsoKnownAs) { 219 - const handleAtUri = doc.alsoKnownAs.find((url) => url.startsWith("at://")); 220 - const handle = handleAtUri?.split("/")[2]; 221 - if (!handle) { 222 - return "Handle not found"; 223 - } else { 224 - cacheSet<string>(localStorageKey, handle); 225 - return handle; 162 + try { 163 + const localStorageKey = `did-handle:${did}`; 164 + const cachedResult = cacheGet<string>(localStorageKey); 165 + if (cachedResult) { 166 + return cachedResult; 167 + } 168 + 169 + const response = await fetch(`/api/handle/${did}`); 170 + if (!response.ok) { 171 + throw new Error(`Failed to fetch handle: ${response.statusText}`); 226 172 } 227 - } else { 228 - return "Handle not found"; 173 + const data = await response.json(); 174 + cacheSet<string>(localStorageKey, data.handle); 175 + return data.handle; 176 + } catch (error) { 177 + console.error(`Error fetching handle for ${did}:`, error); 178 + return 'Handle not found'; 229 179 } 230 180 }; 231 181 ··· 363 313 364 314 const fetchPostsForUser = async (did: At.Did, cursor: string | null) => { 365 315 try { 366 - const { data } = await rpc.get("com.atproto.repo.listRecords", { 316 + const { data } = await rpc.get('com.atproto.repo.listRecords', { 367 317 params: { 368 318 repo: did as At.Identifier, 369 - collection: "app.bsky.feed.post", 319 + collection: 'app.bsky.feed.post', 370 320 limit: Config.MAX_POSTS, 371 321 cursor: cursor || undefined, 372 322 }, ··· 389 339 }; 390 340 391 341 const getTealNowListeningTo = async (did: At.Did) => { 392 - const { data } = await rpc.get("com.atproto.repo.listRecords", { 342 + const { data } = await rpc.get('com.atproto.repo.listRecords', { 393 343 params: { 394 344 repo: did as At.Identifier, 395 - collection: "fm.teal.alpha.feed.play", 345 + collection: 'fm.teal.alpha.feed.play', 396 346 limit: 1, 397 347 }, 398 348 }); 399 349 if (data.records.length > 0) { 400 350 const record = data.records[0] as ComAtprotoRepoListRecords.Record; 401 351 const value = record.value as dietTeal; 402 - const artists = value.artists.map((artist) => artist.artistName).join(", "); 352 + const artists = value.artists.map((artist) => artist.artistName).join(', '); 403 353 const timeStamp = 404 - moment(value.playedTime).isBefore(moment().subtract(1, "month")) 405 - ? moment(value.playedTime).format("MMM D, YYYY") 354 + moment(value.playedTime).isBefore(moment().subtract(1, 'month')) 355 + ? moment(value.playedTime).format('MMM D, YYYY') 406 356 : moment(value.playedTime).fromNow(); 407 357 return `Listening to ${value.trackName} by ${artists} ${timeStamp}`; 408 358 } 409 - console.log(data); 410 359 return null; 411 360 }; 412 361 ··· 415 364 }; 416 365 417 366 const getStatusSphere = async (did: At.Did) => { 418 - const { data } = await rpc.get("com.atproto.repo.listRecords", { 367 + const { data } = await rpc.get('com.atproto.repo.listRecords', { 419 368 params: { 420 369 repo: did as At.Identifier, 421 - collection: "xyz.statusphere.status", 370 + collection: 'xyz.statusphere.status', 422 371 limit: 1, 423 372 }, 424 373 }); ··· 434 383 expire_timestamp: number; 435 384 }; 436 385 386 + // In-memory cache using Map (will be replaced with SQLite later) 387 + const inMemoryCache = new Map<string, CacheEntry<unknown>>(); 388 + 437 389 const cacheSet = <T>(key: string, value: T) => { 438 390 try { 439 391 const day = 60 * 60 * 24 * 1000; ··· 441 393 data: value, 442 394 expire_timestamp: Date.now() + day, 443 395 }; 444 - localStorage.setItem(key, JSON.stringify(cacheData)); 396 + inMemoryCache.set(key, cacheData); 445 397 } catch (e) { 446 - console.error("Error caching data:", e); 447 - //Going just clear the cache and assume it's full. 448 - localStorage.clear(); 398 + console.error('Error caching data:', e); 399 + // Clear the cache if something goes wrong 400 + inMemoryCache.clear(); 449 401 } 450 402 }; 451 403 452 404 const cacheGet = <T>(key: string): T | null => { 453 405 try { 454 - const cachedData = localStorage.getItem(key); 406 + const cachedData = inMemoryCache.get(key); 455 407 if (cachedData) { 456 - const parsedData = JSON.parse(cachedData) as CacheEntry<T>; 408 + const parsedData = cachedData as CacheEntry<T>; 457 409 if (parsedData.expire_timestamp > Date.now()) { 458 410 return parsedData.data; 459 411 } else { 460 - localStorage.removeItem(key); 412 + inMemoryCache.delete(key); 461 413 } 462 414 } 463 415 //Return null if empty or expired 464 416 return null; 465 417 } catch (e) { 466 - console.error("Error fetching data from cache:", e); 418 + console.error('Error fetching data from cache:', e); 467 419 return null; 468 420 } 469 421 };
+48
src/lib/server/identity.ts
··· 1 + import type { At } from '@atcute/client/lexicons'; 2 + import { 3 + CompositeDidDocumentResolver, 4 + PlcDidDocumentResolver, 5 + WebDidDocumentResolver, 6 + } from '@atcute/identity-resolver'; 7 + import { identityCache } from './sqlCache'; 8 + 9 + const identityResolve = async (did: At.Did) => { 10 + const resolver = new CompositeDidDocumentResolver({ 11 + methods: { 12 + plc: new PlcDidDocumentResolver(), 13 + web: new WebDidDocumentResolver(), 14 + }, 15 + }); 16 + 17 + if (did.startsWith('did:plc:') || did.startsWith('did:web:')) { 18 + const doc = await resolver.resolve( 19 + did as `did:plc:${string}` | `did:web:${string}`, 20 + ); 21 + return doc; 22 + } else { 23 + throw new Error(`Unsupported DID type: ${did}`); 24 + } 25 + }; 26 + 27 + export const blueskyHandleFromDid = async (did: At.Did) => { 28 + // Check cache first 29 + const cachedResult = identityCache.get(did); 30 + if (cachedResult) { 31 + return cachedResult.handle; 32 + } 33 + 34 + const doc = await identityResolve(did); 35 + if (doc.alsoKnownAs) { 36 + const handleAtUri = doc.alsoKnownAs.find((url) => url.startsWith('at://')); 37 + const handle = handleAtUri?.split('/')[2]; 38 + if (!handle) { 39 + return 'Handle not found'; 40 + } else { 41 + // Cache the result 42 + identityCache.set(did, { handle }); 43 + return handle; 44 + } 45 + } else { 46 + return 'Handle not found'; 47 + } 48 + };
+48
src/lib/server/sqlCache.ts
··· 1 + import {SQLiteCache} from 'sqlite-cache'; 2 + import {Type} from '@sinclair/typebox'; 3 + 4 + const DB_NAME = './cache.db' 5 + const LOGGING_ENABLED = false; 6 + 7 + type Identity = { 8 + handle: string; 9 + } 10 + 11 + type AccountMetadata = { 12 + did: string; 13 + displayName: string; 14 + handle: string; 15 + avatarCid: string | null; 16 + } 17 + 18 + // Define your data schema 19 + const IdentitySchema = Type.Object({ 20 + handle: Type.String(), 21 + }) 22 + 23 + const AccountMetadataSchema = Type.Object({ 24 + did: Type.String(), 25 + displayName: Type.String(), 26 + handle: Type.String(), 27 + avatarCid: Type.Union([Type.String(), Type.Null()]), 28 + }) 29 + 30 + const identityCache = new SQLiteCache<string, Identity>({ 31 + path: DB_NAME, 32 + schema: IdentitySchema, 33 + ttl: 60_000 * 60, // 1 hour 34 + max: 1000, // Maximum 1000 entries 35 + log: LOGGING_ENABLED // Enable logging 36 + }) 37 + 38 + const accountMetadataCache = new SQLiteCache<string, AccountMetadata>({ 39 + path: DB_NAME, 40 + schema: AccountMetadataSchema, 41 + ttl: 60_000 * 10, // 1 hour 42 + max: 1000, // Maximum 1000 entries 43 + log: LOGGING_ENABLED // Enable logging 44 + }) 45 + 46 + export { identityCache, accountMetadataCache }; 47 + export type { AccountMetadata }; 48 + export default identityCache;
+4 -4
src/main.ts
··· 1 - import { mount } from "svelte"; 2 - import "./app.css"; 3 - import App from "./App.svelte"; 1 + import { mount } from 'svelte'; 2 + import './app.css'; 3 + import App from './App.svelte'; 4 4 5 5 const app = mount(App, { 6 - target: document.getElementById("app")!, 6 + target: document.getElementById('app')!, 7 7 }); 8 8 9 9 export default app;
+9
src/routes/+layout.svelte
··· 1 + <script lang="ts"> 2 + import '$lib/assets/theme.css' 3 + import Navbar from '$lib/components/Navbar.svelte'; 4 + </script> 5 + 6 + <Navbar /> 7 + <main style="padding-top: 80px; width: 100%; max-width: 100vw; overflow-x: hidden;"> 8 + <slot /> 9 + </main>
+6
src/routes/+page.svelte
··· 1 + <script lang="ts"> 2 + import LandingPage from '$lib/components/landing/LandingPage.svelte'; 3 + </script> 4 + 5 + 6 + <LandingPage/>
+93
src/routes/api/accounts/+server.ts
··· 1 + import type { RequestHandler } from './$types'; 2 + import type { At, AppBskyActorProfile } from '@atcute/client/lexicons'; 3 + import { accountMetadataCache } from '$lib/server/sqlCache'; 4 + import type { AccountMetadata } from '$lib/server/sqlCache'; 5 + import { json } from '@sveltejs/kit'; 6 + import { simpleFetchHandler, XRPC } from '@atcute/client'; 7 + import '@atcute/bluesky/lexicons'; 8 + import { Config } from '$lib/config'; 9 + import type { Repo } from '@atproto/api/dist/client/types/com/atproto/sync/listRepos'; 10 + import { blueskyHandleFromDid } from '$lib/server/identity'; 11 + 12 + const rpc = new XRPC({ 13 + handler: simpleFetchHandler({ 14 + service: Config.PDS_URL, 15 + }), 16 + }); 17 + 18 + const getAccountMetadata = async (did: At.Did): Promise<AccountMetadata | null> => { 19 + // Check cache first with the accounts:${did} key 20 + const cacheKey = `metadata:${did}`; 21 + const cachedResult = accountMetadataCache.get(cacheKey); 22 + if (cachedResult) { 23 + return cachedResult; 24 + } 25 + 26 + const account: AccountMetadata = { 27 + did: did, 28 + handle: '', // Guaranteed to be filled out later 29 + displayName: '', 30 + avatarCid: null, 31 + }; 32 + 33 + try { 34 + const { data } = await rpc.get('com.atproto.repo.getRecord', { 35 + params: { 36 + repo: did, 37 + collection: 'app.bsky.actor.profile', 38 + rkey: 'self', 39 + }, 40 + }); 41 + const value = data.value as AppBskyActorProfile.Record; 42 + account.displayName = value.displayName || ''; 43 + if (value.avatar) { 44 + account.avatarCid = value.avatar.ref['$link']; 45 + } 46 + } catch (e) { 47 + console.warn(`Error fetching profile for ${did}:`, e); 48 + } 49 + 50 + try { 51 + account.handle = await blueskyHandleFromDid(did); 52 + } catch (e) { 53 + console.error(`Error fetching handle for ${did}:`, e); 54 + return null; 55 + } 56 + 57 + // Cache the result with the accounts:${did} key 58 + accountMetadataCache.set(cacheKey, account); 59 + return account; 60 + }; 61 + 62 + const getDidsFromPDS = async (): Promise<At.Did[]> => { 63 + const { data } = await rpc.get('com.atproto.sync.listRepos', { 64 + params: { 65 + limit: 1000, 66 + }, 67 + }); 68 + return data.repos.filter((x) => x.active).map((repo: Repo) => repo.did) 69 + .reverse() as At.Did[]; 70 + }; 71 + 72 + const getAllMetadataFromPds = async (): Promise<AccountMetadata[]> => { 73 + const dids = await getDidsFromPDS(); 74 + const metadata = await Promise.all( 75 + dids.map(async (repo: `did:${string}:${string}`) => { 76 + return await getAccountMetadata(repo); 77 + }), 78 + ); 79 + return metadata.filter((account) => account !== null) as AccountMetadata[]; 80 + }; 81 + 82 + export const GET: RequestHandler = async () => { 83 + try { 84 + const metadata = await getAllMetadataFromPds(); 85 + return json(metadata); 86 + } catch (error) { 87 + console.error('Error fetching all accounts:', error); 88 + return json( 89 + { error: 'Failed to fetch accounts' }, 90 + { status: 500 } 91 + ); 92 + } 93 + };
+23
src/routes/api/handle/[did]/+server.ts
··· 1 + import type { RequestHandler } from './$types'; 2 + import type { At } from '@atcute/client/lexicons'; 3 + import { json } from '@sveltejs/kit'; 4 + import { blueskyHandleFromDid } from '$lib/server/identity'; 5 + 6 + export const GET: RequestHandler = async ({ params }) => { 7 + const { did } = params; 8 + 9 + if (!did || (!did.startsWith('did:plc:') && !did.startsWith('did:web:'))) { 10 + return json({ error: 'Invalid DID format' }, { status: 400 }); 11 + } 12 + 13 + try { 14 + const handle = await blueskyHandleFromDid(did as At.Did); 15 + return json({ handle }); 16 + } catch (error) { 17 + console.error(`Error fetching handle for ${did}:`, error); 18 + return json( 19 + { error: 'Failed to fetch handle' }, 20 + { status: 500 } 21 + ); 22 + } 23 + };
+215
src/routes/info/+page.svelte
··· 1 + <script lang="ts"> 2 + import PDSHeader from '$lib/components/PDSHeader.svelte'; 3 + 4 + const faqs = [ 5 + { 6 + id: 'what-is-selfhosted-social', 7 + question: 'What is selfhosted.social?', 8 + answer: `selfhosted.social is an <a href="https://atproto.com/guides/glossary#pds-personal-data-server"> ATProto PDS</a>. We welcome anyone who agrees with our <a href="/legal">Terms of Service and Privacy Policy</a>. 9 + ` 10 + }, 11 + { 12 + id: 'invite-code', 13 + question: 'Does your PDS require an invite code?', 14 + answer: ` 15 + Nope! We have an open PDS as long as you agree with our <a href="/legal">Terms of Service and Privacy Policy</a>. 16 + You can use this <a href="https://pdsmoover.com/moover/selfhosted.social">PDS MOOver link</a> to migrate your ATProto account to our PDS from another PDS. 17 + Or if you are creating a new account, you can do this on <a href="https://bsky.app/">Bluesky's website</a>, 18 + click create a new account, and then click the pencil icon next to the text "You are creating an account on Bluesky Social". 19 + On the custom screen you can enter "https://selfhosted.social". Then you complete the registration process as normal and you're good to go!'. 20 + ` 21 + }, 22 + { 23 + id: 'server-location-backups', 24 + question: 'What about the server? Where is it located? Is there backups?', 25 + answer: ` 26 + The PDS is hosted on <a href="https://www.digitalocean.com/">DigitalOcean</a>. On a VPS that is located in Atlanta, GA, USA. We do nightly backups of the whole server, and each individual account is also backed up with <a href="https://pdsmoover.com">PDS MOOver</a>. 27 + You can manage them by signing in to the <a href="https://pdsmoover.com/backups">backups page</a> with your ATProto account. 28 + ` 29 + }, 30 + { 31 + id: 'is-it-free', 32 + question: 'Is it free?', 33 + answer: ` 34 + Yes, but sponsorships and tips are welcomed to help cover server costs! Can use <a href="https://github.com/sponsors/fatfingers23">GitHub sponsors</a> or <a href="https://ko-fi.com/baileytownsend">Ko-Fi</a> to support us. 35 + ` 36 + }, 37 + { 38 + id: 'support-contact', 39 + question: 'How do I get support? Reach an admin?', 40 + answer: ` 41 + You can reach out directly to me on Bluesky <a href="https://bsky.app/profile/baileytownsend.dev">@baileytownsend.dev</a> or email us at <a href="&#x6d;&#x61;&#105;&#108;&#x74;&#000111;&#58;&#109;&#x6f;&#x64;&#x6d;&#00097;&#x69;&#000108;&#x40;&#115;&#101;&#000108;&#x66;&#000104;&#x6f;&#000115;&#x74;&#x65;&#100;&#46;&#000115;&#111;&#x63;&#x69;&#x61;&#x6c;?subject=&cc=&bcc=&body=" style="" class="" id="">&#109;&#x6f;&#x64;&#000109;&#x61;&#105;&#108;&#x40;&#115;&#101;&#108;&#000102;&#x68;&#x6f;&#115;&#000116;&#101;&#x64;&#00046;&#000115;&#000111;&#x63;&#000105;&#x61;&#x6c;</a>. 42 + ` 43 + }, 44 + { 45 + id: 'other-pdses', 46 + question: 'I don\'t think this is the PDS for me.', 47 + answer: ` 48 + Perfectly okay! Independent PDSs are becoming more common, and here is a list of some of our favorites that welcome new users and hope if you can't find a home with us that you can find one that works for you. 49 + <ul> 50 + <li><a href="https://docs.blacksky.community/migrating-to-blacksky-pds-complete-guide">Blacksky</a></li> 51 + <li><a href="https://leaflet.pub/2191cd16-e793-4dd8-95ff-c6b02e89bb6a">Northsky</a></li> 52 + <li><a href="https://bsky.app/profile/witchcraft.systems">witchcraft.systems</a></li> 53 + <li><a href="https://tophhie.social/">tophhie.social</a></li> 54 + <li><a href="https://bsky.app/profile/altq.net">altq.net</a></li> 55 + 56 + </ul> 57 + ` 58 + } 59 + ]; 60 + </script> 61 + 62 + <div class="page-container"> 63 + 64 + <PDSHeader/> 65 + 66 + <section class="faq-section"> 67 + <h2>Frequently Asked Questions</h2> 68 + <div class="faq-list"> 69 + {#each faqs as faq (faq.id)} 70 + <div id={faq.id} class="faq-item"> 71 + <h3> 72 + <a href="#{faq.id}" class="faq-question">{faq.question}</a> 73 + </h3> 74 + <div class="faq-answer"> 75 + <div class="answer-content"> 76 + {@html faq.answer} 77 + </div> 78 + </div> 79 + </div> 80 + {/each} 81 + </div> 82 + </section> 83 + </div> 84 + 85 + <style> 86 + .page-container { 87 + max-width: 1200px; 88 + margin: 2rem auto; 89 + padding: 2rem; 90 + } 91 + 92 + .faq-section { 93 + margin-top: 3rem; 94 + } 95 + 96 + h2 { 97 + font-size: 2rem; 98 + font-weight: 700; 99 + color: var(--text-color, #111827); 100 + margin-bottom: 2rem; 101 + text-align: center; 102 + } 103 + 104 + .faq-list { 105 + display: flex; 106 + flex-direction: column; 107 + gap: 2.5rem; 108 + } 109 + 110 + .faq-item { 111 + scroll-margin-top: 6rem; 112 + } 113 + 114 + h3 { 115 + color: var(--text-color, #111827); 116 + font-size: 1.5rem; 117 + font-weight: 600; 118 + margin: 0 0 1rem 0; 119 + } 120 + 121 + .faq-question { 122 + color: inherit; 123 + text-decoration: none; 124 + transition: color 0.2s ease; 125 + } 126 + 127 + .faq-question:hover { 128 + color: var(--link-color, #6366f1); 129 + } 130 + 131 + .faq-question:focus { 132 + outline: 2px solid var(--link-color, #6366f1); 133 + outline-offset: 4px; 134 + border-radius: 4px; 135 + } 136 + 137 + .faq-answer { 138 + padding: 0; 139 + } 140 + 141 + .answer-content { 142 + color: var(--text-color, #111827); 143 + opacity: 0.8; 144 + line-height: 1.7; 145 + } 146 + 147 + .answer-content :global(a) { 148 + color: var(--link-color, #6366f1); 149 + text-decoration: none; 150 + font-weight: 500; 151 + transition: opacity 0.2s ease; 152 + border-bottom: 1px solid rgba(99, 102, 241, 0.3); 153 + } 154 + 155 + .answer-content :global(a:hover) { 156 + opacity: 0.8; 157 + border-bottom-color: var(--link-color, #6366f1); 158 + } 159 + 160 + .answer-content :global(a:focus) { 161 + outline: 2px solid var(--link-color, #6366f1); 162 + outline-offset: 2px; 163 + border-radius: 2px; 164 + } 165 + 166 + @media (max-width: 768px) { 167 + .page-container { 168 + padding: 1rem; 169 + } 170 + 171 + h2 { 172 + font-size: 1.5rem; 173 + margin-bottom: 1.5rem; 174 + } 175 + 176 + h3 { 177 + font-size: 1.25rem; 178 + } 179 + 180 + .faq-list { 181 + gap: 2rem; 182 + } 183 + 184 + .faq-item { 185 + scroll-margin-top: 5rem; 186 + } 187 + } 188 + 189 + @media (max-width: 480px) { 190 + .page-container { 191 + padding: 0.75rem; 192 + margin: 1rem auto; 193 + } 194 + 195 + h2 { 196 + font-size: 1.25rem; 197 + } 198 + 199 + h3 { 200 + font-size: 1.1rem; 201 + } 202 + 203 + .faq-list { 204 + gap: 1.5rem; 205 + } 206 + 207 + .faq-item { 208 + scroll-margin-top: 4rem; 209 + } 210 + 211 + .answer-content { 212 + font-size: 0.95rem; 213 + } 214 + } 215 + </style>
+353
src/routes/legal/+page.svelte
··· 1 + <script lang="ts"> 2 + </script> 3 + 4 + <div class="page-container"> 5 + 6 + <section id="privacy-policy" class="legal-section"> 7 + <h1> 8 + <a href="#privacy-policy" class="section-link">Privacy Policy</a> 9 + </h1> 10 + 11 + <p><em>Last Updated: December 2, 2025</em></p> 12 + 13 + <h3 id="your-data"> 14 + <a href="#your-data" class="section-link">Your Data</a> 15 + </h3> 16 + <p> 17 + Your <a href="https://blueskyweb.zendesk.com/hc/en-us/articles/15835264007693-Data-Privacy">ATProto data</a> is public and accessible to anyone. This is a core concept of the ATProto protocol. This data is accessible on the server via <a href="https://docs.bsky.app/docs/category/http-reference">API endpoints</a>. 18 + It is also stored in our nightly backups as well as you are signed up for backups automatically with <a href="https://pdsmoover.com/backups">PDS MOOver</a>. 19 + </p> 20 + <p> 21 + Your private data, such as your email address and password, are kept private on the server and included in nightly server backups. We do not share this data with any third parties or sell it to advertisers. Your private messages (DMs) are stored on Bluesky's servers; your ATProto account is what gives you access to those messages on their servers. 22 + </p> 23 + 24 + <h3 id="service-provider-location"> 25 + <a href="#service-provider-location" class="section-link">Service Provider and Location</a> 26 + </h3> 27 + <p> 28 + The PDS is hosted on <a href="https://www.digitalocean.com/">DigitalOcean</a> on a VPS located in Atlanta, GA, USA. We perform nightly backups of the entire server, and each individual account is also backed up with <a href="https://pdsmoover.com">PDS MOOver</a>. 29 + You can manage your backups by signing in to the <a href="https://pdsmoover.com/backups">backups page</a> with your ATProto account. 30 + </p> 31 + 32 + <h3 id="data-collection"> 33 + <a href="#data-collection" class="section-link">Data Collection</a> 34 + </h3> 35 + <p> 36 + We collect only the information necessary to operate your ATProto account: 37 + </p> 38 + <ul> 39 + <li><strong>Account Information:</strong> Email address, and other public ATProto data</li> 40 + <li><strong>Usage Data:</strong> Server logs that may include IP addresses, access times, and API requests for operational purposes</li> 41 + <li><strong>Public Content:</strong> Posts, media, and other content you publish through the ATProto network</li> 42 + </ul> 43 + 44 + 45 + <h3 id="data-retention"> 46 + <a href="#data-retention" class="section-link">Data Retention</a> 47 + </h3> 48 + <p> 49 + Your account data is retained as long as your account is active. If your account becomes deactivated, or you migrate your account to another PDS, your data could be deleted after 30 days if resources are needed. If you would like to delete your data on our servers please delete your account when you migrate to another PDS or decide to no longer use the service. 50 + </p> 51 + 52 + 53 + <h3 id="childrens-privacy"> 54 + <a href="#childrens-privacy" class="section-link">Children's Privacy</a> 55 + </h3> 56 + <p> 57 + Our service is not intended for users under the age of 13. We do not knowingly collect personal information from children under 13. If you believe a child has created an account, please contact us immediately. 58 + </p> 59 + 60 + <h3 id="changes-policy"> 61 + <a href="#changes-policy" class="section-link">Changes to This Policy</a> 62 + </h3> 63 + <p> 64 + We may update this Privacy Policy from time to time. We will notify users of any material changes by updating the "Last Updated" date at the top of this policy. Continued use of the service after changes constitutes acceptance of the updated policy. 65 + </p> 66 + 67 + <h3 id="privacy-contact"> 68 + <a href="#privacy-contact" class="section-link">Contact</a> 69 + </h3> 70 + <p> 71 + If you have questions about this Privacy Policy, please contact us at <a href="&#x6d;&#x61;&#105;&#108;&#x74;&#000111;&#58;&#109;&#x6f;&#x64;&#x6d;&#00097;&#x69;&#000108;&#x40;&#115;&#101;&#000108;&#x66;&#000104;&#x6f;&#000115;&#x74;&#x65;&#100;&#46;&#000115;&#111;&#x63;&#x69;&#x61;&#x6c;">&#109;&#x6f;&#x64;&#000109;&#x61;&#105;&#108;&#x40;&#115;&#101;&#108;&#000102;&#x68;&#x6f;&#115;&#000116;&#101;&#x64;&#00046;&#000115;&#000111;&#x63;&#000105;&#x61;&#x6c;</a> or reach out on Bluesky at <a href="https://bsky.app/profile/baileytownsend.dev">@baileytownsend.dev</a>. 72 + </p> 73 + 74 + </section> 75 + 76 + <section id="terms-of-service" class="legal-section"> 77 + <h2> 78 + <a href="#terms-of-service" class="section-link">Terms of Service</a> 79 + </h2> 80 + 81 + <p><em>Last Updated: December 2, 2025</em></p> 82 + 83 + <h3 id="acceptance-terms"> 84 + <a href="#acceptance-terms" class="section-link">Acceptance of Terms</a> 85 + </h3> 86 + <p> 87 + By creating an account on selfhosted.social or migrating an existing ATProto account, you agree to comply with these Terms of Service and our Privacy Policy. If you do not agree to these terms, please do not use our service. 88 + </p> 89 + 90 + <h3 id="account-registration"> 91 + <a href="#account-registration" class="section-link">Account Registration</a> 92 + </h3> 93 + <p> 94 + You must be at least 13 years old to create an account. You are responsible for maintaining the security of your account credentials. You must provide accurate information during registration and keep your contact information up to date. 95 + </p> 96 + 97 + <h3 id="acceptable-use"> 98 + <a href="#acceptable-use" class="section-link">Acceptable Use</a> 99 + </h3> 100 + <p> 101 + You agree to use selfhosted.social in compliance with all applicable laws and regulations. When using our service, you must not: 102 + </p> 103 + <ul> 104 + <li>Create accounts solely for the purpose of spamming or harassment</li> 105 + <li>Engage in spam, bulk messaging, or automated posting that disrupts the network</li> 106 + <li>Post illegal content or content that violates the rights of others</li> 107 + <li>Impersonate others or misrepresent your identity</li> 108 + <li>Attempt to gain unauthorized access to the server or other users' accounts</li> 109 + <li>Use the service to distribute malware or conduct phishing attacks</li> 110 + <li>Engage in any activity that could harm the server or other users</li> 111 + </ul> 112 + 113 + <h3 id="automated-accounts-bots"> 114 + <a href="#automated-accounts-bots" class="section-link">Automated Accounts and Bots</a> 115 + </h3> 116 + <p> 117 + Automated accounts and bots are permitted on selfhosted.social, provided they comply with these terms. Bot accounts must: 118 + </p> 119 + <ul> 120 + <li>Clearly identify themselves as automated accounts</li> 121 + <li>Not engage in spam or disruptive behavior</li> 122 + <li>Respect rate limits and not place excessive load on the server</li> 123 + <li>Comply with all other terms of service and applicable laws</li> 124 + </ul> 125 + 126 + <h3 id="content-conduct"> 127 + <a href="#content-conduct" class="section-link">Content and Conduct</a> 128 + </h3> 129 + <p> 130 + Your public content on the ATProto network is subject to <a href="https://bsky.social/about/support/community-guidelines">Bluesky's Community Guidelines</a> when using Bluesky. While we operate independently, we expect users to maintain respectful conduct across the ATProto network. 131 + </p> 132 + <p> 133 + We reserve the right to remove content or suspend accounts that violate these terms, applicable laws, or pose a risk to the service or other users. 134 + </p> 135 + 136 + <h3 id="service-availability"> 137 + <a href="#service-availability" class="section-link">Service Availability</a> 138 + </h3> 139 + <p> 140 + We strive to maintain reliable service but cannot guarantee 100% uptime. The service is provided "as is" without warranties of any kind. We may modify, suspend, or discontinue the service at any time with or without notice. 141 + </p> 142 + 143 + <h3 id="account-portability"> 144 + <a href="#account-portability" class="section-link">Account Portability</a> 145 + </h3> 146 + <p> 147 + One of the benefits of ATProto is account portability. You may migrate your account to another PDS at any time using <a href="https://pdsmoover.com/moover">PDS MOOver</a> or other ATProto migration tools. 148 + </p> 149 + 150 + <h3 id="termination"> 151 + <a href="#termination" class="section-link">Termination</a> 152 + </h3> 153 + <p> 154 + We reserve the right to suspend or terminate accounts that violate these terms without prior notice. You may also delete your account at any time. Upon termination, your private data will be deleted in accordance with our Privacy Policy, but your public ATProto data may persist on other servers in the network. 155 + </p> 156 + 157 + <h3 id="limitation-liability"> 158 + <a href="#limitation-liability" class="section-link">Limitation of Liability</a> 159 + </h3> 160 + <p> 161 + selfhosted.social is provided as a free community service. To the fullest extent permitted by law, we are not liable for any damages arising from your use of the service, including but not limited to data loss, service interruptions, or security breaches. 162 + </p> 163 + 164 + <h3 id="changes-terms"> 165 + <a href="#changes-terms" class="section-link">Changes to Terms</a> 166 + </h3> 167 + <p> 168 + We may update these Terms of Service from time to time. Material changes will be communicated by updating the "Last Updated" date at the top of this document. Continued use of the service after changes constitutes acceptance of the updated terms. 169 + </p> 170 + 171 + <h3 id="terms-contact"> 172 + <a href="#terms-contact" class="section-link">Contact</a> 173 + </h3> 174 + <p> 175 + If you have questions about these Terms of Service, please contact us at <a href="&#x6d;&#x61;&#105;&#108;&#x74;&#000111;&#58;&#109;&#x6f;&#x64;&#x6d;&#00097;&#x69;&#000108;&#x40;&#115;&#101;&#000108;&#x66;&#000104;&#x6f;&#000115;&#x74;&#x65;&#100;&#46;&#000115;&#111;&#x63;&#x69;&#x61;&#x6c;">&#109;&#x6f;&#x64;&#000109;&#x61;&#105;&#108;&#x40;&#115;&#101;&#108;&#000102;&#x68;&#x6f;&#115;&#000116;&#101;&#x64;&#00046;&#000115;&#000111;&#x63;&#000105;&#x61;&#x6c;</a> or reach out on Bluesky at <a href="https://bsky.app/profile/baileytownsend.dev">@baileytownsend.dev</a>. 176 + </p> 177 + 178 + </section> 179 + </div> 180 + 181 + <style> 182 + .page-container { 183 + max-width: 1200px; 184 + margin: 2rem auto; 185 + padding: 2rem; 186 + } 187 + 188 + h1 { 189 + color: var(--text-color, #111827); 190 + margin-bottom: 2rem; 191 + font-size: 2.5rem; 192 + font-weight: 700; 193 + } 194 + 195 + .legal-section { 196 + margin-bottom: 4rem; 197 + scroll-margin-top: 6rem; 198 + } 199 + 200 + .legal-section:last-child { 201 + margin-bottom: 2rem; 202 + } 203 + 204 + h2 { 205 + color: var(--text-color, #111827); 206 + font-size: 2rem; 207 + font-weight: 700; 208 + margin-bottom: 1.5rem; 209 + padding-bottom: 0.5rem; 210 + border-bottom: 2px solid var(--border-color, #e2e8f0); 211 + } 212 + 213 + h3 { 214 + color: var(--text-color, #111827); 215 + font-size: 1.5rem; 216 + font-weight: 600; 217 + margin-top: 2rem; 218 + margin-bottom: 1rem; 219 + scroll-margin-top: 6rem; 220 + } 221 + 222 + .section-link { 223 + color: inherit; 224 + text-decoration: none; 225 + transition: color 0.2s ease; 226 + } 227 + 228 + .section-link:hover { 229 + color: var(--link-color, #6366f1); 230 + } 231 + 232 + .section-link:focus { 233 + outline: 2px solid var(--link-color, #6366f1); 234 + outline-offset: 4px; 235 + border-radius: 4px; 236 + } 237 + 238 + p { 239 + color: var(--text-color, #111827); 240 + line-height: 1.8; 241 + margin-bottom: 1rem; 242 + opacity: 0.9; 243 + } 244 + 245 + p:last-child { 246 + margin-bottom: 0; 247 + } 248 + 249 + em { 250 + color: var(--text-color, #111827); 251 + opacity: 0.7; 252 + font-size: 0.9rem; 253 + } 254 + 255 + ul { 256 + color: var(--text-color, #111827); 257 + line-height: 1.8; 258 + margin: 1rem 0 1.5rem 1.5rem; 259 + opacity: 0.9; 260 + } 261 + 262 + li { 263 + margin-bottom: 0.5rem; 264 + } 265 + 266 + li:last-child { 267 + margin-bottom: 0; 268 + } 269 + 270 + strong { 271 + font-weight: 600; 272 + color: var(--text-color, #111827); 273 + } 274 + 275 + a { 276 + color: var(--link-color, #6366f1); 277 + text-decoration: none; 278 + border-bottom: 1px solid rgba(99, 102, 241, 0.3); 279 + transition: opacity 0.2s ease, border-bottom-color 0.2s ease; 280 + } 281 + 282 + a:hover { 283 + opacity: 0.8; 284 + border-bottom-color: var(--link-color, #6366f1); 285 + } 286 + 287 + a:focus { 288 + outline: 2px solid var(--link-color, #6366f1); 289 + outline-offset: 2px; 290 + border-radius: 2px; 291 + } 292 + 293 + @media (max-width: 768px) { 294 + .page-container { 295 + padding: 1rem; 296 + } 297 + 298 + h1 { 299 + font-size: 2rem; 300 + margin-bottom: 1.5rem; 301 + } 302 + 303 + h2 { 304 + font-size: 1.5rem; 305 + } 306 + 307 + h3 { 308 + font-size: 1.25rem; 309 + margin-top: 1.5rem; 310 + scroll-margin-top: 5rem; 311 + } 312 + 313 + .legal-section { 314 + margin-bottom: 3rem; 315 + scroll-margin-top: 5rem; 316 + } 317 + 318 + ul { 319 + margin-left: 1.25rem; 320 + } 321 + } 322 + 323 + @media (max-width: 480px) { 324 + .page-container { 325 + padding: 0.75rem; 326 + margin: 1rem auto; 327 + } 328 + 329 + h1 { 330 + font-size: 1.75rem; 331 + } 332 + 333 + h2 { 334 + font-size: 1.25rem; 335 + } 336 + 337 + h3 { 338 + font-size: 1.1rem; 339 + margin-top: 1.25rem; 340 + scroll-margin-top: 4rem; 341 + } 342 + 343 + .legal-section { 344 + margin-bottom: 2rem; 345 + scroll-margin-top: 4rem; 346 + } 347 + 348 + ul { 349 + margin-left: 1rem; 350 + font-size: 0.95rem; 351 + } 352 + } 353 + </style>
+10 -2
svelte.config.js
··· 1 - import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; 1 + import adapter from '@sveltejs/adapter-node'; 2 + import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 2 3 3 - export default { 4 + /** @type {import('@sveltejs/kit').Config} */ 5 + const config = { 4 6 // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 5 7 // for more information about preprocessors 6 8 preprocess: vitePreprocess(), 9 + 10 + kit: { 11 + adapter: adapter() 12 + } 7 13 }; 14 + 15 + export default config;
+29 -78
themes/dark/theme.css src/lib/assets/theme.css
··· 1 1 /* Modern Theme for pds-dash */ 2 2 3 + * { 4 + box-sizing: border-box; 5 + } 6 + 7 + html { 8 + overflow-x: hidden; 9 + width: 100%; 10 + } 11 + 3 12 :root { 4 13 /* Dark theme derived from provided OKLCH palette */ 5 14 color-scheme: dark; ··· 65 74 66 75 body { 67 76 margin: 0; 68 - display: flex; 69 - place-items: center; 77 + padding: 0; 70 78 min-width: 320px; 71 79 min-height: 100vh; 72 80 background-color: var(--background-color); ··· 80 88 overflow-wrap: break-word; 81 89 word-break: break-word; 82 90 hyphens: none; 91 + overflow-x: hidden; 83 92 } 84 93 85 94 a { ··· 165 174 } 166 175 167 176 #postLink { 168 - color: var(--time-color); 177 + color: var(--time-color) !important; 169 178 font-size: 0.85em; 170 179 padding: 0; 171 180 margin: 0; ··· 207 216 word-break: break-word; 208 217 max-width: 80%; 209 218 max-height: 95%; 210 - overflow: hidden; 211 219 align-self: flex-start; 212 220 margin-top: auto; 213 221 margin-bottom: auto; ··· 338 346 #Content { 339 347 display: flex; 340 348 width: 100%; 349 + max-width: 100vw; 341 350 height: 100%; 342 351 flex-direction: row; 343 352 justify-content: space-between; 344 - align-items: center; 353 + align-items: flex-start; 345 354 background-color: var(--background-color); 346 355 color: var(--text-color); 347 - gap: 24px; 356 + gap: 20px; 357 + padding: 0 16px; 348 358 } 349 359 350 360 #Feed { 351 361 overflow-y: auto; 352 - width: 65%; 362 + flex: 1; 363 + min-width: 0; 353 364 height: 100vh; 354 - padding-right: 16px; 355 365 align-self: flex-start; 356 366 } 357 367 ··· 363 373 } 364 374 365 375 #Account { 366 - width: 35%; 376 + flex: 0 0 400px; 377 + max-width: 400px; 367 378 display: flex; 368 379 flex-direction: column; 369 380 border: 1px solid var(--border-color); 370 381 background-color: var(--content-background-color); 371 382 max-height: 80vh; 372 383 padding: 24px; 373 - margin-left: 16px; 374 384 border-radius: 12px; 375 385 box-shadow: var(--card-shadow); 376 386 } ··· 400 410 @media screen and (max-width: 768px) { 401 411 #Content { 402 412 flex-direction: column; 403 - width: auto; 413 + width: 100%; 414 + max-width: 100vw; 404 415 padding: 12px; 405 - margin-top: 0; 416 + margin: 0; 417 + gap: 16px; 406 418 } 407 419 408 420 #Account { 409 - width: calc(100% - 32px); 421 + flex: 1 1 auto; 422 + width: 100%; 423 + max-width: 100%; 410 424 padding: 16px; 411 - margin-bottom: 20px; 412 - margin-left: 0; 413 - margin-right: 0; 425 + margin: 0; 414 426 height: auto; 415 427 order: -1; 416 428 } 417 429 418 430 #Feed { 431 + flex: 1 1 auto; 419 432 width: 100%; 420 433 margin: 0; 421 434 padding: 0; ··· 469 482 -webkit-scrollbar: none; /* Safari */ 470 483 } 471 484 472 - :root { 473 - /* Dark theme derived from provided OKLCH palette (applied via valid :root) */ 474 - color-scheme: dark; 475 - 476 - /* Base and content colors */ 477 - --color-base-100: oklch(25.33% 0.016 252.42); 478 - --color-base-200: oklch(23.26% 0.014 253.1); 479 - --color-base-300: oklch(21.15% 0.012 254.09); 480 - --color-base-content: oklch(97.807% 0.029 256.847); 481 - 482 - /* Brand and semantic colors */ 483 - --color-primary: oklch(58% 0.233 277.117); 484 - --color-primary-content: oklch(96% 0.018 272.314); 485 - --color-secondary: oklch(65% 0.241 354.308); 486 - --color-secondary-content: oklch(94% 0.028 342.258); 487 - --color-accent: oklch(77% 0.152 181.912); 488 - --color-accent-content: oklch(38% 0.063 188.416); 489 - --color-neutral: oklch(14% 0.005 285.823); 490 - --color-neutral-content: oklch(92% 0.004 286.32); 491 - --color-info: oklch(74% 0.16 232.661); 492 - --color-info-content: oklch(29% 0.066 243.157); 493 - --color-success: oklch(76% 0.177 163.223); 494 - --color-success-content: oklch(37% 0.077 168.94); 495 - --color-warning: oklch(82% 0.189 84.429); 496 - --color-warning-content: oklch(41% 0.112 45.904); 497 - --color-error: oklch(71% 0.194 13.428); 498 - --color-error-content: oklch(27% 0.105 12.094); 499 - 500 - /* Radii, sizes, borders */ 501 - --radius-selector: 0.5rem; 502 - --radius-field: 0.25rem; 503 - --radius-box: 0.5rem; 504 - --size-selector: 0.25rem; 505 - --size-field: 0.25rem; 506 - --border: 1px; 507 - --depth: 1; 508 - --noise: 0; 509 - 510 - /* Mappings for the rest of the CSS */ 511 - --background-color: var(--color-base-300); 512 - --header-background-color: var(--color-base-200); 513 - --content-background-color: var(--color-base-200); 514 - --text-color: var(--color-base-content); 515 - --text-secondary-color: color-mix( 516 - in oklab, 517 - var(--color-base-content) 70%, 518 - var(--color-base-100) 519 - ); 520 - --border-color: var(--color-base-300); 521 - --link-color: var(--color-primary); 522 - --link-hover-color: var(--color-primary-content); 523 - --time-color: var(--color-secondary); 524 - --indicator-inactive-color: var(--color-base-300); 525 - --indicator-active-color: var(--color-primary); 526 - 527 - /* Subtle hover background for dark */ 528 - --button-hover: color-mix( 529 - in oklab, 530 - var(--color-base-200) 80%, 531 - var(--color-base-content) 532 - ); 533 - }
-426
themes/default/theme.css
··· 1 - /* Modern Theme for pds-dash */ 2 - 3 - :root { 4 - /* Modern color palette */ 5 - --primary-h: 243; 6 - --link-color: hsl(var(--primary-h), 73%, 59%); 7 - --link-hover-color: #4338ca; 8 - --time-color: #8b5cf6; 9 - --background-color: #f8fafc; 10 - --header-background-color: #ffffff; 11 - --content-background-color: #ffffff; 12 - --text-color: #111827; 13 - --text-secondary-color: #4b5563; 14 - --border-color: #e2e8f0; 15 - --indicator-inactive-color: #cbd5e1; 16 - --indicator-active-color: #6366f1; 17 - 18 - /* Modern shadows */ 19 - --button-hover: #f3f4f6; 20 - } 21 - 22 - body { 23 - margin: 0; 24 - display: flex; 25 - place-items: center; 26 - min-width: 320px; 27 - min-height: 100vh; 28 - background-color: var(--background-color); 29 - font-family: 30 - "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, 31 - Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 32 - font-size: 18px; 33 - line-height: 1.5; 34 - color: var(--text-color); 35 - border-color: var(--border-color); 36 - overflow-wrap: break-word; 37 - word-break: break-word; 38 - hyphens: none; 39 - } 40 - 41 - a { 42 - font-weight: 500; 43 - color: var(--link-color); 44 - text-decoration: none; 45 - transition: color 0.15s ease; 46 - } 47 - a:hover { 48 - color: var(--link-hover-color); 49 - } 50 - 51 - h1 { 52 - font-size: 2.5em; 53 - line-height: 1.2; 54 - font-weight: 700; 55 - } 56 - 57 - #app { 58 - max-width: 1400px; 59 - width: 100%; 60 - margin: 0 auto; 61 - padding: 0; 62 - text-align: center; 63 - } 64 - 65 - /* Post Component */ 66 - #postContainer { 67 - display: flex; 68 - flex-direction: column; 69 - border-radius: 12px; 70 - border: 1px solid var(--border-color); 71 - background-color: var(--content-background-color); 72 - margin-bottom: 20px; 73 - overflow-wrap: break-word; 74 - overflow: hidden; 75 - box-shadow: var(--card-shadow); 76 - transition: transform 0.2s ease, box-shadow 0.2s ease; 77 - } 78 - 79 - #postContainer:hover { 80 - transform: translateY(-2px); 81 - box-shadow: 82 - 0 10px 15px -3px rgba(0, 0, 0, 0.1), 83 - 0 4px 6px -2px rgba(0, 0, 0, 0.05); 84 - } 85 - 86 - #postHeader { 87 - display: flex; 88 - flex-direction: row; 89 - align-items: center; 90 - justify-content: start; 91 - background-color: var(--header-background-color); 92 - padding: 12px 16px; 93 - height: 60px; 94 - border-bottom: 1px solid var(--border-color); 95 - font-weight: 600; 96 - overflow-wrap: break-word; 97 - } 98 - 99 - #displayName { 100 - display: block; 101 - color: var(--text-color); 102 - font-size: 1.1em; 103 - padding: 0; 104 - margin: 0 0 2px 0; 105 - text-overflow: ellipsis; 106 - overflow: hidden; 107 - white-space: nowrap; 108 - width: 100%; 109 - letter-spacing: -0.01em; 110 - } 111 - 112 - #handle { 113 - display: flex; 114 - align-items: center; 115 - color: #6b7280; 116 - font-size: 0.85em; 117 - font-weight: 400; 118 - padding: 0; 119 - margin: 0; 120 - gap: 8px; 121 - } 122 - 123 - #postLink { 124 - color: var(--time-color); 125 - font-size: 0.85em; 126 - padding: 0; 127 - margin: 0; 128 - opacity: 0.9; 129 - } 130 - 131 - #postContent { 132 - display: flex; 133 - text-align: start; 134 - flex-direction: column; 135 - padding: 16px; 136 - background-color: var(--content-background-color); 137 - color: var(--text-color); 138 - overflow-wrap: break-word; 139 - white-space: pre-line; 140 - line-height: 1.6; 141 - } 142 - 143 - #replyingText, #quotingText { 144 - font-size: 0.8em; 145 - margin: 0; 146 - padding: 0 0 10px 0; 147 - color: #6b7280; 148 - } 149 - 150 - #postText { 151 - margin: 0 0 8px 0; 152 - padding: 0; 153 - overflow-wrap: break-word; 154 - word-break: break-word; 155 - hyphens: none; 156 - font-size: 1.05em; 157 - } 158 - 159 - #headerText { 160 - margin-left: 12px; 161 - font-size: 0.9em; 162 - text-align: start; 163 - word-break: break-word; 164 - max-width: 80%; 165 - max-height: 95%; 166 - overflow: hidden; 167 - align-self: flex-start; 168 - margin-top: auto; 169 - margin-bottom: auto; 170 - } 171 - 172 - #carouselContainer { 173 - position: relative; 174 - width: 100%; 175 - margin-top: 12px; 176 - display: flex; 177 - flex-direction: column; 178 - align-items: center; 179 - border-radius: 8px; 180 - overflow: hidden; 181 - } 182 - 183 - #carouselControls { 184 - display: flex; 185 - justify-content: space-between; 186 - align-items: center; 187 - width: 100%; 188 - max-width: 500px; 189 - margin-top: 10px; 190 - } 191 - 192 - #carouselIndicators { 193 - display: flex; 194 - gap: 6px; 195 - } 196 - 197 - .indicator { 198 - width: 6px; 199 - height: 6px; 200 - background-color: var(--indicator-inactive-color); 201 - border-radius: 50%; 202 - transition: background-color 0.2s ease, transform 0.2s ease; 203 - } 204 - 205 - .indicator.active { 206 - background-color: var(--indicator-active-color); 207 - transform: scale(1.3); 208 - } 209 - 210 - #prevBtn, 211 - #nextBtn { 212 - background-color: var(--button-bg); 213 - color: var(--text-color); 214 - border: 1px solid var(--border-color); 215 - width: 32px; 216 - height: 32px; 217 - cursor: pointer; 218 - display: flex; 219 - align-items: center; 220 - justify-content: center; 221 - border-radius: 50%; 222 - transition: background-color 0.15s ease, transform 0.15s ease; 223 - font-size: 16px; 224 - } 225 - 226 - #prevBtn:hover:not(:disabled), 227 - #nextBtn:hover:not(:disabled) { 228 - background-color: var(--button-hover); 229 - transform: scale(1.05); 230 - } 231 - 232 - #prevBtn:disabled, 233 - #nextBtn:disabled { 234 - opacity: 0.4; 235 - cursor: not-allowed; 236 - } 237 - 238 - #embedVideo { 239 - width: 100%; 240 - max-width: 500px; 241 - margin-top: 12px; 242 - align-self: center; 243 - border-radius: 8px; 244 - overflow: hidden; 245 - } 246 - 247 - #embedImages { 248 - min-width: min(100%, 500px); 249 - max-width: min(100%, 500px); 250 - max-height: 500px; 251 - object-fit: contain; 252 - margin: 0; 253 - border-radius: 8px; 254 - } 255 - 256 - /* Account Component */ 257 - #accountContainer { 258 - display: flex; 259 - text-align: start; 260 - align-items: center; 261 - background-color: var(--content-background-color); 262 - padding: 12px; 263 - margin-bottom: 15px; 264 - border: 1px solid var(--border-color); 265 - border-radius: 12px; 266 - transition: background-color 0.15s ease; 267 - } 268 - 269 - #accountContainer:hover { 270 - background-color: var(--hover-bg); 271 - } 272 - 273 - #accountName { 274 - margin-left: 12px; 275 - font-size: 0.95em; 276 - max-width: 80%; 277 - overflow: hidden; 278 - text-overflow: ellipsis; 279 - white-space: nowrap; 280 - font-weight: 500; 281 - } 282 - 283 - #avatar { 284 - width: 48px; 285 - height: 48px; 286 - margin: 0; 287 - object-fit: cover; 288 - border-radius: 50%; 289 - border: 2px solid white; 290 - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 291 - } 292 - 293 - /* App.Svelte Layout */ 294 - #Content { 295 - display: flex; 296 - width: 100%; 297 - height: 100%; 298 - flex-direction: row; 299 - justify-content: space-between; 300 - align-items: center; 301 - background-color: var(--background-color); 302 - color: var(--text-color); 303 - gap: 24px; 304 - } 305 - 306 - #Feed { 307 - overflow-y: auto; 308 - width: 65%; 309 - height: 100vh; 310 - padding-right: 16px; 311 - align-self: flex-start; 312 - } 313 - 314 - #spacer { 315 - padding: 0; 316 - margin: 0; 317 - height: 10vh; 318 - width: 100%; 319 - } 320 - 321 - #Account { 322 - width: 35%; 323 - display: flex; 324 - flex-direction: column; 325 - border: 1px solid var(--border-color); 326 - background-color: var(--content-background-color); 327 - max-height: 80vh; 328 - padding: 24px; 329 - margin-left: 16px; 330 - border-radius: 12px; 331 - box-shadow: var(--card-shadow); 332 - } 333 - 334 - #accountsList { 335 - display: flex; 336 - flex-direction: column; 337 - overflow-y: auto; 338 - height: 100%; 339 - width: 100%; 340 - padding: 8px 0; 341 - margin: 0; 342 - } 343 - 344 - #Header { 345 - text-align: center; 346 - font-size: 1.8em; 347 - margin-bottom: 16px; 348 - font-weight: 700; 349 - background: linear-gradient(to right, var(--link-color), #8b5cf6); 350 - -webkit-background-clip: text; 351 - -webkit-text-fill-color: transparent; 352 - background-clip: text; 353 - } 354 - 355 - /* Mobile Styles */ 356 - @media screen and (max-width: 768px) { 357 - #Content { 358 - flex-direction: column; 359 - width: auto; 360 - padding: 12px; 361 - margin-top: 0; 362 - } 363 - 364 - #Account { 365 - width: calc(100% - 32px); 366 - padding: 16px; 367 - margin-bottom: 20px; 368 - margin-left: 0; 369 - margin-right: 0; 370 - height: auto; 371 - order: -1; 372 - } 373 - 374 - #Feed { 375 - width: 100%; 376 - margin: 0; 377 - padding: 0; 378 - overflow-y: visible; 379 - } 380 - 381 - #spacer { 382 - height: 5vh; 383 - } 384 - 385 - body { 386 - font-size: 16px; 387 - } 388 - 389 - #postHeader { 390 - padding: 10px; 391 - height: auto; 392 - min-height: 50px; 393 - } 394 - } 395 - 396 - /* Scrollbar Styles */ 397 - ::-webkit-scrollbar { 398 - width: 0px; 399 - background: transparent; 400 - padding: 0; 401 - margin: 0; 402 - } 403 - ::-webkit-scrollbar-thumb { 404 - background: transparent; 405 - border-radius: 0; 406 - } 407 - ::-webkit-scrollbar-track { 408 - background: transparent; 409 - border-radius: 0; 410 - } 411 - ::-webkit-scrollbar-corner { 412 - background: transparent; 413 - border-radius: 0; 414 - } 415 - ::-webkit-scrollbar-button { 416 - background: transparent; 417 - border-radius: 0; 418 - } 419 - 420 - * { 421 - scrollbar-width: none; 422 - scrollbar-color: transparent transparent; 423 - -ms-overflow-style: none; /* IE and Edge */ 424 - -webkit-overflow-scrolling: touch; 425 - -webkit-scrollbar: none; /* Safari */ 426 - }
-375
themes/express/theme.css
··· 1 - @import url("https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap"); 2 - 3 - :root { 4 - /* Color overrides, edit to whatever you want */ 5 - --primary-h: 341; /* Hue */ 6 - --background-color: hsl(var(--primary-h), 62%, 30%); 7 - --text-color: hsl(var(--primary-h), 69%, 18%); 8 - --link-color: hsl(var(--primary-h), 100%, 20%); 9 - --link-hover-color: hsl(var(--primary-h), 20%, 20%); 10 - --border-color: hsl(var(--primary-h), 59%, 52%); 11 - --content-background-color: hsl(var(--primary-h), 97%, 73%); 12 - 13 - --header-background-color: hsl(var(--primary-h), 97%, 73%); 14 - --indicator-inactive-color: #4a4a4a; 15 - --indicator-active-color: var(--border-color); 16 - } 17 - 18 - a { 19 - font-weight: 500; 20 - color: var(--link-color); 21 - text-decoration: inherit; 22 - } 23 - a:hover { 24 - color: var(--link-hover-color); 25 - text-decoration: underline; 26 - } 27 - 28 - body { 29 - margin: 0; 30 - display: flex; 31 - place-items: center; 32 - min-width: 320px; 33 - min-height: 100vh; 34 - background-color: var(--background-color); 35 - font-family: "Share Tech Mono", monospace; 36 - font-size: 24px; 37 - color: var(--text-color); 38 - border-color: var(--border-color); 39 - overflow-wrap: break-word; 40 - word-wrap: normal; 41 - word-break: break-word; 42 - hyphens: none; 43 - } 44 - 45 - h1 { 46 - font-size: 3.2em; 47 - line-height: 1.1; 48 - } 49 - 50 - #app { 51 - max-width: 1400px; 52 - width: 100%; 53 - margin: 0; 54 - padding: 0; 55 - margin-left: auto; 56 - margin-right: auto; 57 - text-align: center; 58 - } 59 - 60 - /* Post Component */ 61 - a:hover { 62 - text-decoration: underline; 63 - } 64 - #postContainer { 65 - display: flex; 66 - flex-direction: column; 67 - border: 4px solid var(--border-color); 68 - background-color: var(--background-color); 69 - margin-bottom: 15px; 70 - overflow-wrap: break-word; 71 - box-shadow: var(--border-color) 10px 10px; 72 - } 73 - #postHeader { 74 - display: flex; 75 - flex-direction: row; 76 - align-items: center; 77 - justify-content: start; 78 - background-color: var(--header-background-color); 79 - padding: 0px 0px; 80 - height: fit-content; 81 - 82 - font-weight: bold; 83 - overflow-wrap: break-word; 84 - height: 64px; 85 - } 86 - #displayName { 87 - display: block; 88 - color: var(--text-color); 89 - font-size: 1.2em; 90 - padding: 0; 91 - margin: 0; 92 - overflow-wrap: normal; 93 - word-wrap: break-word; 94 - word-break: break-word; 95 - text-overflow: ellipsis; 96 - overflow: hidden; 97 - white-space: nowrap; 98 - width: 100%; 99 - } 100 - #handle { 101 - display: block; 102 - color: var(--border-color); 103 - font-size: 0.8em; 104 - padding: 0; 105 - margin: 0; 106 - } 107 - 108 - #postLink { 109 - color: var(--link-hover-color); 110 - font-size: 0.8em; 111 - padding: 0; 112 - margin: 0; 113 - } 114 - #postContent { 115 - display: flex; 116 - text-align: start; 117 - flex-direction: column; 118 - padding: 10px; 119 - background-color: var(--content-background-color); 120 - color: var(--text-color); 121 - overflow-wrap: break-word; 122 - white-space: pre-line; 123 - } 124 - #replyingText { 125 - font-size: 0.7em; 126 - margin: 0; 127 - padding: 0; 128 - padding-bottom: 5px; 129 - } 130 - #quotingText { 131 - font-size: 0.7em; 132 - margin: 0; 133 - padding: 0; 134 - padding-bottom: 5px; 135 - } 136 - #postText { 137 - margin: 0; 138 - padding: 0; 139 - overflow-wrap: break-word; 140 - word-wrap: normal; 141 - word-break: break-word; 142 - hyphens: none; 143 - } 144 - #headerText { 145 - margin-left: 10px; 146 - font-size: 0.9em; 147 - text-align: start; 148 - word-break: break-word; 149 - max-width: 80%; 150 - max-height: 95%; 151 - overflow: hidden; 152 - align-self: flex-start; 153 - margin-top: auto; 154 - margin-bottom: auto; 155 - } 156 - #avatar { 157 - height: 30px; 158 - width: 30px; 159 - overflow: hidden; 160 - object-fit: cover; 161 - } 162 - #postContainer #avatar { 163 - height: 60px; 164 - width: 60px; 165 - border-right: var(--border-color) 4px solid; 166 - border-bottom: var(--border-color) 4px solid; 167 - } 168 - #carouselContainer { 169 - position: relative; 170 - width: 100%; 171 - margin-top: 10px; 172 - display: flex; 173 - flex-direction: column; 174 - align-items: center; 175 - } 176 - #carouselControls { 177 - display: flex; 178 - justify-content: space-between; 179 - align-items: center; 180 - width: 100%; 181 - max-width: 500px; 182 - margin-top: 5px; 183 - } 184 - #carouselIndicators { 185 - display: flex; 186 - gap: 5px; 187 - } 188 - .indicator { 189 - width: 8px; 190 - height: 8px; 191 - background-color: var(--indicator-inactive-color); 192 - } 193 - .indicator.active { 194 - background-color: var(--indicator-active-color); 195 - } 196 - #prevBtn, 197 - #nextBtn { 198 - background-color: rgba(31, 17, 69, 0.7); 199 - color: var(--text-color); 200 - border: 4px solid var(--border-color); 201 - width: 30px; 202 - height: 30px; 203 - cursor: pointer; 204 - display: flex; 205 - align-items: center; 206 - justify-content: center; 207 - } 208 - #prevBtn:disabled, 209 - #nextBtn:disabled { 210 - opacity: 0.5; 211 - cursor: not-allowed; 212 - } 213 - #embedVideo { 214 - width: 100%; 215 - max-width: 500px; 216 - margin-top: 10px; 217 - align-self: center; 218 - } 219 - 220 - #embedImages { 221 - min-width: min(100%, 500px); 222 - max-width: min(100%, 500px); 223 - max-height: 500px; 224 - object-fit: contain; 225 - 226 - margin: 0; 227 - } 228 - 229 - /* Account Component */ 230 - #accountContainer { 231 - display: flex; 232 - text-align: start; 233 - align-items: center; 234 - background-color: var(--header-background-color); 235 - padding: 0px; 236 - margin-bottom: 15px; 237 - margin-right: 4px; 238 - border: 4px solid var(--border-color); 239 - box-shadow: var(--border-color) 10px 10px; 240 - min-height: 30px; 241 - } 242 - #accountName { 243 - margin-left: 10px; 244 - font-size: 1em; 245 - max-width: 80%; 246 - 247 - /* replace overflow with ellipsis */ 248 - overflow: hidden; 249 - text-overflow: ellipsis; 250 - white-space: nowrap; 251 - } 252 - 253 - .no-avatar { 254 - margin-left: 40px !important; 255 - } 256 - 257 - /* App.Svelte */ 258 - /* desktop style */ 259 - 260 - #Content { 261 - display: flex; 262 - /* split the screen in half, left for accounts, right for posts */ 263 - width: 100%; 264 - height: 100%; 265 - flex-direction: row; 266 - justify-content: space-between; 267 - align-items: center; 268 - background-color: var(--background-color); 269 - color: var(--text-color); 270 - } 271 - #Feed { 272 - overflow-y: scroll; 273 - width: 65%; 274 - height: 100vh; 275 - padding: 20px; 276 - padding-bottom: 0; 277 - padding-top: 0; 278 - margin-top: 0; 279 - margin-bottom: 0; 280 - } 281 - #spacer { 282 - padding: 0; 283 - margin: 0; 284 - height: 10vh; 285 - width: 100%; 286 - } 287 - #Account { 288 - width: 35%; 289 - display: flex; 290 - flex-direction: column; 291 - border: 4px solid var(--border-color); 292 - background-color: var(--content-background-color); 293 - box-shadow: var(--border-color) 10px 10px; 294 - height: 80vh; 295 - padding: 20px; 296 - margin-left: 20px; 297 - } 298 - #accountsList { 299 - display: flex; 300 - flex-direction: column; 301 - overflow-y: scroll; 302 - height: 100%; 303 - width: 100%; 304 - padding: 0px; 305 - margin: 0px; 306 - } 307 - 308 - #Header { 309 - text-align: center; 310 - font-size: 2em; 311 - margin-bottom: 20px; 312 - } 313 - 314 - /* mobile style */ 315 - @media screen and (max-width: 600px) { 316 - #Content { 317 - flex-direction: column; 318 - width: auto; 319 - padding-left: 0px; 320 - padding-right: 0px; 321 - margin-top: 5%; 322 - } 323 - #Account { 324 - width: 85%; 325 - padding-left: 5%; 326 - padding-right: 5%; 327 - margin-bottom: 20px; 328 - margin-left: 5%; 329 - margin-right: 5%; 330 - height: auto; 331 - } 332 - #Feed { 333 - width: 95%; 334 - margin: 0px; 335 - margin-left: 10%; 336 - margin-right: 10%; 337 - padding: 0px; 338 - overflow-y: visible; 339 - } 340 - 341 - #spacer { 342 - height: 0; 343 - } 344 - } 345 - 346 - ::-webkit-scrollbar { 347 - width: 0px; 348 - background: transparent; 349 - padding: 0; 350 - margin: 0; 351 - } 352 - ::-webkit-scrollbar-thumb { 353 - background: transparent; 354 - border-radius: 0; 355 - } 356 - ::-webkit-scrollbar-track { 357 - background: transparent; 358 - border-radius: 0; 359 - } 360 - ::-webkit-scrollbar-corner { 361 - background: transparent; 362 - border-radius: 0; 363 - } 364 - ::-webkit-scrollbar-button { 365 - background: transparent; 366 - border-radius: 0; 367 - } 368 - 369 - * { 370 - scrollbar-width: none; 371 - scrollbar-color: transparent transparent; 372 - -ms-overflow-style: none; /* IE and Edge */ 373 - -webkit-overflow-scrolling: touch; 374 - -webkit-scrollbar: none; /* Safari */ 375 - }
-371
themes/witchcraft/theme.css
··· 1 - @font-face { 2 - font-family: "ProggyClean"; 3 - src: url(https://witchcraft.systems/ProggyCleanNerdFont-Regular.ttf); 4 - } 5 - 6 - :root { 7 - /* Color overrides, edit to whatever you want */ 8 - --primary-h: 260; /* Hue */ 9 - 10 - --link-color: hsl(calc(var(--primary-h) - 30), 75%, 60%); 11 - --link-hover-color: hsl(calc(var(--primary-h) - 30), 75%, 50%); 12 - --background-color: hsl(var(--primary-h), 75%, 10%); 13 - --header-background-color: hsl(var(--primary-h), 75%, 18%); 14 - --content-background-color: hsl(var(--primary-h), 75%, 8%); 15 - --text-color: #fff; 16 - --border-color: hsl(var(--primary-h), 75%, 60%); 17 - --indicator-inactive-color: #4a4a4a; 18 - --indicator-active-color: var(--border-color); 19 - } 20 - 21 - a { 22 - font-weight: 500; 23 - color: var(--link-color); 24 - text-decoration: inherit; 25 - } 26 - a:hover { 27 - color: var(--link-hover-color); 28 - text-decoration: underline; 29 - } 30 - 31 - body { 32 - margin: 0; 33 - display: flex; 34 - place-items: center; 35 - min-width: 320px; 36 - min-height: 100vh; 37 - background-color: var(--background-color); 38 - font-family: "ProggyClean", monospace; 39 - font-size: 24px; 40 - color: var(--text-color); 41 - border-color: var(--border-color); 42 - overflow-wrap: break-word; 43 - word-wrap: normal; 44 - word-break: break-word; 45 - hyphens: none; 46 - } 47 - 48 - h1 { 49 - font-size: 3.2em; 50 - line-height: 1.1; 51 - } 52 - 53 - #app { 54 - max-width: 1400px; 55 - width: 100%; 56 - margin: 0; 57 - padding: 0; 58 - margin-left: auto; 59 - margin-right: auto; 60 - text-align: center; 61 - } 62 - 63 - /* Post Component */ 64 - a:hover { 65 - text-decoration: underline; 66 - } 67 - #postContainer { 68 - display: flex; 69 - flex-direction: column; 70 - border: 1px solid var(--border-color); 71 - background-color: var(--background-color); 72 - margin-bottom: 15px; 73 - overflow-wrap: break-word; 74 - } 75 - #postHeader { 76 - display: flex; 77 - flex-direction: row; 78 - align-items: center; 79 - justify-content: start; 80 - background-color: var(--header-background-color); 81 - padding: 0px 0px; 82 - height: fit-content; 83 - border-bottom: 1px solid var(--border-color); 84 - font-weight: bold; 85 - overflow-wrap: break-word; 86 - height: 60px; 87 - } 88 - #displayName { 89 - display: block; 90 - color: var(--text-color); 91 - font-size: 1.2em; 92 - padding: 0; 93 - margin: 0; 94 - overflow-wrap: normal; 95 - word-wrap: break-word; 96 - word-break: break-word; 97 - text-overflow: ellipsis; 98 - overflow: hidden; 99 - white-space: nowrap; 100 - width: 100%; 101 - } 102 - #handle { 103 - display: block; 104 - color: var(--border-color); 105 - font-size: 0.8em; 106 - padding: 0; 107 - margin: 0; 108 - } 109 - 110 - #postLink { 111 - color: var(--border-color); 112 - font-size: 0.8em; 113 - padding: 0; 114 - margin: 0; 115 - } 116 - #postContent { 117 - display: flex; 118 - text-align: start; 119 - flex-direction: column; 120 - padding: 10px; 121 - background-color: var(--content-background-color); 122 - color: var(--text-color); 123 - overflow-wrap: break-word; 124 - white-space: pre-line; 125 - } 126 - #replyingText { 127 - font-size: 0.7em; 128 - margin: 0; 129 - padding: 0; 130 - padding-bottom: 5px; 131 - } 132 - #quotingText { 133 - font-size: 0.7em; 134 - margin: 0; 135 - padding: 0; 136 - padding-bottom: 5px; 137 - } 138 - #postText { 139 - margin: 0; 140 - padding: 0; 141 - overflow-wrap: break-word; 142 - word-wrap: normal; 143 - word-break: break-word; 144 - hyphens: none; 145 - } 146 - #headerText { 147 - margin-left: 10px; 148 - font-size: 0.9em; 149 - text-align: start; 150 - word-break: break-word; 151 - max-width: 80%; 152 - max-height: 95%; 153 - overflow: hidden; 154 - align-self: flex-start; 155 - margin-top: auto; 156 - margin-bottom: auto; 157 - } 158 - #avatar { 159 - height: 60px; 160 - width: 60px; 161 - margin: 0px; 162 - margin-left: 0px; 163 - overflow: hidden; 164 - object-fit: cover; 165 - border-right: var(--border-color) 1px solid; 166 - } 167 - #carouselContainer { 168 - position: relative; 169 - width: 100%; 170 - margin-top: 10px; 171 - display: flex; 172 - flex-direction: column; 173 - align-items: center; 174 - } 175 - #carouselControls { 176 - display: flex; 177 - justify-content: space-between; 178 - align-items: center; 179 - width: 100%; 180 - max-width: 500px; 181 - margin-top: 5px; 182 - } 183 - #carouselIndicators { 184 - display: flex; 185 - gap: 5px; 186 - } 187 - .indicator { 188 - width: 8px; 189 - height: 8px; 190 - background-color: var(--indicator-inactive-color); 191 - } 192 - .indicator.active { 193 - background-color: var(--indicator-active-color); 194 - } 195 - #prevBtn, 196 - #nextBtn { 197 - background-color: rgba(31, 17, 69, 0.7); 198 - color: var(--text-color); 199 - border: 1px solid var(--border-color); 200 - width: 30px; 201 - height: 30px; 202 - cursor: pointer; 203 - display: flex; 204 - align-items: center; 205 - justify-content: center; 206 - } 207 - #prevBtn:disabled, 208 - #nextBtn:disabled { 209 - opacity: 0.5; 210 - cursor: not-allowed; 211 - } 212 - #embedVideo { 213 - width: 100%; 214 - max-width: 500px; 215 - margin-top: 10px; 216 - align-self: center; 217 - } 218 - 219 - #embedImages { 220 - min-width: min(100%, 500px); 221 - max-width: min(100%, 500px); 222 - max-height: 500px; 223 - object-fit: contain; 224 - 225 - margin: 0; 226 - } 227 - 228 - /* Account Component */ 229 - #accountContainer { 230 - display: flex; 231 - text-align: start; 232 - align-items: center; 233 - background-color: var(--background-color); 234 - padding: 0px; 235 - margin-bottom: 15px; 236 - border: 1px solid var(--border-color); 237 - min-height: 30px; 238 - } 239 - #accountName { 240 - margin-left: 10px; 241 - font-size: 1em; 242 - max-width: 80%; 243 - 244 - /* replace overflow with ellipsis */ 245 - overflow: hidden; 246 - text-overflow: ellipsis; 247 - white-space: nowrap; 248 - } 249 - 250 - .no-avatar { 251 - margin-left: 70px !important; 252 - } 253 - 254 - /* App.Svelte */ 255 - /* desktop style */ 256 - 257 - #Content { 258 - display: flex; 259 - /* split the screen in half, left for accounts, right for posts */ 260 - width: 100%; 261 - height: 100%; 262 - flex-direction: row; 263 - justify-content: space-between; 264 - align-items: center; 265 - background-color: var(--background-color); 266 - color: var(--text-color); 267 - } 268 - #Feed { 269 - overflow-y: scroll; 270 - width: 65%; 271 - height: 100vh; 272 - padding: 20px; 273 - padding-bottom: 0; 274 - padding-top: 0; 275 - margin-top: 0; 276 - margin-bottom: 0; 277 - } 278 - #spacer { 279 - padding: 0; 280 - margin: 0; 281 - height: 10vh; 282 - width: 100%; 283 - } 284 - #Account { 285 - width: 35%; 286 - display: flex; 287 - flex-direction: column; 288 - border: 1px solid var(--border-color); 289 - background-color: var(--content-background-color); 290 - height: 80vh; 291 - padding: 20px; 292 - margin-left: 20px; 293 - } 294 - #accountsList { 295 - display: flex; 296 - flex-direction: column; 297 - overflow-y: scroll; 298 - height: 100%; 299 - width: 100%; 300 - padding: 0px; 301 - margin: 0px; 302 - } 303 - 304 - #Header { 305 - text-align: center; 306 - font-size: 2em; 307 - margin-bottom: 20px; 308 - } 309 - 310 - /* mobile style */ 311 - @media screen and (max-width: 600px) { 312 - #Content { 313 - flex-direction: column; 314 - width: auto; 315 - padding-left: 0px; 316 - padding-right: 0px; 317 - margin-top: 5%; 318 - } 319 - #Account { 320 - width: 85%; 321 - padding-left: 5%; 322 - padding-right: 5%; 323 - margin-bottom: 20px; 324 - margin-left: 5%; 325 - margin-right: 5%; 326 - height: auto; 327 - } 328 - #Feed { 329 - width: 95%; 330 - margin: 0px; 331 - margin-left: 10%; 332 - margin-right: 10%; 333 - padding: 0px; 334 - overflow-y: visible; 335 - } 336 - 337 - #spacer { 338 - height: 0; 339 - } 340 - } 341 - 342 - ::-webkit-scrollbar { 343 - width: 0px; 344 - background: transparent; 345 - padding: 0; 346 - margin: 0; 347 - } 348 - ::-webkit-scrollbar-thumb { 349 - background: transparent; 350 - border-radius: 0; 351 - } 352 - ::-webkit-scrollbar-track { 353 - background: transparent; 354 - border-radius: 0; 355 - } 356 - ::-webkit-scrollbar-corner { 357 - background: transparent; 358 - border-radius: 0; 359 - } 360 - ::-webkit-scrollbar-button { 361 - background: transparent; 362 - border-radius: 0; 363 - } 364 - 365 - * { 366 - scrollbar-width: none; 367 - scrollbar-color: transparent transparent; 368 - -ms-overflow-style: none; /* IE and Edge */ 369 - -webkit-overflow-scrolling: touch; 370 - -webkit-scrollbar: none; /* Safari */ 371 - }
-35
theming.ts
··· 1 - import { Plugin } from "vite"; 2 - import { Config } from "./config"; 3 - 4 - // Replaces app.css with the contents of the file specified in the 5 - // config file. 6 - export const themePlugin = (): Plugin => { 7 - const themeFolder = Config.THEME; 8 - console.log(`Using theme folder: ${themeFolder}`); 9 - return { 10 - name: "theme-generator", 11 - enforce: "pre", // Ensure this plugin runs first 12 - transform(_code, id) { 13 - if (id.endsWith("app.css")) { 14 - // Read the theme file and replace the contents of app.css with it 15 - // Needs full path to the file 16 - //@ts-ignore Deno 17 - const themeCode = Deno.readTextFileSync( 18 - //@ts-ignore Deno 19 - Deno.cwd() + "/themes/" + themeFolder + "/theme.css", 20 - ); 21 - // Replace the contents of app.css with the theme code 22 - 23 - // and add a comment at the top 24 - const themeComment = `/* Generated from ${themeFolder} */\n`; 25 - const themeCodeWithComment = themeComment + themeCode; 26 - // Return the theme code as the new contents of app.css 27 - return { 28 - code: themeCodeWithComment, 29 - map: null, 30 - }; 31 - } 32 - return null; 33 - }, 34 - }; 35 - };
+2 -3
tsconfig.app.json
··· 1 1 { 2 - "extends": "@tsconfig/svelte/tsconfig.json", 2 + "extends": "./.svelte-kit/tsconfig.json", 3 3 "compilerOptions": { 4 4 "target": "ESNext", 5 5 "useDefineForClassFields": true, ··· 15 15 "checkJs": true, 16 16 "isolatedModules": true, 17 17 "moduleDetection": "force" 18 - }, 19 - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"] 18 + } 20 19 }
+10 -8
vite.config.ts
··· 1 - import { defineConfig } from "vite"; 2 - import { svelte } from "@sveltejs/vite-plugin-svelte"; 3 - import { themePlugin } from "./theming.ts"; 1 + import { sveltekit } from '@sveltejs/kit/vite'; 2 + import { defineConfig } from 'vite'; 3 + 4 4 5 5 // https://vite.dev/config/ 6 - export default defineConfig({ 7 - plugins: [ 8 - themePlugin(), 9 - svelte(), 10 - ], 6 + export default defineConfig(() => { 7 + 8 + return { 9 + plugins: [ 10 + sveltekit(), 11 + ], 12 + }; 11 13 });