diff --git a/.gitignore b/.gitignore index 3b0fe33..5d31321 100644 --- a/.gitignore +++ b/.gitignore @@ -170,3 +170,5 @@ dist .dev.vars .wrangler/ + +.idea/ diff --git a/package.json b/package.json index d70f4dd..61232be 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,10 @@ "cf-typegen": "wrangler types" }, "devDependencies": { - "@cloudflare/vitest-pool-workers": "^0.5.2", + "@cloudflare/vitest-pool-workers": "^0.5.32", "@cloudflare/workers-types": "^4.20241202.0", - "typescript": "^5.5.2", + "typescript": "^5.7.2", "vitest": "2.0.5", - "wrangler": "^3.60.3" + "wrangler": "^3.91.0" } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a35ff1..52f80ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,20 +6,20 @@ settings: devDependencies: '@cloudflare/vitest-pool-workers': - specifier: ^0.5.2 - version: 0.5.2(@cloudflare/workers-types@4.20241202.0)(@vitest/runner@2.0.5)(@vitest/snapshot@2.0.5)(vitest@2.0.5) + specifier: ^0.5.32 + version: 0.5.32(@cloudflare/workers-types@4.20241202.0)(@vitest/runner@2.1.8)(@vitest/snapshot@2.1.8)(vitest@2.0.5) '@cloudflare/workers-types': specifier: ^4.20241202.0 version: 4.20241202.0 typescript: - specifier: ^5.5.2 - version: 5.5.2 + specifier: ^5.7.2 + version: 5.7.2 vitest: specifier: 2.0.5 version: 2.0.5 wrangler: - specifier: ^3.60.3 - version: 3.60.3(@cloudflare/workers-types@4.20241202.0) + specifier: ^3.91.0 + version: 3.91.0(@cloudflare/workers-types@4.20241202.0) packages: @@ -31,13 +31,6 @@ packages: '@jridgewell/trace-mapping': 0.3.25 dev: true - /@cloudflare/kv-asset-handler@0.3.2: - resolution: {integrity: sha512-EeEjMobfuJrwoctj7FA1y1KEbM0+Q1xSjobIEyie9k4haVEBB7vkDvsasw1pM3rO39mL2akxIAzLMUAtrMHZhA==} - engines: {node: '>=16.13'} - dependencies: - mime: 3.0.0 - dev: true - /@cloudflare/kv-asset-handler@0.3.4: resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} engines: {node: '>=16.13'} @@ -45,23 +38,23 @@ packages: mime: 3.0.0 dev: true - /@cloudflare/vitest-pool-workers@0.5.2(@cloudflare/workers-types@4.20241202.0)(@vitest/runner@2.0.5)(@vitest/snapshot@2.0.5)(vitest@2.0.5): - resolution: {integrity: sha512-4VuIRDBQ1FJcFjoDYxlOPDeNtxYYjtz2TMPkm9bKnCssf+7K71VVuwkbV31PmLOclaenFcSLuyvygVXtZ9DgtA==} + /@cloudflare/vitest-pool-workers@0.5.32(@cloudflare/workers-types@4.20241202.0)(@vitest/runner@2.1.8)(@vitest/snapshot@2.1.8)(vitest@2.0.5): + resolution: {integrity: sha512-lJHwXq3VWKgzy7BzXs61O/QukT9QQ42hl27eRcqCV6P20OF4/bLH8rmUaYxdR8IxLlmNY7Q5h0wGN0nXBn8XKg==} peerDependencies: - '@vitest/runner': 2.0.x - '@vitest/snapshot': 2.0.x - vitest: 2.0.x + '@vitest/runner': 2.0.x - 2.1.x + '@vitest/snapshot': 2.0.x - 2.1.x + vitest: 2.0.x - 2.1.x dependencies: - '@vitest/runner': 2.0.5 - '@vitest/snapshot': 2.0.5 + '@vitest/runner': 2.1.8 + '@vitest/snapshot': 2.1.8 birpc: 0.2.14 cjs-module-lexer: 1.4.1 devalue: 4.3.3 esbuild: 0.17.19 - miniflare: 3.20240909.1 + miniflare: 3.20241106.1 semver: 7.6.3 vitest: 2.0.5 - wrangler: 3.78.2(@cloudflare/workers-types@4.20241202.0) + wrangler: 3.91.0(@cloudflare/workers-types@4.20241202.0) zod: 3.23.8 transitivePeerDependencies: - '@cloudflare/workers-types' @@ -70,8 +63,8 @@ packages: - utf-8-validate dev: true - /@cloudflare/workerd-darwin-64@1.20240610.1: - resolution: {integrity: sha512-YanZ1iXgMGaUWlleB5cswSE6qbzyjQ8O7ENWZcPAcZZ6BfuL7q3CWi0t9iM1cv2qx92rRztsRTyjcfq099++XQ==} + /@cloudflare/workerd-darwin-64@1.20241106.1: + resolution: {integrity: sha512-zxvaToi1m0qzAScrxFt7UvFVqU8DxrCO2CinM1yQkv5no7pA1HolpIrwZ0xOhR3ny64Is2s/J6BrRjpO5dM9Zw==} engines: {node: '>=16'} cpu: [x64] os: [darwin] @@ -79,26 +72,8 @@ packages: dev: true optional: true - /@cloudflare/workerd-darwin-64@1.20240909.0: - resolution: {integrity: sha512-nJ8jm/6PR8DPzVb4QifNAfSdrFZXNblwIdOhLTU5FpSvFFocmzFX5WgzQagvtmcC9/ZAQyxuf7WynDNyBcoe0Q==} - engines: {node: '>=16'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@cloudflare/workerd-darwin-arm64@1.20240610.1: - resolution: {integrity: sha512-bRe/y/LKjIgp3L2EHjc+CvoCzfHhf4aFTtOBkv2zW+VToNJ4KlXridndf7LvR9urfsFRRo9r4TXCssuKaU+ypQ==} - engines: {node: '>=16'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@cloudflare/workerd-darwin-arm64@1.20240909.0: - resolution: {integrity: sha512-gJqKa811oSsoxy9xuoQn7bS0Hr1sY+o3EUORTcEnulG6Kz9NQ6nd8QNdp2Hrk2jmmSqwrNkn+a6PZkWzk6Q0Gw==} + /@cloudflare/workerd-darwin-arm64@1.20241106.1: + resolution: {integrity: sha512-j3dg/42D/bPgfNP3cRUBxF+4waCKO/5YKwXNj+lnVOwHxDu+ne5pFw9TIkKYcWTcwn0ZUkbNZNM5rhJqRn4xbg==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] @@ -106,8 +81,8 @@ packages: dev: true optional: true - /@cloudflare/workerd-linux-64@1.20240610.1: - resolution: {integrity: sha512-2zDcadR7+Gs9SjcMXmwsMji2Xs+yASGNA2cEHDuFc4NMUup+eL1mkzxc/QzvFjyBck98e92rBjMZt2dVscpGKg==} + /@cloudflare/workerd-linux-64@1.20241106.1: + resolution: {integrity: sha512-Ih+Ye8E1DMBXcKrJktGfGztFqHKaX1CeByqshmTbODnWKHt6O65ax3oTecUwyC0+abuyraOpAtdhHNpFMhUkmw==} engines: {node: '>=16'} cpu: [x64] os: [linux] @@ -115,17 +90,8 @@ packages: dev: true optional: true - /@cloudflare/workerd-linux-64@1.20240909.0: - resolution: {integrity: sha512-sJrmtccfMg73sZljiBpe4R+lhF58TqzqhF2pQG8HRjyxkzkM1sjpZqfEFaIkNUDqd3/Ibji49fklhPCGXljKSg==} - engines: {node: '>=16'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@cloudflare/workerd-linux-arm64@1.20240610.1: - resolution: {integrity: sha512-7y41rPi5xmIYJN8CY+t3RHnjLL0xx/WYmaTd/j552k1qSr02eTE2o/TGyWZmGUC+lWnwdPQJla0mXbvdqgRdQg==} + /@cloudflare/workerd-linux-arm64@1.20241106.1: + resolution: {integrity: sha512-mdQFPk4+14Yywn7n1xIzI+6olWM8Ybz10R7H3h+rk0XulMumCWUCy1CzIDauOx6GyIcSgKIibYMssVHZR30ObA==} engines: {node: '>=16'} cpu: [arm64] os: [linux] @@ -133,26 +99,8 @@ packages: dev: true optional: true - /@cloudflare/workerd-linux-arm64@1.20240909.0: - resolution: {integrity: sha512-dTbSdceyRXPOSER+18AwYRbPQG0e/Dwl2trmfMMCETkfJhNLv1fU3FFMJPjfILijKnhTZHSnHCx0+xwHdon2fg==} - engines: {node: '>=16'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@cloudflare/workerd-windows-64@1.20240610.1: - resolution: {integrity: sha512-B0LyT3DB6rXHWNptnntYHPaoJIy0rXnGfeDBM3nEVV8JIsQrx8MEFn2F2jYioH1FkUVavsaqKO/zUosY3tZXVA==} - engines: {node: '>=16'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@cloudflare/workerd-windows-64@1.20240909.0: - resolution: {integrity: sha512-/d4BT0kcWFa7Qc0K4K9+cwVQ1qyPNKiO42JZUijlDlco+TYTPkLO3qGEohmwbfMq+BieK7JTMSgjO81ZHpA0HQ==} + /@cloudflare/workerd-windows-64@1.20241106.1: + resolution: {integrity: sha512-4rtcss31E/Rb/PeFocZfr+B9i1MdrkhsTBWizh8siNR4KMmkslU2xs2wPaH1z8+ErxkOsHrKRa5EPLh5rIiFeg==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -160,8 +108,8 @@ packages: dev: true optional: true - /@cloudflare/workers-shared@0.5.3: - resolution: {integrity: sha512-Yk5Im7zsyKbzd7qi+DrL7ZJR9+bdZwq9BqZWS4muDIWA8MCUeSLsUC+C9u+jdwfPSi5It2AcQG4f0iwZr6jkkQ==} + /@cloudflare/workers-shared@0.9.0: + resolution: {integrity: sha512-eP6Ir45uPbKnpADVzUCtkRUYxYxjB1Ew6n/whTJvHu8H4m93USHAceCMm736VBZdlxuhXXUjEP3fCUxKPn+cfw==} engines: {node: '>=16.7.0'} dependencies: mime: 3.0.0 @@ -832,6 +780,13 @@ packages: pathe: 1.1.2 dev: true + /@vitest/runner@2.1.8: + resolution: {integrity: sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==} + dependencies: + '@vitest/utils': 2.1.8 + pathe: 1.1.2 + dev: true + /@vitest/snapshot@2.0.5: resolution: {integrity: sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==} dependencies: @@ -840,6 +795,14 @@ packages: pathe: 1.1.2 dev: true + /@vitest/snapshot@2.1.8: + resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} + dependencies: + '@vitest/pretty-format': 2.1.8 + magic-string: 0.30.14 + pathe: 1.1.2 + dev: true + /@vitest/spy@2.0.5: resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==} dependencies: @@ -855,6 +818,14 @@ packages: tinyrainbow: 1.2.0 dev: true + /@vitest/utils@2.1.8: + resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} + dependencies: + '@vitest/pretty-format': 2.1.8 + loupe: 3.1.2 + tinyrainbow: 1.2.0 + dev: true + /acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -868,14 +839,6 @@ packages: hasBin: true dev: true - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - /as-table@1.0.55: resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} dependencies: @@ -887,11 +850,6 @@ packages: engines: {node: '>=12'} dev: true - /binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - dev: true - /birpc@0.2.14: resolution: {integrity: sha512-37FHE8rqsYM5JEKCnXFyHpBCzvgHEExwVVTq+nUmloInU7l8ezD1TpOhKpS8oe1DTYFqEK27rFZVKG43oTqXRA==} dev: true @@ -900,13 +858,6 @@ packages: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} dev: true - /braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.1.1 - dev: true - /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -937,30 +888,17 @@ packages: engines: {node: '>= 16'} dev: true - /chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} + /chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 + readdirp: 4.0.2 dev: true /cjs-module-lexer@1.4.1: resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} dev: true - /consola@3.2.3: - resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} - engines: {node: ^14.18.0 || >=16.10.0} - dev: true - /cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} @@ -979,8 +917,8 @@ packages: resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} dev: true - /date-fns@3.6.0: - resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + /date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} dev: true /debug@4.3.7: @@ -1104,13 +1042,6 @@ packages: engines: {node: '>=6'} dev: true - /fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - dev: true - /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1135,13 +1066,6 @@ packages: engines: {node: '>=16'} dev: true - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - dev: true - /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} dev: true @@ -1158,13 +1082,6 @@ packages: engines: {node: '>=16.17.0'} dev: true - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - dependencies: - binary-extensions: 2.3.0 - dev: true - /is-core-module@2.15.1: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} @@ -1172,23 +1089,6 @@ packages: hasown: 2.0.2 dev: true - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true - /is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1198,6 +1098,10 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true + /itty-time@1.0.6: + resolution: {integrity: sha512-+P8IZaLLBtFv8hCkIjcymZOp4UJ+xW6bSlQsXGqrkmJh7vSiMFSlNne0mCYagEE0N7HDNR5jJBRxwN0oYv61Rw==} + dev: true + /loupe@3.1.2: resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} dev: true @@ -1229,31 +1133,8 @@ packages: engines: {node: '>=12'} dev: true - /miniflare@3.20240610.0: - resolution: {integrity: sha512-J6aXmkII5gcq+kC4TurxKiR4rC++apPST/K8P/YjqoQQgrJ+NRPacBhf6iVh8R3ujnXYXaq+Ae+gm+LM0XHK/w==} - engines: {node: '>=16.13'} - hasBin: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - acorn: 8.14.0 - acorn-walk: 8.3.4 - capnp-ts: 0.7.0 - exit-hook: 2.2.1 - glob-to-regexp: 0.4.1 - stoppable: 1.1.0 - undici: 5.28.4 - workerd: 1.20240610.1 - ws: 8.18.0 - youch: 3.3.4 - zod: 3.23.8 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /miniflare@3.20240909.1: - resolution: {integrity: sha512-tdzJFApHmqFYlpjfpqBDnsE6dHUDLHejBrNgXftLfTf/ni5NySgXKnuntCCMdRtnTpjUKmkHiusGrBCf9b1rnA==} + /miniflare@3.20241106.1: + resolution: {integrity: sha512-dM3RBlJE8rUFxnqlPCaFCq0E7qQqEQvKbYX7W/APGCK+rLcyLmEBzC4GQR/niXdNM/oV6gdg9AA50ghnn2ALuw==} engines: {node: '>=16.13'} hasBin: true dependencies: @@ -1265,7 +1146,7 @@ packages: glob-to-regexp: 0.4.1 stoppable: 1.1.0 undici: 5.28.4 - workerd: 1.20240909.0 + workerd: 1.20241106.1 ws: 8.18.0 youch: 3.3.4 zod: 3.23.8 @@ -1290,20 +1171,11 @@ packages: hasBin: true dev: true - /node-fetch-native@1.6.4: - resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} - dev: true - /node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} dev: true - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true - /npm-run-path@5.3.0: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1353,11 +1225,6 @@ packages: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} dev: true - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true - /postcss@8.4.49: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} @@ -1371,11 +1238,9 @@ packages: resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} dev: true - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - dependencies: - picomatch: 2.3.1 + /readdirp@4.0.2: + resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} + engines: {node: '>= 14.16.0'} dev: true /resolve.exports@2.0.3: @@ -1540,19 +1405,12 @@ packages: engines: {node: '>=14.0.0'} dev: true - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - dev: true - /tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} dev: true - /typescript@5.5.2: - resolution: {integrity: sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==} + /typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} engines: {node: '>=14.17'} hasBin: true dev: true @@ -1572,19 +1430,8 @@ packages: '@fastify/busboy': 2.1.1 dev: true - /unenv-nightly@1.10.0-1717606461.a117952: - resolution: {integrity: sha512-u3TfBX02WzbHTpaEfWEKwDijDSFAHcgXkayUZ+MVDrjhLFvgAJzFGTSTmwlEhwWi2exyRQey23ah9wELMM6etg==} - dependencies: - consola: 3.2.3 - defu: 6.1.4 - mime: 3.0.0 - node-fetch-native: 1.6.4 - pathe: 1.1.2 - ufo: 1.5.4 - dev: true - - /unenv-nightly@2.0.0-1724863496.70db6f1: - resolution: {integrity: sha512-r+VIl1gnsI4WQxluruSQhy8alpAf1AsLRLm4sEKp3otCyTIVD6I6wHEYzeQnwsyWgaD4+3BD4A/eqrgOpdTzhw==} + /unenv-nightly@2.0.0-20241121-161142-806b5c0: + resolution: {integrity: sha512-RnFOasE/O0Q55gBkNB1b84OgKttgLEijGO0JCWpbn+O4XxpyCQg89NmcqQ5RGUiy4y+rMIrKzePTquQcLQF5pQ==} dependencies: defu: 6.1.4 ohash: 1.1.4 @@ -1724,94 +1571,48 @@ packages: stackback: 0.0.2 dev: true - /workerd@1.20240610.1: - resolution: {integrity: sha512-Rtut5GrsODQMh6YU43b9WZ980Wd05Ov1/ds88pT/SoetmXFBvkBzdRfiHiATv+azmGX8KveE0i/Eqzk/yI01ug==} + /workerd@1.20241106.1: + resolution: {integrity: sha512-1GdKl0kDw8rrirr/ThcK66Kbl4/jd4h8uHx5g7YHBrnenY5SX1UPuop2cnCzYUxlg55kPjzIqqYslz1muRFgFw==} engines: {node: '>=16'} hasBin: true requiresBuild: true optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20240610.1 - '@cloudflare/workerd-darwin-arm64': 1.20240610.1 - '@cloudflare/workerd-linux-64': 1.20240610.1 - '@cloudflare/workerd-linux-arm64': 1.20240610.1 - '@cloudflare/workerd-windows-64': 1.20240610.1 - dev: true - - /workerd@1.20240909.0: - resolution: {integrity: sha512-NwuYh/Fgr/MK0H+Ht687sHl/f8tumwT5CWzYR0MZMHri8m3CIYu2IaY4tBFWoKE/tOU1Z5XjEXECa9zXY4+lwg==} - engines: {node: '>=16'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20240909.0 - '@cloudflare/workerd-darwin-arm64': 1.20240909.0 - '@cloudflare/workerd-linux-64': 1.20240909.0 - '@cloudflare/workerd-linux-arm64': 1.20240909.0 - '@cloudflare/workerd-windows-64': 1.20240909.0 - dev: true - - /wrangler@3.60.3(@cloudflare/workers-types@4.20241202.0): - resolution: {integrity: sha512-a6zn/KFnYaYp3nxJR/aP0TeaBvJDkrrfI89KoxUtx28H7zpya/5/VLu3CxQ3PRspEojJGF0s6f3/pddRy3F+BQ==} - engines: {node: '>=16.17.0'} - hasBin: true - peerDependencies: - '@cloudflare/workers-types': ^4.20240605.0 - peerDependenciesMeta: - '@cloudflare/workers-types': - optional: true - dependencies: - '@cloudflare/kv-asset-handler': 0.3.2 - '@cloudflare/workers-types': 4.20241202.0 - '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) - '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) - blake3-wasm: 2.1.5 - chokidar: 3.6.0 - esbuild: 0.17.19 - miniflare: 3.20240610.0 - nanoid: 3.3.8 - path-to-regexp: 6.3.0 - resolve: 1.22.8 - resolve.exports: 2.0.3 - selfsigned: 2.4.1 - source-map: 0.6.1 - unenv: /unenv-nightly@1.10.0-1717606461.a117952 - xxhash-wasm: 1.1.0 - optionalDependencies: - fsevents: 2.3.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate + '@cloudflare/workerd-darwin-64': 1.20241106.1 + '@cloudflare/workerd-darwin-arm64': 1.20241106.1 + '@cloudflare/workerd-linux-64': 1.20241106.1 + '@cloudflare/workerd-linux-arm64': 1.20241106.1 + '@cloudflare/workerd-windows-64': 1.20241106.1 dev: true - /wrangler@3.78.2(@cloudflare/workers-types@4.20241202.0): - resolution: {integrity: sha512-PL7GchswGrNm2OvdSw5yG3ZAqNjpaQIO++p8E1TaCi63DSyssKFYeYqTvfFshsQPP2u1dox5JFXtLc6IE/m1xw==} + /wrangler@3.91.0(@cloudflare/workers-types@4.20241202.0): + resolution: {integrity: sha512-Hdzn6wbY9cz5kL85ZUvWLwLIH7nPaEVRblfms40jhRf4qQO/Zf74aFlku8rQFbe8/2aVZFaxJVfBd6JQMeMSBQ==} engines: {node: '>=16.17.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20240909.0 + '@cloudflare/workers-types': ^4.20241106.0 peerDependenciesMeta: '@cloudflare/workers-types': optional: true dependencies: '@cloudflare/kv-asset-handler': 0.3.4 - '@cloudflare/workers-shared': 0.5.3 + '@cloudflare/workers-shared': 0.9.0 '@cloudflare/workers-types': 4.20241202.0 '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) blake3-wasm: 2.1.5 - chokidar: 3.6.0 - date-fns: 3.6.0 + chokidar: 4.0.1 + date-fns: 4.1.0 esbuild: 0.17.19 - miniflare: 3.20240909.1 + itty-time: 1.0.6 + miniflare: 3.20241106.1 nanoid: 3.3.8 path-to-regexp: 6.3.0 resolve: 1.22.8 resolve.exports: 2.0.3 selfsigned: 2.4.1 source-map: 0.6.1 - unenv: /unenv-nightly@2.0.0-1724863496.70db6f1 - workerd: 1.20240909.0 + unenv: /unenv-nightly@2.0.0-20241121-161142-806b5c0 + workerd: 1.20241106.1 xxhash-wasm: 1.1.0 optionalDependencies: fsevents: 2.3.3 diff --git a/src/index.ts b/src/index.ts index 9efd7ce..fbda4b6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,18 +1,159 @@ -/** - * Welcome to Cloudflare Workers! This is your first worker. - * - * - Run `npm run dev` in your terminal to start a development server - * - Open a browser tab at http://localhost:8787/ to see your worker in action - * - Run `npm run deploy` to publish your worker - * - * Bind resources to your worker in `wrangler.toml`. After adding bindings, a type definition for the - * `Env` object can be regenerated with `npm run cf-typegen`. - * - * Learn more at https://developers.cloudflare.com/workers/ - */ +const DOCKER_HUB = 'https://registry-1.docker.io'; +const PROXY_MAP: Record = { + [`docker.`]: DOCKER_HUB, + [`quay.`]: 'https://quay.io', + [`gcr.`]: 'https://gcr.io', + [`k8s-gcr.`]: 'https://k8s.gcr.io', + [`k8s.`]: 'https://registry.k8s.io', + [`ghcr.`]: 'https://ghcr.io', + [`cloudsmith.`]: 'https://docker.cloudsmith.io', + [`ecr.`]: 'https://public.ecr.aws' +}; + +function getUpstream(hostname: string): string { + for (const [prefix, upstream] of Object.entries(PROXY_MAP)) { + if (hostname.startsWith(prefix)) { + return upstream; + } + } + + throw new Error(`No upstream found for ${hostname}`); +} + +async function upstream_v2(url: URL, authorization: string | null): Promise { + const newUrl = URL.parse('/v2/', getUpstream(url.hostname)); + if (!newUrl) { + return new Response('Invalid upstream', { status: 500 }); + } + + const headers = new Headers(); + if (authorization) { + headers.set('Authorization', authorization); + } + + const res = await fetch(newUrl.toString(), { method: 'GET', headers, redirect: 'follow' }); + if (res.status === 401) { + return new Response(res.statusText, { + status: res.status, + headers: { 'WWW-Authenticate': `Bearer realm="https://${url.hostname}/v2/auth",service="cloudflare-docker-proxy` } + }); + } + + return res; +} + +async function upstream_v2_auth(url: URL, authorization: string | null): Promise { + const upstream = getUpstream(url.hostname); + const newUrl = URL.parse('/v2/', upstream); + if (!newUrl) { + return new Response('Invalid upstream', { status: 500 }); + } + + const res = await fetch(newUrl.toString(), { method: 'GET', redirect: 'follow' }); + if (res.status !== 401) { + return res; + } + + const wwwAuthenticate = res.headers.get('WWW-Authenticate'); + if (!wwwAuthenticate) { + return res; + } + + const authenticate = parseAuthenticate(wwwAuthenticate); + const isDockerHub = upstream === DOCKER_HUB; + let scope = url.searchParams.get('scope'); + + if (!!scope && isDockerHub) { + let scopeParts = scope.split(':'); + if (scopeParts.length === 3 && !scopeParts[1].includes('/')) { + scopeParts[1] = 'library/' + scopeParts[1]; + scope = scopeParts.join(':'); + } + } + + const realmUrl = new URL(authenticate.realm); + + if (authenticate.service.length) { + realmUrl.searchParams.set('service', authenticate.service); + } + + if (scope) { + realmUrl.searchParams.set('scope', scope); + } + + const headers = new Headers(); + if (authorization) { + headers.set('Authorization', authorization); + } + + return await fetch(realmUrl, { method: 'GET', headers }); +} + +function parseAuthenticate(authenticate: string) { + // sample: Bearer realm="https://auth.ipv6.docker.com/token",service="registry.docker.io" + // match strings after =" and before " + const reg = /(?<==")(?:\\.|[^"\\])*(?=")/g; + const matches = authenticate.match(reg); + if (matches == null || matches.length < 2) { + throw new Error(`invalid Www-Authenticate Header: ${authenticate}`); + } + return { + realm: matches[0], + service: matches[1] + }; +} export default { async fetch(request, env, ctx): Promise { - return new Response('Hello World!'); - }, + try { + + const url = new URL(request.url); + const authorization = request.headers.get('Authorization'); + + if (url.pathname === '/v2/') { + return await upstream_v2(url, authorization); + } + + if (url.pathname === '/v2/auth') { + return await upstream_v2_auth(url, authorization); + } + + + const upstream = getUpstream(url.hostname); + const isDockerHub = upstream === DOCKER_HUB; + + if (isDockerHub) { + const pathParts = url.pathname.split('/'); + if (pathParts.length === 5) { + pathParts.splice(2, 0, 'library'); + const redirectUrl = new URL(url); + redirectUrl.pathname = pathParts.join('/'); + return Response.redirect(redirectUrl.toString(), 302); + } + } + + const proxyUrl = URL.parse(url.pathname, upstream); + if (!proxyUrl) { + return new Response('Invalid upstream', { status: 500 }); + } + + const req = new Request(proxyUrl, { + method: request.method, + headers: request.headers, + redirect: 'follow' + }); + + const res = await fetch(req); + if (res.status === 401) { + return new Response(res.statusText, { + status: res.status, + headers: { 'WWW-Authenticate': `Bearer realm="https://${url.hostname}/v2/auth",service="cloudflare-docker-proxy` } + }); + } + + return res; + } catch (e: any) { + return new Response(e.message, { status: 500 }); + } + } } satisfies ExportedHandler; diff --git a/worker-configuration.d.ts b/worker-configuration.d.ts index 5b2319b..d846b6e 100644 --- a/worker-configuration.d.ts +++ b/worker-configuration.d.ts @@ -1,4 +1,5 @@ -// Generated by Wrangler -// After adding bindings to `wrangler.toml`, regenerate this interface via `npm run cf-typegen` +// Generated by Wrangler by running `wrangler types` + +// eslint-disable-next-line @typescript-eslint/no-empty-interface,@typescript-eslint/no-empty-object-type interface Env { } diff --git a/wrangler.toml b/wrangler.toml index 58ba959..dfb8d8a 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -4,11 +4,23 @@ main = "src/index.ts" compatibility_date = "2024-12-02" compatibility_flags = ["nodejs_compat"] +# 发布时配置自己的域名前缀 +routes = [ + { pattern = "docker.xxx.com", custom_domain = true }, + { pattern = "k8s.xxx.com", custom_domain = true } +] +workers_dev = false + # Workers Logs # Docs: https://developers.cloudflare.com/workers/observability/logs/workers-logs/ # Configuration: https://developers.cloudflare.com/workers/observability/logs/workers-logs/#enable-workers-logs [observability] +enabled = false + +[observability.logs] enabled = true +head_sampling_rate = 1 +invocation_logs = true # Automatically place your workloads in an optimal location to minimize latency. # If you are running back-end logic in a Worker, running it closer to your back-end infrastructure @@ -22,8 +34,8 @@ enabled = true # - https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables # Note: Use secrets to store sensitive data. # - https://developers.cloudflare.com/workers/configuration/secrets/ -# [vars] -# MY_VARIABLE = "production_value" +#[vars] +#CUSTOM_DOMAIN = "" # Bind the Workers AI model catalog. Run machine learning models, powered by serverless GPUs, on Cloudflare’s global network # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#workers-ai