diff --git a/deno.json b/deno.json index 671586b..e2f6a3a 100644 --- a/deno.json +++ b/deno.json @@ -153,7 +153,7 @@ }, "imports": { "react": "npm:react@^19.2.4", - "@types/react": "npm:@types/react@^19.2.13" + "@types/react": "npm:@types/react@^19.2.14" }, "compilerOptions": { "lib": [ diff --git a/deno.lock b/deno.lock index db7607b..079852f 100644 --- a/deno.lock +++ b/deno.lock @@ -3,60 +3,68 @@ "specifiers": { "jsr:@deno/esbuild-plugin@^1.2.1": "1.2.1", "jsr:@deno/loader@~0.3.10": "0.3.11", - "jsr:@std/assert@^1.0.17": "1.0.18", - "jsr:@std/assert@^1.0.18": "1.0.18", - "jsr:@std/async@^1.1.0": "1.1.0", - "jsr:@std/async@^1.1.1": "1.1.1", + "jsr:@std/assert@^1.0.17": "1.0.19", + "jsr:@std/assert@^1.0.19": "1.0.19", + "jsr:@std/async@^1.1.0": "1.2.0", + "jsr:@std/async@^1.2.0": "1.2.0", "jsr:@std/bytes@^1.0.6": "1.0.6", - "jsr:@std/cli@^1.0.26": "1.0.26", - "jsr:@std/collections@^1.1.4": "1.1.4", - "jsr:@std/collections@^1.1.5": "1.1.5", + "jsr:@std/cli@^1.0.26": "1.0.28", + "jsr:@std/cli@^1.0.28": "1.0.28", + "jsr:@std/collections@^1.1.4": "1.1.6", + "jsr:@std/collections@^1.1.6": "1.1.6", "jsr:@std/crypto@^1.0.5": "1.0.5", "jsr:@std/data-structures@^1.0.10": "1.0.10", "jsr:@std/encoding@^1.0.10": "1.0.10", - "jsr:@std/fs@^1.0.22": "1.0.22", - "jsr:@std/http@^1.0.22": "1.0.23", + "jsr:@std/fmt@^1.0.9": "1.0.9", + "jsr:@std/fs@^1.0.22": "1.0.23", + "jsr:@std/fs@^1.0.23": "1.0.23", + "jsr:@std/http@^1.0.22": "1.0.24", "jsr:@std/internal@^1.0.12": "1.0.12", "jsr:@std/path@^1.1.1": "1.1.4", "jsr:@std/path@^1.1.2": "1.1.4", "jsr:@std/path@^1.1.4": "1.1.4", "jsr:@std/streams@^1.0.17": "1.0.17", + "jsr:@std/testing@*": "1.0.17", "jsr:@std/testing@^1.0.17": "1.0.17", "jsr:@std/uuid@^1.1.0": "1.1.0", "jsr:@udibo/esbuild-plugin-postcss@0.3": "0.3.0", "jsr:@udibo/esbuild-plugin-postcss@0.3.0": "0.3.0", "jsr:@udibo/http-error@~0.11.1": "0.11.1", - "jsr:@udibo/juniper@~0.3.2": "0.3.2", - "npm:@babel/core@^7.28.6": "7.28.6", - "npm:@modelcontextprotocol/sdk@^1.25.3": "1.25.3_zod@4.3.6_hono@4.11.9_ajv@8.17.1_express@5.2.1", + "jsr:@udibo/juniper@~0.3.3": "0.3.3", + "npm:@babel/core@^7.28.6": "7.29.0", + "npm:@babel/core@^7.29.0": "7.29.0", + "npm:@modelcontextprotocol/sdk@^1.27.1": "1.27.1_zod@4.3.6", "npm:@opentelemetry/api@^1.9.0": "1.9.0", - "npm:@tailwindcss/postcss@^4.1.18": "4.1.18", - "npm:@tanstack/react-query@^5.90.20": "5.90.20_react@19.2.4", - "npm:@testing-library/react@^16.3.2": "16.3.2_@testing-library+dom@10.4.1_@types+react@19.2.13_react@19.2.4_react-dom@19.2.4__react@19.2.4", + "npm:@tailwindcss/postcss@^4.2.2": "4.2.2", + "npm:@tanstack/react-query@^5.95.2": "5.95.2_react@19.2.4", + "npm:@testing-library/react@^16.3.2": "16.3.2_@types+react@19.2.14_react@19.2.4_react-dom@19.2.4__react@19.2.4", "npm:@testing-library/user-event@^14.6.1": "14.6.1_@testing-library+dom@10.4.1", - "npm:@types/react@^19.2.13": "19.2.13", - "npm:@types/react@^19.2.9": "19.2.13", + "npm:@types/react@^19.2.14": "19.2.14", "npm:babel-plugin-react-compiler@1": "1.0.0", - "npm:cbor2@^2.2.1": "2.2.1", + "npm:cbor2@^2.2.1": "2.3.0", + "npm:cbor2@^2.3.0": "2.3.0", "npm:esbuild@~0.25.12": "0.25.12", "npm:esbuild@~0.25.5": "0.25.12", - "npm:esbuild@~0.27.2": "0.27.2", + "npm:esbuild@~0.27.2": "0.27.4", + "npm:esbuild@~0.27.4": "0.27.4", "npm:global-jsdom@27": "27.0.0_jsdom@27.4.0", - "npm:hono@^4.11.6": "4.11.9", - "npm:hono@^4.11.9": "4.11.9", - "npm:isbot@^5.1.34": "5.1.34", - "npm:less@^4.4.2": "4.5.1", + "npm:hono@^4.11.6": "4.12.9", + "npm:hono@^4.12.9": "4.12.9", + "npm:isbot@^5.1.34": "5.1.36", + "npm:isbot@^5.1.36": "5.1.36", + "npm:less@^4.4.2": "4.6.4", "npm:playwright@^1.58.2": "1.58.2", "npm:postcss-modules@^6.0.1": "6.0.1_postcss@8.5.6", "npm:postcss@^8.5.6": "8.5.6", "npm:quick-lru@^7.3.0": "7.3.0", "npm:react-dom@^19.2.4": "19.2.4_react@19.2.4", - "npm:react-error-boundary@^6.1.0": "6.1.0_react@19.2.4", - "npm:react-router@^7.13.0": "7.13.0_react@19.2.4_react-dom@19.2.4__react@19.2.4", + "npm:react-error-boundary@^6.1.1": "6.1.1_react@19.2.4", + "npm:react-router@^7.13.0": "7.13.2_react@19.2.4_react-dom@19.2.4__react@19.2.4", + "npm:react-router@^7.13.2": "7.13.2_react@19.2.4_react-dom@19.2.4__react@19.2.4", "npm:react@^19.2.4": "19.2.4", - "npm:sass@^1.93.3": "1.97.3", + "npm:sass@^1.93.3": "1.98.0", "npm:stylus@0.64": "0.64.0", - "npm:tailwindcss@^4.1.18": "4.1.18", + "npm:tailwindcss@^4.2.2": "4.2.2", "npm:zod@^4.3.6": "4.3.6" }, "jsr": { @@ -71,38 +79,27 @@ "@deno/loader@0.3.11": { "integrity": "7c62f4f09cdfc34e66ba25b5a775a1830cbb5266b3e39f67b0f620c75484df8d" }, - "@std/assert@1.0.17": { - "integrity": "df5ebfffe77c03b3fa1401e11c762cc8f603d51021c56c4d15a8c7ab45e90dbe", + "@std/assert@1.0.19": { + "integrity": "eaada96ee120cb980bc47e040f82814d786fe8162ecc53c91d8df60b8755991e", "dependencies": [ "jsr:@std/internal" ] }, - "@std/assert@1.0.18": { - "integrity": "270245e9c2c13b446286de475131dc688ca9abcd94fc5db41d43a219b34d1c78", - "dependencies": [ - "jsr:@std/internal" - ] - }, - "@std/async@1.1.0": { - "integrity": "72418df08d1be84668a53e48aab3520d68ae6882182f8a5ca75c6d1f087220d1" - }, - "@std/async@1.1.1": { - "integrity": "8a79beb3378cc229ce65ba2c746cfd03e4855ddd891d1eb6b9e32128e0d5339c" + "@std/async@1.2.0": { + "integrity": "c059c6f6d95ca7cc012ae8e8d7164d1697113d54b0b679e4372b354b11c2dee5" }, "@std/bytes@1.0.6": { "integrity": "f6ac6adbd8ccd99314045f5703e23af0a68d7f7e58364b47d2c7f408aeb5820a" }, - "@std/cli@1.0.26": { - "integrity": "53679a2b041406f15c3ff193986852595f3d11ba7b9d4b0c71a42589662e8fb5", + "@std/cli@1.0.28": { + "integrity": "74ef9b976db59ca6b23a5283469c9072be6276853807a83ec6c7ce412135c70a", "dependencies": [ + "jsr:@std/fmt", "jsr:@std/internal" ] }, - "@std/collections@1.1.4": { - "integrity": "90a7acae07652b0f7227db9b22116ddf4b7cfb0886f8e409c1d7f0c39c526bc1" - }, - "@std/collections@1.1.5": { - "integrity": "c37cc6bbbbf90fec3e782535a46c9c8a3210f19118c61add71fcea86b0ffd491" + "@std/collections@1.1.6": { + "integrity": "b458160ce65ea5ad35da05d0a5cbee4b583677c8b443a10d7beb0c4ac63f2baa" }, "@std/crypto@1.0.5": { "integrity": "0dcfbb319fe0bba1bd3af904ceb4f948cde1b92979ec1614528380ed308a3b40" @@ -113,15 +110,18 @@ "@std/encoding@1.0.10": { "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1" }, - "@std/fs@1.0.22": { - "integrity": "de0f277a58a867147a8a01bc1b181d0dfa80bfddba8c9cf2bacd6747bcec9308", + "@std/fmt@1.0.9": { + "integrity": "2487343e8899fb2be5d0e3d35013e54477ada198854e52dd05ed0422eddcabe0" + }, + "@std/fs@1.0.23": { + "integrity": "3ecbae4ce4fee03b180fa710caff36bb5adb66631c46a6460aaad49515565a37", "dependencies": [ "jsr:@std/internal", "jsr:@std/path@^1.1.4" ] }, - "@std/http@1.0.23": { - "integrity": "6634e9e034c589bf35101c1b5ee5bbf052a5987abca20f903e58bdba85c80dee" + "@std/http@1.0.24": { + "integrity": "4dd59afd7cfd6e2e96e175b67a5a829b449ae55f08575721ec691e5d85d886d4" }, "@std/internal@1.0.12": { "integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027" @@ -144,7 +144,7 @@ "jsr:@std/assert@^1.0.17", "jsr:@std/async@^1.1.0", "jsr:@std/data-structures", - "jsr:@std/fs", + "jsr:@std/fs@^1.0.22", "jsr:@std/internal", "jsr:@std/path@^1.1.4" ] @@ -174,30 +174,30 @@ "jsr:@std/http" ] }, - "@udibo/juniper@0.3.2": { - "integrity": "e1bf0c780130995acc740cf2aa65157f5f2a3979cd1d0c23432cecb9b29bbdaf", + "@udibo/juniper@0.3.3": { + "integrity": "0721703c91a84162d21626babbb230a1f26d27f5f70ad8b494a2122900ebdc04", "dependencies": [ "jsr:@deno/esbuild-plugin", "jsr:@std/async@^1.1.0", - "jsr:@std/cli", + "jsr:@std/cli@^1.0.26", "jsr:@std/collections@^1.1.4", - "jsr:@std/fs", + "jsr:@std/fs@^1.0.22", "jsr:@std/path@^1.1.4", "jsr:@std/streams", - "jsr:@std/testing", + "jsr:@std/testing@^1.0.17", "jsr:@udibo/http-error", - "npm:@babel/core", + "npm:@babel/core@^7.28.6", "npm:@opentelemetry/api", "npm:babel-plugin-react-compiler", - "npm:cbor2", + "npm:cbor2@^2.2.1", "npm:esbuild@~0.27.2", "npm:global-jsdom", "npm:hono@^4.11.6", - "npm:isbot", + "npm:isbot@^5.1.34", "npm:quick-lru", "npm:react", "npm:react-dom", - "npm:react-router" + "npm:react-router@^7.13.0" ] } }, @@ -211,42 +211,42 @@ "@alloc/quick-lru@5.2.0": { "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==" }, - "@asamuzakjp/css-color@4.1.1_@csstools+css-parser-algorithms@3.0.5__@csstools+css-tokenizer@3.0.4_@csstools+css-tokenizer@3.0.4": { - "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", + "@asamuzakjp/css-color@4.1.2": { + "integrity": "sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==", "dependencies": [ "@csstools/css-calc", "@csstools/css-color-parser", "@csstools/css-parser-algorithms", "@csstools/css-tokenizer", - "lru-cache@11.2.5" + "lru-cache@11.2.7" ] }, - "@asamuzakjp/dom-selector@6.7.6": { - "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", + "@asamuzakjp/dom-selector@6.8.1": { + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", "dependencies": [ "@asamuzakjp/nwsapi", "bidi-js", "css-tree", "is-potential-custom-element-name", - "lru-cache@11.2.5" + "lru-cache@11.2.7" ] }, "@asamuzakjp/nwsapi@2.3.9": { "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==" }, - "@babel/code-frame@7.28.6": { - "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "@babel/code-frame@7.29.0": { + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dependencies": [ "@babel/helper-validator-identifier", "js-tokens", "picocolors" ] }, - "@babel/compat-data@7.28.6": { - "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==" + "@babel/compat-data@7.29.0": { + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==" }, - "@babel/core@7.28.6": { - "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "@babel/core@7.29.0": { + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dependencies": [ "@babel/code-frame", "@babel/generator", @@ -265,8 +265,8 @@ "semver@6.3.1" ] }, - "@babel/generator@7.28.6": { - "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", + "@babel/generator@7.29.1": { + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dependencies": [ "@babel/parser", "@babel/types", @@ -295,7 +295,7 @@ "@babel/types" ] }, - "@babel/helper-module-transforms@7.28.6_@babel+core@7.28.6": { + "@babel/helper-module-transforms@7.28.6_@babel+core@7.29.0": { "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dependencies": [ "@babel/core", @@ -313,15 +313,15 @@ "@babel/helper-validator-option@7.27.1": { "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==" }, - "@babel/helpers@7.28.6": { - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "@babel/helpers@7.29.2": { + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "dependencies": [ "@babel/template", "@babel/types" ] }, - "@babel/parser@7.28.6": { - "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "@babel/parser@7.29.2": { + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dependencies": [ "@babel/types" ], @@ -338,8 +338,8 @@ "@babel/types" ] }, - "@babel/traverse@7.28.6": { - "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "@babel/traverse@7.29.0": { + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dependencies": [ "@babel/code-frame", "@babel/generator", @@ -350,25 +350,25 @@ "debug" ] }, - "@babel/types@7.28.6": { - "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "@babel/types@7.29.0": { + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dependencies": [ "@babel/helper-string-parser", "@babel/helper-validator-identifier" ] }, - "@csstools/color-helpers@5.1.0": { - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==" + "@csstools/color-helpers@6.0.2": { + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==" }, - "@csstools/css-calc@2.1.4_@csstools+css-parser-algorithms@3.0.5__@csstools+css-tokenizer@3.0.4_@csstools+css-tokenizer@3.0.4": { - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "@csstools/css-calc@3.1.1_@csstools+css-parser-algorithms@4.0.0__@csstools+css-tokenizer@4.0.0_@csstools+css-tokenizer@4.0.0": { + "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", "dependencies": [ "@csstools/css-parser-algorithms", "@csstools/css-tokenizer" ] }, - "@csstools/css-color-parser@3.1.0_@csstools+css-parser-algorithms@3.0.5__@csstools+css-tokenizer@3.0.4_@csstools+css-tokenizer@3.0.4": { - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "@csstools/css-color-parser@4.0.2_@csstools+css-parser-algorithms@4.0.0__@csstools+css-tokenizer@4.0.0_@csstools+css-tokenizer@4.0.0": { + "integrity": "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==", "dependencies": [ "@csstools/color-helpers", "@csstools/css-calc", @@ -376,28 +376,34 @@ "@csstools/css-tokenizer" ] }, - "@csstools/css-parser-algorithms@3.0.5_@csstools+css-tokenizer@3.0.4": { - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "@csstools/css-parser-algorithms@4.0.0_@csstools+css-tokenizer@4.0.0": { + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", "dependencies": [ "@csstools/css-tokenizer" ] }, - "@csstools/css-syntax-patches-for-csstree@1.0.26": { - "integrity": "sha512-6boXK0KkzT5u5xOgF6TKB+CLq9SOpEGmkZw0g5n9/7yg85wab3UzSxB8TxhLJ31L4SGJ6BCFRw/iftTha1CJXA==" + "@csstools/css-syntax-patches-for-csstree@1.1.1_css-tree@3.2.1": { + "integrity": "sha512-BvqN0AMWNAnLk9G8jnUT77D+mUbY/H2b3uDTvg2isJkHaOufUE2R3AOwxWo7VBQKT1lOdwdvorddo2B/lk64+w==", + "dependencies": [ + "css-tree" + ], + "optionalPeers": [ + "css-tree" + ] }, - "@csstools/css-tokenizer@3.0.4": { - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==" + "@csstools/css-tokenizer@4.0.0": { + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==" }, - "@cto.af/wtf8@0.0.4": { - "integrity": "sha512-GbVy/i3DNrlp6klsqA7MatSERqp338xeWdMDHSGMxUKE19hC2Yk2dydLL0LtNC9Kjbb5bXbdwHHKa/mtnIRTZw==" + "@cto.af/wtf8@0.0.5": { + "integrity": "sha512-LfUFi+Vv4eDzj+XAtR89e3wwjXA/NZjUSwU5NhwbBrLecxPaBYFy3exCuc1j+D4UZeOVdqlsl8G7LmOt18V0tg==" }, "@esbuild/aix-ppc64@0.25.12": { "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "os": ["aix"], "cpu": ["ppc64"] }, - "@esbuild/aix-ppc64@0.27.2": { - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "@esbuild/aix-ppc64@0.27.4": { + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", "os": ["aix"], "cpu": ["ppc64"] }, @@ -406,8 +412,8 @@ "os": ["android"], "cpu": ["arm64"] }, - "@esbuild/android-arm64@0.27.2": { - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "@esbuild/android-arm64@0.27.4": { + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", "os": ["android"], "cpu": ["arm64"] }, @@ -416,8 +422,8 @@ "os": ["android"], "cpu": ["arm"] }, - "@esbuild/android-arm@0.27.2": { - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "@esbuild/android-arm@0.27.4": { + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", "os": ["android"], "cpu": ["arm"] }, @@ -426,8 +432,8 @@ "os": ["android"], "cpu": ["x64"] }, - "@esbuild/android-x64@0.27.2": { - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "@esbuild/android-x64@0.27.4": { + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", "os": ["android"], "cpu": ["x64"] }, @@ -436,8 +442,8 @@ "os": ["darwin"], "cpu": ["arm64"] }, - "@esbuild/darwin-arm64@0.27.2": { - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "@esbuild/darwin-arm64@0.27.4": { + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", "os": ["darwin"], "cpu": ["arm64"] }, @@ -446,8 +452,8 @@ "os": ["darwin"], "cpu": ["x64"] }, - "@esbuild/darwin-x64@0.27.2": { - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "@esbuild/darwin-x64@0.27.4": { + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", "os": ["darwin"], "cpu": ["x64"] }, @@ -456,8 +462,8 @@ "os": ["freebsd"], "cpu": ["arm64"] }, - "@esbuild/freebsd-arm64@0.27.2": { - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "@esbuild/freebsd-arm64@0.27.4": { + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", "os": ["freebsd"], "cpu": ["arm64"] }, @@ -466,8 +472,8 @@ "os": ["freebsd"], "cpu": ["x64"] }, - "@esbuild/freebsd-x64@0.27.2": { - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "@esbuild/freebsd-x64@0.27.4": { + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", "os": ["freebsd"], "cpu": ["x64"] }, @@ -476,8 +482,8 @@ "os": ["linux"], "cpu": ["arm64"] }, - "@esbuild/linux-arm64@0.27.2": { - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "@esbuild/linux-arm64@0.27.4": { + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", "os": ["linux"], "cpu": ["arm64"] }, @@ -486,8 +492,8 @@ "os": ["linux"], "cpu": ["arm"] }, - "@esbuild/linux-arm@0.27.2": { - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "@esbuild/linux-arm@0.27.4": { + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", "os": ["linux"], "cpu": ["arm"] }, @@ -496,8 +502,8 @@ "os": ["linux"], "cpu": ["ia32"] }, - "@esbuild/linux-ia32@0.27.2": { - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "@esbuild/linux-ia32@0.27.4": { + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", "os": ["linux"], "cpu": ["ia32"] }, @@ -506,8 +512,8 @@ "os": ["linux"], "cpu": ["loong64"] }, - "@esbuild/linux-loong64@0.27.2": { - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "@esbuild/linux-loong64@0.27.4": { + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", "os": ["linux"], "cpu": ["loong64"] }, @@ -516,8 +522,8 @@ "os": ["linux"], "cpu": ["mips64el"] }, - "@esbuild/linux-mips64el@0.27.2": { - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "@esbuild/linux-mips64el@0.27.4": { + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", "os": ["linux"], "cpu": ["mips64el"] }, @@ -526,8 +532,8 @@ "os": ["linux"], "cpu": ["ppc64"] }, - "@esbuild/linux-ppc64@0.27.2": { - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "@esbuild/linux-ppc64@0.27.4": { + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", "os": ["linux"], "cpu": ["ppc64"] }, @@ -536,8 +542,8 @@ "os": ["linux"], "cpu": ["riscv64"] }, - "@esbuild/linux-riscv64@0.27.2": { - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "@esbuild/linux-riscv64@0.27.4": { + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", "os": ["linux"], "cpu": ["riscv64"] }, @@ -546,8 +552,8 @@ "os": ["linux"], "cpu": ["s390x"] }, - "@esbuild/linux-s390x@0.27.2": { - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "@esbuild/linux-s390x@0.27.4": { + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", "os": ["linux"], "cpu": ["s390x"] }, @@ -556,8 +562,8 @@ "os": ["linux"], "cpu": ["x64"] }, - "@esbuild/linux-x64@0.27.2": { - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "@esbuild/linux-x64@0.27.4": { + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", "os": ["linux"], "cpu": ["x64"] }, @@ -566,8 +572,8 @@ "os": ["netbsd"], "cpu": ["arm64"] }, - "@esbuild/netbsd-arm64@0.27.2": { - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "@esbuild/netbsd-arm64@0.27.4": { + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", "os": ["netbsd"], "cpu": ["arm64"] }, @@ -576,8 +582,8 @@ "os": ["netbsd"], "cpu": ["x64"] }, - "@esbuild/netbsd-x64@0.27.2": { - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "@esbuild/netbsd-x64@0.27.4": { + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", "os": ["netbsd"], "cpu": ["x64"] }, @@ -586,8 +592,8 @@ "os": ["openbsd"], "cpu": ["arm64"] }, - "@esbuild/openbsd-arm64@0.27.2": { - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "@esbuild/openbsd-arm64@0.27.4": { + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", "os": ["openbsd"], "cpu": ["arm64"] }, @@ -596,8 +602,8 @@ "os": ["openbsd"], "cpu": ["x64"] }, - "@esbuild/openbsd-x64@0.27.2": { - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "@esbuild/openbsd-x64@0.27.4": { + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", "os": ["openbsd"], "cpu": ["x64"] }, @@ -606,8 +612,8 @@ "os": ["openharmony"], "cpu": ["arm64"] }, - "@esbuild/openharmony-arm64@0.27.2": { - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "@esbuild/openharmony-arm64@0.27.4": { + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", "os": ["openharmony"], "cpu": ["arm64"] }, @@ -616,8 +622,8 @@ "os": ["sunos"], "cpu": ["x64"] }, - "@esbuild/sunos-x64@0.27.2": { - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "@esbuild/sunos-x64@0.27.4": { + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", "os": ["sunos"], "cpu": ["x64"] }, @@ -626,8 +632,8 @@ "os": ["win32"], "cpu": ["arm64"] }, - "@esbuild/win32-arm64@0.27.2": { - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "@esbuild/win32-arm64@0.27.4": { + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", "os": ["win32"], "cpu": ["arm64"] }, @@ -636,8 +642,8 @@ "os": ["win32"], "cpu": ["ia32"] }, - "@esbuild/win32-ia32@0.27.2": { - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "@esbuild/win32-ia32@0.27.4": { + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", "os": ["win32"], "cpu": ["ia32"] }, @@ -646,16 +652,16 @@ "os": ["win32"], "cpu": ["x64"] }, - "@esbuild/win32-x64@0.27.2": { - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "@esbuild/win32-x64@0.27.4": { + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", "os": ["win32"], "cpu": ["x64"] }, - "@exodus/bytes@1.10.0": { - "integrity": "sha512-tf8YdcbirXdPnJ+Nd4UN1EXnz+IP2DI45YVEr3vvzcVTOyrApkmIB4zvOQVd3XPr7RXnfBtAx+PXImXOIU0Ajg==" + "@exodus/bytes@1.15.0": { + "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==" }, - "@hono/node-server@1.19.9_hono@4.11.9": { - "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "@hono/node-server@1.19.11_hono@4.12.9": { + "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", "dependencies": [ "hono" ] @@ -665,7 +671,7 @@ "dependencies": [ "string-width@5.1.2", "string-width-cjs@npm:string-width@4.2.3", - "strip-ansi@7.1.2", + "strip-ansi@7.2.0", "strip-ansi-cjs@npm:strip-ansi@6.0.1", "wrap-ansi@8.1.0", "wrap-ansi-cjs@npm:wrap-ansi@7.0.0" @@ -698,8 +704,8 @@ "@jridgewell/sourcemap-codec" ] }, - "@modelcontextprotocol/sdk@1.25.3_zod@4.3.6_hono@4.11.9_ajv@8.17.1_express@5.2.1": { - "integrity": "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==", + "@modelcontextprotocol/sdk@1.27.1_zod@4.3.6": { + "integrity": "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==", "dependencies": [ "@hono/node-server", "ajv", @@ -711,6 +717,7 @@ "eventsource-parser", "express", "express-rate-limit", + "hono", "jose", "json-schema-typed", "pkce-challenge", @@ -815,8 +822,8 @@ "@pkgjs/parseargs@0.11.0": { "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==" }, - "@tailwindcss/node@4.1.18": { - "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", + "@tailwindcss/node@4.2.2": { + "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==", "dependencies": [ "@jridgewell/remapping", "enhanced-resolve", @@ -827,67 +834,67 @@ "tailwindcss" ] }, - "@tailwindcss/oxide-android-arm64@4.1.18": { - "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", + "@tailwindcss/oxide-android-arm64@4.2.2": { + "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==", "os": ["android"], "cpu": ["arm64"] }, - "@tailwindcss/oxide-darwin-arm64@4.1.18": { - "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", + "@tailwindcss/oxide-darwin-arm64@4.2.2": { + "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==", "os": ["darwin"], "cpu": ["arm64"] }, - "@tailwindcss/oxide-darwin-x64@4.1.18": { - "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", + "@tailwindcss/oxide-darwin-x64@4.2.2": { + "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==", "os": ["darwin"], "cpu": ["x64"] }, - "@tailwindcss/oxide-freebsd-x64@4.1.18": { - "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", + "@tailwindcss/oxide-freebsd-x64@4.2.2": { + "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==", "os": ["freebsd"], "cpu": ["x64"] }, - "@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18": { - "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", + "@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2": { + "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==", "os": ["linux"], "cpu": ["arm"] }, - "@tailwindcss/oxide-linux-arm64-gnu@4.1.18": { - "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", + "@tailwindcss/oxide-linux-arm64-gnu@4.2.2": { + "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==", "os": ["linux"], "cpu": ["arm64"] }, - "@tailwindcss/oxide-linux-arm64-musl@4.1.18": { - "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", + "@tailwindcss/oxide-linux-arm64-musl@4.2.2": { + "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==", "os": ["linux"], "cpu": ["arm64"] }, - "@tailwindcss/oxide-linux-x64-gnu@4.1.18": { - "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", + "@tailwindcss/oxide-linux-x64-gnu@4.2.2": { + "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==", "os": ["linux"], "cpu": ["x64"] }, - "@tailwindcss/oxide-linux-x64-musl@4.1.18": { - "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", + "@tailwindcss/oxide-linux-x64-musl@4.2.2": { + "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==", "os": ["linux"], "cpu": ["x64"] }, - "@tailwindcss/oxide-wasm32-wasi@4.1.18": { - "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", + "@tailwindcss/oxide-wasm32-wasi@4.2.2": { + "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==", "cpu": ["wasm32"] }, - "@tailwindcss/oxide-win32-arm64-msvc@4.1.18": { - "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", + "@tailwindcss/oxide-win32-arm64-msvc@4.2.2": { + "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==", "os": ["win32"], "cpu": ["arm64"] }, - "@tailwindcss/oxide-win32-x64-msvc@4.1.18": { - "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", + "@tailwindcss/oxide-win32-x64-msvc@4.2.2": { + "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==", "os": ["win32"], "cpu": ["x64"] }, - "@tailwindcss/oxide@4.1.18": { - "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", + "@tailwindcss/oxide@4.2.2": { + "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==", "optionalDependencies": [ "@tailwindcss/oxide-android-arm64", "@tailwindcss/oxide-darwin-arm64", @@ -903,8 +910,8 @@ "@tailwindcss/oxide-win32-x64-msvc" ] }, - "@tailwindcss/postcss@4.1.18": { - "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==", + "@tailwindcss/postcss@4.2.2": { + "integrity": "sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==", "dependencies": [ "@alloc/quick-lru", "@tailwindcss/node", @@ -913,11 +920,11 @@ "tailwindcss" ] }, - "@tanstack/query-core@5.90.20": { - "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==" + "@tanstack/query-core@5.95.2": { + "integrity": "sha512-o4T8vZHZET4Bib3jZ/tCW9/7080urD4c+0/AUaYVpIqOsr7y0reBc1oX3ttNaSW5mYyvZHctiQ/UOP2PfdmFEQ==" }, - "@tanstack/react-query@5.90.20_react@19.2.4": { - "integrity": "sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw==", + "@tanstack/react-query@5.95.2_react@19.2.4": { + "integrity": "sha512-/wGkvLj/st5Ud1Q76KF1uFxScV7WeqN1slQx5280ycwAyYkIPGaRZAEgHxe3bjirSd5Zpwkj6zNcR4cqYni/ZA==", "dependencies": [ "@tanstack/query-core", "react" @@ -926,7 +933,6 @@ "@testing-library/dom@10.4.1": { "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dependencies": [ - "@babel/code-frame", "@babel/runtime", "@types/aria-query", "aria-query", @@ -936,7 +942,7 @@ "pretty-format" ] }, - "@testing-library/react@16.3.2_@testing-library+dom@10.4.1_@types+react@19.2.13_react@19.2.4_react-dom@19.2.4__react@19.2.4": { + "@testing-library/react@16.3.2_@types+react@19.2.14_react@19.2.4_react-dom@19.2.4__react@19.2.4": { "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", "dependencies": [ "@babel/runtime", @@ -958,8 +964,8 @@ "@types/aria-query@5.0.4": { "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==" }, - "@types/react@19.2.13": { - "integrity": "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==", + "@types/react@19.2.14": { + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dependencies": [ "csstype" ] @@ -974,7 +980,7 @@ "agent-base@7.1.4": { "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==" }, - "ajv-formats@3.0.1_ajv@8.17.1": { + "ajv-formats@3.0.1_ajv@8.18.0": { "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dependencies": [ "ajv" @@ -983,8 +989,8 @@ "ajv" ] }, - "ajv@8.17.1": { - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "ajv@8.18.0": { + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dependencies": [ "fast-deep-equal", "fast-uri", @@ -1025,8 +1031,8 @@ "balanced-match@1.0.2": { "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "baseline-browser-mapping@2.9.18": { - "integrity": "sha512-e23vBV1ZLfjb9apvfPk4rHVu2ry6RIr2Wfs+O324okSidrX7pTAnEJPCh/O5BtRlr7QtZI7ktOP3vsqr7Z5XoA==", + "baseline-browser-mapping@2.10.10": { + "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==", "bin": true }, "bidi-js@1.0.3": { @@ -1083,11 +1089,11 @@ "get-intrinsic" ] }, - "caniuse-lite@1.0.30001766": { - "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==" + "caniuse-lite@1.0.30001781": { + "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==" }, - "cbor2@2.2.1": { - "integrity": "sha512-gZrpQweRAfue3Gmd4pG+AakX1zqVrOmXsu+2FwfUfFyYujNGSAOp81iPbHgnG212Xr3KV5vZXxxCXQRbWjZCWw==", + "cbor2@2.3.0": { + "integrity": "sha512-76WB3hq8BoaGkMkBVJ27fW5LJU+qqDLEpgRNCG/SYKhODWXpVPOTD4UcUto3IEzYLA52nsvbhb0wabhHDn3qXg==", "dependencies": [ "@cto.af/wtf8" ] @@ -1125,8 +1131,8 @@ "cookie@1.1.1": { "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==" }, - "copy-anything@2.0.6": { - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "copy-anything@3.0.5": { + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", "dependencies": [ "is-what" ] @@ -1146,8 +1152,8 @@ "which" ] }, - "css-tree@3.1.0": { - "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "css-tree@3.2.1": { + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "dependencies": [ "mdn-data", "source-map-js" @@ -1163,7 +1169,7 @@ "@asamuzakjp/css-color", "@csstools/css-syntax-patches-for-csstree", "css-tree", - "lru-cache@11.2.5" + "lru-cache@11.2.7" ] }, "csstype@3.2.3": { @@ -1211,8 +1217,8 @@ "ee-first@1.1.1": { "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, - "electron-to-chromium@1.5.279": { - "integrity": "sha512-0bblUU5UNdOt5G7XqGiJtpZMONma6WAfq9vsFmtn9x1+joAObr6x1chfqyxFSDCAFwFhCQDrqeAr6MYdpwJ9Hg==" + "electron-to-chromium@1.5.321": { + "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==" }, "emoji-regex@8.0.0": { "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" @@ -1223,8 +1229,8 @@ "encodeurl@2.0.0": { "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, - "enhanced-resolve@5.18.4": { - "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "enhanced-resolve@5.20.1": { + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", "dependencies": [ "graceful-fs", "tapable" @@ -1285,35 +1291,35 @@ "scripts": true, "bin": true }, - "esbuild@0.27.2": { - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "esbuild@0.27.4": { + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", "optionalDependencies": [ - "@esbuild/aix-ppc64@0.27.2", - "@esbuild/android-arm@0.27.2", - "@esbuild/android-arm64@0.27.2", - "@esbuild/android-x64@0.27.2", - "@esbuild/darwin-arm64@0.27.2", - "@esbuild/darwin-x64@0.27.2", - "@esbuild/freebsd-arm64@0.27.2", - "@esbuild/freebsd-x64@0.27.2", - "@esbuild/linux-arm@0.27.2", - "@esbuild/linux-arm64@0.27.2", - "@esbuild/linux-ia32@0.27.2", - "@esbuild/linux-loong64@0.27.2", - "@esbuild/linux-mips64el@0.27.2", - "@esbuild/linux-ppc64@0.27.2", - "@esbuild/linux-riscv64@0.27.2", - "@esbuild/linux-s390x@0.27.2", - "@esbuild/linux-x64@0.27.2", - "@esbuild/netbsd-arm64@0.27.2", - "@esbuild/netbsd-x64@0.27.2", - "@esbuild/openbsd-arm64@0.27.2", - "@esbuild/openbsd-x64@0.27.2", - "@esbuild/openharmony-arm64@0.27.2", - "@esbuild/sunos-x64@0.27.2", - "@esbuild/win32-arm64@0.27.2", - "@esbuild/win32-ia32@0.27.2", - "@esbuild/win32-x64@0.27.2" + "@esbuild/aix-ppc64@0.27.4", + "@esbuild/android-arm@0.27.4", + "@esbuild/android-arm64@0.27.4", + "@esbuild/android-x64@0.27.4", + "@esbuild/darwin-arm64@0.27.4", + "@esbuild/darwin-x64@0.27.4", + "@esbuild/freebsd-arm64@0.27.4", + "@esbuild/freebsd-x64@0.27.4", + "@esbuild/linux-arm@0.27.4", + "@esbuild/linux-arm64@0.27.4", + "@esbuild/linux-ia32@0.27.4", + "@esbuild/linux-loong64@0.27.4", + "@esbuild/linux-mips64el@0.27.4", + "@esbuild/linux-ppc64@0.27.4", + "@esbuild/linux-riscv64@0.27.4", + "@esbuild/linux-s390x@0.27.4", + "@esbuild/linux-x64@0.27.4", + "@esbuild/netbsd-arm64@0.27.4", + "@esbuild/netbsd-x64@0.27.4", + "@esbuild/openbsd-arm64@0.27.4", + "@esbuild/openbsd-x64@0.27.4", + "@esbuild/openharmony-arm64@0.27.4", + "@esbuild/sunos-x64@0.27.4", + "@esbuild/win32-arm64@0.27.4", + "@esbuild/win32-ia32@0.27.4", + "@esbuild/win32-x64@0.27.4" ], "scripts": true, "bin": true @@ -1336,10 +1342,11 @@ "eventsource-parser" ] }, - "express-rate-limit@7.5.1_express@5.2.1": { - "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "express-rate-limit@8.3.1_express@5.2.1": { + "integrity": "sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==", "dependencies": [ - "express" + "express", + "ip-address" ] }, "express@5.2.1": { @@ -1478,8 +1485,8 @@ "function-bind" ] }, - "hono@4.11.9": { - "integrity": "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==" + "hono@4.12.9": { + "integrity": "sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==" }, "html-encoding-sniffer@6.0.0": { "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", @@ -1533,12 +1540,15 @@ "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "bin": true }, - "immutable@5.1.4": { - "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==" + "immutable@5.1.5": { + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==" }, "inherits@2.0.4": { "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ip-address@10.1.0": { + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==" + }, "ipaddr.js@1.9.1": { "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, @@ -1560,11 +1570,11 @@ "is-promise@4.0.0": { "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" }, - "is-what@3.14.1": { - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + "is-what@4.1.16": { + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==" }, - "isbot@5.1.34": { - "integrity": "sha512-aCMIBSKd/XPRYdiCQTLC8QHH4YT8B3JUADu+7COgYIZPvkeoMcUHMRjZLM9/7V8fCj+l7FSREc1lOPNjzogo/A==" + "isbot@5.1.36": { + "integrity": "sha512-C/ZtXyJqDPZ7G7JPr06ApWyYoHjYexQbS6hPYD4WYCzpv2Qes6Z+CCEfTX4Owzf+1EJ933PoI2p+B9v7wpGZBQ==" }, "isexe@2.0.0": { "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" @@ -1582,8 +1592,8 @@ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "bin": true }, - "jose@6.1.3": { - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==" + "jose@6.2.2": { + "integrity": "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==" }, "js-tokens@4.0.0": { "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" @@ -1627,12 +1637,11 @@ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": true }, - "less@4.5.1": { - "integrity": "sha512-UKgI3/KON4u6ngSsnDADsUERqhZknsVZbnuzlRZXLQCmfC/MDld42fTydUE9B+Mla1AL6SJ/Pp6SlEFi/AVGfw==", + "less@4.6.4": { + "integrity": "sha512-OJmO5+HxZLLw0RLzkqaNHzcgEAQG7C0y3aMbwtCzIUFZsLMNNq/1IdAdHEycQ58CwUO3jPTHmoN+tE5I7FQxNg==", "dependencies": [ "copy-anything", - "parse-node-version", - "tslib" + "parse-node-version" ], "optionalDependencies": [ "errno", @@ -1643,66 +1652,65 @@ "needle", "source-map@0.6.1" ], - "scripts": true, "bin": true }, - "lightningcss-android-arm64@1.30.2": { - "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "lightningcss-android-arm64@1.32.0": { + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", "os": ["android"], "cpu": ["arm64"] }, - "lightningcss-darwin-arm64@1.30.2": { - "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "lightningcss-darwin-arm64@1.32.0": { + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", "os": ["darwin"], "cpu": ["arm64"] }, - "lightningcss-darwin-x64@1.30.2": { - "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "lightningcss-darwin-x64@1.32.0": { + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", "os": ["darwin"], "cpu": ["x64"] }, - "lightningcss-freebsd-x64@1.30.2": { - "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "lightningcss-freebsd-x64@1.32.0": { + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", "os": ["freebsd"], "cpu": ["x64"] }, - "lightningcss-linux-arm-gnueabihf@1.30.2": { - "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "lightningcss-linux-arm-gnueabihf@1.32.0": { + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", "os": ["linux"], "cpu": ["arm"] }, - "lightningcss-linux-arm64-gnu@1.30.2": { - "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "lightningcss-linux-arm64-gnu@1.32.0": { + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", "os": ["linux"], "cpu": ["arm64"] }, - "lightningcss-linux-arm64-musl@1.30.2": { - "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "lightningcss-linux-arm64-musl@1.32.0": { + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", "os": ["linux"], "cpu": ["arm64"] }, - "lightningcss-linux-x64-gnu@1.30.2": { - "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "lightningcss-linux-x64-gnu@1.32.0": { + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", "os": ["linux"], "cpu": ["x64"] }, - "lightningcss-linux-x64-musl@1.30.2": { - "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "lightningcss-linux-x64-musl@1.32.0": { + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", "os": ["linux"], "cpu": ["x64"] }, - "lightningcss-win32-arm64-msvc@1.30.2": { - "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "lightningcss-win32-arm64-msvc@1.32.0": { + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", "os": ["win32"], "cpu": ["arm64"] }, - "lightningcss-win32-x64-msvc@1.30.2": { - "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "lightningcss-win32-x64-msvc@1.32.0": { + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", "os": ["win32"], "cpu": ["x64"] }, - "lightningcss@1.30.2": { - "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "lightningcss@1.32.0": { + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", "dependencies": [ "detect-libc" ], @@ -1729,8 +1737,8 @@ "lru-cache@10.4.3": { "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, - "lru-cache@11.2.5": { - "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==" + "lru-cache@11.2.7": { + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==" }, "lru-cache@5.1.1": { "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", @@ -1758,8 +1766,8 @@ "math-intrinsics@1.1.0": { "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" }, - "mdn-data@2.12.2": { - "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==" + "mdn-data@2.27.1": { + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==" }, "media-typer@1.1.0": { "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==" @@ -1780,14 +1788,14 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "bin": true }, - "minimatch@9.0.5": { - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "minimatch@9.0.9": { + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dependencies": [ "brace-expansion" ] }, - "minipass@7.1.2": { - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==" + "minipass@7.1.3": { + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==" }, "ms@2.1.3": { "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" @@ -1796,8 +1804,8 @@ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "bin": true }, - "needle@3.3.1": { - "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "needle@3.5.0": { + "integrity": "sha512-jaQyPKKk2YokHrEg+vFDYxXIHTCBgiZwSHOoVx/8V3GIBS8/VN6NdVRmg8q1ERtPkMvmOvebsgga4sAj5hls/w==", "dependencies": [ "iconv-lite@0.6.3", "sax" @@ -1810,8 +1818,8 @@ "node-addon-api@7.1.1": { "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==" }, - "node-releases@2.0.27": { - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==" + "node-releases@2.0.36": { + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==" }, "object-assign@4.1.1": { "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" @@ -1967,8 +1975,8 @@ "punycode@2.3.1": { "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" }, - "qs@6.14.1": { - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "qs@6.15.0": { + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "dependencies": [ "side-channel" ] @@ -1995,8 +2003,8 @@ "scheduler" ] }, - "react-error-boundary@6.1.0_react@19.2.4": { - "integrity": "sha512-02k9WQ/mUhdbXir0tC1NiMesGzRPaCsJEWU/4bcFrbY1YMZOtHShtZP6zw0SJrBWA/31H0KT9/FgdL8+sPKgHA==", + "react-error-boundary@6.1.1_react@19.2.4": { + "integrity": "sha512-BrYwPOdXi5mqkk5lw+Uvt0ThHx32rCt3BkukS4X23A2AIWDPSGX6iaWTc0y9TU/mHDA/6qOSGel+B2ERkOvD1w==", "dependencies": [ "react" ] @@ -2004,8 +2012,8 @@ "react-is@17.0.2": { "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, - "react-router@7.13.0_react@19.2.4_react-dom@19.2.4__react@19.2.4": { - "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", + "react-router@7.13.2_react@19.2.4_react-dom@19.2.4__react@19.2.4": { + "integrity": "sha512-tX1Aee+ArlKQP+NIUd7SE6Li+CiGKwQtbS+FfRxPX6Pe4vHOo6nr9d++u5cwg+Z8K/x8tP+7qLmujDtfrAoUJA==", "dependencies": [ "cookie@1.1.1", "react", @@ -2038,8 +2046,8 @@ "safer-buffer@2.1.2": { "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "sass@1.97.3": { - "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "sass@1.98.0": { + "integrity": "sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==", "dependencies": [ "chokidar", "immutable", @@ -2177,7 +2185,7 @@ "dependencies": [ "eastasianwidth", "emoji-regex@9.2.2", - "strip-ansi@7.1.2" + "strip-ansi@7.2.0" ] }, "strip-ansi@6.0.1": { @@ -2186,8 +2194,8 @@ "ansi-regex@5.0.1" ] }, - "strip-ansi@7.1.2": { - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "strip-ansi@7.2.0": { + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dependencies": [ "ansi-regex@6.2.2" ] @@ -2206,17 +2214,17 @@ "symbol-tree@3.2.4": { "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, - "tailwindcss@4.1.18": { - "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==" + "tailwindcss@4.2.2": { + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==" }, - "tapable@2.3.0": { - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==" + "tapable@2.3.1": { + "integrity": "sha512-b+u3CEM6FjDHru+nhUSjDofpWSBp2rINziJWgApm72wwGasQ/wKXftZe4tI2Y5HPv6OpzXSZHOFq87H4vfsgsw==" }, - "tldts-core@7.0.19": { - "integrity": "sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==" + "tldts-core@7.0.27": { + "integrity": "sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg==" }, - "tldts@7.0.19": { - "integrity": "sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==", + "tldts@7.0.27": { + "integrity": "sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg==", "dependencies": [ "tldts-core" ], @@ -2225,8 +2233,8 @@ "toidentifier@1.0.1": { "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, - "tough-cookie@6.0.0": { - "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "tough-cookie@6.0.1": { + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", "dependencies": [ "tldts" ] @@ -2237,9 +2245,6 @@ "punycode" ] }, - "tslib@2.8.1": { - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, "type-is@2.0.1": { "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "dependencies": [ @@ -2308,14 +2313,14 @@ "dependencies": [ "ansi-styles@6.2.3", "string-width@5.1.2", - "strip-ansi@7.1.2" + "strip-ansi@7.2.0" ] }, "wrappy@1.0.2": { "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "ws@8.19.0": { - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==" + "ws@8.20.0": { + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==" }, "xml-name-validator@5.0.0": { "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==" @@ -2338,128 +2343,128 @@ }, "workspace": { "dependencies": [ - "npm:@types/react@^19.2.13", + "npm:@types/react@^19.2.14", "npm:react@^19.2.4" ], "members": { "example": { "dependencies": [ - "jsr:@std/assert@^1.0.18", - "jsr:@std/async@^1.1.1", - "jsr:@std/collections@^1.1.5", + "jsr:@std/assert@^1.0.19", + "jsr:@std/async@^1.2.0", + "jsr:@std/collections@^1.1.6", "jsr:@std/encoding@^1.0.10", "jsr:@std/path@^1.1.4", "jsr:@std/streams@^1.0.17", "jsr:@std/testing@^1.0.17", "jsr:@std/uuid@^1.1.0", "jsr:@udibo/esbuild-plugin-postcss@0.3", - "jsr:@udibo/juniper@~0.3.2", + "jsr:@udibo/juniper@~0.3.3", "npm:@opentelemetry/api@^1.9.0", - "npm:@tailwindcss/postcss@^4.1.18", + "npm:@tailwindcss/postcss@^4.2.2", "npm:@testing-library/react@^16.3.2", "npm:@testing-library/user-event@^14.6.1", - "npm:@types/react@^19.2.13", - "npm:hono@^4.11.9", + "npm:@types/react@^19.2.14", + "npm:hono@^4.12.9", "npm:playwright@^1.58.2", - "npm:react-router@^7.13.0", + "npm:react-router@^7.13.2", "npm:react@^19.2.4", - "npm:tailwindcss@^4.1.18", + "npm:tailwindcss@^4.2.2", "npm:zod@^4.3.6" ] }, "src": { "dependencies": [ "jsr:@deno/esbuild-plugin@^1.2.1", - "jsr:@std/assert@^1.0.17", - "jsr:@std/async@^1.1.0", - "jsr:@std/cli@^1.0.26", - "jsr:@std/collections@^1.1.4", - "jsr:@std/fs@^1.0.22", + "jsr:@std/assert@^1.0.19", + "jsr:@std/async@^1.2.0", + "jsr:@std/cli@^1.0.28", + "jsr:@std/collections@^1.1.6", + "jsr:@std/fs@^1.0.23", "jsr:@std/path@^1.1.4", "jsr:@std/streams@^1.0.17", "jsr:@std/testing@^1.0.17", "jsr:@udibo/http-error@~0.11.1", - "npm:@babel/core@^7.28.6", - "npm:@modelcontextprotocol/sdk@^1.25.3", + "npm:@babel/core@^7.29.0", + "npm:@modelcontextprotocol/sdk@^1.27.1", "npm:@opentelemetry/api@^1.9.0", "npm:@testing-library/react@^16.3.2", - "npm:@types/react@^19.2.9", + "npm:@types/react@^19.2.14", "npm:babel-plugin-react-compiler@1", - "npm:cbor2@^2.2.1", - "npm:esbuild@~0.27.2", + "npm:cbor2@^2.3.0", + "npm:esbuild@~0.27.4", "npm:global-jsdom@27", - "npm:hono@^4.11.6", - "npm:isbot@^5.1.34", + "npm:hono@^4.12.9", + "npm:isbot@^5.1.36", "npm:quick-lru@^7.3.0", "npm:react-dom@^19.2.4", - "npm:react-error-boundary@^6.1.0", - "npm:react-router@^7.13.0", + "npm:react-error-boundary@^6.1.1", + "npm:react-router@^7.13.2", "npm:react@^19.2.4" ] }, "templates/minimal": { "dependencies": [ - "jsr:@std/assert@^1.0.18", + "jsr:@std/assert@^1.0.19", "jsr:@std/path@^1.1.4", "jsr:@std/streams@^1.0.17", "jsr:@std/testing@^1.0.17", - "jsr:@udibo/juniper@~0.3.2", + "jsr:@udibo/juniper@~0.3.3", "npm:@opentelemetry/api@^1.9.0", "npm:@testing-library/react@^16.3.2", - "npm:@types/react@^19.2.13", - "npm:hono@^4.11.9", - "npm:react-router@^7.13.0", + "npm:@types/react@^19.2.14", + "npm:hono@^4.12.9", + "npm:react-router@^7.13.2", "npm:react@^19.2.4" ] }, "templates/tailwindcss": { "dependencies": [ - "jsr:@std/assert@^1.0.18", + "jsr:@std/assert@^1.0.19", "jsr:@std/path@^1.1.4", "jsr:@std/streams@^1.0.17", "jsr:@std/testing@^1.0.17", "jsr:@udibo/esbuild-plugin-postcss@0.3.0", - "jsr:@udibo/juniper@~0.3.2", + "jsr:@udibo/juniper@~0.3.3", "npm:@opentelemetry/api@^1.9.0", - "npm:@tailwindcss/postcss@^4.1.18", + "npm:@tailwindcss/postcss@^4.2.2", "npm:@testing-library/react@^16.3.2", - "npm:@types/react@^19.2.13", - "npm:hono@^4.11.9", - "npm:react-router@^7.13.0", + "npm:@types/react@^19.2.14", + "npm:hono@^4.12.9", + "npm:react-router@^7.13.2", "npm:react@^19.2.4", - "npm:tailwindcss@^4.1.18" + "npm:tailwindcss@^4.2.2" ] }, "templates/tanstack": { "dependencies": [ - "jsr:@std/assert@^1.0.18", - "jsr:@std/async@^1.1.1", + "jsr:@std/assert@^1.0.19", + "jsr:@std/async@^1.2.0", "jsr:@std/path@^1.1.4", "jsr:@std/streams@^1.0.17", "jsr:@std/testing@^1.0.17", - "jsr:@udibo/juniper@~0.3.2", + "jsr:@udibo/juniper@~0.3.3", "npm:@opentelemetry/api@^1.9.0", - "npm:@tanstack/react-query@^5.90.20", + "npm:@tanstack/react-query@^5.95.2", "npm:@testing-library/react@^16.3.2", "npm:@testing-library/user-event@^14.6.1", - "npm:@types/react@^19.2.13", - "npm:hono@^4.11.9", - "npm:react-router@^7.13.0", + "npm:@types/react@^19.2.14", + "npm:hono@^4.12.9", + "npm:react-router@^7.13.2", "npm:react@^19.2.4" ] }, "tutorials/blog": { "dependencies": [ - "jsr:@std/assert@^1.0.18", + "jsr:@std/assert@^1.0.19", "jsr:@std/path@^1.1.4", "jsr:@std/streams@^1.0.17", "jsr:@std/testing@^1.0.17", - "jsr:@udibo/juniper@~0.3.2", + "jsr:@udibo/juniper@~0.3.3", "npm:@opentelemetry/api@^1.9.0", "npm:@testing-library/react@^16.3.2", - "npm:@types/react@^19.2.13", - "npm:hono@^4.11.9", - "npm:react-router@^7.13.0", + "npm:@types/react@^19.2.14", + "npm:hono@^4.12.9", + "npm:react-router@^7.13.2", "npm:react@^19.2.4" ] } diff --git a/docs/testing.md b/docs/testing.md index 92487ab..7c98f4c 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -284,10 +284,13 @@ Test loaders with `createRoutesStub`: ```tsx import "@udibo/juniper/utils/global-jsdom"; import { afterEach, beforeEach, describe, it } from "@std/testing/bdd"; -import { cleanup, render, screen, waitFor } from "@testing-library/react"; +import { cleanup, render, screen } from "@testing-library/react"; import { stub } from "@std/testing/mock"; import { FakeTime } from "@std/testing/time"; -import { createRoutesStub } from "@udibo/juniper/utils/testing"; +import { + createRoutesStub, + waitForFakeTime, +} from "@udibo/juniper/utils/testing"; import * as loaderRoute from "./loader.tsx"; @@ -310,7 +313,7 @@ describe("LoaderDemo route", () => { const Stub = createRoutesStub([loaderRoute]); render(); - await waitFor(() => { + await waitForFakeTime(time, () => { screen.getByText("Loading data..."); }); }); @@ -321,7 +324,7 @@ describe("LoaderDemo route", () => { await time.tickAsync(600); - await waitFor(() => { + await waitForFakeTime(time, () => { screen.getByText("Data loaded successfully!"); }); }); @@ -482,6 +485,66 @@ describe("Time-dependent tests", () => { }); ``` +> **Important:** `FakeTime` is incompatible with `waitFor` from +> `@testing-library/react` — see [waitForFakeTime](#waitforfaketime) below for +> the solution. + +### waitForFakeTime + +`waitFor` from `@testing-library/react` hangs when `FakeTime` is active. This +happens because `@testing-library/react` internally uses +`setTimeout(resolve, 0)` to drain microtasks after `waitFor` resolves. With +`FakeTime`, that timer is captured by the fake queue and never fires. + +Use `waitForFakeTime` from `@udibo/juniper/utils/testing` as a drop-in +replacement whenever `FakeTime` is active. It uses `FakeTime.restoreFor` to +periodically flush the fake timer queue with a real interval: + +```tsx +import "@udibo/juniper/utils/global-jsdom"; +import { cleanup, render, screen, waitFor } from "@testing-library/react"; +import { afterEach, describe, it } from "@std/testing/bdd"; +import { FakeTime } from "@std/testing/time"; +import { + createRoutesStub, + waitForFakeTime, +} from "@udibo/juniper/utils/testing"; + +import * as indexRoute from "./index.tsx"; + +describe("Home route", () => { + afterEach(cleanup); + + it("should render with fake time", async () => { + using time = new FakeTime("2025-01-15T12:00:00.000Z"); + const Stub = createRoutesStub([indexRoute]); + render(); + + // Use waitForFakeTime when FakeTime is active + await waitForFakeTime(time, () => { + screen.getByRole("heading", { name: "Hello, World!" }); + }); + screen.getByText("Current time: 2025-01-15T12:00:00.000Z"); + }); + + it("should render with stubbed data", async () => { + // No FakeTime — use regular waitFor + const Stub = createRoutesStub([{ + ...indexRoute, + loader: () => ({ message: "Custom!", now: new Date() }), + }]); + render(); + + await waitFor(() => { + screen.getByRole("heading", { name: "Custom!" }); + }); + }); +}); +``` + +**Rule of thumb:** If `FakeTime` is active in the test, use `waitForFakeTime`. +Otherwise, use the regular `waitFor` from `@testing-library/react`. + ### Testing with Deno KV Use in-memory KV for isolated tests: diff --git a/example/deno.json b/example/deno.json index e2e0fb6..dc50d0b 100644 --- a/example/deno.json +++ b/example/deno.json @@ -36,9 +36,9 @@ "@udibo/juniper": "jsr:@udibo/juniper@^0.3.3", "@udibo/esbuild-plugin-postcss": "jsr:@udibo/esbuild-plugin-postcss@^0.3.0", "@std/testing": "jsr:@std/testing@^1.0.17", - "@std/assert": "jsr:@std/assert@^1.0.18", - "@std/async": "jsr:@std/async@^1.1.1", - "@std/collections": "jsr:@std/collections@^1.1.5", + "@std/assert": "jsr:@std/assert@^1.0.19", + "@std/async": "jsr:@std/async@^1.2.0", + "@std/collections": "jsr:@std/collections@^1.1.6", "@std/encoding": "jsr:@std/encoding@^1.0.10", "@std/path": "jsr:@std/path@^1.1.4", "@std/streams": "jsr:@std/streams@^1.0.17", @@ -46,11 +46,11 @@ "@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0", "playwright": "npm:playwright@^1.58.2", "react": "npm:react@^19.2.4", - "@types/react": "npm:@types/react@^19.2.13", - "react-router": "npm:react-router@^7.13.0", - "hono": "npm:hono@^4.11.9", - "tailwindcss": "npm:tailwindcss@^4.1.18", - "@tailwindcss/postcss": "npm:@tailwindcss/postcss@^4.1.18", + "@types/react": "npm:@types/react@^19.2.14", + "react-router": "npm:react-router@^7.13.2", + "hono": "npm:hono@^4.12.9", + "tailwindcss": "npm:tailwindcss@^4.2.2", + "@tailwindcss/postcss": "npm:@tailwindcss/postcss@^4.2.2", "zod": "npm:zod@^4.3.6", "@testing-library/react": "npm:@testing-library/react@^16.3.2", "@testing-library/user-event": "npm:@testing-library/user-event@^14.6.1" diff --git a/example/routes/features/data/loader.test.tsx b/example/routes/features/data/loader.test.tsx index f7238f9..c5fcccc 100644 --- a/example/routes/features/data/loader.test.tsx +++ b/example/routes/features/data/loader.test.tsx @@ -1,11 +1,14 @@ import "@udibo/juniper/utils/global-jsdom"; -import { cleanup, render, screen, waitFor } from "@testing-library/react"; +import { cleanup, render, screen } from "@testing-library/react"; import { afterEach, beforeEach, describe, it } from "@std/testing/bdd"; import { stub } from "@std/testing/mock"; import { FakeTime } from "@std/testing/time"; -import { createRoutesStub } from "@udibo/juniper/utils/testing"; +import { + createRoutesStub, + waitForFakeTime, +} from "@udibo/juniper/utils/testing"; import * as loaderRoute from "./loader.tsx"; @@ -28,7 +31,7 @@ describe("LoaderDemo route", () => { const Stub = createRoutesStub([loaderRoute]); render(); - await waitFor(() => { + await waitForFakeTime(time, () => { screen.getByText("Loading data..."); }); }); @@ -37,13 +40,13 @@ describe("LoaderDemo route", () => { const Stub = createRoutesStub([loaderRoute]); render(); - await waitFor(() => { + await waitForFakeTime(time, () => { screen.getByText("Loading data..."); }); await time.tickAsync(600); - await waitFor(() => { + await waitForFakeTime(time, () => { screen.getByText("Data loaded successfully!"); }); @@ -57,7 +60,7 @@ describe("LoaderDemo route", () => { await time.tickAsync(600); - await waitFor(() => { + await waitForFakeTime(time, () => { screen.getByRole("heading", { name: "Loader" }); }); }); @@ -75,7 +78,7 @@ describe("LoaderDemo route", () => { }]); render(); - await waitFor(() => { + await waitForFakeTime(time, () => { screen.getByText("Stubbed data!"); }); diff --git a/src/_server.tsx b/src/_server.tsx index 35c71b0..c355d11 100644 --- a/src/_server.tsx +++ b/src/_server.tsx @@ -414,18 +414,34 @@ async function renderDocument( c.status(statusCode); for (const [key, value] of actionHeaders?.entries() ?? []) { - c.header(key, value); + if (key.toLowerCase() !== "set-cookie") { + c.header(key, value); + } + } + for (const cookie of actionHeaders?.getSetCookie() ?? []) { + c.header("Set-Cookie", cookie, { append: true }); } for (const [key, value] of loaderHeaders?.entries() ?? []) { - c.header(key, value); + if (key.toLowerCase() !== "set-cookie") { + c.header(key, value); + } + } + for (const cookie of loaderHeaders?.getSetCookie() ?? []) { + c.header("Set-Cookie", cookie, { append: true }); } if (presetError?.headers) { for (const [key, value] of presetError.headers.entries()) { - if (key.toLowerCase() !== "content-type") { + if ( + key.toLowerCase() !== "content-type" && + key.toLowerCase() !== "set-cookie" + ) { c.header(key, value); } } + for (const cookie of presetError.headers.getSetCookie()) { + c.header("Set-Cookie", cookie, { append: true }); + } } c.header("Content-Type", "text/html; charset=utf-8"); @@ -738,11 +754,18 @@ export function createHandlers< if ( lowerKey !== "location" && lowerKey !== "content-type" && - lowerKey !== "content-length" + lowerKey !== "content-length" && + lowerKey !== "set-cookie" ) { c.header(key, value); } } + // Handle Set-Cookie headers separately to avoid corruption + // from Headers.entries() which merges multiple Set-Cookie + // values with commas + for (const cookie of dataOrResponse.headers.getSetCookie()) { + c.header("Set-Cookie", cookie, { append: true }); + } c.header("X-Juniper", "redirect"); return c.json({ location }); } @@ -791,10 +814,16 @@ export function createHandlers< }); if (error.headers) { for (const [key, value] of error.headers.entries()) { - if (key.toLowerCase() !== "content-type") { + if ( + key.toLowerCase() !== "content-type" && + key.toLowerCase() !== "set-cookie" + ) { headers.set(key, value); } } + for (const cookie of error.headers.getSetCookie()) { + headers.append("Set-Cookie", cookie); + } } return new Response(cborData as unknown as BodyInit, { status: error.status, diff --git a/src/client.test.tsx b/src/client.test.tsx index 4fa96f7..eedf6a8 100644 --- a/src/client.test.tsx +++ b/src/client.test.tsx @@ -333,6 +333,7 @@ describe("createRoute", () => { unstable_data: undefined, unstable_allowRouteDeterminism: undefined, unstable_pattern: "/blog", + unstable_url: new URL("http://localhost/blog"), } as ActionFunctionArgs; const result = await routeObject.action(actionArgs); assertEquals(result, payload); diff --git a/src/deno.json b/src/deno.json index 731e7e7..45be314 100644 --- a/src/deno.json +++ b/src/deno.json @@ -25,30 +25,30 @@ } }, "imports": { - "@babel/core": "npm:@babel/core@^7.28.6", - "@modelcontextprotocol/sdk": "npm:@modelcontextprotocol/sdk@^1.25.3", + "@babel/core": "npm:@babel/core@^7.29.0", + "@modelcontextprotocol/sdk": "npm:@modelcontextprotocol/sdk@^1.27.1", "@udibo/http-error": "jsr:@udibo/http-error@^0.11.1", "@std/testing": "jsr:@std/testing@^1.0.17", - "@std/assert": "jsr:@std/assert@^1.0.17", - "@std/async": "jsr:@std/async@^1.1.0", - "@std/cli": "jsr:@std/cli@^1.0.26", - "@std/collections": "jsr:@std/collections@^1.1.4", - "@std/fs": "jsr:@std/fs@^1.0.22", + "@std/assert": "jsr:@std/assert@^1.0.19", + "@std/async": "jsr:@std/async@^1.2.0", + "@std/cli": "jsr:@std/cli@^1.0.28", + "@std/collections": "jsr:@std/collections@^1.1.6", + "@std/fs": "jsr:@std/fs@^1.0.23", "@std/path": "jsr:@std/path@^1.1.4", "@std/streams": "jsr:@std/streams@^1.0.17", "@deno/esbuild-plugin": "jsr:@deno/esbuild-plugin@^1.2.1", "@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0", "babel-plugin-react-compiler": "npm:babel-plugin-react-compiler@^1.0.0", - "cbor2": "npm:cbor2@^2.2.1", - "esbuild": "npm:esbuild@^0.27.2", - "isbot": "npm:isbot@^5.1.34", + "cbor2": "npm:cbor2@^2.3.0", + "esbuild": "npm:esbuild@^0.27.4", + "isbot": "npm:isbot@^5.1.36", "quick-lru": "npm:quick-lru@^7.3.0", - "hono": "npm:hono@^4.11.6", + "hono": "npm:hono@^4.12.9", "react": "npm:react@^19.2.4", - "@types/react": "npm:@types/react@^19.2.9", + "@types/react": "npm:@types/react@^19.2.14", "react-dom": "npm:react-dom@^19.2.4", - "react-error-boundary": "npm:react-error-boundary@^6.1.0", - "react-router": "npm:react-router@^7.13.0", + "react-error-boundary": "npm:react-error-boundary@^6.1.1", + "react-router": "npm:react-router@^7.13.2", "@testing-library/react": "npm:@testing-library/react@^16.3.2", "global-jsdom": "npm:global-jsdom@^27" }, diff --git a/src/server.test.tsx b/src/server.test.tsx index 1e06e0f..6b75d75 100644 --- a/src/server.test.tsx +++ b/src/server.test.tsx @@ -767,6 +767,50 @@ describe("redirect header preservation", () => { const data = await res.json(); assertEquals(data, { location: "/dashboard" }); }); + + it("should preserve multiple Set-Cookie headers from redirect response", async () => { + const client = new Client({ + path: "/", + main: { default: () =>
Home
}, + }); + + const server = createServer(import.meta.url, client, { + path: "/", + main: { + loader: () => { + const headers = new Headers(); + headers.append("Location", "/dashboard"); + headers.append( + "Set-Cookie", + "access_token=abc; Path=/; HttpOnly", + ); + headers.append( + "Set-Cookie", + "refresh_token=xyz; Path=/auth/refresh; HttpOnly", + ); + return Promise.resolve( + new Response(null, { status: 302, headers }), + ); + }, + }, + }); + + const res = await server.request("http://localhost/", { + headers: { "X-Juniper-Route-Id": "/" }, + }); + + assertEquals(res.status, 200); + assertEquals(res.headers.get("X-Juniper"), "redirect"); + + // Multiple Set-Cookie headers should be preserved individually + const cookies = res.headers.getSetCookie(); + assertEquals(cookies.length, 2); + assertEquals(cookies[0], "access_token=abc; Path=/; HttpOnly"); + assertEquals( + cookies[1], + "refresh_token=xyz; Path=/auth/refresh; HttpOnly", + ); + }); }); describe("build artifact cache control", () => { diff --git a/src/utils/testing.ts b/src/utils/testing.ts index 8f58f9b..b755bf3 100644 --- a/src/utils/testing.ts +++ b/src/utils/testing.ts @@ -15,6 +15,8 @@ import { import type { HydrationState, RouteObject } from "react-router"; import { stub } from "@std/testing/mock"; import type { Stub } from "@std/testing/mock"; +import type { FakeTime } from "@std/testing/time"; +import type { waitFor as WaitForType } from "@testing-library/react"; import type { AnyParams, RouteModule } from "../mod.ts"; @@ -301,20 +303,29 @@ export function createRoutesStub( return function RoutesStub( { initialEntries, hydrationData }: RoutesStubProps, ) { - const context = React.useMemo(() => { + const contextRef = React.useRef(null!); + const routerRef = React.useRef>( + null!, + ); + if (routerRef.current == null) { const ctx = new RouterContextProvider(); options?.getContext?.(ctx); - return ctx; - }, []); - const router = createMemoryRouter(routeObjects, { - initialEntries: initialEntries ?? [firstPath], - hydrationData, - getContext: () => context, - }); + contextRef.current = ctx; + routerRef.current = createMemoryRouter(routeObjects, { + initialEntries: initialEntries ?? [firstPath], + hydrationData, + getContext: () => ctx, + }); + } return React.createElement( JuniperContextProvider, - { context, children: React.createElement(RouterProvider, { router }) }, + { + context: contextRef.current!, + children: React.createElement(RouterProvider, { + router: routerRef.current, + }), + }, ); }; } @@ -581,3 +592,63 @@ export function stubFormData(): FormDataStub { [Symbol.dispose]: restore, }; } + +/** + * A drop-in replacement for `waitFor` from `@testing-library/react` that works + * correctly when `FakeTime` from `@std/testing/time` is active. + * + * `@testing-library/react` uses `setTimeout(resolve, 0)` internally to drain + * microtasks after `waitFor` resolves. When `FakeTime` is active, that timer is + * captured by the fake timer queue and never fires, causing `await waitFor()` + * to hang and leaving an unresolved promise that triggers Deno's + * "Promise resolution is still pending" error at process exit. + * + * This wrapper uses `FakeTime.restoreFor` to create a real interval that + * periodically flushes the fake timer queue, allowing the internal + * `setTimeout(resolve, 0)` to fire. + * + * @example Using with FakeTime and createRoutesStub + * ```tsx + * import "@udibo/juniper/utils/global-jsdom"; + * import { cleanup, render, screen } from "@testing-library/react"; + * import { afterEach, describe, it } from "@std/testing/bdd"; + * import { FakeTime } from "@std/testing/time"; + * import { createRoutesStub, waitForFakeTime } from "@udibo/juniper/utils/testing"; + * + * import * as myRoute from "./my-route.tsx"; + * + * describe("My route", () => { + * afterEach(cleanup); + * + * it("should render with fake time", async () => { + * using time = new FakeTime("2025-01-15T12:00:00.000Z"); + * const Stub = createRoutesStub([myRoute]); + * render(); + * + * await waitForFakeTime(time, () => { + * screen.getByText("2025-01-15T12:00:00.000Z"); + * }); + * }); + * }); + * ``` + * + * @param time The active FakeTime instance. + * @param callback The callback to pass to `waitFor`. + * @param options Optional `waitFor` options. + * @returns The result of the `waitFor` callback. + */ +export async function waitForFakeTime( + time: FakeTime, + callback: () => T, + options?: Parameters[1], +): Promise { + const { FakeTime: FT } = await import("@std/testing/time"); + const { waitFor } = await import("@testing-library/react"); + const promise = waitFor(callback, options); + const id = await FT.restoreFor(() => setInterval(() => time.tick(0), 10)); + try { + return await promise; + } finally { + await FT.restoreFor(() => clearInterval(id)); + } +} diff --git a/templates/minimal/deno.json b/templates/minimal/deno.json index 3092b8a..2036f33 100644 --- a/templates/minimal/deno.json +++ b/templates/minimal/deno.json @@ -33,14 +33,14 @@ "@/": "./", "@udibo/juniper": "jsr:@udibo/juniper@^0.3.3", "@std/testing": "jsr:@std/testing@^1.0.17", - "@std/assert": "jsr:@std/assert@^1.0.18", + "@std/assert": "jsr:@std/assert@^1.0.19", "@std/path": "jsr:@std/path@^1.1.4", "@std/streams": "jsr:@std/streams@^1.0.17", "@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0", "react": "npm:react@^19.2.4", - "@types/react": "npm:@types/react@^19.2.13", - "react-router": "npm:react-router@^7.13.0", - "hono": "npm:hono@^4.11.9", + "@types/react": "npm:@types/react@^19.2.14", + "react-router": "npm:react-router@^7.13.2", + "hono": "npm:hono@^4.12.9", "@testing-library/react": "npm:@testing-library/react@^16.3.2" }, "permissions": { diff --git a/templates/minimal/routes/index.test.tsx b/templates/minimal/routes/index.test.tsx index e6dd10d..a779bfe 100644 --- a/templates/minimal/routes/index.test.tsx +++ b/templates/minimal/routes/index.test.tsx @@ -4,7 +4,10 @@ import { cleanup, render, screen, waitFor } from "@testing-library/react"; import { afterEach, describe, it } from "@std/testing/bdd"; import { FakeTime } from "@std/testing/time"; -import { createRoutesStub } from "@udibo/juniper/utils/testing"; +import { + createRoutesStub, + waitForFakeTime, +} from "@udibo/juniper/utils/testing"; import * as indexRoute from "./index.tsx"; @@ -12,11 +15,11 @@ describe("Home route", () => { afterEach(cleanup); it("should render loader data", async () => { - using _time = new FakeTime("2025-01-15T12:00:00.000Z"); + using time = new FakeTime("2025-01-15T12:00:00.000Z"); const Stub = createRoutesStub([indexRoute]); render(); - await waitFor(() => { + await waitForFakeTime(time, () => { screen.getByRole("heading", { name: "Hello, World!" }); }); screen.getByText("Current time: 2025-01-15T12:00:00.000Z"); diff --git a/templates/tailwindcss/deno.json b/templates/tailwindcss/deno.json index 9ae9908..46993d1 100644 --- a/templates/tailwindcss/deno.json +++ b/templates/tailwindcss/deno.json @@ -35,16 +35,16 @@ "@udibo/juniper": "jsr:@udibo/juniper@^0.3.3", "@udibo/esbuild-plugin-postcss": "jsr:@udibo/esbuild-plugin-postcss@0.3.0", "@std/testing": "jsr:@std/testing@^1.0.17", - "@std/assert": "jsr:@std/assert@^1.0.18", + "@std/assert": "jsr:@std/assert@^1.0.19", "@std/path": "jsr:@std/path@^1.1.4", "@std/streams": "jsr:@std/streams@^1.0.17", "@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0", "react": "npm:react@^19.2.4", - "@types/react": "npm:@types/react@^19.2.13", - "react-router": "npm:react-router@^7.13.0", - "hono": "npm:hono@^4.11.9", - "tailwindcss": "npm:tailwindcss@^4.1.18", - "@tailwindcss/postcss": "npm:@tailwindcss/postcss@^4.1.18", + "@types/react": "npm:@types/react@^19.2.14", + "react-router": "npm:react-router@^7.13.2", + "hono": "npm:hono@^4.12.9", + "tailwindcss": "npm:tailwindcss@^4.2.2", + "@tailwindcss/postcss": "npm:@tailwindcss/postcss@^4.2.2", "@testing-library/react": "npm:@testing-library/react@^16.3.2" }, "permissions": { diff --git a/templates/tailwindcss/routes/index.test.tsx b/templates/tailwindcss/routes/index.test.tsx index e6dd10d..a779bfe 100644 --- a/templates/tailwindcss/routes/index.test.tsx +++ b/templates/tailwindcss/routes/index.test.tsx @@ -4,7 +4,10 @@ import { cleanup, render, screen, waitFor } from "@testing-library/react"; import { afterEach, describe, it } from "@std/testing/bdd"; import { FakeTime } from "@std/testing/time"; -import { createRoutesStub } from "@udibo/juniper/utils/testing"; +import { + createRoutesStub, + waitForFakeTime, +} from "@udibo/juniper/utils/testing"; import * as indexRoute from "./index.tsx"; @@ -12,11 +15,11 @@ describe("Home route", () => { afterEach(cleanup); it("should render loader data", async () => { - using _time = new FakeTime("2025-01-15T12:00:00.000Z"); + using time = new FakeTime("2025-01-15T12:00:00.000Z"); const Stub = createRoutesStub([indexRoute]); render(); - await waitFor(() => { + await waitForFakeTime(time, () => { screen.getByRole("heading", { name: "Hello, World!" }); }); screen.getByText("Current time: 2025-01-15T12:00:00.000Z"); diff --git a/templates/tanstack/deno.json b/templates/tanstack/deno.json index cf39ba1..8d4498d 100644 --- a/templates/tanstack/deno.json +++ b/templates/tanstack/deno.json @@ -31,18 +31,18 @@ }, "imports": { "@/": "./", - "@tanstack/react-query": "npm:@tanstack/react-query@^5.90.20", + "@tanstack/react-query": "npm:@tanstack/react-query@^5.95.2", "@udibo/juniper": "jsr:@udibo/juniper@^0.3.3", - "@std/async": "jsr:@std/async@^1.1.1", + "@std/async": "jsr:@std/async@^1.2.0", "@std/testing": "jsr:@std/testing@^1.0.17", - "@std/assert": "jsr:@std/assert@^1.0.18", + "@std/assert": "jsr:@std/assert@^1.0.19", "@std/path": "jsr:@std/path@^1.1.4", "@std/streams": "jsr:@std/streams@^1.0.17", "@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0", "react": "npm:react@^19.2.4", - "@types/react": "npm:@types/react@^19.2.13", - "react-router": "npm:react-router@^7.13.0", - "hono": "npm:hono@^4.11.9", + "@types/react": "npm:@types/react@^19.2.14", + "react-router": "npm:react-router@^7.13.2", + "hono": "npm:hono@^4.12.9", "@testing-library/react": "npm:@testing-library/react@^16.3.2", "@testing-library/user-event": "npm:@testing-library/user-event@^14.6.1" }, diff --git a/templates/tanstack/routes/index.test.tsx b/templates/tanstack/routes/index.test.tsx index 44b3391..3693a02 100644 --- a/templates/tanstack/routes/index.test.tsx +++ b/templates/tanstack/routes/index.test.tsx @@ -4,7 +4,10 @@ import { cleanup, render, screen, waitFor } from "@testing-library/react"; import { afterEach, describe, it } from "@std/testing/bdd"; import { FakeTime } from "@std/testing/time"; -import { createRoutesStub } from "@udibo/juniper/utils/testing"; +import { + createRoutesStub, + waitForFakeTime, +} from "@udibo/juniper/utils/testing"; import * as indexRoute from "./index.ts"; import * as indexRouteClient from "./index.tsx"; @@ -13,14 +16,14 @@ describe("Home route", () => { afterEach(cleanup); it("should render loader data", async () => { - using _time = new FakeTime("2025-01-15T12:00:00.000Z"); + using time = new FakeTime("2025-01-15T12:00:00.000Z"); const Stub = createRoutesStub([{ ...indexRouteClient, loader: indexRoute.loader, }]); render(); - await waitFor(() => { + await waitForFakeTime(time, () => { screen.getByRole("heading", { name: "Hello, World!" }); }); screen.getByText("Current time: 2025-01-15T12:00:00.000Z"); diff --git a/tutorials/blog/deno.json b/tutorials/blog/deno.json index c3e0192..ef242d7 100644 --- a/tutorials/blog/deno.json +++ b/tutorials/blog/deno.json @@ -34,14 +34,14 @@ "@/": "./", "@udibo/juniper": "jsr:@udibo/juniper@^0.3.3", "@std/testing": "jsr:@std/testing@^1.0.17", - "@std/assert": "jsr:@std/assert@^1.0.18", + "@std/assert": "jsr:@std/assert@^1.0.19", "@std/path": "jsr:@std/path@^1.1.4", "@std/streams": "jsr:@std/streams@^1.0.17", "@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0", "react": "npm:react@^19.2.4", - "@types/react": "npm:@types/react@^19.2.13", - "react-router": "npm:react-router@^7.13.0", - "hono": "npm:hono@^4.11.9", + "@types/react": "npm:@types/react@^19.2.14", + "react-router": "npm:react-router@^7.13.2", + "hono": "npm:hono@^4.12.9", "@testing-library/react": "npm:@testing-library/react@^16.3.2" }, "permissions": {