diff --git a/package.json b/package.json index e958889..4b0306d 100644 --- a/package.json +++ b/package.json @@ -11,15 +11,15 @@ "@clack/prompts": "^1.2.0", "chanfana": "^3.3.0", "cloudflare": "^5.2.0", - "hono": "4.12.9", + "hono": "4.12.10", "zod": "^4.3.6" }, "devDependencies": { - "@cloudflare/vitest-pool-workers": "0.14.0", + "@cloudflare/vitest-pool-workers": "0.14.1", "@types/node": "25.5.0", "typescript": "6.0.2", "vitest": "4.1.2", - "wrangler": "4.79.0" + "wrangler": "4.80.0" }, "scripts": { "cf-typegen": "wrangler types", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf7c6ce..07995f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,15 +18,15 @@ importers: specifier: ^5.2.0 version: 5.2.0 hono: - specifier: 4.12.9 - version: 4.12.9 + specifier: 4.12.10 + version: 4.12.10 zod: specifier: ^4.3.6 version: 4.3.6 devDependencies: '@cloudflare/vitest-pool-workers': - specifier: 0.14.0 - version: 0.14.0(@vitest/runner@4.1.2)(@vitest/snapshot@4.1.2)(vitest@4.1.2(@types/node@25.5.0)(vite@7.3.1(@types/node@25.5.0)(yaml@2.8.3))) + specifier: 0.14.1 + version: 0.14.1(@vitest/runner@4.1.2)(@vitest/snapshot@4.1.2)(vitest@4.1.2(@types/node@25.5.0)(vite@7.3.1(@types/node@25.5.0)(yaml@2.8.3))) '@types/node': specifier: 25.5.0 version: 25.5.0 @@ -37,8 +37,8 @@ importers: specifier: 4.1.2 version: 4.1.2(@types/node@25.5.0)(vite@7.3.1(@types/node@25.5.0)(yaml@2.8.3)) wrangler: - specifier: 4.79.0 - version: 4.79.0 + specifier: 4.80.0 + version: 4.80.0 packages: @@ -66,39 +66,39 @@ packages: workerd: optional: true - '@cloudflare/vitest-pool-workers@0.14.0': - resolution: {integrity: sha512-e1s3qW0YkUR8LDH0ytw94VjJzj/bLYR/4sJba6n2YlVsV9IyxeFrm4IDJtJrmm8xF9mCuZh+hUAtG8toCB385A==} + '@cloudflare/vitest-pool-workers@0.14.1': + resolution: {integrity: sha512-AuIvoGXi9bMjgD1636JtP84yGsjhdtsk23rYMVFLO9KB84rvwhVPkvwgBv74RbhbURXYDKWV5koPwPucFSFgUg==} peerDependencies: '@vitest/runner': ^4.1.0 '@vitest/snapshot': ^4.1.0 vitest: ^4.1.0 - '@cloudflare/workerd-darwin-64@1.20260329.1': - resolution: {integrity: sha512-oyDXYlPBuGXKkZ85+M3jFz0/qYmvA4AEURN8USIGPDCR5q+HFSRwywSd9neTx3Wi7jhey2wuYaEpD3fEFWyWUA==} + '@cloudflare/workerd-darwin-64@1.20260401.1': + resolution: {integrity: sha512-ZSmceM70jH6k+/62VkEcmMNzrpr4kSctkX5Lsgqv38KktfhPY/hsh75y1lRoPWS3H3kgMa4p2pUSlidZR1u2hw==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20260329.1': - resolution: {integrity: sha512-++ZxVa3ovzYeDLEG6zMqql9gzZAG8vak6ZSBQgprGKZp7akr+GKTpw9f3RrMP552NSi3gTisroLobrrkPBtYLQ==} + '@cloudflare/workerd-darwin-arm64@1.20260401.1': + resolution: {integrity: sha512-7UKWF+IUZ3NXMVPsDg8Cjg0r58b+uYlfvs5Yt8bvtU+geCtW4P2MxRHmRSEo8SryckXOJjb/b8tcncgCykFu8g==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20260329.1': - resolution: {integrity: sha512-kkeywAgIHwbqHkVILqbj/YkfbrA6ARbmutjiYzZA2MwMSfNXlw6/kedAKOY8YwcymZIgepx3YTIPnBP50pOotw==} + '@cloudflare/workerd-linux-64@1.20260401.1': + resolution: {integrity: sha512-MDWUH/0bvL/l9aauN8zEddyYOXId1OueqrUCXXENNJ95R/lSmF6OgGVuXaYhoIhxQkNiEJ/0NOlnVYj9mJq4dw==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20260329.1': - resolution: {integrity: sha512-eYBN20+B7XOUSWEe0mlqkMUbfLoIKjKZnpqQiSxnLbL72JKY0D/KlfN/b7RVGLpewB7i8rTrwTNr0szCKnZzSQ==} + '@cloudflare/workerd-linux-arm64@1.20260401.1': + resolution: {integrity: sha512-UgkzpMzVWM/bwbo3vjCTg2aoKfGcUhiEoQoDdo6RGWvbHRJyLVZ4VQCG9ZcISiztkiS2ICCoYOtPy6M/lV6Gcw==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20260329.1': - resolution: {integrity: sha512-5R+/oxrDhS9nL3oA3ZWtD6ndMOqm7RfKknDNxLcmYW5DkUu7UH3J/s1t/Dz66iFePzr5BJmE7/8gbmve6TjtZQ==} + '@cloudflare/workerd-windows-64@1.20260401.1': + resolution: {integrity: sha512-HBLzcQF5iF4Qv20tQ++pG7xs3OsCnaIbc+GAi6fmhUKZhvmzvml/jwrQzLJ+MPm0cQo41K5OO/U3T4S8tvJetQ==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -107,8 +107,8 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@emnapi/runtime@1.9.1': - resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} '@esbuild/aix-ppc64@0.27.3': resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} @@ -116,8 +116,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.27.4': - resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -128,8 +128,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.27.4': - resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -140,8 +140,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.27.4': - resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -152,8 +152,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.27.4': - resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -164,8 +164,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.27.4': - resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -176,8 +176,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.27.4': - resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -188,8 +188,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.27.4': - resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -200,8 +200,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.4': - resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -212,8 +212,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.27.4': - resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -224,8 +224,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.27.4': - resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -236,8 +236,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.27.4': - resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -248,8 +248,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.27.4': - resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -260,8 +260,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.27.4': - resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -272,8 +272,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.27.4': - resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -284,8 +284,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.27.4': - resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -296,8 +296,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.27.4': - resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -308,8 +308,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.27.4': - resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -320,8 +320,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.27.4': - resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -332,8 +332,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.4': - resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -344,8 +344,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.27.4': - resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -356,8 +356,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.4': - resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -368,8 +368,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.27.4': - resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -380,8 +380,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.27.4': - resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -392,8 +392,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.27.4': - resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -404,8 +404,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.27.4': - resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -416,8 +416,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.27.4': - resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -879,8 +879,8 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.27.4: - resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} hasBin: true @@ -956,8 +956,8 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hono@4.12.9: - resolution: {integrity: sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==} + hono@4.12.10: + resolution: {integrity: sha512-mx/p18PLy5og9ufies2GOSUqep98Td9q4i/EF6X7yJgAiIopxqdfIO3jbqsi3jRgTgw88jMDEzVKi+V2EF+27w==} engines: {node: '>=16.9.0'} humanize-ms@1.2.1: @@ -986,8 +986,8 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - miniflare@4.20260329.0: - resolution: {integrity: sha512-+G+1YFVeuEpw/gZZmUHQR7IfzJV+DDGvnSl0yXzhgvHh8Nbr8Go5uiWIwl17EyZ1Uors3FKUMDUyU6+ejeKZOw==} + miniflare@4.20260401.0: + resolution: {integrity: sha512-lngHPzZFN9sxYG/mhzvnWiBMNVAN5MsO/7g32ttJ07rymtiK/ZBalODTKb8Od+BQdlU5DOR4CjVt9NydjnUyYg==} engines: {node: '>=18.0.0'} hasBin: true @@ -1199,17 +1199,17 @@ packages: engines: {node: '>=8'} hasBin: true - workerd@1.20260329.1: - resolution: {integrity: sha512-+ifMv3uBuD33ee7pan5n8+sgVxm2u5HnbgfXzHKwMNTKw86znqBJSnJoBqtP88+2T5U2Lu11xXUt+khPYioXwQ==} + workerd@1.20260401.1: + resolution: {integrity: sha512-mUYCd+ohaWJWF5nhDzxugWaAD/DM8Dw0ze3B7bu8JaA7S70+XQJXcvcvwE8C4qGcxSdCyqjsrFzqxKubECDwzg==} engines: {node: '>=16'} hasBin: true - wrangler@4.79.0: - resolution: {integrity: sha512-NMinIdB1pXIqdk+NLw4+RjzB7K5z4+lWMxhTxFTfZomwJu3Pm6N+kZ+a66D3nI7w0oCjsdv/umrZVmSHCBp2cg==} + wrangler@4.80.0: + resolution: {integrity: sha512-2ZKF7uPeOZy65BGk3YfvqBCPo/xH1MrAlMmH9mVP+tCNBrTUMnwOHSj1HrZHgR8LttkAqhko0fGz+I4ax1rzyQ==} engines: {node: '>=20.3.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20260329.1 + '@cloudflare/workers-types': ^4.20260401.1 peerDependenciesMeta: '@cloudflare/workers-types': optional: true @@ -1268,47 +1268,47 @@ snapshots: '@cloudflare/kv-asset-handler@0.4.2': {} - '@cloudflare/unenv-preset@2.16.0(unenv@2.0.0-rc.24)(workerd@1.20260329.1)': + '@cloudflare/unenv-preset@2.16.0(unenv@2.0.0-rc.24)(workerd@1.20260401.1)': dependencies: unenv: 2.0.0-rc.24 optionalDependencies: - workerd: 1.20260329.1 + workerd: 1.20260401.1 - '@cloudflare/vitest-pool-workers@0.14.0(@vitest/runner@4.1.2)(@vitest/snapshot@4.1.2)(vitest@4.1.2(@types/node@25.5.0)(vite@7.3.1(@types/node@25.5.0)(yaml@2.8.3)))': + '@cloudflare/vitest-pool-workers@0.14.1(@vitest/runner@4.1.2)(@vitest/snapshot@4.1.2)(vitest@4.1.2(@types/node@25.5.0)(vite@7.3.1(@types/node@25.5.0)(yaml@2.8.3)))': dependencies: '@vitest/runner': 4.1.2 '@vitest/snapshot': 4.1.2 cjs-module-lexer: 1.4.3 esbuild: 0.27.3 - miniflare: 4.20260329.0 + miniflare: 4.20260401.0 vitest: 4.1.2(@types/node@25.5.0)(vite@7.3.1(@types/node@25.5.0)(yaml@2.8.3)) - wrangler: 4.79.0 + wrangler: 4.80.0 zod: 3.25.76 transitivePeerDependencies: - '@cloudflare/workers-types' - bufferutil - utf-8-validate - '@cloudflare/workerd-darwin-64@1.20260329.1': + '@cloudflare/workerd-darwin-64@1.20260401.1': optional: true - '@cloudflare/workerd-darwin-arm64@1.20260329.1': + '@cloudflare/workerd-darwin-arm64@1.20260401.1': optional: true - '@cloudflare/workerd-linux-64@1.20260329.1': + '@cloudflare/workerd-linux-64@1.20260401.1': optional: true - '@cloudflare/workerd-linux-arm64@1.20260329.1': + '@cloudflare/workerd-linux-arm64@1.20260401.1': optional: true - '@cloudflare/workerd-windows-64@1.20260329.1': + '@cloudflare/workerd-windows-64@1.20260401.1': optional: true '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@emnapi/runtime@1.9.1': + '@emnapi/runtime@1.9.2': dependencies: tslib: 2.8.1 optional: true @@ -1316,157 +1316,157 @@ snapshots: '@esbuild/aix-ppc64@0.27.3': optional: true - '@esbuild/aix-ppc64@0.27.4': + '@esbuild/aix-ppc64@0.27.7': optional: true '@esbuild/android-arm64@0.27.3': optional: true - '@esbuild/android-arm64@0.27.4': + '@esbuild/android-arm64@0.27.7': optional: true '@esbuild/android-arm@0.27.3': optional: true - '@esbuild/android-arm@0.27.4': + '@esbuild/android-arm@0.27.7': optional: true '@esbuild/android-x64@0.27.3': optional: true - '@esbuild/android-x64@0.27.4': + '@esbuild/android-x64@0.27.7': optional: true '@esbuild/darwin-arm64@0.27.3': optional: true - '@esbuild/darwin-arm64@0.27.4': + '@esbuild/darwin-arm64@0.27.7': optional: true '@esbuild/darwin-x64@0.27.3': optional: true - '@esbuild/darwin-x64@0.27.4': + '@esbuild/darwin-x64@0.27.7': optional: true '@esbuild/freebsd-arm64@0.27.3': optional: true - '@esbuild/freebsd-arm64@0.27.4': + '@esbuild/freebsd-arm64@0.27.7': optional: true '@esbuild/freebsd-x64@0.27.3': optional: true - '@esbuild/freebsd-x64@0.27.4': + '@esbuild/freebsd-x64@0.27.7': optional: true '@esbuild/linux-arm64@0.27.3': optional: true - '@esbuild/linux-arm64@0.27.4': + '@esbuild/linux-arm64@0.27.7': optional: true '@esbuild/linux-arm@0.27.3': optional: true - '@esbuild/linux-arm@0.27.4': + '@esbuild/linux-arm@0.27.7': optional: true '@esbuild/linux-ia32@0.27.3': optional: true - '@esbuild/linux-ia32@0.27.4': + '@esbuild/linux-ia32@0.27.7': optional: true '@esbuild/linux-loong64@0.27.3': optional: true - '@esbuild/linux-loong64@0.27.4': + '@esbuild/linux-loong64@0.27.7': optional: true '@esbuild/linux-mips64el@0.27.3': optional: true - '@esbuild/linux-mips64el@0.27.4': + '@esbuild/linux-mips64el@0.27.7': optional: true '@esbuild/linux-ppc64@0.27.3': optional: true - '@esbuild/linux-ppc64@0.27.4': + '@esbuild/linux-ppc64@0.27.7': optional: true '@esbuild/linux-riscv64@0.27.3': optional: true - '@esbuild/linux-riscv64@0.27.4': + '@esbuild/linux-riscv64@0.27.7': optional: true '@esbuild/linux-s390x@0.27.3': optional: true - '@esbuild/linux-s390x@0.27.4': + '@esbuild/linux-s390x@0.27.7': optional: true '@esbuild/linux-x64@0.27.3': optional: true - '@esbuild/linux-x64@0.27.4': + '@esbuild/linux-x64@0.27.7': optional: true '@esbuild/netbsd-arm64@0.27.3': optional: true - '@esbuild/netbsd-arm64@0.27.4': + '@esbuild/netbsd-arm64@0.27.7': optional: true '@esbuild/netbsd-x64@0.27.3': optional: true - '@esbuild/netbsd-x64@0.27.4': + '@esbuild/netbsd-x64@0.27.7': optional: true '@esbuild/openbsd-arm64@0.27.3': optional: true - '@esbuild/openbsd-arm64@0.27.4': + '@esbuild/openbsd-arm64@0.27.7': optional: true '@esbuild/openbsd-x64@0.27.3': optional: true - '@esbuild/openbsd-x64@0.27.4': + '@esbuild/openbsd-x64@0.27.7': optional: true '@esbuild/openharmony-arm64@0.27.3': optional: true - '@esbuild/openharmony-arm64@0.27.4': + '@esbuild/openharmony-arm64@0.27.7': optional: true '@esbuild/sunos-x64@0.27.3': optional: true - '@esbuild/sunos-x64@0.27.4': + '@esbuild/sunos-x64@0.27.7': optional: true '@esbuild/win32-arm64@0.27.3': optional: true - '@esbuild/win32-arm64@0.27.4': + '@esbuild/win32-arm64@0.27.7': optional: true '@esbuild/win32-ia32@0.27.3': optional: true - '@esbuild/win32-ia32@0.27.4': + '@esbuild/win32-ia32@0.27.7': optional: true '@esbuild/win32-x64@0.27.3': optional: true - '@esbuild/win32-x64@0.27.4': + '@esbuild/win32-x64@0.27.7': optional: true '@img/colour@1.1.0': {} @@ -1553,7 +1553,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.9.1 + '@emnapi/runtime': 1.9.2 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -1841,34 +1841,34 @@ snapshots: '@esbuild/win32-ia32': 0.27.3 '@esbuild/win32-x64': 0.27.3 - esbuild@0.27.4: + esbuild@0.27.7: optionalDependencies: - '@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 + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 estree-walker@3.0.3: dependencies: @@ -1942,7 +1942,7 @@ snapshots: dependencies: function-bind: 1.1.2 - hono@4.12.9: {} + hono@4.12.10: {} humanize-ms@1.2.1: dependencies: @@ -1966,12 +1966,12 @@ snapshots: dependencies: mime-db: 1.52.0 - miniflare@4.20260329.0: + miniflare@4.20260401.0: dependencies: '@cspotcode/source-map-support': 0.8.1 sharp: 0.34.5 undici: 7.24.4 - workerd: 1.20260329.1 + workerd: 1.20260401.1 ws: 8.18.0 youch: 4.1.0-beta.10 transitivePeerDependencies: @@ -2114,7 +2114,7 @@ snapshots: vite@7.3.1(@types/node@25.5.0)(yaml@2.8.3): dependencies: - esbuild: 0.27.4 + esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 postcss: 8.5.8 @@ -2166,24 +2166,24 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - workerd@1.20260329.1: + workerd@1.20260401.1: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20260329.1 - '@cloudflare/workerd-darwin-arm64': 1.20260329.1 - '@cloudflare/workerd-linux-64': 1.20260329.1 - '@cloudflare/workerd-linux-arm64': 1.20260329.1 - '@cloudflare/workerd-windows-64': 1.20260329.1 + '@cloudflare/workerd-darwin-64': 1.20260401.1 + '@cloudflare/workerd-darwin-arm64': 1.20260401.1 + '@cloudflare/workerd-linux-64': 1.20260401.1 + '@cloudflare/workerd-linux-arm64': 1.20260401.1 + '@cloudflare/workerd-windows-64': 1.20260401.1 - wrangler@4.79.0: + wrangler@4.80.0: dependencies: '@cloudflare/kv-asset-handler': 0.4.2 - '@cloudflare/unenv-preset': 2.16.0(unenv@2.0.0-rc.24)(workerd@1.20260329.1) + '@cloudflare/unenv-preset': 2.16.0(unenv@2.0.0-rc.24)(workerd@1.20260401.1) blake3-wasm: 2.1.5 esbuild: 0.27.3 - miniflare: 4.20260329.0 + miniflare: 4.20260401.0 path-to-regexp: 6.3.0 unenv: 2.0.0-rc.24 - workerd: 1.20260329.1 + workerd: 1.20260401.1 optionalDependencies: fsevents: 2.3.3 transitivePeerDependencies: diff --git a/tests/helpers.ts b/tests/helpers.ts index b70c108..41d2128 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -127,6 +127,27 @@ export async function dropLogSchema(db: D1Database): Promise { await db.prepare("DROP TABLE IF EXISTS ddns_logs").run(); } +export async function clearRuntimeTables(db: D1Database): Promise { + for (const statement of [ + "DELETE FROM ddns_logs", + "DELETE FROM ddns_rate_limits", + ]) { + try { + await db.prepare(statement).run(); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + if (!message.includes("no such table")) { + throw error; + } + } + } +} + +export async function dropRateLimitSchema(db: D1Database): Promise { + await db.prepare("DROP INDEX IF EXISTS idx_ddns_rate_limits_updated_at").run(); + await db.prepare("DROP TABLE IF EXISTS ddns_rate_limits").run(); +} + /** Build a Synology-style update URL with sensible defaults. */ export function makeSynologyUrl( overrides: { diff --git a/tests/integration/synology.test.ts b/tests/integration/synology.test.ts index 2067060..6464d2e 100644 --- a/tests/integration/synology.test.ts +++ b/tests/integration/synology.test.ts @@ -2,7 +2,7 @@ import { SELF } from "cloudflare:test"; import { env } from "cloudflare:workers"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { createMockDnsApi, dropLogSchema, makeSynologyUrl } from "../helpers"; +import { clearRuntimeTables, createMockDnsApi, dropLogSchema, makeSynologyUrl } from "../helpers"; const dns = createMockDnsApi(); const DEFAULT_ALLOWED_HOSTNAMES = "nas.example.com,home.example.com"; @@ -11,20 +11,28 @@ function setAllowedHostnames(value: string) { Object.assign(env, { DDNS_ALLOWED_HOSTNAMES: value }); } +function setRateLimitConfig(maxRequests: string, windowSeconds = "60") { + Object.assign(env, { + DDNS_RATE_LIMIT_MAX_REQUESTS: maxRequests, + DDNS_RATE_LIMIT_WINDOW_SECONDS: windowSeconds, + }); +} + beforeEach(() => { setAllowedHostnames(DEFAULT_ALLOWED_HOSTNAMES); + setRateLimitConfig("10"); dns.reset(); dns.install(); }); beforeEach(async () => { - await env.DB.prepare("DELETE FROM ddns_logs").run(); + await clearRuntimeTables(env.DB); }); afterEach(async () => { await new Promise((resolve) => setTimeout(resolve, 25)); - await env.DB.prepare("DELETE FROM ddns_logs").run(); + await clearRuntimeTables(env.DB); dns.restore(); }); @@ -44,6 +52,19 @@ describe("GET /nic/update — authentication", () => { expect(response.status).toBe(200); expect(await response.text()).toBe("badauth"); }); + + it("returns 429 and 911 when a client exceeds the fixed-window rate limit", async () => { + setRateLimitConfig("2"); + const headers = { "CF-Connecting-IP": "198.51.100.201" }; + + expect((await SELF.fetch(makeSynologyUrl(), { headers })).status).toBe(200); + expect((await SELF.fetch(makeSynologyUrl(), { headers })).status).toBe(200); + + const response = await SELF.fetch(makeSynologyUrl(), { headers }); + expect(response.status).toBe(429); + expect(await response.text()).toBe("911"); + expect(response.headers.get("Retry-After")).toBeTruthy(); + }); }); // --------------------------------------------------------------------------- diff --git a/tests/integration/update.test.ts b/tests/integration/update.test.ts index ebc7311..08e840d 100644 --- a/tests/integration/update.test.ts +++ b/tests/integration/update.test.ts @@ -1,8 +1,8 @@ import { SELF } from "cloudflare:test"; -import { env, exports } from "cloudflare:workers"; +import { env } from "cloudflare:workers"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { createMockDnsApi, dropLogSchema } from "../helpers"; +import { clearRuntimeTables, createMockDnsApi, dropLogSchema } from "../helpers"; const dns = createMockDnsApi(); const DEFAULT_ALLOWED_HOSTNAMES = "nas.example.com,home.example.com"; @@ -11,20 +11,28 @@ function setAllowedHostnames(value: string) { Object.assign(env, { DDNS_ALLOWED_HOSTNAMES: value }); } +function setRateLimitConfig(maxRequests: string, windowSeconds = "60") { + Object.assign(env, { + DDNS_RATE_LIMIT_MAX_REQUESTS: maxRequests, + DDNS_RATE_LIMIT_WINDOW_SECONDS: windowSeconds, + }); +} + beforeEach(() => { setAllowedHostnames(DEFAULT_ALLOWED_HOSTNAMES); + setRateLimitConfig("10"); dns.reset(); dns.install(); }); beforeEach(async () => { - await env.DB.prepare("DELETE FROM ddns_logs").run(); + await clearRuntimeTables(env.DB); }); afterEach(async () => { await new Promise((resolve) => setTimeout(resolve, 25)); - await env.DB.prepare("DELETE FROM ddns_logs").run(); + await clearRuntimeTables(env.DB); dns.restore(); }); @@ -74,6 +82,22 @@ describe("POST /update — authentication", () => { const response = await SELF.fetch(makeUpdateRequest({ secret: "wrong", ip: "1.2.3.4" })); expect(response.status).toBe(401); }); + + it("returns 429 when a client exceeds the fixed-window rate limit", async () => { + setRateLimitConfig("2"); + + const request = () => + makeUpdateRequest({ + ip: "1.2.3.4", + cfConnectingIp: "198.51.100.200", + }); + expect((await SELF.fetch(request())).status).toBe(200); + expect((await SELF.fetch(request())).status).toBe(200); + + const response = await SELF.fetch(request()); + expect(response.status).toBe(429); + expect(response.headers.get("Retry-After")).toBeTruthy(); + }); }); // --------------------------------------------------------------------------- diff --git a/tests/vitest.config.mts b/tests/vitest.config.mts index cd97b67..b78d038 100644 --- a/tests/vitest.config.mts +++ b/tests/vitest.config.mts @@ -20,6 +20,10 @@ export default defineConfig({ configPath: "./wrangler.jsonc", }, miniflare: { + // Keep local tests aligned with the bundled workerd version until + // Wrangler/vitest-pool-workers is upgraded to a runtime that supports + // the production compatibility date from wrangler.jsonc. + compatibilityDate: "2026-04-01", bindings: { MIGRATIONS: migrations, // Test credentials — these only exist inside miniflare. @@ -30,12 +34,18 @@ export default defineConfig({ DDNS_PROXIED: "false", DDNS_TTL: "1", DDNS_LOG_RETENTION_DAYS: "30", + DDNS_RATE_LIMIT_MAX_REQUESTS: "10", + DDNS_RATE_LIMIT_WINDOW_SECONDS: "60", }, }, }; }), ], test: { + // Run one worker at a time in local tests. This reduces pressure on the + // bundled workerd/Miniflare runtime while we are pinned to an older local + // engine than the production compatibility date. + maxWorkers: 1, setupFiles: ["./tests/apply-migrations.ts"], }, });