diff --git a/eslint.config.ts b/eslint.config.ts index b5b060394..3d8bf5adc 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -20,6 +20,7 @@ export default defineConfig([ }, }, }, + { files: ['scripts/**'], languageOptions: { @@ -28,4 +29,11 @@ export default defineConfig([ }, }, }, + + { + rules: { + curly: ['error', 'all'], + eqeqeq: ['error', 'always'], + }, + }, ]) diff --git a/package.json b/package.json index f9803792d..c0cc043b7 100644 --- a/package.json +++ b/package.json @@ -15,23 +15,23 @@ }, "dependencies": { "@astrojs/check": "^0.9.9", - "@astrojs/cloudflare": "^13.6.0", + "@astrojs/cloudflare": "^13.6.1", "@astrojs/mdx": "5.0.4", "@astrojs/rss": "^4.0.18", "@astrojs/sitemap": "3.7.2", "@lucide/astro": "^1.17.0", "astro": "6.3.1", - "wrangler": "^4.95.0" + "wrangler": "^4.98.0" }, "devDependencies": { "@eslint/js": "^10.0.1", "@playwright/test": "^1.60.0", "@tailwindcss/cli": "^4.3.0", "@tailwindcss/forms": "^0.5.11", - "@tailwindcss/typography": "^0.5.19", + "@tailwindcss/typography": "^0.5.20", "@tailwindcss/vite": "^4.3.0", - "@types/node": "^25.9.1", - "eslint": "^10.4.0", + "@types/node": "^25.9.2", + "eslint": "^10.4.1", "eslint-plugin-astro": "^1.7.0", "globals": "^17.6.0", "prettier": "^3.8.3", @@ -40,7 +40,7 @@ "rehype-external-links": "^3.0.0", "tailwindcss": "^4.3.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.60.0" + "typescript-eslint": "^8.61.0" }, "overrides": { "vite": "^7" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 085273625..7b3f8d03d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,11 +12,11 @@ importers: specifier: ^0.9.9 version: 0.9.9(prettier-plugin-astro@0.14.1)(prettier@3.8.3)(typescript@6.0.3) '@astrojs/cloudflare': - specifier: ^13.6.0 - version: 13.6.0(@types/node@25.9.1)(astro@6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0))(jiti@2.7.0)(lightningcss@1.32.0)(workerd@1.20260526.1)(wrangler@4.95.0)(yaml@2.9.0) + specifier: ^13.6.1 + version: 13.6.1(@types/node@25.9.2)(astro@6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0))(jiti@2.7.0)(lightningcss@1.32.0)(workerd@1.20260603.1)(wrangler@4.98.0)(yaml@2.9.0) '@astrojs/mdx': specifier: 5.0.4 - version: 5.0.4(astro@6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0)) + version: 5.0.4(astro@6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0)) '@astrojs/rss': specifier: ^4.0.18 version: 4.0.18 @@ -25,17 +25,17 @@ importers: version: 3.7.2 '@lucide/astro': specifier: ^1.17.0 - version: 1.17.0(astro@6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0)) + version: 1.17.0(astro@6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0)) astro: specifier: 6.3.1 - version: 6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0) + version: 6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0) wrangler: - specifier: ^4.95.0 - version: 4.95.0 + specifier: ^4.98.0 + version: 4.98.0 devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.4.0(jiti@2.7.0)) + version: 10.0.1(eslint@10.4.1(jiti@2.7.0)) '@playwright/test': specifier: ^1.60.0 version: 1.60.0 @@ -46,20 +46,20 @@ importers: specifier: ^0.5.11 version: 0.5.11(tailwindcss@4.3.0) '@tailwindcss/typography': - specifier: ^0.5.19 - version: 0.5.19(tailwindcss@4.3.0) + specifier: ^0.5.20 + version: 0.5.20(tailwindcss@4.3.0) '@tailwindcss/vite': specifier: ^4.3.0 - version: 4.3.0(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0)) + version: 4.3.0(vite@7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0)) '@types/node': - specifier: ^25.9.1 - version: 25.9.1 + specifier: ^25.9.2 + version: 25.9.2 eslint: - specifier: ^10.4.0 - version: 10.4.0(jiti@2.7.0) + specifier: ^10.4.1 + version: 10.4.1(jiti@2.7.0) eslint-plugin-astro: specifier: ^1.7.0 - version: 1.7.0(eslint@10.4.0(jiti@2.7.0)) + version: 1.7.0(eslint@10.4.1(jiti@2.7.0)) globals: specifier: ^17.6.0 version: 17.6.0 @@ -82,8 +82,8 @@ importers: specifier: ^6.0.3 version: 6.0.3 typescript-eslint: - specifier: ^8.60.0 - version: 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + specifier: ^8.61.0 + version: 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) packages: @@ -93,8 +93,8 @@ packages: peerDependencies: typescript: ^5.0.0 || ^6.0.0 - '@astrojs/cloudflare@13.6.0': - resolution: {integrity: sha512-BFzj95qunjhmkZIeA8WLU+NhhZhm2WS8/2ceNoaUFxd0WF7i5pVsVb0otyb9DmNvM8zgSwafRP6w8SeK3C16Dw==} + '@astrojs/cloudflare@13.6.1': + resolution: {integrity: sha512-/ghjke33zKmSd2U0IJsmWzZG2ikzwxPm7WAzNjzlIj91oL3rC8GFGcivynVLs6EbcuMct5rY98LuN4uonEKOdw==} peerDependencies: astro: ^6.3.0 wrangler: ^4.83.0 @@ -176,12 +176,12 @@ packages: resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==} engines: {node: '>=18'} - '@clack/core@1.3.1': - resolution: {integrity: sha512-fT1qHVGAag4IEkrupZ6lRRbNCs1vS9P01KB/sG8zKgvUztbYtFBtQpjSITNwooDZ83tpsPzP0mRNs1/KVszCRA==} + '@clack/core@1.4.1': + resolution: {integrity: sha512-FILJa1gGKEFTGZAJE9RpVhrjKz3c3h4ar60dSv6cGuDqufQ84YEIS3GAGvZiN+H6yaLbbvTFNejjCC4tXpZEuw==} engines: {node: '>= 20.12.0'} - '@clack/prompts@1.4.0': - resolution: {integrity: sha512-S0My7XPGIgpRWMDG8uRqalbgT+a6FmCUdOW+HaIOVVpUPHOb7RrpvjTjiODadKp06fsrVDJZlIzc6yCTp4AnxA==} + '@clack/prompts@1.5.1': + resolution: {integrity: sha512-zccHj2z2oCCO4yrDiRSlFOxWerGqRiysP7a5jPK6uoI9URKAquwY42Dd/iUP8JWHxEzdRe4TlbvZCo8z1/mhrw==} engines: {node: '>= 20.12.0'} '@cloudflare/kv-asset-handler@0.5.0': @@ -197,38 +197,39 @@ packages: workerd: optional: true - '@cloudflare/vite-plugin@1.39.0': - resolution: {integrity: sha512-AHC+KSR+3dtGu7Ab7I0Ode4Whx12TxMEmiZt7w+Fc3/2wYNByIzbb6cndWZ78tnveFdO1xhNLv1YaNngxGtOPg==} + '@cloudflare/vite-plugin@1.40.0': + resolution: {integrity: sha512-v77QQ2AdyBB+XW6uzKpWanbQy7ckYqSXFwJgQN871XITqLdJTdYOAWxt/jLPw9tNnHkKS6HTwV9+9bfQcLWz/w==} + hasBin: true peerDependencies: vite: ^6.1.0 || ^7.0.0 || ^8.0.0 - wrangler: ^4.95.0 + wrangler: ^4.98.0 - '@cloudflare/workerd-darwin-64@1.20260526.1': - resolution: {integrity: sha512-/pR3GH3gfv0PUp7DjI8v0aAIDOqFwibq4bg5xT7TZgcVdBV/cJQWckdXCMqiRtHiawLwogUX00EIOINkYJ1Zqg==} + '@cloudflare/workerd-darwin-64@1.20260603.1': + resolution: {integrity: sha512-cEXDWu6V3ZrpmwWkM4OJE9AeXjdAgOY5rh8EHhcBVCuP5rxnzUbPzLtrVOHx0UUUAcCrFq0Xsa6mZKL1VUZsKQ==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20260526.1': - resolution: {integrity: sha512-rcyu0iANYfaiezKh3Mcao1O4IIgVfQldxduiL5TZT1sP0NIeRY4YReSTrzPxNnXxSYaIqaqRHMcHbUM/ic4knA==} + '@cloudflare/workerd-darwin-arm64@1.20260603.1': + resolution: {integrity: sha512-uBPK4LaWJNbbCYwPnUAehlHbbVulhVZPZsdcAhBPfZhHb3QAuAEPAQepO/P67R3V6Cni4YGx1fLbL8A5wwoaNA==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20260526.1': - resolution: {integrity: sha512-5EZAEnlLwa9oGJRo8Nd3iY5Wcd9ROGNNG90xNIGp8MEjj8v2jTn42NC47fCZKFdnLj3+S+vWEhu1x0GVJnALjA==} + '@cloudflare/workerd-linux-64@1.20260603.1': + resolution: {integrity: sha512-ht9l6/8Tk7Rp6kA4S9oFZ4X8u0VjnnFdmU/6B3fnABYKREYTKh2RdOqXqXxcp5eNJseireKnWik/hQOPK1CutQ==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20260526.1': - resolution: {integrity: sha512-X/YBQXeXFeCN7QTStoWrATEBc9WKl7PIqkw/dQkjyJ72gh3rkLe0+Xkzp3wO7gtxTDQMa7NPGy1W4+sdMf8q1g==} + '@cloudflare/workerd-linux-arm64@1.20260603.1': + resolution: {integrity: sha512-LJZ6x00rAjSrobV4m0ZW0TpH5ilBbKcWBzlH+y+KOUsIE/CpTuhAzKV43TbSnFLRX5+jrWKiz2v0hO91lPXy6A==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20260526.1': - resolution: {integrity: sha512-R+tqpFFdcfZIljx8fIW9rj9fRTtDgfoA2yonsfAGa6e8snrmr+38mdFHtkRC0D3UyZpn/hOtmXiUBfdX2gMR7Q==} + '@cloudflare/workerd-windows-64@1.20260603.1': + resolution: {integrity: sha512-DvwqkXMAJRPoDN4PxapAwhlz/6ouD+6R1ttbAEK3cWD/QBvFF5STx7Ds/9Irf+rBly3np3uHWkeX+wZnNFEuzA==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -258,8 +259,8 @@ packages: '@emmetio/stream-reader@2.2.0': resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} - '@emnapi/runtime@1.10.0': - resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.11.0': + resolution: {integrity: sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==} '@esbuild/aix-ppc64@0.27.3': resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} @@ -608,8 +609,8 @@ packages: resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.7.1': - resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==} + '@eslint/plugin-kit@0.7.2': + resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@humanfs/core@0.19.2': @@ -945,170 +946,170 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.60.4': - resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} + '@rollup/rollup-android-arm-eabi@4.61.1': + resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.60.4': - resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} + '@rollup/rollup-android-arm64@4.61.1': + resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.60.4': - resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} + '@rollup/rollup-darwin-arm64@4.61.1': + resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.60.4': - resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} + '@rollup/rollup-darwin-x64@4.61.1': + resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.60.4': - resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} + '@rollup/rollup-freebsd-arm64@4.61.1': + resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.60.4': - resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} + '@rollup/rollup-freebsd-x64@4.61.1': + resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.60.4': - resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} + '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.60.4': - resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} + '@rollup/rollup-linux-arm-musleabihf@4.61.1': + resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.60.4': - resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} + '@rollup/rollup-linux-arm64-gnu@4.61.1': + resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.60.4': - resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} + '@rollup/rollup-linux-arm64-musl@4.61.1': + resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.60.4': - resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} + '@rollup/rollup-linux-loong64-gnu@4.61.1': + resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.60.4': - resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} + '@rollup/rollup-linux-loong64-musl@4.61.1': + resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.60.4': - resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} + '@rollup/rollup-linux-ppc64-gnu@4.61.1': + resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.60.4': - resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} + '@rollup/rollup-linux-ppc64-musl@4.61.1': + resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.60.4': - resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} + '@rollup/rollup-linux-riscv64-gnu@4.61.1': + resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.60.4': - resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} + '@rollup/rollup-linux-riscv64-musl@4.61.1': + resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.60.4': - resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} + '@rollup/rollup-linux-s390x-gnu@4.61.1': + resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.60.4': - resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} + '@rollup/rollup-linux-x64-gnu@4.61.1': + resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.60.4': - resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} + '@rollup/rollup-linux-x64-musl@4.61.1': + resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.60.4': - resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} + '@rollup/rollup-openbsd-x64@4.61.1': + resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.60.4': - resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} + '@rollup/rollup-openharmony-arm64@4.61.1': + resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.60.4': - resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} + '@rollup/rollup-win32-arm64-msvc@4.61.1': + resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.60.4': - resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} + '@rollup/rollup-win32-ia32-msvc@4.61.1': + resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.60.4': - resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} + '@rollup/rollup-win32-x64-gnu@4.61.1': + resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.60.4': - resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} + '@rollup/rollup-win32-x64-msvc@4.61.1': + resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==} cpu: [x64] os: [win32] - '@shikijs/core@4.1.0': - resolution: {integrity: sha512-jLJtSJeuFffqX6/inRE1zqU5aFv2hrszvYgq3OjbAgFRZiWv7abKMDdQzYxuSDfmUPQozZvI/kuy6VMTvnvqTQ==} + '@shikijs/core@4.2.0': + resolution: {integrity: sha512-Hc87Ab1Ld/vEbZRCbwx344I5v+4RU8CVToUTRkqXL1+TjbuOp9U5Xa0M23V4GEWHxVn+yO5otb+HkQVm3ptWQQ==} engines: {node: '>=20'} - '@shikijs/engine-javascript@4.1.0': - resolution: {integrity: sha512-YquhawCUgaBfhsS72e2Y/dI59gCBNPHu3fEO/tvLaXrTssxZrY5ddjtNLTwndrMgPo8b3IscE+xoICDzpTmlFQ==} + '@shikijs/engine-javascript@4.2.0': + resolution: {integrity: sha512-fjETeq1k5ffyXqRgS6+3hpvqseLalp1kjNfRbXpUgWR8FpZ1CmQfiNHovc5lncYjt/Vg5JK/WJEmLahjwMa0og==} engines: {node: '>=20'} - '@shikijs/engine-oniguruma@4.1.0': - resolution: {integrity: sha512-axLpjVs45YBvvINa+dJF+NPW+KtFkNXsFr4SDw2BMj9GdeMnGxVB9PQb2xXlJYovslt/nz6giedAyOANkfc7hg==} + '@shikijs/engine-oniguruma@4.2.0': + resolution: {integrity: sha512-hTorK1dffPkpbMUk6Z+828PgRo7d07HbnizoP0hNPFjhxMHctj0Px/qoHeGMYafc6ju+u9iMldN4JbVzNQM++g==} engines: {node: '>=20'} - '@shikijs/langs@4.1.0': - resolution: {integrity: sha512-nwOMruEkbgdZfQ/b8CgpNBVOpvG1k0N5tbmgiFeqsan401+x3ILqlzZJowSla4Agmq4hG2Uf2wh5jLTEhR8VSg==} + '@shikijs/langs@4.2.0': + resolution: {integrity: sha512-bwrVRlJ0wUhZxAbVdvBbv2TTC9yLsh4C/IO5Ofz0T8MQntgDvyVnkbjw9vi50r1kx7RCIJdnJnjZAwmAsXFLZQ==} engines: {node: '>=20'} - '@shikijs/primitive@4.1.0': - resolution: {integrity: sha512-zx2/2Uwj2q9X3KSyYREEhXO23xBw5WUhP4orK2lE4r+t9JGITmEe0JH+wPmJhqHpOT2bRRs6lAL945+LDvOAGw==} + '@shikijs/primitive@4.2.0': + resolution: {integrity: sha512-NOq+DtUkVBJtZMVXL5A0vI0Xk8nvDYaXetFHSJFlOqjDZIVhIPRYFdGkSoElDqNuegikcc3A76SNUa8dTqtAYA==} engines: {node: '>=20'} - '@shikijs/themes@4.1.0': - resolution: {integrity: sha512-emCcTnUM7yO2wltYbaxm+yLvcCI4+h8XBKc4KmJ7EZUXoSGjcCHifkI//R4OFit9ewpg7H2/9tjOuXrT2v/Knw==} + '@shikijs/themes@4.2.0': + resolution: {integrity: sha512-RX8IHYeLv8Cu2W6ruc3RxUqWn0IYCqSrMBzi/uRGAmfyDNOnNO5BF/Px7o97n4XTpmFTo5GbRaazuOWj+2ak2w==} engines: {node: '>=20'} - '@shikijs/types@4.1.0': - resolution: {integrity: sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA==} + '@shikijs/types@4.2.0': + resolution: {integrity: sha512-VT/MKtlpOhEPZloSH3Pb9WCZEBDoQVMa9jedp5UAwmJOar1DVc9DRODAxmYPW9M93IK4ryuqRejFfmlvlVDemw==} engines: {node: '>=20'} '@shikijs/vscode-textmate@10.0.2': @@ -1219,10 +1220,10 @@ packages: resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} engines: {node: '>= 20'} - '@tailwindcss/typography@0.5.19': - resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} + '@tailwindcss/typography@0.5.20': + resolution: {integrity: sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==} peerDependencies: - tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + tailwindcss: '>=3.0.0 || >=4.0.0 || insiders' '@tailwindcss/vite@4.3.0': resolution: {integrity: sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==} @@ -1238,9 +1239,6 @@ packages: '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} @@ -1253,8 +1251,8 @@ packages: '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - '@types/mdx@2.0.13': - resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} + '@types/mdx@2.0.14': + resolution: {integrity: sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==} '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -1262,11 +1260,11 @@ packages: '@types/nlcst@2.0.3': resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} - '@types/node@24.12.4': - resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==} + '@types/node@24.13.1': + resolution: {integrity: sha512-RSpUJGmvsJ1ZeBehQZFhIdpsz+bIpES0nIQXko4Ybq+N+kX6XvOq3Jo+iJ82FWLdblFq85AsMikd3m35jgezYg==} - '@types/node@25.9.1': - resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==} + '@types/node@25.9.2': + resolution: {integrity: sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==} '@types/sax@1.2.7': resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} @@ -1277,63 +1275,63 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@typescript-eslint/eslint-plugin@8.60.0': - resolution: {integrity: sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==} + '@typescript-eslint/eslint-plugin@8.61.0': + resolution: {integrity: sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.60.0 + '@typescript-eslint/parser': ^8.61.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.60.0': - resolution: {integrity: sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==} + '@typescript-eslint/parser@8.61.0': + resolution: {integrity: sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.60.0': - resolution: {integrity: sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==} + '@typescript-eslint/project-service@8.61.0': + resolution: {integrity: sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.60.0': - resolution: {integrity: sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==} + '@typescript-eslint/scope-manager@8.61.0': + resolution: {integrity: sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.60.0': - resolution: {integrity: sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==} + '@typescript-eslint/tsconfig-utils@8.61.0': + resolution: {integrity: sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.60.0': - resolution: {integrity: sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==} + '@typescript-eslint/type-utils@8.61.0': + resolution: {integrity: sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.60.0': - resolution: {integrity: sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==} + '@typescript-eslint/types@8.61.0': + resolution: {integrity: sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.60.0': - resolution: {integrity: sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==} + '@typescript-eslint/typescript-estree@8.61.0': + resolution: {integrity: sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.60.0': - resolution: {integrity: sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==} + '@typescript-eslint/utils@8.61.0': + resolution: {integrity: sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.60.0': - resolution: {integrity: sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==} + '@typescript-eslint/visitor-keys@8.61.0': + resolution: {integrity: sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.1': @@ -1614,8 +1612,8 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - enhanced-resolve@5.22.1: - resolution: {integrity: sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==} + enhanced-resolve@5.23.0: + resolution: {integrity: sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA==} engines: {node: '>=10.13.0'} entities@4.5.0: @@ -1696,8 +1694,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.4.0: - resolution: {integrity: sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==} + eslint@10.4.1: + resolution: {integrity: sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -2002,8 +2000,8 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + js-yaml@4.2.0: + resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} hasBin: true json-buffer@3.0.1: @@ -2307,8 +2305,8 @@ packages: resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} hasBin: true - miniflare@4.20260526.0: - resolution: {integrity: sha512-JYQ7jPZZWoaaj9jWHb8Ucp6Cu2SbDVqIsAJhumqdzzLkkfq0pYkDeino/sZfW1ixJWPjv/C44zjm9gVJC2izCA==} + miniflare@4.20260603.0: + resolution: {integrity: sha512-+kMQYB82gC8MPOuojHur3icQsUeZUEJ+Sphuo5rVC3Ri9txBLAW/mH33b9OVrpmkogQeaaqPS4tPtugJZhk5Kw==} engines: {node: '>=22.0.0'} hasBin: true @@ -2361,8 +2359,9 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + obug@2.1.2: + resolution: {integrity: sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==} + engines: {node: '>=12.20.0'} ofetch@1.5.1: resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} @@ -2541,8 +2540,8 @@ packages: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} - property-information@7.1.0: - resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -2655,31 +2654,11 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rollup@4.60.4: - resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} + rollup@4.61.1: + resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rosie-skills-darwin-arm64@0.6.4: - resolution: {integrity: sha512-rn1s5hqFKcxeiDEWWoFa1hdGPshR8TkwHLzy/cBavb9XJNAaUxbe3oQ78W9sQkRHAgRyzJYyk9tw68Qrdnizgg==} - cpu: [arm64] - os: [darwin] - - rosie-skills-freebsd-x64@0.6.4: - resolution: {integrity: sha512-SxCRduPBMtfjkQ+q56Yw9OLA3PyaqoALzt7kER7IDKuUVfM2O/1w8sa5xhTDiCvWkZJixnH5d5Ya6KT+/Mwcng==} - cpu: [x64] - os: [freebsd] - - rosie-skills-linux-x64@0.6.4: - resolution: {integrity: sha512-D9Y9mfu7goB0s0X59uU3hcFeUTef3VbpCIDwFMzyvJrAq3XhRACWBDMHQsHlyWdHxTXPX/ILyW65RXyrJlgqng==} - cpu: [x64] - os: [linux] - - rosie-skills@0.6.4: - resolution: {integrity: sha512-ojfhSiQRdZ2QyWbmKAHOSAUbaLYrTc5zIH7mS1jKoP8KCFSQddwVhMyFqldckTeybTfW3zNcsZzyOTzGTN1SBA==} - engines: {node: '>=18'} - hasBin: true - run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -2693,8 +2672,8 @@ packages: resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} engines: {node: '>=11.0.0'} - semver@7.8.1: - resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} + semver@7.8.3: + resolution: {integrity: sha512-wnilbGyMxzbY7dNOl7jpKbLSjcfeweJWU5j4+u5qW+6/wuGD9KzIGOyZnQVSBM9E7DtWaaH3CyHkppYrKYoxwg==} engines: {node: '>=10'} hasBin: true @@ -2710,8 +2689,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@4.1.0: - resolution: {integrity: sha512-l/ABZPUR5v70jI10EzqfMS/I96vjSGv2y0ihUV+WYFzv0EfvW4s54m0Lg8wCrrL+2IkwBzFTuxkZjPf8b2NX9Q==} + shiki@4.2.0: + resolution: {integrity: sha512-hjNax6o/ylDy9lefQEaSDtzaT3iVNtZ3WmpQnbuQNoG4xvnSKf2kSKbihZVO4JRG1TTMejs7CmNRYlWgAL66pQ==} engines: {node: '>=20'} sisteransi@1.0.5: @@ -2786,16 +2765,16 @@ packages: tiny-inflate@1.0.3: resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} - tinyclip@0.1.13: - resolution: {integrity: sha512-8OqlXQ35euK9+e7L68u8UwcODxkHoIkjbGsgXuARKNyQ5G6xt8nw1YPeMbxMLgCPFkToU+UEK5j05t2t8edKpQ==} + tinyclip@0.1.14: + resolution: {integrity: sha512-F1oWdz8tjT17qe1d5JgDK6z03WGOhYYAN0lK3/D/fzNiy93xswLLEw7pk+3g05onhAy6Bsc6PLNUGhdgVjemMQ==} engines: {node: ^16.14.0 || >= 17.3.0} - tinyexec@1.2.3: - resolution: {integrity: sha512-g62dB+w1/OEFnPvmX0yd/HnetYITOL+1nJW7kitOycOeAvmbWC/nu0fwmmQ/kupNojqExzyC/T++pST/jRJ2mQ==} + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} engines: {node: '>=18'} - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} to-regex-range@5.0.1: @@ -2827,8 +2806,8 @@ packages: typescript-auto-import-cache@0.3.6: resolution: {integrity: sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==} - typescript-eslint@8.60.0: - resolution: {integrity: sha512-9f65qWLZdAW9m1JaxBDUHcqRUfL8bkxxXL7XxEfI+F09q56PkBvIfCjLF3yInsDM/BBmwkqmCQdCZe/RYlIWEw==} + typescript-eslint@8.61.0: + resolution: {integrity: sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2848,8 +2827,8 @@ packages: uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} @@ -2974,8 +2953,8 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite@7.3.3: - resolution: {integrity: sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==} + vite@7.3.5: + resolution: {integrity: sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -3095,15 +3074,25 @@ packages: resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} engines: {node: '>=14.0.0'} + vscode-jsonrpc@9.0.0: + resolution: {integrity: sha512-+VvMmQPJhtvJ+8O+zu2JKIRiLxXF8NW7krWgyMGeOHrp4Cn23T5hc0v2LknNeopDOB70wghHAds7mKtcZ0I4Sg==} + engines: {node: '>=14.0.0'} + vscode-languageserver-protocol@3.17.5: resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + vscode-languageserver-protocol@3.18.0: + resolution: {integrity: sha512-Zdz+kJ12Iz6tc11xfZyEo501bBATHXrCjmMfnaR3pMnf1CoqZBKIynba3P+/bi9VEdrMbNtAVKYpKhbODvqy+Q==} + vscode-languageserver-textdocument@1.0.12: resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} vscode-languageserver-types@3.17.5: resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + vscode-languageserver-types@3.18.0: + resolution: {integrity: sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g==} + vscode-languageserver@9.0.1: resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} hasBin: true @@ -3130,17 +3119,17 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - workerd@1.20260526.1: - resolution: {integrity: sha512-IHzymht98p10JH1zzwdCpbViAqw97HrwKl7+KfZeASFMsYSrIsAULWdPn0LRC5FTUzBpamLNyKCCKxbgXHgRHQ==} + workerd@1.20260603.1: + resolution: {integrity: sha512-NPcbhI1++CS+fnELyXtsIR52en+5kwr/OrKeiQeYXGy10HxmPdsQBv9N+DU7hJIOOmBHhOGAAsoGDjyiQ2YCaA==} engines: {node: '>=16'} hasBin: true - wrangler@4.95.0: - resolution: {integrity: sha512-vgXzFVSCdUbeCadgVXvu8fK5tzNm8T9W+7lriyGWZMx0B1+CAdr4d8JTlZszHfgjypRAHmAxb49etZGIRD9pgg==} + wrangler@4.98.0: + resolution: {integrity: sha512-cXfFUuF4rMIvE0hiMnXjEAB27ERryaCgquBJdUoPIjFzYYE1rbRdMUkEdQ18qDPUtsPvhJdqxLntixT9OfSzQw==} engines: {node: '>=22.0.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20260526.1 + '@cloudflare/workers-types': ^4.20260603.1 peerDependenciesMeta: '@cloudflare/workers-types': optional: true @@ -3231,16 +3220,16 @@ snapshots: - prettier - prettier-plugin-astro - '@astrojs/cloudflare@13.6.0(@types/node@25.9.1)(astro@6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0))(jiti@2.7.0)(lightningcss@1.32.0)(workerd@1.20260526.1)(wrangler@4.95.0)(yaml@2.9.0)': + '@astrojs/cloudflare@13.6.1(@types/node@25.9.2)(astro@6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0))(jiti@2.7.0)(lightningcss@1.32.0)(workerd@1.20260603.1)(wrangler@4.98.0)(yaml@2.9.0)': dependencies: '@astrojs/internal-helpers': 0.10.0 '@astrojs/underscore-redirects': 1.0.3 - '@cloudflare/vite-plugin': 1.39.0(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))(workerd@1.20260526.1)(wrangler@4.95.0) - astro: 6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0) + '@cloudflare/vite-plugin': 1.40.0(vite@7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))(workerd@1.20260603.1)(wrangler@4.98.0) + astro: 6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0) piccolore: 0.1.3 - tinyglobby: 0.2.16 - vite: 7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) - wrangler: 4.95.0 + tinyglobby: 0.2.17 + vite: 7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) + wrangler: 4.98.0 transitivePeerDependencies: - '@types/node' - bufferutil @@ -3267,10 +3256,10 @@ snapshots: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - js-yaml: 4.1.1 + js-yaml: 4.2.0 picomatch: 4.0.4 retext-smartypants: 6.2.0 - shiki: 4.1.0 + shiki: 4.2.0 smol-toml: 1.6.1 unified: 11.0.5 @@ -3288,7 +3277,7 @@ snapshots: '@volar/language-server': 2.4.28 '@volar/language-service': 2.4.28 muggle-string: 0.4.1 - tinyglobby: 0.2.16 + tinyglobby: 0.2.17 volar-service-css: 0.0.70(@volar/language-service@2.4.28) volar-service-emmet: 0.0.70(@volar/language-service@2.4.28) volar-service-html: 0.0.70(@volar/language-service@2.4.28) @@ -3311,7 +3300,7 @@ snapshots: github-slugger: 2.0.0 hast-util-from-html: 2.0.3 hast-util-to-text: 4.0.2 - js-yaml: 4.1.1 + js-yaml: 4.2.0 mdast-util-definitions: 6.0.0 rehype-raw: 7.0.0 rehype-stringify: 10.0.1 @@ -3320,7 +3309,7 @@ snapshots: remark-rehype: 11.1.2 remark-smartypants: 3.0.2 retext-smartypants: 6.2.0 - shiki: 4.1.0 + shiki: 4.2.0 smol-toml: 1.6.1 unified: 11.0.5 unist-util-remove-position: 5.0.0 @@ -3330,12 +3319,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/mdx@5.0.4(astro@6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0))': + '@astrojs/mdx@5.0.4(astro@6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0))': dependencies: '@astrojs/markdown-remark': 7.1.1 '@mdx-js/mdx': 3.1.1 acorn: 8.16.0 - astro: 6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0) + astro: 6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0) es-module-lexer: 2.1.0 estree-util-visit: 2.0.0 hast-util-to-html: 9.0.5 @@ -3396,52 +3385,52 @@ snapshots: dependencies: fontkitten: 1.0.3 - '@clack/core@1.3.1': + '@clack/core@1.4.1': dependencies: fast-wrap-ansi: 0.2.2 sisteransi: 1.0.5 - '@clack/prompts@1.4.0': + '@clack/prompts@1.5.1': dependencies: - '@clack/core': 1.3.1 + '@clack/core': 1.4.1 fast-string-width: 3.0.2 fast-wrap-ansi: 0.2.2 sisteransi: 1.0.5 '@cloudflare/kv-asset-handler@0.5.0': {} - '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260526.1)': + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1)': dependencies: unenv: 2.0.0-rc.24 optionalDependencies: - workerd: 1.20260526.1 + workerd: 1.20260603.1 - '@cloudflare/vite-plugin@1.39.0(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))(workerd@1.20260526.1)(wrangler@4.95.0)': + '@cloudflare/vite-plugin@1.40.0(vite@7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))(workerd@1.20260603.1)(wrangler@4.98.0)': dependencies: - '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260526.1) - miniflare: 4.20260526.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1) + miniflare: 4.20260603.0 unenv: 2.0.0-rc.24 - vite: 7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) - wrangler: 4.95.0 + vite: 7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) + wrangler: 4.98.0 ws: 8.20.1 transitivePeerDependencies: - bufferutil - utf-8-validate - workerd - '@cloudflare/workerd-darwin-64@1.20260526.1': + '@cloudflare/workerd-darwin-64@1.20260603.1': optional: true - '@cloudflare/workerd-darwin-arm64@1.20260526.1': + '@cloudflare/workerd-darwin-arm64@1.20260603.1': optional: true - '@cloudflare/workerd-linux-64@1.20260526.1': + '@cloudflare/workerd-linux-64@1.20260603.1': optional: true - '@cloudflare/workerd-linux-arm64@1.20260526.1': + '@cloudflare/workerd-linux-arm64@1.20260603.1': optional: true - '@cloudflare/workerd-windows-64@1.20260526.1': + '@cloudflare/workerd-windows-64@1.20260603.1': optional: true '@cspotcode/source-map-support@0.8.1': @@ -3471,7 +3460,7 @@ snapshots: '@emmetio/stream-reader@2.2.0': {} - '@emnapi/runtime@1.10.0': + '@emnapi/runtime@1.11.0': dependencies: tslib: 2.8.1 optional: true @@ -3632,9 +3621,9 @@ snapshots: '@esbuild/win32-x64@0.27.7': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.4.0(jiti@2.7.0))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.4.1(jiti@2.7.0))': dependencies: - eslint: 10.4.0(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -3655,13 +3644,13 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.4.0(jiti@2.7.0))': + '@eslint/js@10.0.1(eslint@10.4.1(jiti@2.7.0))': optionalDependencies: - eslint: 10.4.0(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) '@eslint/object-schema@3.0.5': {} - '@eslint/plugin-kit@0.7.1': + '@eslint/plugin-kit@0.7.2': dependencies: '@eslint/core': 1.2.1 levn: 0.4.1 @@ -3766,7 +3755,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.10.0 + '@emnapi/runtime': 1.11.0 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -3802,16 +3791,16 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@lucide/astro@1.17.0(astro@6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0))': + '@lucide/astro@1.17.0(astro@6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0))': dependencies: - astro: 6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0) + astro: 6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0) '@mdx-js/mdx@3.1.1': dependencies: '@types/estree': 1.0.9 '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 - '@types/mdx': 2.0.13 + '@types/mdx': 2.0.14 acorn: 8.16.0 collapse-white-space: 2.1.0 devlop: 1.1.0 @@ -3930,123 +3919,123 @@ snapshots: '@poppinss/exception@1.2.3': {} - '@rollup/pluginutils@5.4.0(rollup@4.60.4)': + '@rollup/pluginutils@5.4.0(rollup@4.61.1)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.4 optionalDependencies: - rollup: 4.60.4 + rollup: 4.61.1 - '@rollup/rollup-android-arm-eabi@4.60.4': + '@rollup/rollup-android-arm-eabi@4.61.1': optional: true - '@rollup/rollup-android-arm64@4.60.4': + '@rollup/rollup-android-arm64@4.61.1': optional: true - '@rollup/rollup-darwin-arm64@4.60.4': + '@rollup/rollup-darwin-arm64@4.61.1': optional: true - '@rollup/rollup-darwin-x64@4.60.4': + '@rollup/rollup-darwin-x64@4.61.1': optional: true - '@rollup/rollup-freebsd-arm64@4.60.4': + '@rollup/rollup-freebsd-arm64@4.61.1': optional: true - '@rollup/rollup-freebsd-x64@4.60.4': + '@rollup/rollup-freebsd-x64@4.61.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + '@rollup/rollup-linux-arm-gnueabihf@4.61.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.4': + '@rollup/rollup-linux-arm-musleabihf@4.61.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.4': + '@rollup/rollup-linux-arm64-gnu@4.61.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.60.4': + '@rollup/rollup-linux-arm64-musl@4.61.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.4': + '@rollup/rollup-linux-loong64-gnu@4.61.1': optional: true - '@rollup/rollup-linux-loong64-musl@4.60.4': + '@rollup/rollup-linux-loong64-musl@4.61.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.4': + '@rollup/rollup-linux-ppc64-gnu@4.61.1': optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.4': + '@rollup/rollup-linux-ppc64-musl@4.61.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.4': + '@rollup/rollup-linux-riscv64-gnu@4.61.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.4': + '@rollup/rollup-linux-riscv64-musl@4.61.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.4': + '@rollup/rollup-linux-s390x-gnu@4.61.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.60.4': + '@rollup/rollup-linux-x64-gnu@4.61.1': optional: true - '@rollup/rollup-linux-x64-musl@4.60.4': + '@rollup/rollup-linux-x64-musl@4.61.1': optional: true - '@rollup/rollup-openbsd-x64@4.60.4': + '@rollup/rollup-openbsd-x64@4.61.1': optional: true - '@rollup/rollup-openharmony-arm64@4.60.4': + '@rollup/rollup-openharmony-arm64@4.61.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.4': + '@rollup/rollup-win32-arm64-msvc@4.61.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.4': + '@rollup/rollup-win32-ia32-msvc@4.61.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.60.4': + '@rollup/rollup-win32-x64-gnu@4.61.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.60.4': + '@rollup/rollup-win32-x64-msvc@4.61.1': optional: true - '@shikijs/core@4.1.0': + '@shikijs/core@4.2.0': dependencies: - '@shikijs/primitive': 4.1.0 - '@shikijs/types': 4.1.0 + '@shikijs/primitive': 4.2.0 + '@shikijs/types': 4.2.0 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 hast-util-to-html: 9.0.5 - '@shikijs/engine-javascript@4.1.0': + '@shikijs/engine-javascript@4.2.0': dependencies: - '@shikijs/types': 4.1.0 + '@shikijs/types': 4.2.0 '@shikijs/vscode-textmate': 10.0.2 oniguruma-to-es: 4.3.6 - '@shikijs/engine-oniguruma@4.1.0': + '@shikijs/engine-oniguruma@4.2.0': dependencies: - '@shikijs/types': 4.1.0 + '@shikijs/types': 4.2.0 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@4.1.0': + '@shikijs/langs@4.2.0': dependencies: - '@shikijs/types': 4.1.0 + '@shikijs/types': 4.2.0 - '@shikijs/primitive@4.1.0': + '@shikijs/primitive@4.2.0': dependencies: - '@shikijs/types': 4.1.0 + '@shikijs/types': 4.2.0 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 - '@shikijs/themes@4.1.0': + '@shikijs/themes@4.2.0': dependencies: - '@shikijs/types': 4.1.0 + '@shikijs/types': 4.2.0 - '@shikijs/types@4.1.0': + '@shikijs/types@4.2.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -4062,7 +4051,7 @@ snapshots: '@parcel/watcher': 2.5.6 '@tailwindcss/node': 4.3.0 '@tailwindcss/oxide': 4.3.0 - enhanced-resolve: 5.22.1 + enhanced-resolve: 5.23.0 mri: 1.2.0 picocolors: 1.1.1 tailwindcss: 4.3.0 @@ -4075,7 +4064,7 @@ snapshots: '@tailwindcss/node@4.3.0': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.22.1 + enhanced-resolve: 5.23.0 jiti: 2.7.0 lightningcss: 1.32.0 magic-string: 0.30.21 @@ -4133,17 +4122,17 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 - '@tailwindcss/typography@0.5.19(tailwindcss@4.3.0)': + '@tailwindcss/typography@0.5.20(tailwindcss@4.3.0)': dependencies: postcss-selector-parser: 6.0.10 tailwindcss: 4.3.0 - '@tailwindcss/vite@4.3.0(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.0(vite@7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.0 '@tailwindcss/oxide': 4.3.0 tailwindcss: 4.3.0 - vite: 7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) + vite: 7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) '@types/debug@4.1.13': dependencies: @@ -4155,8 +4144,6 @@ snapshots: dependencies: '@types/estree': 1.0.9 - '@types/estree@1.0.8': {} - '@types/estree@1.0.9': {} '@types/hast@3.0.4': @@ -4169,7 +4156,7 @@ snapshots: dependencies: '@types/unist': 3.0.3 - '@types/mdx@2.0.13': {} + '@types/mdx@2.0.14': {} '@types/ms@2.1.0': {} @@ -4177,31 +4164,31 @@ snapshots: dependencies: '@types/unist': 3.0.3 - '@types/node@24.12.4': + '@types/node@24.13.1': dependencies: - undici-types: 7.16.0 + undici-types: 7.18.2 - '@types/node@25.9.1': + '@types/node@25.9.2': dependencies: undici-types: 7.24.6 '@types/sax@1.2.7': dependencies: - '@types/node': 25.9.1 + '@types/node': 25.9.2 '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} - '@typescript-eslint/eslint-plugin@8.60.0(@typescript-eslint/parser@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.60.0 - '@typescript-eslint/type-utils': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.60.0 - eslint: 10.4.0(jiti@2.7.0) + '@typescript-eslint/parser': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/type-utils': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.61.0 + eslint: 10.4.1(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -4209,79 +4196,79 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.60.0 - '@typescript-eslint/types': 8.60.0 - '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.60.0 + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.61.0 debug: 4.4.3 - eslint: 10.4.0(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.60.0(typescript@6.0.3)': + '@typescript-eslint/project-service@8.61.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.60.0(typescript@6.0.3) - '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@6.0.3) + '@typescript-eslint/types': 8.61.0 debug: 4.4.3 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.60.0': + '@typescript-eslint/scope-manager@8.61.0': dependencies: - '@typescript-eslint/types': 8.60.0 - '@typescript-eslint/visitor-keys': 8.60.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/visitor-keys': 8.61.0 - '@typescript-eslint/tsconfig-utils@8.60.0(typescript@6.0.3)': + '@typescript-eslint/tsconfig-utils@8.61.0(typescript@6.0.3)': dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.60.0 - '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) debug: 4.4.3 - eslint: 10.4.0(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.60.0': {} + '@typescript-eslint/types@8.61.0': {} - '@typescript-eslint/typescript-estree@8.60.0(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.61.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.60.0(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.60.0(typescript@6.0.3) - '@typescript-eslint/types': 8.60.0 - '@typescript-eslint/visitor-keys': 8.60.0 + '@typescript-eslint/project-service': 8.61.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@6.0.3) + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/visitor-keys': 8.61.0 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.8.1 - tinyglobby: 0.2.16 + semver: 7.8.3 + tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/utils@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.0(jiti@2.7.0)) - '@typescript-eslint/scope-manager': 8.60.0 - '@typescript-eslint/types': 8.60.0 - '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) - eslint: 10.4.0(jiti@2.7.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + eslint: 10.4.1(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.60.0': + '@typescript-eslint/visitor-keys@8.61.0': dependencies: - '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/types': 8.61.0 eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.3.1': {} @@ -4307,14 +4294,14 @@ snapshots: path-browserify: 1.0.1 request-light: 0.7.0 vscode-languageserver: 9.0.1 - vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-protocol: 3.18.0 vscode-languageserver-textdocument: 1.0.12 vscode-uri: 3.1.0 '@volar/language-service@2.4.28': dependencies: '@volar/language-core': 2.4.28 - vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-protocol: 3.18.0 vscode-languageserver-textdocument: 1.0.12 vscode-uri: 3.1.0 @@ -4331,7 +4318,7 @@ snapshots: emmet: 2.4.11 jsonc-parser: 2.3.1 vscode-languageserver-textdocument: 1.0.12 - vscode-languageserver-types: 3.17.5 + vscode-languageserver-types: 3.18.0 vscode-uri: 3.1.0 '@vscode/l10n@0.0.18': {} @@ -4384,8 +4371,8 @@ snapshots: astro-eslint-parser@1.4.0: dependencies: '@astrojs/compiler': 3.0.1 - '@typescript-eslint/scope-manager': 8.60.0 - '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 astrojs-compiler-sync: 1.1.1(@astrojs/compiler@3.0.1) debug: 4.4.3 entities: 7.0.1 @@ -4394,20 +4381,20 @@ snapshots: espree: 10.4.0 fast-glob: 3.3.3 is-glob: 4.0.3 - semver: 7.8.1 + semver: 7.8.3 transitivePeerDependencies: - supports-color - astro@6.3.1(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(yaml@2.9.0): + astro@6.3.1(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.1)(yaml@2.9.0): dependencies: '@astrojs/compiler': 4.0.0 '@astrojs/internal-helpers': 0.9.0 '@astrojs/markdown-remark': 7.1.1 '@astrojs/telemetry': 3.3.2 '@capsizecss/unpack': 4.0.0 - '@clack/prompts': 1.4.0 + '@clack/prompts': 1.5.1 '@oslojs/encoding': 1.1.0 - '@rollup/pluginutils': 5.4.0(rollup@4.60.4) + '@rollup/pluginutils': 5.4.0(rollup@4.61.1) aria-query: 5.3.2 axobject-query: 4.1.0 ci-info: 4.4.0 @@ -4425,33 +4412,33 @@ snapshots: github-slugger: 2.0.0 html-escaper: 3.0.3 http-cache-semantics: 4.2.0 - js-yaml: 4.1.1 + js-yaml: 4.2.0 jsonc-parser: 3.3.1 magic-string: 0.30.21 magicast: 0.5.3 mrmime: 2.0.1 neotraverse: 0.6.18 - obug: 2.1.1 + obug: 2.1.2 p-limit: 7.3.0 p-queue: 9.3.0 package-manager-detector: 1.6.0 piccolore: 0.1.3 picomatch: 4.0.4 rehype: 13.0.2 - semver: 7.8.1 - shiki: 4.1.0 + semver: 7.8.3 + shiki: 4.2.0 smol-toml: 1.6.1 svgo: 4.0.1 - tinyclip: 0.1.13 - tinyexec: 1.2.3 - tinyglobby: 0.2.16 + tinyclip: 0.1.14 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 ultrahtml: 1.6.0 unifont: 0.7.4 unist-util-visit: 5.1.0 unstorage: 1.17.5 vfile: 6.0.3 - vite: 7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) - vitefu: 1.1.3(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0)) + vite: 7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) + vitefu: 1.1.3(vite@7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0)) xxhash-wasm: 1.1.0 yargs-parser: 22.0.0 zod: 4.4.3 @@ -4649,7 +4636,7 @@ snapshots: emoji-regex@8.0.0: {} - enhanced-resolve@5.22.1: + enhanced-resolve@5.23.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 @@ -4742,19 +4729,19 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-compat-utils@0.6.5(eslint@10.4.0(jiti@2.7.0)): + eslint-compat-utils@0.6.5(eslint@10.4.1(jiti@2.7.0)): dependencies: - eslint: 10.4.0(jiti@2.7.0) - semver: 7.8.1 + eslint: 10.4.1(jiti@2.7.0) + semver: 7.8.3 - eslint-plugin-astro@1.7.0(eslint@10.4.0(jiti@2.7.0)): + eslint-plugin-astro@1.7.0(eslint@10.4.1(jiti@2.7.0)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.0(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0)) '@jridgewell/sourcemap-codec': 1.5.5 - '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/types': 8.61.0 astro-eslint-parser: 1.4.0 - eslint: 10.4.0(jiti@2.7.0) - eslint-compat-utils: 0.6.5(eslint@10.4.0(jiti@2.7.0)) + eslint: 10.4.1(jiti@2.7.0) + eslint-compat-utils: 0.6.5(eslint@10.4.1(jiti@2.7.0)) globals: 16.5.0 postcss: 8.5.15 postcss-selector-parser: 7.1.1 @@ -4779,14 +4766,14 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.4.0(jiti@2.7.0): + eslint@10.4.1(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.0(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.6.0 '@eslint/core': 1.2.1 - '@eslint/plugin-kit': 0.7.1 + '@eslint/plugin-kit': 0.7.2 '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 @@ -5011,7 +4998,7 @@ snapshots: '@types/unist': 3.0.3 devlop: 1.1.0 hastscript: 9.0.1 - property-information: 7.1.0 + property-information: 7.2.0 vfile: 6.0.3 vfile-location: 5.0.3 web-namespaces: 2.0.1 @@ -5053,7 +5040,7 @@ snapshots: mdast-util-mdx-expression: 2.0.1 mdast-util-mdx-jsx: 3.2.0 mdast-util-mdxjs-esm: 2.0.1 - property-information: 7.1.0 + property-information: 7.2.0 space-separated-tokens: 2.0.2 style-to-js: 1.1.21 unist-util-position: 5.0.0 @@ -5070,7 +5057,7 @@ snapshots: hast-util-whitespace: 3.0.0 html-void-elements: 3.0.0 mdast-util-to-hast: 13.2.1 - property-information: 7.1.0 + property-information: 7.2.0 space-separated-tokens: 2.0.2 stringify-entities: 4.0.4 zwitch: 2.0.4 @@ -5087,7 +5074,7 @@ snapshots: mdast-util-mdx-expression: 2.0.1 mdast-util-mdx-jsx: 3.2.0 mdast-util-mdxjs-esm: 2.0.1 - property-information: 7.1.0 + property-information: 7.2.0 space-separated-tokens: 2.0.2 style-to-js: 1.1.21 unist-util-position: 5.0.0 @@ -5100,7 +5087,7 @@ snapshots: '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 devlop: 1.1.0 - property-information: 7.1.0 + property-information: 7.2.0 space-separated-tokens: 2.0.2 web-namespaces: 2.0.1 zwitch: 2.0.4 @@ -5121,7 +5108,7 @@ snapshots: '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 hast-util-parse-selector: 4.0.0 - property-information: 7.1.0 + property-information: 7.2.0 space-separated-tokens: 2.0.2 html-escaper@3.0.3: {} @@ -5181,7 +5168,7 @@ snapshots: jiti@2.7.0: {} - js-yaml@4.1.1: + js-yaml@4.2.0: dependencies: argparse: 2.0.1 @@ -5725,12 +5712,12 @@ snapshots: mini-svg-data-uri@1.4.4: {} - miniflare@4.20260526.0: + miniflare@4.20260603.0: dependencies: '@cspotcode/source-map-support': 0.8.1 sharp: 0.34.5 undici: 7.24.8 - workerd: 1.20260526.1 + workerd: 1.20260603.1 ws: 8.20.1 youch: 4.1.0-beta.10 transitivePeerDependencies: @@ -5771,7 +5758,7 @@ snapshots: dependencies: boolbase: 1.0.0 - obug@2.1.1: {} + obug@2.1.2: {} ofetch@1.5.1: dependencies: @@ -5904,7 +5891,7 @@ snapshots: prismjs@1.30.0: {} - property-information@7.1.0: {} + property-information@7.2.0: {} punycode@2.3.1: {} @@ -6082,52 +6069,37 @@ snapshots: reusify@1.1.0: {} - rollup@4.60.4: + rollup@4.61.1: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.4 - '@rollup/rollup-android-arm64': 4.60.4 - '@rollup/rollup-darwin-arm64': 4.60.4 - '@rollup/rollup-darwin-x64': 4.60.4 - '@rollup/rollup-freebsd-arm64': 4.60.4 - '@rollup/rollup-freebsd-x64': 4.60.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 - '@rollup/rollup-linux-arm-musleabihf': 4.60.4 - '@rollup/rollup-linux-arm64-gnu': 4.60.4 - '@rollup/rollup-linux-arm64-musl': 4.60.4 - '@rollup/rollup-linux-loong64-gnu': 4.60.4 - '@rollup/rollup-linux-loong64-musl': 4.60.4 - '@rollup/rollup-linux-ppc64-gnu': 4.60.4 - '@rollup/rollup-linux-ppc64-musl': 4.60.4 - '@rollup/rollup-linux-riscv64-gnu': 4.60.4 - '@rollup/rollup-linux-riscv64-musl': 4.60.4 - '@rollup/rollup-linux-s390x-gnu': 4.60.4 - '@rollup/rollup-linux-x64-gnu': 4.60.4 - '@rollup/rollup-linux-x64-musl': 4.60.4 - '@rollup/rollup-openbsd-x64': 4.60.4 - '@rollup/rollup-openharmony-arm64': 4.60.4 - '@rollup/rollup-win32-arm64-msvc': 4.60.4 - '@rollup/rollup-win32-ia32-msvc': 4.60.4 - '@rollup/rollup-win32-x64-gnu': 4.60.4 - '@rollup/rollup-win32-x64-msvc': 4.60.4 + '@rollup/rollup-android-arm-eabi': 4.61.1 + '@rollup/rollup-android-arm64': 4.61.1 + '@rollup/rollup-darwin-arm64': 4.61.1 + '@rollup/rollup-darwin-x64': 4.61.1 + '@rollup/rollup-freebsd-arm64': 4.61.1 + '@rollup/rollup-freebsd-x64': 4.61.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.61.1 + '@rollup/rollup-linux-arm-musleabihf': 4.61.1 + '@rollup/rollup-linux-arm64-gnu': 4.61.1 + '@rollup/rollup-linux-arm64-musl': 4.61.1 + '@rollup/rollup-linux-loong64-gnu': 4.61.1 + '@rollup/rollup-linux-loong64-musl': 4.61.1 + '@rollup/rollup-linux-ppc64-gnu': 4.61.1 + '@rollup/rollup-linux-ppc64-musl': 4.61.1 + '@rollup/rollup-linux-riscv64-gnu': 4.61.1 + '@rollup/rollup-linux-riscv64-musl': 4.61.1 + '@rollup/rollup-linux-s390x-gnu': 4.61.1 + '@rollup/rollup-linux-x64-gnu': 4.61.1 + '@rollup/rollup-linux-x64-musl': 4.61.1 + '@rollup/rollup-openbsd-x64': 4.61.1 + '@rollup/rollup-openharmony-arm64': 4.61.1 + '@rollup/rollup-win32-arm64-msvc': 4.61.1 + '@rollup/rollup-win32-ia32-msvc': 4.61.1 + '@rollup/rollup-win32-x64-gnu': 4.61.1 + '@rollup/rollup-win32-x64-msvc': 4.61.1 fsevents: 2.3.3 - rosie-skills-darwin-arm64@0.6.4: - optional: true - - rosie-skills-freebsd-x64@0.6.4: - optional: true - - rosie-skills-linux-x64@0.6.4: - optional: true - - rosie-skills@0.6.4: - optionalDependencies: - rosie-skills-darwin-arm64: 0.6.4 - rosie-skills-freebsd-x64: 0.6.4 - rosie-skills-linux-x64: 0.6.4 - run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -6140,13 +6112,13 @@ snapshots: sax@1.6.0: {} - semver@7.8.1: {} + semver@7.8.3: {} sharp@0.34.5: dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 - semver: 7.8.1 + semver: 7.8.3 optionalDependencies: '@img/sharp-darwin-arm64': 0.34.5 '@img/sharp-darwin-x64': 0.34.5 @@ -6179,14 +6151,14 @@ snapshots: shebang-regex@3.0.0: {} - shiki@4.1.0: + shiki@4.2.0: dependencies: - '@shikijs/core': 4.1.0 - '@shikijs/engine-javascript': 4.1.0 - '@shikijs/engine-oniguruma': 4.1.0 - '@shikijs/langs': 4.1.0 - '@shikijs/themes': 4.1.0 - '@shikijs/types': 4.1.0 + '@shikijs/core': 4.2.0 + '@shikijs/engine-javascript': 4.2.0 + '@shikijs/engine-oniguruma': 4.2.0 + '@shikijs/langs': 4.2.0 + '@shikijs/themes': 4.2.0 + '@shikijs/types': 4.2.0 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -6194,7 +6166,7 @@ snapshots: sitemap@9.0.1: dependencies: - '@types/node': 24.12.4 + '@types/node': 24.13.1 '@types/sax': 1.2.7 arg: 5.0.2 sax: 1.6.0 @@ -6260,11 +6232,11 @@ snapshots: tiny-inflate@1.0.3: {} - tinyclip@0.1.13: {} + tinyclip@0.1.14: {} - tinyexec@1.2.3: {} + tinyexec@1.2.4: {} - tinyglobby@0.2.16: + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 @@ -6292,15 +6264,15 @@ snapshots: typescript-auto-import-cache@0.3.6: dependencies: - semver: 7.8.1 + semver: 7.8.3 - typescript-eslint@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3): + typescript-eslint@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.60.0(@typescript-eslint/parser@8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/parser': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.0(eslint@10.4.0(jiti@2.7.0))(typescript@6.0.3) - eslint: 10.4.0(jiti@2.7.0) + '@typescript-eslint/eslint-plugin': 8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.4.1(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -6313,7 +6285,7 @@ snapshots: uncrypto@0.1.3: {} - undici-types@7.16.0: {} + undici-types@7.18.2: {} undici-types@7.24.6: {} @@ -6417,24 +6389,24 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0): + vite@7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0): dependencies: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 postcss: 8.5.15 - rollup: 4.60.4 - tinyglobby: 0.2.16 + rollup: 4.61.1 + tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 25.9.1 + '@types/node': 25.9.2 fsevents: 2.3.3 jiti: 2.7.0 lightningcss: 1.32.0 yaml: 2.9.0 - vitefu@1.1.3(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0)): + vitefu@1.1.3(vite@7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0)): optionalDependencies: - vite: 7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) + vite: 7.3.5(@types/node@25.9.2)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) volar-service-css@0.0.70(@volar/language-service@2.4.28): dependencies: @@ -6477,7 +6449,7 @@ snapshots: volar-service-typescript@0.0.70(@volar/language-service@2.4.28): dependencies: path-browserify: 1.0.1 - semver: 7.8.1 + semver: 7.8.3 typescript-auto-import-cache: 0.3.6 vscode-languageserver-textdocument: 1.0.12 vscode-nls: 5.2.0 @@ -6503,28 +6475,37 @@ snapshots: dependencies: '@vscode/l10n': 0.0.18 vscode-languageserver-textdocument: 1.0.12 - vscode-languageserver-types: 3.17.5 + vscode-languageserver-types: 3.18.0 vscode-uri: 3.1.0 vscode-json-languageservice@4.1.8: dependencies: jsonc-parser: 3.3.1 vscode-languageserver-textdocument: 1.0.12 - vscode-languageserver-types: 3.17.5 + vscode-languageserver-types: 3.18.0 vscode-nls: 5.2.0 vscode-uri: 3.1.0 vscode-jsonrpc@8.2.0: {} + vscode-jsonrpc@9.0.0: {} + vscode-languageserver-protocol@3.17.5: dependencies: vscode-jsonrpc: 8.2.0 vscode-languageserver-types: 3.17.5 + vscode-languageserver-protocol@3.18.0: + dependencies: + vscode-jsonrpc: 9.0.0 + vscode-languageserver-types: 3.18.0 + vscode-languageserver-textdocument@1.0.12: {} vscode-languageserver-types@3.17.5: {} + vscode-languageserver-types@3.18.0: {} + vscode-languageserver@9.0.1: dependencies: vscode-languageserver-protocol: 3.17.5 @@ -6543,25 +6524,24 @@ snapshots: word-wrap@1.2.5: {} - workerd@1.20260526.1: + workerd@1.20260603.1: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20260526.1 - '@cloudflare/workerd-darwin-arm64': 1.20260526.1 - '@cloudflare/workerd-linux-64': 1.20260526.1 - '@cloudflare/workerd-linux-arm64': 1.20260526.1 - '@cloudflare/workerd-windows-64': 1.20260526.1 + '@cloudflare/workerd-darwin-64': 1.20260603.1 + '@cloudflare/workerd-darwin-arm64': 1.20260603.1 + '@cloudflare/workerd-linux-64': 1.20260603.1 + '@cloudflare/workerd-linux-arm64': 1.20260603.1 + '@cloudflare/workerd-windows-64': 1.20260603.1 - wrangler@4.95.0: + wrangler@4.98.0: dependencies: '@cloudflare/kv-asset-handler': 0.5.0 - '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260526.1) + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1) blake3-wasm: 2.1.5 esbuild: 0.27.3 - miniflare: 4.20260526.0 + miniflare: 4.20260603.0 path-to-regexp: 6.3.0 - rosie-skills: 0.6.4 unenv: 2.0.0-rc.24 - workerd: 1.20260526.1 + workerd: 1.20260603.1 optionalDependencies: fsevents: 2.3.3 transitivePeerDependencies: @@ -6592,7 +6572,7 @@ snapshots: vscode-json-languageservice: 4.1.8 vscode-languageserver: 9.0.1 vscode-languageserver-textdocument: 1.0.12 - vscode-languageserver-types: 3.17.5 + vscode-languageserver-types: 3.18.0 vscode-uri: 3.1.0 yaml: 2.7.1 diff --git a/scripts/generate-dark-variants.js b/scripts/generate-dark-variants.js index 9ceb0fce8..f5bf33f3f 100644 --- a/scripts/generate-dark-variants.js +++ b/scripts/generate-dark-variants.js @@ -5,48 +5,8 @@ import { fileURLToPath } from 'url' import fs from 'fs' import path from 'path' -const SHADE_MAP = { - 50: 800, - 100: 800, - 200: 700, - 300: 600, - 400: 500, - 500: 400, - 600: 300, - 700: 200, - 800: 100, - 900: 50, -} - -const COLOR_MAP = { - white: 'gray-900', - black: 'white', -} - -const COLOR_FAMILIES = [ - 'red', - 'orange', - 'amber', - 'yellow', - 'lime', - 'green', - 'emerald', - 'teal', - 'cyan', - 'sky', - 'blue', - 'indigo', - 'violet', - 'purple', - 'fuchsia', - 'pink', - 'rose', - 'slate', - 'gray', - 'zinc', - 'neutral', - 'stone', -] +import { DEFAULT_CONFIG } from '../src/lib/dark-mode/config.js' +import { transformHtmlString } from '../src/lib/dark-mode/transform-html.js' function getProjectRoot() { const scriptFilePath = fileURLToPath(import.meta.url) @@ -54,88 +14,6 @@ function getProjectRoot() { return path.resolve(path.dirname(scriptFilePath), '..') } -function splitVariantPrefix(className) { - const lastSeparatorIndex = className.lastIndexOf(':') - - if (lastSeparatorIndex === -1) { - return { - variantPrefix: '', - classWithoutVariant: className, - } - } - - return { - variantPrefix: className.slice(0, lastSeparatorIndex + 1), - classWithoutVariant: className.slice(lastSeparatorIndex + 1), - } -} - -function transformClass(className) { - const { variantPrefix, classWithoutVariant } = splitVariantPrefix(className) - - const gray900Match = classWithoutVariant.match(/^(.*?)(gray-900)(\/\d+)?$/) - - if (gray900Match) { - const grayPrefix = gray900Match[1] ?? '' - const graySuffix = gray900Match[3] ?? '' - - return `${className} dark:${variantPrefix}${grayPrefix}white${graySuffix}` - } - - for (const [lightColor, darkColor] of Object.entries(COLOR_MAP)) { - if (classWithoutVariant.includes(lightColor)) { - const colorMatch = classWithoutVariant.match(/^((?:[\w]+-)*)(white|black)(\/\d+)?$/) - - if (colorMatch) { - const colorPrefix = colorMatch[1] ?? '' - const colorSuffix = colorMatch[3] ?? '' - const darkClass = `${colorPrefix}${darkColor}${colorSuffix}` - - return `${className} dark:${variantPrefix}${darkClass}` - } - } - } - - for (const colorFamily of COLOR_FAMILIES) { - const colorRegex = new RegExp(`^([\\w-]*?)${colorFamily}-(\\d+)(.*?)$`) - const colorMatch = classWithoutVariant.match(colorRegex) - - if (colorMatch) { - const colorPrefix = colorMatch[1] ?? '' - const colorShade = colorMatch[2] ?? '0' - const colorSuffix = colorMatch[3] ?? '' - const shadeNum = parseInt(colorShade, 10) - - if (shadeNum in SHADE_MAP) { - const darkShade = SHADE_MAP[shadeNum] - const darkClass = `${colorPrefix}${colorFamily}-${darkShade}${colorSuffix}` - - return `${className} dark:${variantPrefix}${darkClass}` - } - } - } - - return className -} - -function transformClassAttribute(classAttr) { - if (!classAttr) return classAttr - - return classAttr - .split(/\s+/) - .filter(Boolean) - .map((className) => (className.includes('dark:') ? className : transformClass(className))) - .join(' ') -} - -function transformHtmlContent(htmlContent) { - return htmlContent.replace(/class="([^"]*)"/g, (_, classAttr) => { - const transformedClass = transformClassAttribute(classAttr) - - return `class="${transformedClass}"` - }) -} - function isPathWithinBounds(targetPath, allowedParent) { const normalizedTarget = path.normalize(path.resolve(targetPath)) const normalizedParent = path.normalize(path.resolve(allowedParent)) @@ -244,7 +122,7 @@ function processFolder() { try { const lightContent = fs.readFileSync(lightPath, 'utf-8') - const darkContent = transformHtmlContent(lightContent) + const darkContent = transformHtmlString(lightContent, DEFAULT_CONFIG) fs.writeFileSync(darkPath, darkContent, 'utf-8') diff --git a/src/components/BaseHead.astro b/src/components/BaseHead.astro index 79f377d60..1df148de9 100644 --- a/src/components/BaseHead.astro +++ b/src/components/BaseHead.astro @@ -5,7 +5,7 @@ import { Font } from 'astro:assets' import OgImage from '../assets/og.jpg' -import { SITE_TITLE } from '../consts' +import { SITE_TITLE } from '../constants/seo' import type { ImageMetadata } from 'astro' diff --git a/src/components/DarkModeGenerator.astro b/src/components/DarkModeGenerator.astro new file mode 100644 index 000000000..461bf5d20 --- /dev/null +++ b/src/components/DarkModeGenerator.astro @@ -0,0 +1,474 @@ +--- +import DarkModeSidePanel from './DarkModeSidePanel.astro' +import DarkModePreviewPanel from './DarkModePreviewPanel.astro' +import DarkModeRulesDialog from './DarkModeRulesDialog.astro' +import DarkModeInspector from './DarkModeInspector.astro' +--- + + +
+ + +
+ + + +
+ + + + diff --git a/src/components/DarkModeInspector.astro b/src/components/DarkModeInspector.astro new file mode 100644 index 000000000..8aa2fb1e1 --- /dev/null +++ b/src/components/DarkModeInspector.astro @@ -0,0 +1,136 @@ +--- +import { Pencil, X } from '@lucide/astro' +import { FORM_INPUT_CLASS, NUMBER_INPUT_CLASS } from '../lib/dark-mode/element-constants.js' +--- + + +
+
+ + + + + +
+ + +
+ +
+
+

+ Apply when +

+

+ In dark mode +

+

+ Skip when +

+ + + + + + + + + + + + +
+
+
diff --git a/src/components/DarkModePreviewPanel.astro b/src/components/DarkModePreviewPanel.astro new file mode 100644 index 000000000..5ce5fb117 --- /dev/null +++ b/src/components/DarkModePreviewPanel.astro @@ -0,0 +1,77 @@ +--- +import { Clipboard } from '@lucide/astro' +--- + +
+
+ + +
+ + + + + + + +
+
+ + + +
+ + + +
+
diff --git a/src/components/DarkModeRulesDialog.astro b/src/components/DarkModeRulesDialog.astro new file mode 100644 index 000000000..342feae15 --- /dev/null +++ b/src/components/DarkModeRulesDialog.astro @@ -0,0 +1,152 @@ +--- +import { X } from '@lucide/astro' +--- + + +
+

Rule examples

+ + +
+ +
+

+ Rules let you override the shade map for specific utilities, shades, or colours. The first + matching enabled rule wins. +

+ +
+

Make all text lighter in dark mode

+ +

+ Match any text-* class and force shade + 300 in dark mode, regardless of the shade map. +

+ +
+
Utilities
+
text
+
Shade
+
+
In dark mode
+
300
+
+ +
+
+
+

Before

+ +
<h1 class="text-gray-900">Title</h1>
+<p class="text-gray-600">Subtitle</p>
+
+ +
+

After

+ +
<h1 class="text-gray-900 dark:text-gray-300">Title</h1>
+<p class="text-gray-600 dark:text-gray-300">Subtitle</p>
+
+
+
+
+ +
+

Invert heavy backgrounds, skip buttons

+ +

+ Match bg-* at shade 900 and map it to 100 + in dark mode, but skip <button> elements. +

+ +
+
Utilities
+
bg
+
Shade
+
900
+
In dark mode
+
100
+
Skip elements
+
button
+
+ +
+
+
+

Before

+ +
<div class="bg-gray-900 p-4">Panel</div>
+<button class="bg-gray-900 px-4 py-2">Save</button>
+
+ +
+

After

+ +
<div class="bg-gray-900 dark:bg-gray-100 p-4">Panel</div>
+<button class="bg-gray-900 px-4 py-2">Save</button>
+
+
+
+
+ +
+

Keep brand colours untouched

+ +

+ Match any utility but exclude indigo and violet so brand colours pass through without + modification. +

+ +
+
Utilities
+
+
Shade
+
+
In dark mode
+
+
Skip colours
+
indigo, violet
+
+ +
+
+
+

Before

+ +
<p class="text-gray-900">Text</p>
+<span class="text-indigo-600">Brand</span>
+
+ +
+

After

+ +
<p class="text-gray-900 dark:text-gray-300">Text</p>
+<span class="text-indigo-600">Brand</span>
+
+
+
+
+
+
diff --git a/src/components/DarkModeSidePanel.astro b/src/components/DarkModeSidePanel.astro new file mode 100644 index 000000000..19fbaafd9 --- /dev/null +++ b/src/components/DarkModeSidePanel.astro @@ -0,0 +1,130 @@ +--- +import { ChevronDown, Info, Plus } from '@lucide/astro' +--- + + diff --git a/src/components/DropdownMenu.astro b/src/components/DropdownMenu.astro index b88b09c81..c9b5bcab7 100644 --- a/src/components/DropdownMenu.astro +++ b/src/components/DropdownMenu.astro @@ -23,6 +23,8 @@ import HeaderLink from './HeaderLink.astro' Neobrutalism + Tools + Blog Application Marketing Neobrutalism + Tools Blog } */ (rawData) + + return { + shadeMap: normalizeShadeMap(rawConfigRecord.shadeMap), + colorMap: normalizeColorMap(rawConfigRecord.colorMap), + utilities: normalizeUtilities(rawConfigRecord.utilities), + rules: normalizeRules(rawConfigRecord.rules), + overwriteExisting: + typeof rawConfigRecord.overwriteExisting === 'boolean' + ? rawConfigRecord.overwriteExisting + : DEFAULT_CONFIG.overwriteExisting, + } +} + +/** @param {unknown} rawData @returns {DarkModeConfig['shadeMap']} */ +function normalizeShadeMap(rawData) { + if (!rawData || typeof rawData !== 'object') { + return { ...DEFAULT_CONFIG.shadeMap } + } + + const normalizedShadeMap = { ...DEFAULT_CONFIG.shadeMap } + + for (const [shadeKey, shadeValue] of Object.entries(rawData)) { + const parsedShade = parseInt(shadeKey, 10) + + if (!isNaN(parsedShade) && typeof shadeValue === 'number') { + normalizedShadeMap[parsedShade] = shadeValue + } + } + + return normalizedShadeMap +} + +/** @param {unknown} rawData @returns {DarkModeConfig['colorMap']} */ +function normalizeColorMap(rawData) { + if (!rawData || typeof rawData !== 'object') { + return { ...DEFAULT_CONFIG.colorMap } + } + + const normalizedColorMap = { ...DEFAULT_CONFIG.colorMap } + + for (const [colorKey, colorValue] of Object.entries(rawData)) { + if (typeof colorKey === 'string' && typeof colorValue === 'string') { + normalizedColorMap[colorKey] = colorValue + } + } + + return normalizedColorMap +} + +/** @param {unknown} rawData @returns {DarkModeConfig['utilities']} */ +function normalizeUtilities(rawData) { + if (!rawData || typeof rawData !== 'object') { + return { ...DEFAULT_CONFIG.utilities } + } + + const normalizedUtilities = { ...DEFAULT_CONFIG.utilities } + + for (const [utilityKey, utilityValue] of Object.entries(rawData)) { + if (typeof utilityKey === 'string' && typeof utilityValue === 'boolean') { + normalizedUtilities[utilityKey] = utilityValue + } + } + + return normalizedUtilities +} + +/** @param {unknown} rawData @returns {Rule[]} */ +function normalizeRules(rawData) { + if (!Array.isArray(rawData)) { + return [] + } + + return rawData.map(normalizeRule).filter(Boolean) +} + +/** @param {unknown} rawRule @returns {Rule | null} */ +function normalizeRule(rawRule) { + if (!rawRule || typeof rawRule !== 'object') { + return null + } + + const ruleRecord = /** @type {Record} */ (rawRule) + + if (typeof ruleRecord.id !== 'string') { + return null + } + + // Migrate old `utility: string` field to `utilities: string[]` + let utilityList = null + if (Array.isArray(ruleRecord.utilities)) { + utilityList = ruleRecord.utilities.filter((utilityItem) => typeof utilityItem === 'string') + } else if (typeof ruleRecord.utility === 'string' && ruleRecord.utility) { + utilityList = [ruleRecord.utility] + } + + return { + id: ruleRecord.id, + name: typeof ruleRecord.name === 'string' ? ruleRecord.name : '', + enabled: typeof ruleRecord.enabled === 'boolean' ? ruleRecord.enabled : true, + utilities: utilityList && utilityList.length > 0 ? utilityList : null, + shade: typeof ruleRecord.shade === 'number' ? ruleRecord.shade : null, + colors: Array.isArray(ruleRecord.colors) + ? ruleRecord.colors.filter((colorItem) => typeof colorItem === 'string') + : null, + darkShade: typeof ruleRecord.darkShade === 'number' ? ruleRecord.darkShade : null, + excludeElements: Array.isArray(ruleRecord.excludeElements) + ? ruleRecord.excludeElements.filter((elementItem) => typeof elementItem === 'string') + : [], + excludeColors: Array.isArray(ruleRecord.excludeColors) + ? ruleRecord.excludeColors.filter((colorItem) => typeof colorItem === 'string') + : [], + } +} + +// Browser-only helpers (guard against SSR / Node) + +/** @returns {DarkModeConfig} */ +export function loadConfig() { + if (typeof localStorage === 'undefined') { + return { ...DEFAULT_CONFIG } + } + + try { + const storedJson = localStorage.getItem(STORAGE_KEY) + + if (!storedJson) { + return { ...DEFAULT_CONFIG } + } + + return normalizeConfig(JSON.parse(storedJson)) + } catch { + return { ...DEFAULT_CONFIG } + } +} + +/** @param {DarkModeConfig} configData @returns {void} */ +export function saveConfig(configData) { + if (typeof localStorage === 'undefined') { + return + } + + try { + localStorage.setItem(STORAGE_KEY, JSON.stringify(configData)) + } catch { + // quota exceeded etc. — silently ignore + } +} + +/** @returns {DarkModeConfig} */ +export function resetConfig() { + if (typeof localStorage !== 'undefined') { + try { + localStorage.removeItem(STORAGE_KEY) + } catch { + // ignore + } + } + + return { ...DEFAULT_CONFIG } +} + +/** @param {DarkModeConfig} configData @returns {string} */ +export function exportConfig(configData) { + return JSON.stringify(configData, null, 2) +} + +/** + * @param {string} jsonString + * @returns {{ ok: true, config: DarkModeConfig } | { ok: false, error: string }} + */ +export function importConfig(jsonString) { + try { + const parsedJson = JSON.parse(jsonString) + const normalizedConfig = normalizeConfig(parsedJson) + + return { ok: true, config: normalizedConfig } + } catch { + return { ok: false, error: 'Invalid JSON' } + } +} diff --git a/src/lib/dark-mode/element-constants.js b/src/lib/dark-mode/element-constants.js new file mode 100644 index 000000000..4210feb3e --- /dev/null +++ b/src/lib/dark-mode/element-constants.js @@ -0,0 +1,14 @@ +export const DEBOUNCE_DELAY_MS = 250 + +export const INPUT_NO_SPINNER = + '[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none' + +export const FORM_INPUT_CLASS = 'mt-0.5 text-sm w-full rounded-md border-gray-200' + +export const NUMBER_INPUT_CLASS = `${FORM_INPUT_CLASS} ${INPUT_NO_SPINNER}` + +export const ICON_MOVE_RIGHT = `` + +export const ICON_PLUS = `` + +export const ICON_MINUS = `` diff --git a/src/lib/dark-mode/preview-document.js b/src/lib/dark-mode/preview-document.js new file mode 100644 index 000000000..28a2ab1ec --- /dev/null +++ b/src/lib/dark-mode/preview-document.js @@ -0,0 +1,14 @@ +export function buildPreviewDocument(htmlContent, isDarkMode) { + return ` + + + + + + + + + ${htmlContent} + + ` +} diff --git a/src/lib/dark-mode/rule-renderer.js b/src/lib/dark-mode/rule-renderer.js new file mode 100644 index 000000000..9a7d9c9a0 --- /dev/null +++ b/src/lib/dark-mode/rule-renderer.js @@ -0,0 +1,217 @@ +const INSPECTOR_ABORT_KEY = Symbol('inspectorAbortController') +const INSPECTOR_FLUSH_KEY = Symbol('inspectorFlush') + +export function buildRuleListItem(ruleData, ruleIndex, { onConfigure, onDelete, onToggleEnabled }) { + const ruleListItem = document.createElement('li') + ruleListItem.className = 'flex items-center gap-3 rounded-lg border border-gray-200 bg-white px-3 py-2' + + const defaultRuleName = `Rule ${ruleIndex + 1}` + + ruleListItem.innerHTML = ` + + + + + ` + + const enabledCheckbox = ruleListItem.querySelector('.rule-enabled') + enabledCheckbox.checked = ruleData.enabled + enabledCheckbox.addEventListener('change', () => { + ruleData.enabled = enabledCheckbox.checked + onToggleEnabled() + }) + + ruleListItem.querySelector('span').textContent = ruleData.name || defaultRuleName + + ruleListItem.querySelector('[data-configure-rule]').addEventListener('click', () => { + onConfigure(ruleData.id) + }) + + ruleListItem.querySelector('.rule-delete').addEventListener('click', () => { + onDelete(ruleData.id) + }) + + return ruleListItem +} + +export function bindInspector(inspectorElement, ruleData, ruleIndex, { onChange, onNameChange }) { + const previousFlush = inspectorElement[INSPECTOR_FLUSH_KEY] + if (previousFlush) { + previousFlush() + } + + if (inspectorElement[INSPECTOR_ABORT_KEY]) { + inspectorElement[INSPECTOR_ABORT_KEY].abort() + } + + const abortController = new AbortController() + inspectorElement[INSPECTOR_ABORT_KEY] = abortController + const { signal: abortSignal } = abortController + + const defaultRuleName = `Rule ${ruleIndex + 1}` + + const nameDisplay = inspectorElement.querySelector('[data-inspector-name-display]') + const nameEditButton = inspectorElement.querySelector('[data-inspector-name-edit]') + const nameInput = inspectorElement.querySelector('[data-inspector-name]') + const utilitiesInput = inspectorElement.querySelector('[data-inspector-utilities]') + const shadeInput = inspectorElement.querySelector('[data-inspector-shade]') + const colorsInput = inspectorElement.querySelector('[data-inspector-colors]') + const darkShadeInput = inspectorElement.querySelector('[data-inspector-dark-shade]') + const excludeElementsInput = inspectorElement.querySelector('[data-inspector-exclude-elements]') + const excludeColorsInput = inspectorElement.querySelector('[data-inspector-exclude-colors]') + + nameDisplay.textContent = ruleData.name || defaultRuleName + nameInput.value = ruleData.name || '' + nameInput.placeholder = defaultRuleName + utilitiesInput.value = (ruleData.utilities ?? []).join(', ') + shadeInput.value = ruleData.shade !== null ? String(ruleData.shade) : '' + colorsInput.value = (ruleData.colors ?? []).join(', ') + darkShadeInput.value = ruleData.darkShade !== null ? String(ruleData.darkShade) : '' + excludeElementsInput.value = ruleData.excludeElements.join(', ') + excludeColorsInput.value = ruleData.excludeColors.join(', ') + + nameInput.classList.add('hidden') + nameDisplay.classList.remove('hidden') + nameEditButton.classList.remove('hidden') + + inspectorElement[INSPECTOR_FLUSH_KEY] = () => { + if (!nameInput.classList.contains('hidden')) { + const pendingName = nameInput.value.trim() + if (pendingName !== (ruleData.name || '')) { + ruleData.name = pendingName + onNameChange() + } + } + inspectorElement[INSPECTOR_FLUSH_KEY] = null + } + + nameEditButton.addEventListener( + 'click', + () => { + nameInput.value = ruleData.name || '' + nameDisplay.classList.add('hidden') + nameEditButton.classList.add('hidden') + nameInput.classList.remove('hidden') + nameInput.focus() + nameInput.select() + }, + { signal: abortSignal }, + ) + + nameInput.addEventListener( + 'keydown', + (keyEvent) => { + if (keyEvent.key === 'Enter') { + keyEvent.preventDefault() + nameInput.blur() + } + if (keyEvent.key === 'Escape') { + nameInput.value = ruleData.name || '' + nameInput.blur() + } + }, + { signal: abortSignal }, + ) + + nameInput.addEventListener( + 'blur', + () => { + const updatedName = nameInput.value.trim() + if (updatedName !== (ruleData.name || '')) { + ruleData.name = updatedName + nameDisplay.textContent = updatedName || defaultRuleName + onNameChange() + } else { + nameDisplay.textContent = ruleData.name || defaultRuleName + } + nameInput.classList.add('hidden') + nameDisplay.classList.remove('hidden') + nameEditButton.classList.remove('hidden') + }, + { signal: abortSignal }, + ) + + utilitiesInput.addEventListener( + 'change', + () => { + const parsedItems = utilitiesInput.value + .split(',') + .map((rawEntry) => rawEntry.trim()) + .filter(Boolean) + ruleData.utilities = parsedItems.length > 0 ? parsedItems : null + onChange() + }, + { signal: abortSignal }, + ) + + shadeInput.addEventListener( + 'change', + () => { + const parsedNumber = parseInt(shadeInput.value, 10) + ruleData.shade = isNaN(parsedNumber) ? null : parsedNumber + onChange() + }, + { signal: abortSignal }, + ) + + colorsInput.addEventListener( + 'change', + () => { + const parsedItems = colorsInput.value + .split(',') + .map((rawEntry) => rawEntry.trim()) + .filter(Boolean) + ruleData.colors = parsedItems.length > 0 ? parsedItems : null + onChange() + }, + { signal: abortSignal }, + ) + + darkShadeInput.addEventListener( + 'change', + () => { + const parsedNumber = parseInt(darkShadeInput.value, 10) + ruleData.darkShade = isNaN(parsedNumber) ? null : parsedNumber + onChange() + }, + { signal: abortSignal }, + ) + + excludeElementsInput.addEventListener( + 'change', + () => { + ruleData.excludeElements = excludeElementsInput.value + .split(',') + .map((rawEntry) => rawEntry.trim().toLowerCase()) + .filter(Boolean) + onChange() + }, + { signal: abortSignal }, + ) + + excludeColorsInput.addEventListener( + 'change', + () => { + ruleData.excludeColors = excludeColorsInput.value + .split(',') + .map((rawEntry) => rawEntry.trim()) + .filter(Boolean) + onChange() + }, + { signal: abortSignal }, + ) +} diff --git a/src/lib/dark-mode/transform-class.js b/src/lib/dark-mode/transform-class.js new file mode 100644 index 000000000..8015c4fda --- /dev/null +++ b/src/lib/dark-mode/transform-class.js @@ -0,0 +1,150 @@ +import { COLOR_MAP, COLOR_FAMILIES } from '../../constants/dark-mode.js' + +/** + * @param {string} className + * @returns {{ variantPrefix: string, classWithoutVariant: string }} + */ +export function splitVariantPrefix(className) { + const lastSeparatorIndex = className.lastIndexOf(':') + + if (lastSeparatorIndex === -1) { + return { + variantPrefix: '', + classWithoutVariant: className, + } + } + + return { + variantPrefix: className.slice(0, lastSeparatorIndex + 1), + classWithoutVariant: className.slice(lastSeparatorIndex + 1), + } +} + +/** + * @param {string} utilityName e.g. 'bg', 'text', 'border' + * @param {string} colorFamily e.g. 'blue' + * @param {number} shadeNumber e.g. 600 + * @param {string | null | undefined} tagName e.g. 'BUTTON' (uppercased from el.tagName) + * @param {import('./config.js').DarkModeConfig} configData + * @returns {{ skip: boolean, darkShade: number } | null} null = no override, use shade map + */ +function applyRules(utilityName, colorFamily, shadeNumber, tagName, configData) { + const normalizedTag = tagName ? tagName.toLowerCase() : null + + for (const activeRule of configData.rules) { + if (!activeRule.enabled) { + continue + } + + if ( + activeRule.utilities && + activeRule.utilities.length > 0 && + !activeRule.utilities.includes(utilityName) + ) { + continue + } + if (activeRule.shade !== null && activeRule.shade !== shadeNumber) { + continue + } + if ( + activeRule.colors && + activeRule.colors.length > 0 && + !activeRule.colors.includes(colorFamily) + ) { + continue + } + + if ( + activeRule.excludeElements && + normalizedTag && + activeRule.excludeElements.includes(normalizedTag) + ) { + return { skip: true, darkShade: 0 } + } + + if (activeRule.excludeColors && activeRule.excludeColors.includes(colorFamily)) { + return { skip: true, darkShade: 0 } + } + + if (activeRule.darkShade !== null) { + return { skip: false, darkShade: activeRule.darkShade } + } + } + + return null +} + +/** + * Transform a single Tailwind class to include a dark: variant. + * Returns the original class if no transformation applies. + * + * @param {string} className + * @param {import('./config.js').DarkModeConfig} configData + * @param {string | null} [tagName] lowercase element tag e.g. 'button' (browser only) + * @returns {string} + */ +export function transformClass(className, configData, tagName = null) { + const { variantPrefix, classWithoutVariant } = splitVariantPrefix(className) + + // white/black named colors + for (const [lightColor, darkColor] of Object.entries(COLOR_MAP)) { + if (classWithoutVariant.includes(lightColor)) { + const colorMatch = classWithoutVariant.match(/^((?:[\w]+-)*)(white|black)(\/\d+)?$/) + + if (colorMatch) { + const colorPrefix = colorMatch[1] ?? '' + const colorSuffix = colorMatch[3] ?? '' + const utilityName = colorPrefix.replace(/-$/, '') + + if (configData.utilities[utilityName] === false) { + return className + } + + const ruleResult = applyRules(utilityName, lightColor, 0, tagName, configData) + + if (ruleResult?.skip) { + return className + } + + const darkClass = `${colorPrefix}${darkColor}${colorSuffix}` + + return `${className} dark:${variantPrefix}${darkClass}` + } + } + } + + // color family shades (e.g. bg-blue-600) + for (const colorFamily of COLOR_FAMILIES) { + const colorRegex = new RegExp(`^([\\w-]*?)${colorFamily}-(\\d+)(.*?)$`) + const colorMatch = classWithoutVariant.match(colorRegex) + + if (colorMatch) { + const colorPrefix = colorMatch[1] ?? '' + const colorShade = colorMatch[2] ?? '0' + const colorSuffix = colorMatch[3] ?? '' + const shadeNum = parseInt(colorShade, 10) + const utilityName = colorPrefix.replace(/-$/, '') + + if (configData.utilities[utilityName] === false) { + return className + } + + if (!(shadeNum in configData.shadeMap)) { + return className + } + + const ruleResult = applyRules(utilityName, colorFamily, shadeNum, tagName, configData) + + if (ruleResult?.skip) { + return className + } + + const darkShade = ruleResult?.darkShade ?? configData.shadeMap[shadeNum] + const darkClass = `${colorPrefix}${colorFamily}-${darkShade}${colorSuffix}` + + return `${className} dark:${variantPrefix}${darkClass}` + } + } + + return className +} diff --git a/src/lib/dark-mode/transform-html.js b/src/lib/dark-mode/transform-html.js new file mode 100644 index 000000000..3414eb44b --- /dev/null +++ b/src/lib/dark-mode/transform-html.js @@ -0,0 +1,67 @@ +import { transformClass } from './transform-class.js' + +/** + * Transform class attributes in an HTML string using regex (no DOM, element-unaware). + * Used by the Node CLI. + * + * @param {string} htmlContent + * @param {import('./config.js').DarkModeConfig} configData + * @returns {string} + */ +export function transformHtmlString(htmlContent, configData) { + return htmlContent.replace(/class="([^"]*)"/g, (_, classAttribute) => { + const transformedValue = transformClassAttribute(classAttribute, configData, null) + + return `class="${transformedValue}"` + }) +} + +/** + * Transform class attributes in an HTML string using DOMParser (element-aware). + * Browser-only — requires DOMParser global. + * + * @param {string} htmlContent + * @param {import('./config.js').DarkModeConfig} configData + * @returns {string} + */ +export function transformHtmlDom(htmlContent, configData) { + const domParser = new DOMParser() + const parsedDocument = domParser.parseFromString(htmlContent, 'text/html') + + parsedDocument.querySelectorAll('[class]').forEach((classElement) => { + const tagName = classElement.tagName.toLowerCase() + const transformedValue = transformClassAttribute( + classElement.getAttribute('class') ?? '', + configData, + tagName + ) + + classElement.setAttribute('class', transformedValue) + }) + + return parsedDocument.body.innerHTML +} + +/** + * @param {string | null} classAttribute + * @param {import('./config.js').DarkModeConfig} configData + * @param {string | null} tagName + * @returns {string} + */ +function transformClassAttribute(classAttribute, configData, tagName) { + if (!classAttribute) { + return classAttribute ?? '' + } + + return classAttribute + .split(/\s+/) + .filter(Boolean) + .map((className) => { + if (!configData.overwriteExisting && className.includes('dark:')) { + return className + } + + return transformClass(className, configData, tagName) + }) + .join(' ') +} diff --git a/src/lib/dark-mode/ui-renderer.js b/src/lib/dark-mode/ui-renderer.js new file mode 100644 index 000000000..5baea8707 --- /dev/null +++ b/src/lib/dark-mode/ui-renderer.js @@ -0,0 +1,109 @@ +import { INPUT_NO_SPINNER, ICON_MOVE_RIGHT, ICON_PLUS, ICON_MINUS } from './element-constants.js' +import { buildRuleListItem } from './rule-renderer.js' + +export function renderUtilityToggles(containerElement, configData, onChangeCallback) { + containerElement.innerHTML = '' + + for (const [utilityName, isEnabled] of Object.entries(configData.utilities)) { + const toggleLabel = document.createElement('label') + toggleLabel.className = 'cursor-pointer' + + const toggleCheckbox = document.createElement('input') + toggleCheckbox.type = 'checkbox' + toggleCheckbox.className = 'sr-only peer' + toggleCheckbox.checked = isEnabled + toggleCheckbox.setAttribute('aria-label', `${isEnabled ? 'Disable' : 'Enable'} ${utilityName}`) + + toggleCheckbox.addEventListener('change', () => { + configData.utilities[utilityName] = toggleCheckbox.checked + toggleCheckbox.setAttribute( + 'aria-label', + `${toggleCheckbox.checked ? 'Disable' : 'Enable'} ${utilityName}`, + ) + onChangeCallback() + }) + + const disabledPill = document.createElement('span') + disabledPill.className = + 'peer-checked:hidden inline-flex items-center gap-1 rounded-full border border-gray-200 bg-white px-2.5 py-0.5 text-xs font-medium text-gray-500' + disabledPill.innerHTML = `${ICON_PLUS}${utilityName}` + + const enabledPill = document.createElement('span') + enabledPill.className = + 'hidden peer-checked:inline-flex items-center gap-1 rounded-full border border-gray-900 bg-gray-900 px-2.5 py-0.5 text-xs font-medium text-white' + enabledPill.innerHTML = `${ICON_MINUS}${utilityName}` + + toggleLabel.appendChild(toggleCheckbox) + toggleLabel.appendChild(disabledPill) + toggleLabel.appendChild(enabledPill) + containerElement.appendChild(toggleLabel) + } +} + +export function renderShadeMap(containerElement, configData, onChangeCallback) { + containerElement.innerHTML = '' + + for (const [shadeValue, darkShadeValue] of Object.entries(configData.shadeMap)) { + const shadeWrapper = document.createElement('div') + shadeWrapper.className = 'flex items-center gap-2' + + const shadeLabel = document.createElement('span') + shadeLabel.className = 'w-8 text-right shrink-0 text-sm font-medium text-gray-700' + shadeLabel.textContent = shadeValue + + const iconWrapper = document.createElement('span') + iconWrapper.innerHTML = ICON_MOVE_RIGHT + + const inputId = `dark-mode-shade-${shadeValue}` + + const visualLabel = document.createElement('label') + visualLabel.className = 'sr-only' + visualLabel.setAttribute('for', inputId) + visualLabel.textContent = `Dark shade for shade-${shadeValue}` + + const shadeInput = document.createElement('input') + shadeInput.type = 'number' + shadeInput.id = inputId + shadeInput.className = `w-16 rounded-md border-gray-200 align-bottom text-sm ${INPUT_NO_SPINNER}` + shadeInput.value = String(darkShadeValue) + shadeInput.min = '50' + shadeInput.max = '950' + shadeInput.step = '50' + + shadeInput.addEventListener('change', () => { + const parsedValue = parseInt(shadeInput.value, 10) + if (!isNaN(parsedValue)) { + configData.shadeMap[parseInt(shadeValue, 10)] = parsedValue + onChangeCallback() + } + }) + + shadeWrapper.appendChild(visualLabel) + shadeWrapper.appendChild(shadeLabel) + shadeWrapper.appendChild(iconWrapper) + shadeWrapper.appendChild(shadeInput) + containerElement.appendChild(shadeWrapper) + } +} + +export function renderRules(containerElement, configData, { onDelete, onChange, onConfigure }) { + containerElement.innerHTML = '' + + if (configData.rules.length === 0) { + const emptyMessage = document.createElement('p') + emptyMessage.className = 'text-sm text-gray-600' + emptyMessage.textContent = 'No rules. Add one to override shade map defaults.' + containerElement.appendChild(emptyMessage) + return + } + + configData.rules.forEach((ruleData, ruleIndex) => { + containerElement.appendChild( + buildRuleListItem(ruleData, ruleIndex, { + onConfigure, + onDelete, + onToggleEnabled: onChange, + }), + ) + }) +} diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index 8236e12aa..c2f01ac19 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -1,7 +1,7 @@ --- import { getCollection } from 'astro:content' -import { SEO_TITLE_BLOG, SEO_DESCRIPTION_BLOG } from '../../consts' +import { SEO_TITLE_BLOG, SEO_DESCRIPTION_BLOG } from '../../constants/seo' import BaseLayout from '../../layouts/BaseLayout.astro' import BaseHero from '../../components/BaseHero.astro' diff --git a/src/pages/components/application/index.astro b/src/pages/components/application/index.astro index 137b2ad52..c4252bced 100644 --- a/src/pages/components/application/index.astro +++ b/src/pages/components/application/index.astro @@ -4,7 +4,7 @@ import { getCollection } from 'astro:content' import { SEO_TITLE_APPLICATION_COMPONENTS, SEO_DESCRIPTION_APPLICATION_COMPONENTS, -} from '../../../consts' +} from '../../../constants/seo' import BaseLayout from '../../../layouts/BaseLayout.astro' import ComponentCard from '../../../components/ComponentCard.astro' diff --git a/src/pages/components/marketing/index.astro b/src/pages/components/marketing/index.astro index 4b0272691..c7fe5eae0 100644 --- a/src/pages/components/marketing/index.astro +++ b/src/pages/components/marketing/index.astro @@ -4,7 +4,7 @@ import { getCollection } from 'astro:content' import { SEO_TITLE_MARKETING_COMPONENTS, SEO_DESCRIPTION_MARKETING_COMPONENTS, -} from '../../../consts' +} from '../../../constants/seo' import BaseLayout from '../../../layouts/BaseLayout.astro' import ComponentCard from '../../../components/ComponentCard.astro' diff --git a/src/pages/components/neobrutalism/index.astro b/src/pages/components/neobrutalism/index.astro index f61d57f91..37530f081 100644 --- a/src/pages/components/neobrutalism/index.astro +++ b/src/pages/components/neobrutalism/index.astro @@ -4,7 +4,7 @@ import { getCollection } from 'astro:content' import { SEO_TITLE_NEOBRUTALISM_COMPONENTS, SEO_DESCRIPTION_NEOBRUTALISM_COMPONENTS, -} from '../../../consts' +} from '../../../constants/seo' import BaseLayout from '../../../layouts/BaseLayout.astro' import ComponentCard from '../../../components/ComponentCard.astro' diff --git a/src/pages/index.astro b/src/pages/index.astro index cbb8023a9..298bb5546 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,7 +1,7 @@ --- import { getCollection } from 'astro:content' -import { SEO_TITLE_SITE, SEO_DESCRIPTION_SITE } from '../consts' +import { SEO_TITLE_SITE, SEO_DESCRIPTION_SITE } from '../constants/seo' import BaseAd from '../components/BaseAd.astro' import BaseLayout from '../layouts/BaseLayout.astro' diff --git a/src/pages/rss.xml.ts b/src/pages/rss.xml.ts index 6e7e6ccb4..171fe1d90 100644 --- a/src/pages/rss.xml.ts +++ b/src/pages/rss.xml.ts @@ -4,7 +4,7 @@ import { getCollection } from 'astro:content' import rss from '@astrojs/rss' -import { SITE_TITLE, SEO_DESCRIPTION_BLOG } from '../consts' +import { SITE_TITLE, SEO_DESCRIPTION_BLOG } from '../constants/seo' export async function GET(context: APIContext) { const site = context.site ?? new URL('https://hyperui.dev') diff --git a/src/pages/tools/dark-mode-generator.astro b/src/pages/tools/dark-mode-generator.astro new file mode 100644 index 000000000..a0f8a74ea --- /dev/null +++ b/src/pages/tools/dark-mode-generator.astro @@ -0,0 +1,21 @@ +--- +import { + SEO_TITLE_DARK_MODE_GENERATOR, + SEO_DESCRIPTION_DARK_MODE_GENERATOR, +} from '../../constants/seo' + +import BaseLayout from '../../layouts/BaseLayout.astro' +import BaseHero from '../../components/BaseHero.astro' +import DarkModeGenerator from '../../components/DarkModeGenerator.astro' +--- + + + + +
+ +
+
diff --git a/src/pages/tools/index.astro b/src/pages/tools/index.astro new file mode 100644 index 000000000..114d38b4a --- /dev/null +++ b/src/pages/tools/index.astro @@ -0,0 +1,87 @@ +--- +import { SEO_TITLE_TOOLS, SEO_DESCRIPTION_TOOLS } from '../../constants/seo' + +import BaseLayout from '../../layouts/BaseLayout.astro' +import BaseHero from '../../components/BaseHero.astro' +--- + + + + +
+ +
+
diff --git a/worker-configuration.d.ts b/worker-configuration.d.ts index d796bead2..9ad91b7ec 100644 --- a/worker-configuration.d.ts +++ b/worker-configuration.d.ts @@ -1,6 +1,6 @@ /* eslint-disable */ // Generated by Wrangler by running `wrangler types` (hash: 3574ae6e4abb21b47a08d3dfdea9b975) -// Runtime types generated with workerd@1.20260526.1 2026-04-07 global_fetch_strictly_public +// Runtime types generated with workerd@1.20260603.1 2026-04-07 global_fetch_strictly_public interface __BaseEnv_Env { SESSION: KVNamespace; ASSETS: Fetcher; @@ -3482,6 +3482,229 @@ declare abstract class Span { get isTraced(): boolean; setAttribute(key: string, value?: (boolean | number | string)): void; } +// ============================================================================ +// Agent Memory +// +// Public type surface for user Workers binding to an Agent Memory namespace. +// ============================================================================ +/** Memory type — every memory is classified into exactly one. */ +type AgentMemoryMemoryType = "fact" | "event" | "instruction" | "task"; +/** Search intensity for recall. */ +type AgentMemoryThinkingLevel = "low" | "medium" | "high"; +/** Response verbosity for recall. */ +type AgentMemoryResponseLength = "short" | "medium" | "long"; +/** A conversation message passed to ingest(). */ +interface AgentMemoryMessage { + role: "system" | "user" | "assistant"; + content: string; + /** Optional message timestamp. */ + timestamp?: Date; +} +/** Raw memory content passed to remember(). */ +interface AgentMemoryIncomingMemory { + /** Raw memory content. The service classifies and summarizes automatically. */ + content: string; + /** Optional session identifier to associate with this memory. */ + sessionId?: string | null | undefined; +} +/** A stored memory returned from remember(), get(), and delete(). */ +interface AgentMemoryMemory { + /** Memory ID. */ + id: string; + /** Memory type. */ + type: AgentMemoryMemoryType; + /** Text summary. */ + summary: string; + /** Memory text. */ + content: string; + /** Session that created this memory. */ + sessionId: string | null; + /** Memory creation time. */ + createdAt: Date; + /** Memory last-update time. */ + updatedAt: Date; +} +/** Single entry in a list() response. Same shape as Memory minus full content. */ +type AgentMemoryMemoryListEntry = Omit; +/** A scored memory candidate in a recall result. */ +interface AgentMemoryScoredCandidate { + /** Candidate ID. */ + id: string; + /** Text summary. */ + summary: string; + /** Session that created this candidate, when known. */ + sessionId: string | null; + /** Relevance score (higher is better). Comparable only within a single query. */ + score: number; +} +/** Options for the ingest() method. */ +interface AgentMemoryIngestOptions { + /** Session identifier to associate with memories created during ingestion. */ + sessionId?: string | null | undefined; +} +/** Options for the getSummary() method. */ +interface AgentMemoryGetSummaryOptions { + /** Session identifier to retrieve session summary for. */ + sessionId?: string | null | undefined; +} +/** Response from the getSummary() method. */ +interface AgentMemoryGetSummaryResponse { + /** Markdown summary. */ + summary: string; +} +/** + * Options for the recall() method. + * + * `referenceDate` accepts a Date object, an ISO-8601 date string + * (YYYY-MM-DD), or a full ISO-8601 datetime string. When provided, this + * date is used as "today" for resolving relative time references + * ("how many days ago", "last week") instead of the server's wall-clock time. + */ +interface AgentMemoryRecallOptions { + /** Recall intensity: "low" (default), "medium", or "high". */ + thinkingLevel?: AgentMemoryThinkingLevel; + /** Response verbosity: "short", "medium" (default), or "long". */ + responseLength?: AgentMemoryResponseLength; + /** Temporal anchor for date arithmetic. */ + referenceDate?: Date | string; +} +/** Response from the recall() method. */ +interface AgentMemoryRecallResult { + /** Number of memories retrieved. */ + count: number; + /** LLM-generated answer synthesizing the matching memories. */ + answer: string; + /** Matching memories ranked by relevance. */ + candidates: AgentMemoryScoredCandidate[]; +} +/** + * Options for the list() method. + * + * `cursor` is the opaque continuation token returned by the previous page; + * pass it back unchanged to fetch the next page. `sessionId` and `type` + * are exact-match filters; combining them is allowed. + */ +interface AgentMemoryListMemoriesOptions { + /** Maximum number of memories to return. Default 20, max 500. */ + limit?: number; + /** Opaque cursor from a previous page. */ + cursor?: string; + /** Exact-match session filter. */ + sessionId?: string; + /** Exact-match memory-type filter. */ + type?: AgentMemoryMemoryType; +} +/** Response from the list() method. */ +interface AgentMemoryListMemoriesResult { + memories: AgentMemoryMemoryListEntry[]; + /** Continuation cursor; absent when this page exhausted the result set. */ + cursor?: string; +} +/** + * A single Agent Memory profile, scoped to a profile name. + * + * Returned by {@link AgentMemoryNamespace.getProfile}. + */ +declare abstract class AgentMemoryProfile { + /** + * Retrieve a memory by ID. + * + * @param memoryId - ULID of the memory to retrieve. + * @throws if the memory does not exist. + */ + get(memoryId: string): Promise; + /** + * Delete a memory by ID. + * + * Removes the memory and any source messages linked by the memory's + * source message IDs. + * + * @param memoryId - ULID of the memory to delete. + * @throws if the memory does not exist. + */ + delete(memoryId: string): Promise; + /** + * Store a memory in this profile. The content is automatically classified, + * summarized, and indexed. + * + * @param memory - Raw memory content to persist. + */ + remember(memory: AgentMemoryIncomingMemory): Promise; + /** + * Extract memories from a conversation. + * + * @param messages - Conversation messages to extract memories from. + * @param options - Optional ingest options. + */ + ingest(messages: Iterable, options?: AgentMemoryIngestOptions): Promise; + /** + * Get a profile summary. + * + * @param options - Optional getSummary options. + */ + getSummary(options?: AgentMemoryGetSummaryOptions): Promise; + /** + * Recall memories in this profile. + * + * @param query - Recall query matched against memory content and keywords. + * @param options - Optional recall parameters. + * @returns Matching memories with relevance scores and a synthesized answer. + */ + recall(query: string, options?: AgentMemoryRecallOptions): Promise; + /** + * List active memories in this profile. + * + * Returns a paginated, filterable view of stored memories. Superseded + * versions are excluded. Use the returned `cursor` (when present) to + * fetch the next page. + * + * @param options - Optional pagination and filter options. + */ + list(options?: AgentMemoryListMemoriesOptions): Promise; + /** + * Soft-delete every memory and message in this profile that is tagged + * with `sessionId`. + * + * Idempotent: deleting a sessionId that has no rows is a no-op. + * + * @param sessionId - Session to delete. + */ + deleteSession(sessionId: string): Promise; +} +/** + * Namespace-level Agent Memory binding. + * + * Used as the type of an `env.MEMORY`-style binding backed by the Agent + * Memory product. + * + * @example + * ```ts + * export default { + * async fetch(_request: Request, env: Env): Promise { + * const profile = await env.MEMORY.getProfile("wrangler-e2e"); + * const summary = await profile.getSummary(); + * return Response.json(summary); + * }, + * }; + * ``` + */ +declare abstract class AgentMemoryNamespace { + /** + * Get a memory profile by name. Profiles are isolated by namespace and + * addressed by a compound key (namespaceId:profileName). + * + * @param profileName - Profile name (validated against naming rules). + * @returns RPC target for interacting with the profile. + */ + getProfile(profileName: string): Promise; + /** + * Soft-delete a profile and schedule deferred purge. Marks all + * memories and messages as deleted. + * + * @param profileName - Name of the profile to delete. + */ + deleteProfile(profileName: string): Promise; +} // ============ AI Search Error Interfaces ============ interface AiSearchInternalError extends Error { } @@ -10404,6 +10627,452 @@ declare abstract class AutoRAG { */ aiSearch(params: AutoRagAiSearchRequest): Promise; } +type BrowserRunLifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'; +type BrowserRunResourceType = 'document' | 'stylesheet' | 'image' | 'media' | 'font' | 'script' | 'texttrack' | 'xhr' | 'fetch' | 'prefetch' | 'eventsource' | 'websocket' | 'manifest' | 'signedexchange' | 'ping' | 'cspviolationreport' | 'preflight' | 'other'; +/** Options fields shared by all quick actions. */ +interface BrowserRunBaseOptions { + /** Adds `