diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 20cb85f..b483067 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 with: - version: 9.9 + version: 9.9.0 - name: Use Node uses: actions/setup-node@v4 with: diff --git a/README.md b/README.md index 3bdc13c..ea860f2 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,8 @@ the target registry and setup the credentials. Right now there is some limitations with this container registry. - Pushing with docker is limited to images that have layers of maximum size 500MB. Refer to maximum request body sizes in your Workers plan. -- To circumvent that limitation, you can manually add the layer and the manifest into the R2 bucket or use a client that is able to chunk uploads in sizes less than 500MB (or the limit that you have in your Workers plan). +- To circumvent that limitation, you can either manually interact with the R2 bucket to upload the layer or take a + peek at the `./push` folder for some inspiration on how can you push big layers. - If you use `npx wrangler dev` and push to the R2 registry with docker, the R2 registry will have to buffer the request on the Worker. ## License diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e98e31c..0dbefa0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,45 +16,41 @@ importers: version: 1.12.5 '@tsndr/cloudflare-worker-jwt': specifier: ^2.5.1 - version: 2.5.1 + version: 2.5.3 itty-router: specifier: ^4.0.27 - version: 4.0.27 + version: 4.2.2 zod: specifier: ^3.22.4 - version: 3.22.4 + version: 3.23.8 devDependencies: '@cloudflare/vitest-pool-workers': specifier: ^0.5.7 - version: 0.5.7(@cloudflare/workers-types@4.20240614.0)(@vitest/runner@2.1.1)(@vitest/snapshot@2.1.1)(vitest@2.1.1(@types/node@18.15.3)) + version: 0.5.10(@cloudflare/workers-types@4.20240925.0)(@vitest/runner@2.1.1)(@vitest/snapshot@2.1.1)(vitest@2.1.1(@types/node@18.15.3)) '@cloudflare/workers-types': specifier: ^4.20240614.0 - version: 4.20240614.0 + version: 4.20240925.0 cross-env: specifier: ^7.0.3 version: 7.0.3 eslint: specifier: ^8.57.0 - version: 8.57.0 + version: 8.57.1 miniflare: specifier: 3.20240909.4 version: 3.20240909.4 typescript: specifier: ^5.3.3 - version: 5.3.3 + version: 5.6.2 vitest: specifier: ^2.1.0 version: 2.1.1(@types/node@18.15.3) wrangler: specifier: ^3.78.7 - version: 3.78.7(@cloudflare/workers-types@4.20240614.0) + version: 3.78.10(@cloudflare/workers-types@4.20240925.0) packages: - '@aashutoshrathi/word-wrap@1.2.6': - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - '@cfworker/base64url@1.12.5': resolution: {integrity: sha512-pNLrz0D0MguzFLJisBUv+XOTkpRpRTIMI7/r2QwTWI2MR5VJ7Hysd6ug6DBWksKFy7TK3hCf+qejufdJSN5X+A==} @@ -62,8 +58,8 @@ packages: resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} engines: {node: '>=16.13'} - '@cloudflare/vitest-pool-workers@0.5.7': - resolution: {integrity: sha512-CNMmp0nk0IpVGX/B2mYA2os70K9qkYDnEbj80+r9mrsKO+fxMUoKqoGIDUxiajRVJLxAPwUW4ZsKSGpY65I12A==} + '@cloudflare/vitest-pool-workers@0.5.10': + resolution: {integrity: sha512-BOwbD5u7b1Mko7SXgRHgvNxgUvu9jV6iCY8/q1ETX9ajZ9l0jyPTuFezRph/nfvtJiizi5JRzDSRQqFLaHX2ZA==} peerDependencies: '@vitest/runner': 2.0.x - 2.1.x '@vitest/snapshot': 2.0.x - 2.1.x @@ -75,36 +71,66 @@ packages: cpu: [x64] os: [darwin] + '@cloudflare/workerd-darwin-64@1.20240925.0': + resolution: {integrity: sha512-KdLnSXuzB65CbqZPm+qYzk+zkQ1tUNPaaRGYVd/jPYAxwwtfTUQdQ+ahDPwVVs2tmQELKy7ZjQjf2apqSWUfjw==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + '@cloudflare/workerd-darwin-arm64@1.20240909.0': resolution: {integrity: sha512-gJqKa811oSsoxy9xuoQn7bS0Hr1sY+o3EUORTcEnulG6Kz9NQ6nd8QNdp2Hrk2jmmSqwrNkn+a6PZkWzk6Q0Gw==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] + '@cloudflare/workerd-darwin-arm64@1.20240925.0': + resolution: {integrity: sha512-MiQ6uUmCXjsXgWNV+Ock2tp2/tYqNJGzjuaH6jFioeRF+//mz7Tv7J7EczOL4zq+TH8QFOh0/PUsLyazIWVGng==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + '@cloudflare/workerd-linux-64@1.20240909.0': resolution: {integrity: sha512-sJrmtccfMg73sZljiBpe4R+lhF58TqzqhF2pQG8HRjyxkzkM1sjpZqfEFaIkNUDqd3/Ibji49fklhPCGXljKSg==} engines: {node: '>=16'} cpu: [x64] os: [linux] + '@cloudflare/workerd-linux-64@1.20240925.0': + resolution: {integrity: sha512-Rjix8jsJMfsInmq3Hm3fmiRQ+rwzuWRPV1pg/OWhMSfNP7Qp2RCU+RGkhgeR9Z5eNAje0Sn2BMrFq4RvF9/yRA==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + '@cloudflare/workerd-linux-arm64@1.20240909.0': resolution: {integrity: sha512-dTbSdceyRXPOSER+18AwYRbPQG0e/Dwl2trmfMMCETkfJhNLv1fU3FFMJPjfILijKnhTZHSnHCx0+xwHdon2fg==} engines: {node: '>=16'} cpu: [arm64] os: [linux] + '@cloudflare/workerd-linux-arm64@1.20240925.0': + resolution: {integrity: sha512-VYIPeMHQRtbwQoIjUwS/zULlywPxyDvo46XkTpIW5MScEChfqHvAYviQ7TzYGx6Q+gmZmN+DUB2KOMx+MEpCxA==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + '@cloudflare/workerd-windows-64@1.20240909.0': resolution: {integrity: sha512-/d4BT0kcWFa7Qc0K4K9+cwVQ1qyPNKiO42JZUijlDlco+TYTPkLO3qGEohmwbfMq+BieK7JTMSgjO81ZHpA0HQ==} engines: {node: '>=16'} cpu: [x64] os: [win32] - '@cloudflare/workers-shared@0.5.3': - resolution: {integrity: sha512-Yk5Im7zsyKbzd7qi+DrL7ZJR9+bdZwq9BqZWS4muDIWA8MCUeSLsUC+C9u+jdwfPSi5It2AcQG4f0iwZr6jkkQ==} + '@cloudflare/workerd-windows-64@1.20240925.0': + resolution: {integrity: sha512-C8peGvaU5R51bIySi1VbyfRgwNSSRknqoFSnSbSBI3uTN3THTB3UnmRKy7GXJDmyjgXuT9Pcs1IgaWNubLtNtw==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + + '@cloudflare/workers-shared@0.5.4': + resolution: {integrity: sha512-PNL/0TjKRdUHa1kwgVdqUNJVZ9ez4kacsi8omz+gv859EvJmsVuGiMAClY2YfJnC9LVKhKCcjqmFgKNXG9/IXA==} engines: {node: '>=16.7.0'} - '@cloudflare/workers-types@4.20240614.0': - resolution: {integrity: sha512-fnV3uXD1Hpq5EWnY7XYb+smPcjzIoUFiZpTSV/Tk8qKL3H+w6IqcngZwXQBZ/2U/DwYkDilXHW3FfPhnyD7FZA==} + '@cloudflare/workers-types@4.20240925.0': + resolution: {integrity: sha512-KpqyRWvanEuXgBTKYFzRp4NsWOEcswxjsPRSre1zYQcODmc8PUrraVHQUmgvkJgv3FzB+vI9xm7J6oE4MmZHCA==} '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} @@ -120,8 +146,8 @@ packages: peerDependencies: esbuild: '*' - '@esbuild/aix-ppc64@0.20.2': - resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] @@ -132,8 +158,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.20.2': - resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -144,8 +170,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.20.2': - resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -156,8 +182,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.20.2': - resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -168,8 +194,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.20.2': - resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -180,8 +206,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.20.2': - resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -192,8 +218,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.20.2': - resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -204,8 +230,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.20.2': - resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -216,8 +242,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.20.2': - resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -228,8 +254,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.20.2': - resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -240,8 +266,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.20.2': - resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -252,8 +278,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.20.2': - resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -264,8 +290,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.20.2': - resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -276,8 +302,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.20.2': - resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -288,8 +314,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.20.2': - resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -300,8 +326,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.20.2': - resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -312,8 +338,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.20.2': - resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -324,8 +350,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.20.2': - resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -336,8 +362,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.20.2': - resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -348,8 +374,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.20.2': - resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -360,8 +386,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.20.2': - resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -372,8 +398,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.20.2': - resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -384,8 +410,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.20.2': - resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -396,40 +422,39 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.10.0': - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + '@eslint-community/regexpp@4.11.1': + resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} '@eslint/eslintrc@2.1.4': resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/js@8.57.0': - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} - '@humanwhocodes/config-array@0.11.14': - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@2.0.2': - resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.4.15': - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} @@ -448,87 +473,95 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@rollup/rollup-android-arm-eabi@4.14.0': - resolution: {integrity: sha512-jwXtxYbRt1V+CdQSy6Z+uZti7JF5irRKF8hlKfEnF/xJpcNGuuiZMBvuoYM+x9sr9iWGnzrlM0+9hvQ1kgkf1w==} + '@rollup/rollup-android-arm-eabi@4.22.4': + resolution: {integrity: sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.14.0': - resolution: {integrity: sha512-fI9nduZhCccjzlsA/OuAwtFGWocxA4gqXGTLvOyiF8d+8o0fZUeSztixkYjcGq1fGZY3Tkq4yRvHPFxU+jdZ9Q==} + '@rollup/rollup-android-arm64@4.22.4': + resolution: {integrity: sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.14.0': - resolution: {integrity: sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA==} + '@rollup/rollup-darwin-arm64@4.22.4': + resolution: {integrity: sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.14.0': - resolution: {integrity: sha512-LDyFB9GRolGN7XI6955aFeI3wCdCUszFWumWU0deHA8VpR3nWRrjG6GtGjBrQxQKFevnUTHKCfPR4IvrW3kCgQ==} + '@rollup/rollup-darwin-x64@4.22.4': + resolution: {integrity: sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.14.0': - resolution: {integrity: sha512-ygrGVhQP47mRh0AAD0zl6QqCbNsf0eTo+vgwkY6LunBcg0f2Jv365GXlDUECIyoXp1kKwL5WW6rsO429DBY/bA==} + '@rollup/rollup-linux-arm-gnueabihf@4.22.4': + resolution: {integrity: sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.14.0': - resolution: {integrity: sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A==} + '@rollup/rollup-linux-arm-musleabihf@4.22.4': + resolution: {integrity: sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.22.4': + resolution: {integrity: sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.14.0': - resolution: {integrity: sha512-nrRw8ZTQKg6+Lttwqo6a2VxR9tOroa2m91XbdQ2sUUzHoedXlsyvY1fN4xWdqz8PKmf4orDwejxXHjh7YBGUCA==} + '@rollup/rollup-linux-arm64-musl@4.22.4': + resolution: {integrity: sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.14.0': - resolution: {integrity: sha512-xV0d5jDb4aFu84XKr+lcUJ9y3qpIWhttO3Qev97z8DKLXR62LC3cXT/bMZXrjLF9X+P5oSmJTzAhqwUbY96PnA==} - cpu: [ppc64le] + '@rollup/rollup-linux-powerpc64le-gnu@4.22.4': + resolution: {integrity: sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==} + cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.14.0': - resolution: {integrity: sha512-SDDhBQwZX6LPRoPYjAZWyL27LbcBo7WdBFWJi5PI9RPCzU8ijzkQn7tt8NXiXRiFMJCVpkuMkBf4OxSxVMizAw==} + '@rollup/rollup-linux-riscv64-gnu@4.22.4': + resolution: {integrity: sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.14.0': - resolution: {integrity: sha512-RxB/qez8zIDshNJDufYlTT0ZTVut5eCpAZ3bdXDU9yTxBzui3KhbGjROK2OYTTor7alM7XBhssgoO3CZ0XD3qA==} + '@rollup/rollup-linux-s390x-gnu@4.22.4': + resolution: {integrity: sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.14.0': - resolution: {integrity: sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg==} + '@rollup/rollup-linux-x64-gnu@4.22.4': + resolution: {integrity: sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.14.0': - resolution: {integrity: sha512-i0QwbHYfnOMYsBEyjxcwGu5SMIi9sImDVjDg087hpzXqhBSosxkE7gyIYFHgfFl4mr7RrXksIBZ4DoLoP4FhJg==} + '@rollup/rollup-linux-x64-musl@4.22.4': + resolution: {integrity: sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.14.0': - resolution: {integrity: sha512-Fq52EYb0riNHLBTAcL0cun+rRwyZ10S9vKzhGKKgeD+XbwunszSY0rVMco5KbOsTlwovP2rTOkiII/fQ4ih/zQ==} + '@rollup/rollup-win32-arm64-msvc@4.22.4': + resolution: {integrity: sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.14.0': - resolution: {integrity: sha512-e/PBHxPdJ00O9p5Ui43+vixSgVf4NlLsmV6QneGERJ3lnjIua/kim6PRFe3iDueT1rQcgSkYP8ZBBXa/h4iPvw==} + '@rollup/rollup-win32-ia32-msvc@4.22.4': + resolution: {integrity: sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.14.0': - resolution: {integrity: sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag==} + '@rollup/rollup-win32-x64-msvc@4.22.4': + resolution: {integrity: sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==} cpu: [x64] os: [win32] - '@tsndr/cloudflare-worker-jwt@2.5.1': - resolution: {integrity: sha512-MKB8jOdMcZZTeAovOBbAl2Z1PPmPiyceZUmCM0hlgHapQqOT1riQlvIFX6jOmfEpAhFGp0VaGAq995kr4mNMMg==} + '@tsndr/cloudflare-worker-jwt@2.5.3': + resolution: {integrity: sha512-zbdvjRG86y/ObiBgTJrzBC39t2FcaeGwB6AV7VO4LvHKJNyZvLYRbKT68eaoJhnJldyHhs7yZ69neRVdUd9knA==} '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} @@ -573,17 +606,12 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.3: - resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} - engines: {node: '>=0.4.0'} - - acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.12.0: - resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} engines: {node: '>=0.4.0'} hasBin: true @@ -688,18 +716,6 @@ packages: data-uri-to-buffer@2.0.2: resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} - date-fns@3.6.0: - resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} - - debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -731,8 +747,8 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.20.2: - resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true @@ -748,8 +764,8 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true @@ -757,8 +773,8 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -844,6 +860,7 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} @@ -860,8 +877,8 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} import-fresh@3.3.0: @@ -874,6 +891,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -882,8 +900,9 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} @@ -904,8 +923,8 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - itty-router@4.0.27: - resolution: {integrity: sha512-Q3/GOE2EJvyu3hhxGN3WDWh3QNg4v7h1KFx/jSLcIOOkpSI1jUFTgGefEESXon4j5YwqCIf0DEemjiVAFSBiUw==} + itty-router@4.2.2: + resolution: {integrity: sha512-KegPW0l9SNPadProoFT07AB84uOqLUwzlXQ7HsqkS31WUrxkjdhcemRpTDUuetbMJ89uBtWeQSVoiEmUAu31uw==} js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} @@ -953,12 +972,14 @@ packages: engines: {node: '>=16.13'} hasBin: true + miniflare@3.20240925.0: + resolution: {integrity: sha512-2LmQbKHf0n6ertUKhT+Iltixi53giqDH7P71+wCir3OnGyXIODqYwOECx1mSDNhYThpxM2dav8UdPn6SQiMoXw==} + engines: {node: '>=16.13'} + hasBin: true + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -988,8 +1009,8 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} p-limit@3.1.0: @@ -1029,15 +1050,15 @@ packages: resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} engines: {node: '>= 14.16'} - picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + postcss@8.4.47: + resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -1079,6 +1100,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rollup-plugin-inject@3.0.2: @@ -1091,8 +1113,8 @@ packages: rollup-pluginutils@2.8.2: resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - rollup@4.14.0: - resolution: {integrity: sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ==} + rollup@4.22.4: + resolution: {integrity: sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -1119,8 +1141,8 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} source-map@0.6.1: @@ -1185,8 +1207,8 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -1196,8 +1218,8 @@ packages: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} - typescript@5.3.3: - resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} + typescript@5.6.2: + resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} engines: {node: '>=14.17'} hasBin: true @@ -1219,8 +1241,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite@5.2.8: - resolution: {integrity: sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==} + vite@5.4.8: + resolution: {integrity: sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -1228,6 +1250,7 @@ packages: less: '*' lightningcss: ^1.21.0 sass: '*' + sass-embedded: '*' stylus: '*' sugarss: '*' terser: ^5.4.0 @@ -1240,6 +1263,8 @@ packages: optional: true sass: optional: true + sass-embedded: + optional: true stylus: optional: true sugarss: @@ -1282,17 +1307,26 @@ packages: engines: {node: '>=8'} hasBin: true + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + workerd@1.20240909.0: resolution: {integrity: sha512-NwuYh/Fgr/MK0H+Ht687sHl/f8tumwT5CWzYR0MZMHri8m3CIYu2IaY4tBFWoKE/tOU1Z5XjEXECa9zXY4+lwg==} engines: {node: '>=16'} hasBin: true - wrangler@3.78.7: - resolution: {integrity: sha512-z2ubdgQZ8lh2TEpvihFQOu3HmCNus78sC1LMBiSmgv133i4DeUMuz6SJglles2LayJAKrusjTqFnDYecA2XDDg==} + workerd@1.20240925.0: + resolution: {integrity: sha512-/Jj6+yLwfieZGEt3Kx4+5MoufuC3g/8iFaIh4MPBNGJOGYmdSKXvgCqz09m2+tVCYnysRfbq2zcbVxJRBfOCqQ==} + engines: {node: '>=16'} + hasBin: true + + wrangler@3.78.10: + resolution: {integrity: sha512-Q8Ia0xz0RCzj5X7TMIEQ/EbADSG2cWPmTDRaulGSWnYqfIlFyKoxl7Zx1XXCo1EkDcKfSpX6TZa22pCDmtl4LA==} engines: {node: '>=16.17.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20240909.0 + '@cloudflare/workers-types': ^4.20240925.0 peerDependenciesMeta: '@cloudflare/workers-types': optional: true @@ -1300,8 +1334,8 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.17.1: - resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -1322,13 +1356,11 @@ packages: youch@3.3.3: resolution: {integrity: sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==} - zod@3.22.4: - resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} snapshots: - '@aashutoshrathi/word-wrap@1.2.6': {} - '@cfworker/base64url@1.12.5': dependencies: rfc4648: 1.5.3 @@ -1337,7 +1369,7 @@ snapshots: dependencies: mime: 3.0.0 - '@cloudflare/vitest-pool-workers@0.5.7(@cloudflare/workers-types@4.20240614.0)(@vitest/runner@2.1.1)(@vitest/snapshot@2.1.1)(vitest@2.1.1(@types/node@18.15.3))': + '@cloudflare/vitest-pool-workers@0.5.10(@cloudflare/workers-types@4.20240925.0)(@vitest/runner@2.1.1)(@vitest/snapshot@2.1.1)(vitest@2.1.1(@types/node@18.15.3))': dependencies: '@vitest/runner': 2.1.1 '@vitest/snapshot': 2.1.1 @@ -1345,11 +1377,11 @@ snapshots: cjs-module-lexer: 1.4.1 devalue: 4.3.3 esbuild: 0.17.19 - miniflare: 3.20240909.4 + miniflare: 3.20240925.0 semver: 7.6.3 vitest: 2.1.1(@types/node@18.15.3) - wrangler: 3.78.7(@cloudflare/workers-types@4.20240614.0) - zod: 3.22.4 + wrangler: 3.78.10(@cloudflare/workers-types@4.20240925.0) + zod: 3.23.8 transitivePeerDependencies: - '@cloudflare/workers-types' - bufferutil @@ -1359,24 +1391,39 @@ snapshots: '@cloudflare/workerd-darwin-64@1.20240909.0': optional: true + '@cloudflare/workerd-darwin-64@1.20240925.0': + optional: true + '@cloudflare/workerd-darwin-arm64@1.20240909.0': optional: true + '@cloudflare/workerd-darwin-arm64@1.20240925.0': + optional: true + '@cloudflare/workerd-linux-64@1.20240909.0': optional: true + '@cloudflare/workerd-linux-64@1.20240925.0': + optional: true + '@cloudflare/workerd-linux-arm64@1.20240909.0': optional: true + '@cloudflare/workerd-linux-arm64@1.20240925.0': + optional: true + '@cloudflare/workerd-windows-64@1.20240909.0': optional: true - '@cloudflare/workers-shared@0.5.3': + '@cloudflare/workerd-windows-64@1.20240925.0': + optional: true + + '@cloudflare/workers-shared@0.5.4': dependencies: mime: 3.0.0 - zod: 3.22.4 + zod: 3.23.8 - '@cloudflare/workers-types@4.20240614.0': {} + '@cloudflare/workers-types@4.20240925.0': {} '@cspotcode/source-map-support@0.8.1': dependencies: @@ -1392,155 +1439,155 @@ snapshots: escape-string-regexp: 4.0.0 rollup-plugin-node-polyfills: 0.2.1 - '@esbuild/aix-ppc64@0.20.2': + '@esbuild/aix-ppc64@0.21.5': optional: true '@esbuild/android-arm64@0.17.19': optional: true - '@esbuild/android-arm64@0.20.2': + '@esbuild/android-arm64@0.21.5': optional: true '@esbuild/android-arm@0.17.19': optional: true - '@esbuild/android-arm@0.20.2': + '@esbuild/android-arm@0.21.5': optional: true '@esbuild/android-x64@0.17.19': optional: true - '@esbuild/android-x64@0.20.2': + '@esbuild/android-x64@0.21.5': optional: true '@esbuild/darwin-arm64@0.17.19': optional: true - '@esbuild/darwin-arm64@0.20.2': + '@esbuild/darwin-arm64@0.21.5': optional: true '@esbuild/darwin-x64@0.17.19': optional: true - '@esbuild/darwin-x64@0.20.2': + '@esbuild/darwin-x64@0.21.5': optional: true '@esbuild/freebsd-arm64@0.17.19': optional: true - '@esbuild/freebsd-arm64@0.20.2': + '@esbuild/freebsd-arm64@0.21.5': optional: true '@esbuild/freebsd-x64@0.17.19': optional: true - '@esbuild/freebsd-x64@0.20.2': + '@esbuild/freebsd-x64@0.21.5': optional: true '@esbuild/linux-arm64@0.17.19': optional: true - '@esbuild/linux-arm64@0.20.2': + '@esbuild/linux-arm64@0.21.5': optional: true '@esbuild/linux-arm@0.17.19': optional: true - '@esbuild/linux-arm@0.20.2': + '@esbuild/linux-arm@0.21.5': optional: true '@esbuild/linux-ia32@0.17.19': optional: true - '@esbuild/linux-ia32@0.20.2': + '@esbuild/linux-ia32@0.21.5': optional: true '@esbuild/linux-loong64@0.17.19': optional: true - '@esbuild/linux-loong64@0.20.2': + '@esbuild/linux-loong64@0.21.5': optional: true '@esbuild/linux-mips64el@0.17.19': optional: true - '@esbuild/linux-mips64el@0.20.2': + '@esbuild/linux-mips64el@0.21.5': optional: true '@esbuild/linux-ppc64@0.17.19': optional: true - '@esbuild/linux-ppc64@0.20.2': + '@esbuild/linux-ppc64@0.21.5': optional: true '@esbuild/linux-riscv64@0.17.19': optional: true - '@esbuild/linux-riscv64@0.20.2': + '@esbuild/linux-riscv64@0.21.5': optional: true '@esbuild/linux-s390x@0.17.19': optional: true - '@esbuild/linux-s390x@0.20.2': + '@esbuild/linux-s390x@0.21.5': optional: true '@esbuild/linux-x64@0.17.19': optional: true - '@esbuild/linux-x64@0.20.2': + '@esbuild/linux-x64@0.21.5': optional: true '@esbuild/netbsd-x64@0.17.19': optional: true - '@esbuild/netbsd-x64@0.20.2': + '@esbuild/netbsd-x64@0.21.5': optional: true '@esbuild/openbsd-x64@0.17.19': optional: true - '@esbuild/openbsd-x64@0.20.2': + '@esbuild/openbsd-x64@0.21.5': optional: true '@esbuild/sunos-x64@0.17.19': optional: true - '@esbuild/sunos-x64@0.20.2': + '@esbuild/sunos-x64@0.21.5': optional: true '@esbuild/win32-arm64@0.17.19': optional: true - '@esbuild/win32-arm64@0.20.2': + '@esbuild/win32-arm64@0.21.5': optional: true '@esbuild/win32-ia32@0.17.19': optional: true - '@esbuild/win32-ia32@0.20.2': + '@esbuild/win32-ia32@0.21.5': optional: true '@esbuild/win32-x64@0.17.19': optional: true - '@esbuild/win32-x64@0.20.2': + '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.1)': dependencies: - eslint: 8.57.0 + eslint: 8.57.1 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.10.0': {} + '@eslint-community/regexpp@4.11.1': {} '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.4 + debug: 4.3.7 espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.1 + ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -1548,32 +1595,30 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.0': {} + '@eslint/js@8.57.1': {} '@fastify/busboy@2.1.1': {} - '@humanwhocodes/config-array@0.11.14': + '@humanwhocodes/config-array@0.13.0': dependencies: - '@humanwhocodes/object-schema': 2.0.2 - debug: 4.3.4 + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@2.0.2': {} + '@humanwhocodes/object-schema@2.0.3': {} '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/sourcemap-codec@1.4.15': {} - '@jridgewell/sourcemap-codec@1.5.0': {} '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -1587,55 +1632,60 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@rollup/rollup-android-arm-eabi@4.14.0': + '@rollup/rollup-android-arm-eabi@4.22.4': optional: true - '@rollup/rollup-android-arm64@4.14.0': + '@rollup/rollup-android-arm64@4.22.4': optional: true - '@rollup/rollup-darwin-arm64@4.14.0': + '@rollup/rollup-darwin-arm64@4.22.4': optional: true - '@rollup/rollup-darwin-x64@4.14.0': + '@rollup/rollup-darwin-x64@4.22.4': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.14.0': + '@rollup/rollup-linux-arm-gnueabihf@4.22.4': optional: true - '@rollup/rollup-linux-arm64-gnu@4.14.0': + '@rollup/rollup-linux-arm-musleabihf@4.22.4': optional: true - '@rollup/rollup-linux-arm64-musl@4.14.0': + '@rollup/rollup-linux-arm64-gnu@4.22.4': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.14.0': + '@rollup/rollup-linux-arm64-musl@4.22.4': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.14.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.22.4': optional: true - '@rollup/rollup-linux-s390x-gnu@4.14.0': + '@rollup/rollup-linux-riscv64-gnu@4.22.4': optional: true - '@rollup/rollup-linux-x64-gnu@4.14.0': + '@rollup/rollup-linux-s390x-gnu@4.22.4': optional: true - '@rollup/rollup-linux-x64-musl@4.14.0': + '@rollup/rollup-linux-x64-gnu@4.22.4': optional: true - '@rollup/rollup-win32-arm64-msvc@4.14.0': + '@rollup/rollup-linux-x64-musl@4.22.4': optional: true - '@rollup/rollup-win32-ia32-msvc@4.14.0': + '@rollup/rollup-win32-arm64-msvc@4.22.4': optional: true - '@rollup/rollup-win32-x64-msvc@4.14.0': + '@rollup/rollup-win32-ia32-msvc@4.22.4': optional: true - '@tsndr/cloudflare-worker-jwt@2.5.1': {} + '@rollup/rollup-win32-x64-msvc@4.22.4': + optional: true + + '@tsndr/cloudflare-worker-jwt@2.5.3': {} '@types/estree@1.0.5': {} + '@types/estree@1.0.6': {} + '@types/node-forge@1.3.11': dependencies: '@types/node': 18.15.3 @@ -1651,13 +1701,13 @@ snapshots: chai: 5.1.1 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.2.8(@types/node@18.15.3))': + '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.8(@types/node@18.15.3))': dependencies: '@vitest/spy': 2.1.1 estree-walker: 3.0.3 magic-string: 0.30.11 optionalDependencies: - vite: 5.2.8(@types/node@18.15.3) + vite: 5.4.8(@types/node@18.15.3) '@vitest/pretty-format@2.1.1': dependencies: @@ -1684,17 +1734,15 @@ snapshots: loupe: 3.1.1 tinyrainbow: 1.2.0 - acorn-jsx@5.3.2(acorn@8.11.3): + acorn-jsx@5.3.2(acorn@8.12.1): dependencies: - acorn: 8.11.3 + acorn: 8.12.1 - acorn-walk@8.3.3: + acorn-walk@8.3.4: dependencies: - acorn: 8.12.0 + acorn: 8.12.1 - acorn@8.11.3: {} - - acorn@8.12.0: {} + acorn@8.12.1: {} ajv@6.12.6: dependencies: @@ -1745,8 +1793,8 @@ snapshots: capnp-ts@0.7.0: dependencies: - debug: 4.3.4 - tslib: 2.6.2 + debug: 4.3.7 + tslib: 2.7.0 transitivePeerDependencies: - supports-color @@ -1801,12 +1849,6 @@ snapshots: data-uri-to-buffer@2.0.2: {} - date-fns@3.6.0: {} - - debug@4.3.4: - dependencies: - ms: 2.1.2 - debug@4.3.7: dependencies: ms: 2.1.3 @@ -1848,31 +1890,31 @@ snapshots: '@esbuild/win32-ia32': 0.17.19 '@esbuild/win32-x64': 0.17.19 - esbuild@0.20.2: + esbuild@0.21.5: optionalDependencies: - '@esbuild/aix-ppc64': 0.20.2 - '@esbuild/android-arm': 0.20.2 - '@esbuild/android-arm64': 0.20.2 - '@esbuild/android-x64': 0.20.2 - '@esbuild/darwin-arm64': 0.20.2 - '@esbuild/darwin-x64': 0.20.2 - '@esbuild/freebsd-arm64': 0.20.2 - '@esbuild/freebsd-x64': 0.20.2 - '@esbuild/linux-arm': 0.20.2 - '@esbuild/linux-arm64': 0.20.2 - '@esbuild/linux-ia32': 0.20.2 - '@esbuild/linux-loong64': 0.20.2 - '@esbuild/linux-mips64el': 0.20.2 - '@esbuild/linux-ppc64': 0.20.2 - '@esbuild/linux-riscv64': 0.20.2 - '@esbuild/linux-s390x': 0.20.2 - '@esbuild/linux-x64': 0.20.2 - '@esbuild/netbsd-x64': 0.20.2 - '@esbuild/openbsd-x64': 0.20.2 - '@esbuild/sunos-x64': 0.20.2 - '@esbuild/win32-arm64': 0.20.2 - '@esbuild/win32-ia32': 0.20.2 - '@esbuild/win32-x64': 0.20.2 + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 escape-string-regexp@4.0.0: {} @@ -1883,26 +1925,26 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint@8.57.0: + eslint@8.57.1: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.10.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) + '@eslint-community/regexpp': 4.11.1 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4 + debug: 4.3.7 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 @@ -1910,7 +1952,7 @@ snapshots: glob-parent: 6.0.2 globals: 13.24.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -1920,7 +1962,7 @@ snapshots: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: @@ -1928,11 +1970,11 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) eslint-visitor-keys: 3.4.3 - esquery@1.5.0: + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -1946,7 +1988,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 esutils@2.0.3: {} @@ -2028,7 +2070,7 @@ snapshots: dependencies: function-bind: 1.1.2 - ignore@5.3.1: {} + ignore@5.3.2: {} import-fresh@3.3.0: dependencies: @@ -2048,7 +2090,7 @@ snapshots: dependencies: binary-extensions: 2.3.0 - is-core-module@2.13.1: + is-core-module@2.15.1: dependencies: hasown: 2.0.2 @@ -2064,7 +2106,7 @@ snapshots: isexe@2.0.0: {} - itty-router@4.0.27: {} + itty-router@4.2.2: {} js-yaml@4.1.0: dependencies: @@ -2108,17 +2150,36 @@ snapshots: miniflare@3.20240909.4: dependencies: '@cspotcode/source-map-support': 0.8.1 - acorn: 8.12.0 - acorn-walk: 8.3.3 + acorn: 8.12.1 + 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.20240909.0 - ws: 8.17.1 + ws: 8.18.0 youch: 3.3.3 - zod: 3.22.4 + zod: 3.23.8 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + miniflare@3.20240925.0: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + acorn: 8.12.1 + 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.20240925.0 + ws: 8.18.0 + youch: 3.3.3 + zod: 3.23.8 transitivePeerDependencies: - bufferutil - supports-color @@ -2128,8 +2189,6 @@ snapshots: dependencies: brace-expansion: 1.1.11 - ms@2.1.2: {} - ms@2.1.3: {} mustache@4.2.0: {} @@ -2148,14 +2207,14 @@ snapshots: dependencies: wrappy: 1.0.2 - optionator@0.9.3: + optionator@0.9.4: dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 + word-wrap: 1.2.5 p-limit@3.1.0: dependencies: @@ -2183,15 +2242,15 @@ snapshots: pathval@2.0.0: {} - picocolors@1.0.0: {} + picocolors@1.1.0: {} picomatch@2.3.1: {} - postcss@8.4.38: + postcss@8.4.47: dependencies: nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.2.0 + picocolors: 1.1.0 + source-map-js: 1.2.1 prelude-ls@1.2.1: {} @@ -2211,7 +2270,7 @@ snapshots: resolve@1.22.8: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -2237,25 +2296,26 @@ snapshots: dependencies: estree-walker: 0.6.1 - rollup@4.14.0: + rollup@4.22.4: dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.14.0 - '@rollup/rollup-android-arm64': 4.14.0 - '@rollup/rollup-darwin-arm64': 4.14.0 - '@rollup/rollup-darwin-x64': 4.14.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.14.0 - '@rollup/rollup-linux-arm64-gnu': 4.14.0 - '@rollup/rollup-linux-arm64-musl': 4.14.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.14.0 - '@rollup/rollup-linux-riscv64-gnu': 4.14.0 - '@rollup/rollup-linux-s390x-gnu': 4.14.0 - '@rollup/rollup-linux-x64-gnu': 4.14.0 - '@rollup/rollup-linux-x64-musl': 4.14.0 - '@rollup/rollup-win32-arm64-msvc': 4.14.0 - '@rollup/rollup-win32-ia32-msvc': 4.14.0 - '@rollup/rollup-win32-x64-msvc': 4.14.0 + '@rollup/rollup-android-arm-eabi': 4.22.4 + '@rollup/rollup-android-arm64': 4.22.4 + '@rollup/rollup-darwin-arm64': 4.22.4 + '@rollup/rollup-darwin-x64': 4.22.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.22.4 + '@rollup/rollup-linux-arm-musleabihf': 4.22.4 + '@rollup/rollup-linux-arm64-gnu': 4.22.4 + '@rollup/rollup-linux-arm64-musl': 4.22.4 + '@rollup/rollup-linux-powerpc64le-gnu': 4.22.4 + '@rollup/rollup-linux-riscv64-gnu': 4.22.4 + '@rollup/rollup-linux-s390x-gnu': 4.22.4 + '@rollup/rollup-linux-x64-gnu': 4.22.4 + '@rollup/rollup-linux-x64-musl': 4.22.4 + '@rollup/rollup-win32-arm64-msvc': 4.22.4 + '@rollup/rollup-win32-ia32-msvc': 4.22.4 + '@rollup/rollup-win32-x64-msvc': 4.22.4 fsevents: 2.3.3 run-parallel@1.2.0: @@ -2277,7 +2337,7 @@ snapshots: siginfo@2.0.0: {} - source-map-js@1.2.0: {} + source-map-js@1.2.1: {} source-map@0.6.1: {} @@ -2322,7 +2382,7 @@ snapshots: dependencies: is-number: 7.0.0 - tslib@2.6.2: {} + tslib@2.7.0: {} type-check@0.4.0: dependencies: @@ -2330,7 +2390,7 @@ snapshots: type-fest@0.20.2: {} - typescript@5.3.3: {} + typescript@5.6.2: {} ufo@1.5.4: {} @@ -2354,22 +2414,23 @@ snapshots: cac: 6.7.14 debug: 4.3.7 pathe: 1.1.2 - vite: 5.2.8(@types/node@18.15.3) + vite: 5.4.8(@types/node@18.15.3) transitivePeerDependencies: - '@types/node' - less - lightningcss - sass + - sass-embedded - stylus - sugarss - supports-color - terser - vite@5.2.8(@types/node@18.15.3): + vite@5.4.8(@types/node@18.15.3): dependencies: - esbuild: 0.20.2 - postcss: 8.4.38 - rollup: 4.14.0 + esbuild: 0.21.5 + postcss: 8.4.47 + rollup: 4.22.4 optionalDependencies: '@types/node': 18.15.3 fsevents: 2.3.3 @@ -2377,7 +2438,7 @@ snapshots: vitest@2.1.1(@types/node@18.15.3): dependencies: '@vitest/expect': 2.1.1 - '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.2.8(@types/node@18.15.3)) + '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.8(@types/node@18.15.3)) '@vitest/pretty-format': 2.1.1 '@vitest/runner': 2.1.1 '@vitest/snapshot': 2.1.1 @@ -2392,7 +2453,7 @@ snapshots: tinyexec: 0.3.0 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.2.8(@types/node@18.15.3) + vite: 5.4.8(@types/node@18.15.3) vite-node: 2.1.1(@types/node@18.15.3) why-is-node-running: 2.3.0 optionalDependencies: @@ -2402,6 +2463,7 @@ snapshots: - lightningcss - msw - sass + - sass-embedded - stylus - sugarss - supports-color @@ -2416,6 +2478,8 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + word-wrap@1.2.5: {} + workerd@1.20240909.0: optionalDependencies: '@cloudflare/workerd-darwin-64': 1.20240909.0 @@ -2424,17 +2488,24 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20240909.0 '@cloudflare/workerd-windows-64': 1.20240909.0 - wrangler@3.78.7(@cloudflare/workers-types@4.20240614.0): + workerd@1.20240925.0: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20240925.0 + '@cloudflare/workerd-darwin-arm64': 1.20240925.0 + '@cloudflare/workerd-linux-64': 1.20240925.0 + '@cloudflare/workerd-linux-arm64': 1.20240925.0 + '@cloudflare/workerd-windows-64': 1.20240925.0 + + wrangler@3.78.10(@cloudflare/workers-types@4.20240925.0): dependencies: '@cloudflare/kv-asset-handler': 0.3.4 - '@cloudflare/workers-shared': 0.5.3 + '@cloudflare/workers-shared': 0.5.4 '@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 esbuild: 0.17.19 - miniflare: 3.20240909.4 + miniflare: 3.20240925.0 nanoid: 3.3.7 path-to-regexp: 6.3.0 resolve: 1.22.8 @@ -2442,10 +2513,10 @@ snapshots: selfsigned: 2.4.1 source-map: 0.6.1 unenv: unenv-nightly@2.0.0-20240919-125358-9a64854 - workerd: 1.20240909.0 + workerd: 1.20240925.0 xxhash-wasm: 1.0.2 optionalDependencies: - '@cloudflare/workers-types': 4.20240614.0 + '@cloudflare/workers-types': 4.20240925.0 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil @@ -2454,7 +2525,7 @@ snapshots: wrappy@1.0.2: {} - ws@8.17.1: {} + ws@8.18.0: {} xxhash-wasm@1.0.2: {} @@ -2466,4 +2537,4 @@ snapshots: mustache: 4.2.0 stacktracey: 2.1.8 - zod@3.22.4: {} + zod@3.23.8: {} diff --git a/push/.gitignore b/push/.gitignore new file mode 100644 index 0000000..e76beb6 --- /dev/null +++ b/push/.gitignore @@ -0,0 +1,171 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data +.output-image + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* +*.tar diff --git a/push/README.md b/push/README.md new file mode 100644 index 0000000..f07efe4 --- /dev/null +++ b/push/README.md @@ -0,0 +1,57 @@ +# Push chunked images to serverless-registry + +This is a pretty simple tool that allows you to push docker images to serverless-registry +when the layers are too big. + +## How to run + +```bash +bun install +``` + +Then: + +```bash +docker tag my-image:latest $IMAGE_URI +echo $PASSWORD | USERNAME_REGISTRY= bun run index.ts $IMAGE_URI +``` + +## How does it work + +It exports the image using `docker save`, then pushes each layer to the registry. +It only supports `Basic` authentication as it's the one that serverless-registry uses. + +It's able to chunk layers depending on the header `oci-chunk-max-length` returned by the registry when the client +creates an upload. + +## Interesting output folders + +- Every \*.tar in the push folder is the exported image from docker, which is extracted into `.cache`. +- Then it's compressed to gzip and saved into `.cache`. Files that end in `-ptr` have a digest in the content that + refers to another layer in the folder. + +There is a few more workarounds in the code like having to use node-fetch as Bun overrides the Content-Length +header from the caller. + +This pushing tool is just a workaround on the Worker limitation in request body. + +## Pushing locally + +To push to a localhost registry you need to set the environment variable INSECURE_HTTP_PUSH=true. + +## Other options? + +If the reader is interested, there is more options or alternatives to have a faster pushing chunk tool: + +1. We could redesign this tool to run with the Docker overlay storage. The biggest con is having to run a + privileged docker container that uses https://github.com/justincormack/nsenter1 to access the Docker storage. + +2. Create a localhost proxy that understands V2 registry protocol, and chunks things accordingly. The con is that + docker has issues pushing to localhost registries. + +3. Use podman like described in this [very informative Github comment](https://github.com/cloudflare/serverless-registry/issues/42#issuecomment-2366997382). + +## Improvements + +1. Use zstd instead. +2. Have a better unit test suite. diff --git a/push/bun.lockb b/push/bun.lockb new file mode 100755 index 0000000..9b088e0 Binary files /dev/null and b/push/bun.lockb differ diff --git a/push/index.ts b/push/index.ts new file mode 100644 index 0000000..66a87b3 --- /dev/null +++ b/push/index.ts @@ -0,0 +1,404 @@ +import { $, CryptoHasher, file, write } from "bun"; +import tar from "tar-fs"; + +import stream from "node:stream"; + +const username = process.env["USERNAME_REGISTRY"]; +async function read(stream: stream.Readable): Promise { + const chunks = []; + for await (const chunk of stream.iterator()) { + chunks.push(chunk); + } + + return Buffer.concat(chunks).toString("utf8"); +} + +let password; +if (process.stdin.isTTY) { + console.error( + "You need to pass the password with a pipe operator \n\n\t'echo | USERNAME_REGISTRY=... bun run index.ts'\n", + ); +} else { + password = (await read(process.stdin)).trim(); +} + +if (!username || !password) { + console.error("Username or password not defined, push won't be able to authenticate with registry"); + if (!process.env["SKIP_AUTH"]) { + process.exit(1); + } +} + +const image = process.argv[2]; +if (image === undefined) { + console.error("Usage: bun run index.ts "); + process.exit(1); +} + +// Check if the image has already been saved from Docker + +console.log("Preparing image..."); +let imageMetadata: { ID: string }; +const imageMetadataRes = await $`docker images --format json ${image}`.quiet(); +if (imageMetadataRes.exitCode !== 0) { + console.error( + "Image", + image, + "doesn't exist. The docker daemon might not be running, or the image doesn't exist. Check your existing images with\n\n\tdocker images", + ); + process.exit(1); +} + +const imageMetadataText = imageMetadataRes.text(); +if (imageMetadataText === "") { + console.error("Image", image, "doesn't exist. Check your existing images with\n\n\tdocker images"); + process.exit(1); +} + +imageMetadata = JSON.parse(imageMetadataText); +const tarFile = imageMetadata.ID + ".tar"; +const imagePath = ".output-image"; +if (!(await file(tarFile).exists())) { + const output = await $`docker save ${image} --output ${tarFile}`; + + if (output.exitCode != 0) { + console.error("Error saving image", image, output.text()); + process.exit(1); + } + + const extract = tar.extract(imagePath); + + await Bun.file(tarFile) + .stream() + .pipeTo( + new WritableStream({ + write(value) { + return new Promise((res, rej) => { + extract.write(value, (err) => { + if (err) { + rej(err); + return; + } + }); + extract.once("drain", () => { + res(); + }); + }); + }, + close() { + extract.end(); + }, + }), + ); +} + +type DockerSaveConfigManifest = { + Config: string; + Layers: string[]; +}[]; + +import path from "path"; +const manifests = (await Bun.file(path.join(imagePath, "manifest.json")).json()) as DockerSaveConfigManifest; + +if (manifests.length == 0) { + console.error("unexpected manifest of length 0"); + process.exit(1); +} + +if (manifests.length > 1) { + console.warn("Manifest resolved to multiple images, picking the first one"); +} + +import plimit from "p-limit"; +const pool = plimit(5); +import zlib from "node:zlib"; +import { mkdir, rename, rm } from "node:fs/promises"; + +const cacheFolder = ".cache"; + +await mkdir(cacheFolder, { recursive: true }); + +const [manifest] = manifests; +const tasks = []; + +console.log("compressing..."); +// Iterate through every layer, read it and compress to a file +for (const layer of manifest.Layers) { + tasks.push( + pool(async () => { + let layerPath = path.join(imagePath, layer); + // docker likes to put stuff in two ways: + // 1. blobs/sha256/ + // 2. /layer.tar + // + // This handles both cases. + let layerName = layer.endsWith(".tar") ? path.dirname(layer) : path.basename(layer); + + const layerCachePath = path.join(cacheFolder, layerName + "-ptr"); + { + const layerCacheGzip = file(layerCachePath); + if (await layerCacheGzip.exists()) { + const compressedDigest = await layerCacheGzip.text(); + return compressedDigest; + } + } + + const inprogressPath = path.join(cacheFolder, layerName + "-in-progress"); + + await rm(inprogressPath, { recursive: true }); + const layerCacheGzip = file(inprogressPath, {}); + + const cacheWriter = layerCacheGzip.writer(); + const hasher = new Bun.CryptoHasher("sha256"); + const gzipStream = zlib.createGzip({ level: 9 }); + gzipStream.pipe( + new stream.Writable({ + write(value, _, callback) { + hasher.update(value); + cacheWriter.write(value); + callback(); + }, + }), + ); + + await file(layerPath) + .stream() + .pipeTo( + new WritableStream({ + write(value) { + return new Promise((res, rej) => { + gzipStream.write(value, "binary", (err) => { + if (err) { + rej(err); + return; + } + res(); + }); + }); + }, + close() { + gzipStream.end(); + }, + }), + ); + + await cacheWriter.flush(); + await cacheWriter.end(); + const digest = hasher.digest("hex"); + await rename(inprogressPath, path.join(cacheFolder, digest)); + await write(layerCachePath, digest); + return digest; + }), + ); +} + +const configManifest = path.join(imagePath, manifest.Config); +const config = await file(configManifest).text(); +const configDigest = new CryptoHasher("sha256").update(config).digest("hex"); + +const compressedDigests = await Promise.all(tasks); + +const proto = process.env["INSECURE_HTTP_PUSH"] === "true" ? "http" : "https"; +if (proto === "http") { + console.error("!! Using plain HTTP !!"); +} + +const pushTasks = []; +const url = new URL(proto + "://" + image); +const imageHost = url.host; +const imageRepositoryPathParts = url.pathname.split(":"); +const imageRepositoryPath = imageRepositoryPathParts.slice(0, imageRepositoryPathParts.length - 1).join(":"); +const tag = + imageRepositoryPathParts.length > 1 ? imageRepositoryPathParts[imageRepositoryPathParts.length - 1] : "latest"; + +import fetchNode from "node-fetch"; +import { ReadableLimiter } from "./limiter"; + +const cred = `Basic ${btoa(`${username}:${password}`)}`; + +console.log("Starting push to remote"); +// pushLayer accepts the target digest, the stream to read from, and the total layer size. +// It will do the entire push process by itself. +async function pushLayer(layerDigest: string, readableStream: ReadableStream, totalLayerSize: number) { + const headers = new Headers({ + authorization: cred, + }); + const layerExistsURL = `${proto}://${imageHost}/v2${imageRepositoryPath}/blobs/${layerDigest}`; + const layerExistsResponse = await fetch(layerExistsURL, { + headers, + method: "HEAD", + }); + + if (!layerExistsResponse.ok && layerExistsResponse.status !== 404) { + throw new Error(`${layerExistsURL} responded ${layerExistsResponse.status}: ${await layerExistsResponse.text()}`); + } + + if (layerExistsResponse.ok) { + console.log(`${layerDigest} already exists...`); + return; + } + + const createUploadURL = `${proto}://${imageHost}/v2${imageRepositoryPath}/blobs/uploads/`; + const createUploadResponse = await fetch(createUploadURL, { + headers, + method: "POST", + }); + if (!createUploadResponse.ok) { + throw new Error( + `${createUploadURL} responded ${createUploadResponse.status}: ${await createUploadResponse.text()}`, + ); + } + + const maxChunkLength = +(createUploadResponse.headers.get("oci-chunk-max-length") ?? 500 * 1024 * 1024); + if (isNaN(maxChunkLength)) { + throw new Error(`oci-chunk-max-length header is malformed (not a number)`); + } + + const reader = readableStream.getReader(); + const uploadId = createUploadResponse.headers.get("docker-upload-uuid"); + if (uploadId === null) { + throw new Error("Docker-Upload-UUID not defined in headers"); + } + + let location = createUploadResponse.headers.get("location") ?? `/v2${imageRepositoryPath}/blobs/uploads/${uploadId}`; + const putChunkUploadURL = `${proto}://${imageHost}${location}`; + const maxToWrite = Math.min(maxChunkLength, totalLayerSize); + let end = Math.min(maxChunkLength, totalLayerSize); + let written = 0; + let previousReadable: ReadableLimiter | undefined; + let totalLayerSizeLeft = totalLayerSize; + while (totalLayerSizeLeft > 0) { + const range = `0-${Math.min(end, totalLayerSize) - 1}`; + const current = new ReadableLimiter(reader as ReadableStreamDefaultReader, maxToWrite, previousReadable); + + // we have to do fetchNode because Bun doesn't allow setting custom Content-Length. + // https://github.com/oven-sh/bun/issues/10507 + const putChunkResult = await fetchNode(putChunkUploadURL, { + method: "PATCH", + body: current, + headers: new Headers({ + "range": range, + "authorization": cred, + "content-length": `${Math.min(totalLayerSizeLeft, maxToWrite)}`, + }), + }); + if (!putChunkResult.ok) { + throw new Error( + `uploading chunk ${putChunkUploadURL} returned ${putChunkResult.status}: ${await putChunkResult.text()}`, + ); + } + + const rangeResponse = putChunkResult.headers.get("range"); + if (rangeResponse !== range) { + throw new Error(`unexpected Range header ${rangeResponse}, expected ${range}`); + } + + previousReadable = current; + totalLayerSizeLeft -= previousReadable.written; + written += previousReadable.written; + end += previousReadable.written; + location = putChunkResult.headers.get("location") ?? location; + if (totalLayerSizeLeft != 0) console.log(layerDigest + ":", totalLayerSizeLeft, "upload bytes left."); + } + + const range = `0-${written - 1}`; + const uploadURL = new URL(`${proto}://${imageHost}${location}`); + uploadURL.searchParams.append("digest", layerDigest); + + const response = await fetch(uploadURL.toString(), { + method: "PUT", + headers: new Headers({ + Range: range, + Authorization: cred, + }), + }); + if (!response.ok) { + throw new Error(`${uploadURL.toString()} failed with ${response.status}: ${await response.text()}`); + } + + console.log("Pushed", layerDigest); +} + +const layersManifest = [] as { + readonly mediaType: "application/vnd.oci.image.layer.v1.tar+gzip"; + readonly size: number; + readonly digest: `sha256:${string}`; +}[]; + +for (const compressedDigest of compressedDigests) { + let layer = file(path.join(cacheFolder, compressedDigest)); + layersManifest.push({ + mediaType: "application/vnd.oci.image.layer.v1.tar+gzip", + size: layer.size, + digest: `sha256:${compressedDigest}`, + } as const); + tasks.push( + pool(async () => { + const maxRetries = +(process.env["MAX_RETRIES"] ?? 3); + if (isNaN(maxRetries)) throw new Error("MAX_RETRIES is not a number"); + + for (let i = 0; i < maxRetries; i++) { + const digest = `sha256:${compressedDigest}`; + const stream = layer.stream(); + try { + await pushLayer(digest, stream, layer.size); + return; + } catch (err) { + console.error(digest, "failed to upload", maxRetries - i - 1, "left...", err); + layer = file(path.join(cacheFolder, compressedDigest)); + } + } + }), + ); +} + +pushTasks.push( + pool(async () => { + await pushLayer( + `sha256:${configDigest}`, + new ReadableStream({ + pull(controller) { + controller.enqueue(config); + controller.close(); + }, + }), + config.length, + ); + }), +); + +const promises = await Promise.allSettled(pushTasks); +for (const promise of promises) { + if (promise.status === "rejected") process.exit(1); +} + +const manifestObject = { + schemaVersion: 2, + mediaType: "application/vnd.oci.image.manifest.v1+json", + config: { + mediaType: "application/vnd.oci.image.config.v1+json", + size: config.length, + digest: `sha256:${configDigest}`, + }, + layers: layersManifest, +} as const; + +const manifestUploadURL = `${proto}://${imageHost}/v2${imageRepositoryPath}/manifests/${tag}`; +const responseManifestUpload = await fetch(manifestUploadURL, { + headers: { + "authorization": cred, + "content-type": manifestObject.mediaType, + }, + body: JSON.stringify(manifestObject), + method: "PUT", +}); + +if (!responseManifestUpload.ok) { + throw new Error( + `manifest upload ${manifestUploadURL} returned ${ + responseManifestUpload.status + }: ${await responseManifestUpload.text()}`, + ); +} +console.log(manifestObject); +console.log("OK"); diff --git a/push/limiter.ts b/push/limiter.ts new file mode 100644 index 0000000..422e068 --- /dev/null +++ b/push/limiter.ts @@ -0,0 +1,59 @@ +import stream from "node:stream"; + +// ReadableLimiter is a class that limits the amount of +// data to read. It will never return more data than the configured limit. +// However, it doesn't guarantee that it reads less than the limit from the passed reader. +export class ReadableLimiter extends stream.Readable { + public written: number = 0; + private leftover: Uint8Array | undefined; + + constructor( + // reader will be used to read bytes until limit. + // it might read more than 'limit' due to Bun not supporting byob. + // We workaround this by keeping track of the previousReader that the caller should pass. + private reader: ReadableStreamDefaultReader, + private limit: number, + previousReader?: ReadableLimiter, + ) { + super(); + + if (previousReader) this.leftover = previousReader.leftover; + } + + _read(): void { + if (this.limit === 0) { + this.push(null); + } + + if (this.leftover !== undefined) { + const toPushNow = this.leftover.slice(0, this.limit); + this.leftover = this.leftover.slice(this.limit); + this.push(toPushNow); + this.limit -= toPushNow.length; + this.written += toPushNow.length; + + // if no leftovers left to write from before + if (this.leftover.length == 0) { + this.leftover = undefined; + } + return; + } + + this.reader.read().then((result) => { + if (result.done) return this.push(null); + + let arr = result.value as Uint8Array; + if (arr.length > this.limit) { + const toPushNow = arr.slice(0, this.limit); + this.leftover = arr.slice(this.limit); + arr = toPushNow; + } + + if (arr.length === 0) return this.push(null); + + this.push(arr); + this.limit -= arr.length; + this.written += arr.length; + }); + } +} diff --git a/push/package.json b/push/package.json new file mode 100644 index 0000000..54940d1 --- /dev/null +++ b/push/package.json @@ -0,0 +1,17 @@ +{ + "name": "push", + "module": "index.ts", + "type": "module", + "devDependencies": { + "@types/tar-fs": "^2.0.4", + "bun-types": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "node-fetch": "^3.3.2", + "p-limit": "^6.1.0", + "tar-fs": "^3.0.6" + } +} diff --git a/push/tsconfig.json b/push/tsconfig.json new file mode 100644 index 0000000..1449bc3 --- /dev/null +++ b/push/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": ["ESNext"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "preserve", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" // add Bun global + ] + } +} diff --git a/src/chunk.ts b/src/chunk.ts index f3b2e52..a0ecfd6 100644 --- a/src/chunk.ts +++ b/src/chunk.ts @@ -8,8 +8,8 @@ export const MINIMUM_CHUNK = 1024 * 1024 * 5; // 5GiB export const MAXIMUM_CHUNK = MINIMUM_CHUNK * 1024; -// 500MB -export const MAXIMUM_CHUNK_UPLOAD_SIZE = 1000 * 1000 * 500; +// 100MB +export const MAXIMUM_CHUNK_UPLOAD_SIZE = 1000 * 1000 * 100; export const getHelperR2Path = (id: string): string => { return `${id}-helper`;