diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71f0b53..4af1f57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,21 +24,24 @@ jobs: name: Backend runs-on: ubuntu-latest steps: + - name: Enable Corepack + run: corepack enable - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 - cache: npm - cache-dependency-path: backend/package-lock.json + cache: yarn + cache-dependency-path: backend/yarn.lock + - name: Install working-directory: backend - run: npm ci + run: yarn install --immutable - name: Worker-only backend guard working-directory: backend - run: npm run check:worker-only + run: yarn run check:worker-only - name: Build working-directory: backend - run: npm run build + run: yarn run build - name: Test working-directory: backend - run: npm test + run: yarn test diff --git a/backend/README.md b/backend/README.md index c4f42eb..2334f84 100644 --- a/backend/README.md +++ b/backend/README.md @@ -22,6 +22,7 @@ Cloudflare Worker for GoodDollar Celo-vault credit accounting and Celo → Base - `POST /v1/analytics/refresh` - `POST /v1/accounts/:account/stream-credits` - `POST /v1/accounts/:account/operator-consent` +- `POST /v1/accounts/:account/operator-revoke` - `POST /v1/accounts/:account/withdraw` - `POST /v1/celo/events/record` - `POST /v1/channels/:channelId/close` @@ -41,6 +42,7 @@ Cloudflare Worker for GoodDollar Celo-vault credit accounting and Celo → Base - `{ "account": "0x...", "fromBlock": "0x...", "toBlock": "latest" }` `GET /v1/analytics` returns daily analytics (last 30 days by default). + - query: `days` (default `30`, max `365`) - response: `{ days, daily, global, lastRun }` - `daily` — one record per UTC day, newest last; the current day is always recomputed from midnight to now on each refresh and its snapshot is overwritten diff --git a/backend/package-lock.json b/backend/package-lock.json deleted file mode 100644 index 87efc78..0000000 --- a/backend/package-lock.json +++ /dev/null @@ -1,3687 +0,0 @@ -{ - "name": "@gooddollar/antseed-integration-worker", - "version": "0.2.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@gooddollar/antseed-integration-worker", - "version": "0.2.0", - "dependencies": { - "@antseed/node": "^0.2.96", - "ethers": "^6.13.5", - "zod": "^3.24.1" - }, - "devDependencies": { - "@cloudflare/workers-types": "^4.20260518.0", - "@types/node": "^22.10.2", - "tsx": "^4.22.4", - "typescript": "^5.7.2", - "wrangler": "^4.18.0" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", - "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", - "license": "MIT" - }, - "node_modules/@antseed/api-adapter": { - "version": "0.1.39", - "resolved": "https://registry.npmjs.org/@antseed/api-adapter/-/api-adapter-0.1.39.tgz", - "integrity": "sha512-3h3hZG77Lr/+6gj/Tkmg4RCej8m2DdQ79uClNpbg2T5X0w8D9IQ9MfsB4fQNWjlZSZAtrF09MPOh9LH/Lc/Z2Q==" - }, - "node_modules/@antseed/node": { - "version": "0.2.96", - "resolved": "https://registry.npmjs.org/@antseed/node/-/node-0.2.96.tgz", - "integrity": "sha512-SpllE1aPk0xpDpdKHk/HDdxk0FvYAvQGNpE3UDfgDGinzfbikOHu7i2TV176ZaoAvqYKeXxs0eDJBNtzJrfnRg==", - "hasInstallScript": true, - "dependencies": { - "@antseed/api-adapter": "0.1.39", - "@silentbot1/nat-api": "^0.4.9", - "better-sqlite3": "^12.6.2", - "bittorrent-dht": "^11.0.11", - "ethers": "~6.16.0", - "node-datachannel": "^0.7.0", - "tokenx": "^1.3.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "optionalDependencies": { - "keytar": "^7.9.0" - } - }, - "node_modules/@cloudflare/kv-asset-handler": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.5.0.tgz", - "integrity": "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==", - "dev": true, - "license": "MIT OR Apache-2.0", - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@cloudflare/unenv-preset": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.1.tgz", - "integrity": "sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==", - "dev": true, - "license": "MIT OR Apache-2.0", - "peerDependencies": { - "unenv": "2.0.0-rc.24", - "workerd": ">1.20260305.0 <2.0.0-0" - }, - "peerDependenciesMeta": { - "workerd": { - "optional": true - } - } - }, - "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20260515.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260515.1.tgz", - "integrity": "sha512-Wtw44el2pNbzixvTkWdfeBDTrQwQbJRz7/JUvPKV27I0pQWXbhNJPpM8cstq/pbrU5AGcA/HjFH6yPMRTIRKig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20260515.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260515.1.tgz", - "integrity": "sha512-X8EqkZej6FfmhF9AVAQ3FhyQRr9acS4RcDunMU2YiuxKHF1IU8zzH3vY30/POaG+rUu9vGDp/VgUl49VPenHJQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20260515.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260515.1.tgz", - "integrity": "sha512-CDC89QxQ7Y7t7RG1Jd9vj/qolE1sQRkI2OSEuV5BMJi0vW/gV4OVG6xjpdK3b1OYnSWDzF7NpvlR5Yg86q7k4g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20260515.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260515.1.tgz", - "integrity": "sha512-WxbW/PToYES4fvHXzsr/5qOiETQs/Z9iZ0mjSZAiEwq5cMLZemzGN0COx+uFb9OvQwzh6Pg159qPFnw3+i9FuA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20260515.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260515.1.tgz", - "integrity": "sha512-WmV/iv+MHjYsvkcMVzpM2B5/mf06UUkdpVhZrtMfV9graWjBGPYFvE/eab8748RPVGKh1Xe1vXofLzDSwc08lA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@cloudflare/workers-types": { - "version": "4.20260518.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260518.1.tgz", - "integrity": "sha512-xXzGrbRi8RHRBNQFgXYkzrB4DgF0RXvmp8E1vCxoBmINpeitM/ZjVDd1CNC+N3uXjgcNjacoz4OgTa0rxgig1A==", - "dev": true, - "license": "MIT OR Apache-2.0" - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", - "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", - "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", - "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", - "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", - "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", - "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", - "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", - "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", - "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", - "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", - "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", - "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", - "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", - "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", - "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", - "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", - "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", - "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", - "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", - "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", - "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", - "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", - "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", - "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", - "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", - "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/colour": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.7.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@poppinss/colors": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz", - "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^4.1.5" - } - }, - "node_modules/@poppinss/dumper": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz", - "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@poppinss/colors": "^4.1.5", - "@sindresorhus/is": "^7.0.2", - "supports-color": "^10.0.0" - } - }, - "node_modules/@poppinss/exception": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz", - "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", - "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", - "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", - "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", - "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", - "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", - "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", - "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", - "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", - "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", - "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", - "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", - "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", - "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", - "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", - "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", - "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", - "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", - "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", - "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", - "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", - "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", - "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", - "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", - "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", - "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@silentbot1/nat-api": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/@silentbot1/nat-api/-/nat-api-0.4.9.tgz", - "integrity": "sha512-Bm2Fr0sJyGr4B/XgKjQxjGe7Rzs/OlK91OIHsghObxhP3Y4j2y8o7Xjlledu/pxzFEIWaTbZIBSl8ABqoP/WhQ==", - "license": "MIT", - "dependencies": { - "chrome-dgram": "^3.0.6", - "cross-fetch-ponyfill": "^1.0.3", - "debug": "^4.4.0", - "default-gateway": "^7.2.2", - "unordered-array-remove": "^1.0.2", - "xml2js": "^0.6.2" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@sindresorhus/is": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", - "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@speed-highlight/core": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.15.tgz", - "integrity": "sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.19.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", - "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "license": "MIT" - }, - "node_modules/b4a": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", - "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", - "license": "Apache-2.0", - "peerDependencies": { - "react-native-b4a": "*" - }, - "peerDependenciesMeta": { - "react-native-b4a": { - "optional": true - } - } - }, - "node_modules/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bencode": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bencode/-/bencode-4.0.1.tgz", - "integrity": "sha512-/bCR3FvgfB8AZk4LlowShU+nfaTNRM2vruJ9aejDa5LpgkCoRjFyEauFiZFxbpxVxQbBFapYCN42Er2dkE/Qgw==", - "license": "MIT", - "dependencies": { - "uint8-util": "^2.2.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/better-sqlite3": { - "version": "12.11.1", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.11.1.tgz", - "integrity": "sha512-dq9AtApgg5PGFtBzPFSBl3HZQjHok5gaQCM6zh2Yk0aSmDCs1CbnVI8/HgASQkNKsWFpseIO9beg5xxpYhbIfA==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "bindings": "^1.5.0", - "prebuild-install": "^7.1.1" - }, - "engines": { - "node": "20.x || 22.x || 23.x || 24.x || 25.x || 26.x" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bittorrent-dht": { - "version": "11.0.12", - "resolved": "https://registry.npmjs.org/bittorrent-dht/-/bittorrent-dht-11.0.12.tgz", - "integrity": "sha512-bFmQq874HMIBon/6KNMf/U1OG+UxJ0UzI9oPra2IRlZLuPA7VwBiA7uEpWaO2ww8G76OFjxB1p1XCOS94FuCPQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "bencode": "^4.0.1", - "debug": "^4.4.3", - "k-bucket": "^5.1.0", - "k-rpc": "^5.1.0", - "last-one-wins": "^1.0.4", - "lru": "^3.1.0", - "randombytes": "^2.1.0", - "record-cache": "^1.2.0" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/blake3-wasm": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", - "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC" - }, - "node_modules/chrome-dgram": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/chrome-dgram/-/chrome-dgram-3.0.6.tgz", - "integrity": "sha512-bqBsUuaOiXiqxXt/zA/jukNJJ4oaOtc7ciwqJpZVEaaXwwxqgI2/ZdG02vXYWUhHGziDlvGMQWk0qObgJwVYKA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "run-series": "^1.1.9" - } - }, - "node_modules/chrome-dns": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chrome-dns/-/chrome-dns-1.0.1.tgz", - "integrity": "sha512-HqsYJgIc8ljJJOqOzLphjAs79EUuWSX3nzZi2LNkzlw3GIzAeZbaSektC8iT/tKvLqZq8yl1GJu5o6doA4TRbg==", - "license": "MIT", - "dependencies": { - "chrome-net": "^3.3.2" - } - }, - "node_modules/chrome-net": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/chrome-net/-/chrome-net-3.3.4.tgz", - "integrity": "sha512-Jzy2EnzmE+ligqIZUsmWnck9RBXLuUy6CaKyuNMtowFG3ZvLt8d+WBJCTPEludV0DHpIKjAOlwjFmTaEdfdWCw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1" - } - }, - "node_modules/cookie": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/cross-fetch-ponyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cross-fetch-ponyfill/-/cross-fetch-ponyfill-1.0.3.tgz", - "integrity": "sha512-uOBkDhUAGAbx/FEzNKkOfx3w57H8xReBBXoZvUnOKTI0FW0Xvrj3GrYv2iZXUqlffC1LMGfQzhmBM/ke+6eTDA==", - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "node-fetch": "^3.3.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/default-gateway": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-7.2.2.tgz", - "integrity": "sha512-AD7TrdNNPXRZIGw63dw+lnGmT4v7ggZC5NHNJgAYWm5njrwoze1q5JSAW9YuLy2tjnoLUG/r8FEB93MCh9QJPg==", - "license": "BSD-2-Clause", - "dependencies": { - "execa": "^7.1.1" - }, - "engines": { - "node": ">= 16" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/error-stack-parser-es": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", - "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/esbuild": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", - "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.0", - "@esbuild/android-arm": "0.28.0", - "@esbuild/android-arm64": "0.28.0", - "@esbuild/android-x64": "0.28.0", - "@esbuild/darwin-arm64": "0.28.0", - "@esbuild/darwin-x64": "0.28.0", - "@esbuild/freebsd-arm64": "0.28.0", - "@esbuild/freebsd-x64": "0.28.0", - "@esbuild/linux-arm": "0.28.0", - "@esbuild/linux-arm64": "0.28.0", - "@esbuild/linux-ia32": "0.28.0", - "@esbuild/linux-loong64": "0.28.0", - "@esbuild/linux-mips64el": "0.28.0", - "@esbuild/linux-ppc64": "0.28.0", - "@esbuild/linux-riscv64": "0.28.0", - "@esbuild/linux-s390x": "0.28.0", - "@esbuild/linux-x64": "0.28.0", - "@esbuild/netbsd-arm64": "0.28.0", - "@esbuild/netbsd-x64": "0.28.0", - "@esbuild/openbsd-arm64": "0.28.0", - "@esbuild/openbsd-x64": "0.28.0", - "@esbuild/openharmony-arm64": "0.28.0", - "@esbuild/sunos-x64": "0.28.0", - "@esbuild/win32-arm64": "0.28.0", - "@esbuild/win32-ia32": "0.28.0", - "@esbuild/win32-x64": "0.28.0" - } - }, - "node_modules/ethers": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", - "integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "1.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.17.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/ethers/node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/ethers/node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/fetch-blob/node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT" - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT" - }, - "node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/k-bucket": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/k-bucket/-/k-bucket-5.1.0.tgz", - "integrity": "sha512-Fac7iINEovXIWU20GPnOMLUbjctiS+cnmyjC4zAUgvs3XPf1vo9akfCHkigftSic/jiKqKl+KA3a/vFcJbHyCg==", - "license": "MIT", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/k-rpc": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/k-rpc/-/k-rpc-5.1.0.tgz", - "integrity": "sha512-FGc+n70Hcjoa/X2JTwP+jMIOpBz+pkRffHnSl9yrYiwUxg3FIgD50+u1ePfJUOnRCnx6pbjmVk5aAeB1wIijuQ==", - "license": "MIT", - "dependencies": { - "k-bucket": "^5.0.0", - "k-rpc-socket": "^1.7.2", - "randombytes": "^2.0.5" - } - }, - "node_modules/k-rpc-socket": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/k-rpc-socket/-/k-rpc-socket-1.11.1.tgz", - "integrity": "sha512-8xtA8oqbZ6v1Niryp2/g4GxW16EQh5MvrUylQoOG+zcrDff5CKttON2XUXvMwlIHq4/2zfPVFiinAccJ+WhxoA==", - "license": "MIT", - "dependencies": { - "bencode": "^2.0.0", - "chrome-dgram": "^3.0.2", - "chrome-dns": "^1.0.0", - "chrome-net": "^3.3.2" - } - }, - "node_modules/k-rpc-socket/node_modules/bencode": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/bencode/-/bencode-2.0.3.tgz", - "integrity": "sha512-D/vrAD4dLVX23NalHwb8dSvsUsxeRPO8Y7ToKA015JQYq69MLDOMkC0uGZYA/MPpltLO8rt8eqFC2j8DxjTZ/w==", - "license": "MIT" - }, - "node_modules/keytar": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", - "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "node-addon-api": "^4.3.0", - "prebuild-install": "^7.0.1" - } - }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/last-one-wins": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/last-one-wins/-/last-one-wins-1.0.4.tgz", - "integrity": "sha512-t+KLJFkHPQk8lfN6WBOiGkiUXoub+gnb2XTYI2P3aiISL+94xgZ1vgz1SXN/N4hthuOoLXarXfBZPUruyjQtfA==", - "license": "MIT" - }, - "node_modules/lru": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lru/-/lru-3.1.0.tgz", - "integrity": "sha512-5OUtoiVIGU4VXBOshidmtOsvBIvcQR6FD/RzWSvaeHyxCGB+PCUCu+52lqMfdc0h/2CLvHhZS4TwUmMQrrMbBQ==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/miniflare": { - "version": "4.20260515.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260515.0.tgz", - "integrity": "sha512-2j0oQWizk1Eu4Cm8tDX7Z+Nsjd0nebIj1TQcQ+Oy1QKeo0Ay9+bdn8wfLAtOj9znDCybDCUlnS1+nYvKXEdfNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "0.8.1", - "sharp": "^0.34.5", - "undici": "7.24.8", - "workerd": "1.20260515.1", - "ws": "8.18.0", - "youch": "4.1.0-beta.10" - }, - "bin": { - "miniflare": "bootstrap.js" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/miniflare/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/napi-build-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", - "license": "MIT" - }, - "node_modules/node-abi": { - "version": "3.93.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.93.0.tgz", - "integrity": "sha512-Cu6yUpX5Iavugm8BeX7c0wgU9CvOqfd1yM6A1d2q2ZMjym7GjpASv2GdRcTq3Fx+Sb5OgBkEEpw4VnAbY6Y5RA==", - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "license": "MIT", - "optional": true - }, - "node_modules/node-datachannel": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/node-datachannel/-/node-datachannel-0.7.0.tgz", - "integrity": "sha512-A4sQjvZxzaTDYs5FyUSx9dfdCtQt9r2kXyoyK/Wa+ID6iR5XLm5HDEd//R/oDHINZQdBFlx1/UTzyTiY1MTzxQ==", - "hasInstallScript": true, - "license": "MPL 2.0", - "dependencies": { - "node-domexception": "^2.0.1", - "prebuild-install": "^7.0.1", - "rollup": "^4.14.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/node-domexception": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-2.0.2.tgz", - "integrity": "sha512-Qf9vHK9c5MGgUXj8SnucCIS4oEPuUstjRaMplLGeZpbWMfNV1rvEcXuwoXfN51dUfD1b4muPHPQtCx/5Dj/QAA==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", - "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/prebuild-install": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/record-cache": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/record-cache/-/record-cache-1.2.0.tgz", - "integrity": "sha512-kyy3HWCez2WrotaL3O4fTn0rsIdfRKOdQQcEJ9KpvmKmbffKVvwsloX063EgRUlpJIXHiDQFhJcTbZequ2uTZw==", - "license": "MIT", - "dependencies": { - "b4a": "^1.3.1" - } - }, - "node_modules/rollup": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", - "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.9" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.62.2", - "@rollup/rollup-android-arm64": "4.62.2", - "@rollup/rollup-darwin-arm64": "4.62.2", - "@rollup/rollup-darwin-x64": "4.62.2", - "@rollup/rollup-freebsd-arm64": "4.62.2", - "@rollup/rollup-freebsd-x64": "4.62.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", - "@rollup/rollup-linux-arm-musleabihf": "4.62.2", - "@rollup/rollup-linux-arm64-gnu": "4.62.2", - "@rollup/rollup-linux-arm64-musl": "4.62.2", - "@rollup/rollup-linux-loong64-gnu": "4.62.2", - "@rollup/rollup-linux-loong64-musl": "4.62.2", - "@rollup/rollup-linux-ppc64-gnu": "4.62.2", - "@rollup/rollup-linux-ppc64-musl": "4.62.2", - "@rollup/rollup-linux-riscv64-gnu": "4.62.2", - "@rollup/rollup-linux-riscv64-musl": "4.62.2", - "@rollup/rollup-linux-s390x-gnu": "4.62.2", - "@rollup/rollup-linux-x64-gnu": "4.62.2", - "@rollup/rollup-linux-x64-musl": "4.62.2", - "@rollup/rollup-openbsd-x64": "4.62.2", - "@rollup/rollup-openharmony-arm64": "4.62.2", - "@rollup/rollup-win32-arm64-msvc": "4.62.2", - "@rollup/rollup-win32-ia32-msvc": "4.62.2", - "@rollup/rollup-win32-x64-gnu": "4.62.2", - "@rollup/rollup-win32-x64-msvc": "4.62.2", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-series": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", - "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=11.0.0" - } - }, - "node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@img/colour": "^1.0.0", - "detect-libc": "^2.1.2", - "semver": "^7.7.3" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5", - "@img/sharp-darwin-x64": "0.34.5", - "@img/sharp-libvips-darwin-arm64": "1.2.4", - "@img/sharp-libvips-darwin-x64": "1.2.4", - "@img/sharp-libvips-linux-arm": "1.2.4", - "@img/sharp-libvips-linux-arm64": "1.2.4", - "@img/sharp-libvips-linux-ppc64": "1.2.4", - "@img/sharp-libvips-linux-riscv64": "1.2.4", - "@img/sharp-libvips-linux-s390x": "1.2.4", - "@img/sharp-libvips-linux-x64": "1.2.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", - "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5", - "@img/sharp-linux-arm64": "0.34.5", - "@img/sharp-linux-ppc64": "0.34.5", - "@img/sharp-linux-riscv64": "0.34.5", - "@img/sharp-linux-s390x": "0.34.5", - "@img/sharp-linux-x64": "0.34.5", - "@img/sharp-linuxmusl-arm64": "0.34.5", - "@img/sharp-linuxmusl-x64": "0.34.5", - "@img/sharp-wasm32": "0.34.5", - "@img/sharp-win32-arm64": "0.34.5", - "@img/sharp-win32-ia32": "0.34.5", - "@img/sharp-win32-x64": "0.34.5" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", - "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/tar-fs": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz", - "integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==", - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tokenx": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tokenx/-/tokenx-1.3.0.tgz", - "integrity": "sha512-NLdXTEZkKiO0gZuLtMoZKjCXTREXeZZt8nnnNeyoXtNZAfG/GKGSbQtLU5STspc0rMSwcA+UJfWZkbNU01iKmQ==", - "license": "MIT" - }, - "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "license": "0BSD" - }, - "node_modules/tsx": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", - "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/uint8-util": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/uint8-util/-/uint8-util-2.2.6.tgz", - "integrity": "sha512-r+ZjS8CzPhtPF771ROOadUoqC40OVdiMKBI8lTfJQWb4W7+73sMBwMYmai/uvNcmZ7tBJJyZSad03yMWIt3RQg==", - "license": "MIT", - "dependencies": { - "base64-arraybuffer": "^1.0.2" - } - }, - "node_modules/undici": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.8.tgz", - "integrity": "sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unenv": { - "version": "2.0.0-rc.24", - "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", - "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "pathe": "^2.0.3" - } - }, - "node_modules/unordered-array-remove": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz", - "integrity": "sha512-45YsfD6svkgaCBNyvD+dFHm4qFX9g3wRSIVgWVPtm2OCnphvPxzJoe20ATsiNpNJrmzHifnxm+BN5F7gFT/4gw==", - "license": "MIT" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/workerd": { - "version": "1.20260515.1", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260515.1.tgz", - "integrity": "sha512-MjKOJLcvU45xXedQowvuiHtJTxu4WTHYQeIlF7YmjuqhiI6dImTFxWCEoRQHiskztxuVSNEmdO7/0UfDu6OMnQ==", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "bin": { - "workerd": "bin/workerd" - }, - "engines": { - "node": ">=16" - }, - "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20260515.1", - "@cloudflare/workerd-darwin-arm64": "1.20260515.1", - "@cloudflare/workerd-linux-64": "1.20260515.1", - "@cloudflare/workerd-linux-arm64": "1.20260515.1", - "@cloudflare/workerd-windows-64": "1.20260515.1" - } - }, - "node_modules/wrangler": { - "version": "4.92.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.92.0.tgz", - "integrity": "sha512-/DKpQHPxkuZbQsO9dFW2700VTD/4DSZMHjy92fO/frNoDRi/zQsFCAd2ONCV6TGqcUoXcP3D8Bo2gj/L4M0qQQ==", - "dev": true, - "license": "MIT OR Apache-2.0", - "dependencies": { - "@cloudflare/kv-asset-handler": "0.5.0", - "@cloudflare/unenv-preset": "2.16.1", - "blake3-wasm": "2.1.5", - "esbuild": "0.27.3", - "miniflare": "4.20260515.0", - "path-to-regexp": "6.3.0", - "unenv": "2.0.0-rc.24", - "workerd": "1.20260515.1" - }, - "bin": { - "wrangler": "bin/wrangler.js", - "wrangler2": "bin/wrangler.js" - }, - "engines": { - "node": ">=22.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@cloudflare/workers-types": "^4.20260515.1" - }, - "peerDependenciesMeta": { - "@cloudflare/workers-types": { - "optional": true - } - } - }, - "node_modules/wrangler/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/wrangler/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml2js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", - "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/youch": { - "version": "4.1.0-beta.10", - "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz", - "integrity": "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@poppinss/colors": "^4.1.5", - "@poppinss/dumper": "^0.6.4", - "@speed-highlight/core": "^1.2.7", - "cookie": "^1.0.2", - "youch-core": "^0.3.3" - } - }, - "node_modules/youch-core": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz", - "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@poppinss/exception": "^1.2.2", - "error-stack-parser-es": "^1.0.5" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/backend/package.json b/backend/package.json index bef5681..0d18a5a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -11,7 +11,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit", "test": "tsx --test test/*.test.ts", "check:worker-only": "node scripts/check-worker-only.mjs", - "lint": "npm run typecheck && npm run check:worker-only" + "lint": "yarn run typecheck && yarn run check:worker-only", + "migrate:buyer-accounting": "tsx scripts/migrate-buyer-accounting.ts" }, "dependencies": { "@antseed/node": "^0.2.96", diff --git a/backend/scripts/gen-buyer-sig.ts b/backend/scripts/gen-buyer-sig.ts index a0a76cd..db88ea9 100644 --- a/backend/scripts/gen-buyer-sig.ts +++ b/backend/scripts/gen-buyer-sig.ts @@ -1,9 +1,6 @@ -import { - signSetOperator, - makeDepositsDomain, - SET_OPERATOR_TYPES, -} from '@antseed/node/payments'; -import { ethers } from 'ethers'; +import { signSetOperator, makeDepositsDomain, SET_OPERATOR_TYPES } from "@antseed/node/payments"; +import { AbstractSigner } from "ethers"; +import { ethers } from "ethers"; // also exported from '@antseed/node' const chainId = 8453; @@ -12,12 +9,11 @@ const domain = makeDepositsDomain(chainId, "0x0F7a3a8f4Da01637d1202bb5443fcF7F88 let wallet = new ethers.Wallet(process.argv[2]); //connect to base rpc provider wallet = wallet.connect(new ethers.JsonRpcProvider("https://base.drpc.org")); -const operator = "0x192288D921045aa96903e5286E116960e5fb4607" +const operator = "0x192288D921045aa96903e5286E116960e5fb4607"; const nonce = 0n; -const buyerSig = await signSetOperator(wallet, domain, { +const buyerSig = await signSetOperator(wallet as any, domain, { operator, - nonce, + nonce }); console.log("buyerSig", buyerSig); - diff --git a/backend/scripts/migrate-buyer-accounting.ts b/backend/scripts/migrate-buyer-accounting.ts new file mode 100644 index 0000000..ac885fc --- /dev/null +++ b/backend/scripts/migrate-buyer-accounting.ts @@ -0,0 +1,145 @@ +import { ethers } from "ethers"; + +const OPERATOR_ABI = [ + "event BuyerDepositFunded(address indexed buyer,uint256 principal,uint256 bonus)", + "event BuyerDepositFundedWithId(address indexed buyer,uint256 principal,uint256 bonus,string id)", + "function buyerAccountingMigrated(address buyer) view returns (bool)", + "function migrateBuyerAccounting(address[] buyers) external" +] as const; + +type BlockRange = { + fromBlock: number; + toBlock: number; +}; +const rpcUrl = "https://mainnet.base.org"; +const provider = new ethers.JsonRpcProvider(rpcUrl); +const operatorAddress = "0x192288D921045aa96903e5286E116960e5fb4607"; +const dryRun = process.env.DRY_RUN === "1" || process.env.DRY_RUN === "true"; +const runner = new ethers.Wallet(process.env.OPERATOR_OWNER_PRIVATE_KEY as string, provider); +const operator = new ethers.Contract(operatorAddress, OPERATOR_ABI, runner); +const eventInterface = new ethers.Interface(OPERATOR_ABI); + +const main = async () => { + const toBlock = await resolveToBlock(); + const fromBlock = 48055111; + const batchSize = optionalNumberEnv("BATCH_SIZE", 100); + + // new ethers.Wallet(mustAny(["DEPLOYER_PRIVATE_KEY", "OPERATOR_OWNER_PRIVATE_KEY", "ANTSEED_FUNDING_OPERATOR_PRIVATE_KEY"]), provider); + + if (fromBlock > toBlock) { + throw new Error(`FROM_BLOCK (${fromBlock}) must be <= TO_BLOCK (${toBlock})`); + } + + console.log(`Scanning ${operatorAddress} deposit events from block ${fromBlock} to ${toBlock}`); + + const buyers = await collectHistoricalBuyers({ fromBlock, toBlock }); + console.log(`Found ${buyers.length} unique buyer(s) in deposit events`); + + const unmigratedBuyers = await filterUnmigratedBuyers(buyers); + console.log(`${unmigratedBuyers.length} buyer(s) still need accounting migration`); + + if (dryRun) { + for (const buyer of unmigratedBuyers) console.log(buyer); + process.exit(0); + } + + for (let index = 0; index < unmigratedBuyers.length; index += batchSize) { + const batch = unmigratedBuyers.slice(index, index + batchSize); + console.log(`Migrating batch ${index / batchSize + 1}: ${batch.length} buyer(s)`); + const tx = await operator["migrateBuyerAccounting(address[])"](batch); + console.log(` sent ${tx.hash}`); + const receipt = await tx.wait(); + console.log(` confirmed in block ${receipt?.blockNumber}`); + } + + console.log("Buyer accounting migration complete"); +}; + +async function collectHistoricalBuyers(range: BlockRange): Promise { + const logChunkSize = optionalNumberEnv("LOG_CHUNK_SIZE", 10_000); + const buyers = new Map(); + const depositTopics = [ethers.id("BuyerDepositFunded(address,uint256,uint256)"), ethers.id("BuyerDepositFundedWithId(address,uint256,uint256,string)")]; + + for (const topic of depositTopics) { + for (let start = range.fromBlock; start <= range.toBlock; start += logChunkSize) { + console.log(`Querying logs for topic ${topic} from block ${start} to ${Math.min(start + logChunkSize - 1, range.toBlock)}`); + const end = Math.min(start + logChunkSize - 1, range.toBlock); + const logs = await provider.getLogs({ + address: operatorAddress, + fromBlock: start, + toBlock: end, + topics: [topic] + }); + + for (const log of logs) { + const parsed = eventInterface.parseLog(log); + if (!parsed) continue; + const buyer = ethers.getAddress(parsed.args.buyer as string); + buyers.set(buyer.toLowerCase(), buyer); + } + + if (logs.length > 0) { + console.log(` blocks ${start}-${end}: ${logs.length} deposit event(s)`); + } + } + } + + return [...buyers.values()].sort((left, right) => left.localeCompare(right)); +} + +async function filterUnmigratedBuyers(buyers: string[]): Promise { + const result: string[] = []; + for (const buyer of buyers) { + if (!(await operator.buyerAccountingMigrated(buyer))) { + result.push(buyer); + } + } + return result; +} + +async function resolveToBlock(): Promise { + const raw = process.env.TO_BLOCK; + if (!raw || raw === "latest") return provider.getBlockNumber(); + return parseBlockNumber(raw, "TO_BLOCK"); +} + +function optionalNumberEnv(name: string, fallback: number): number { + const value = process.env[name]; + if (!value) return fallback; + return parseBlockNumber(value, name); +} + +function parseBlockNumber(value: string, name: string): number { + if (!/^\d+$/.test(value)) throw new Error(`${name} must be a positive integer block number`); + const parsed = Number(value); + if (!Number.isSafeInteger(parsed)) throw new Error(`${name} is outside JavaScript safe integer range`); + return parsed; +} + +function printUsage(): void { + console.log(`Usage: + BASE_RPC_URL=https://mainnet.base.org \\ + ANTSEED_BUYER_OPERATOR_ADDRESS=0x... \\ + FROM_BLOCK= \\ + yarn migrate:buyer-accounting + +Required for sending migration transactions: + DEPLOYER_PRIVATE_KEY=0x... Owner/admin key for AntseedBuyerOperator + +Options: + TO_BLOCK=latest| Defaults to latest + DRY_RUN=1 Print unmigrated buyers without requiring a private key + BATCH_SIZE= Defaults to 100 buyers per transaction + LOG_CHUNK_SIZE= Defaults to 50000 blocks per log query + +Address fallback: + If ANTSEED_BUYER_OPERATOR_ADDRESS is omitted, deploy-base-output.json at the repository root is used. +`); +} + +if (process.argv.includes("--help") || process.argv.includes("-h")) { + printUsage(); + process.exit(0); +} else { + main(); +} diff --git a/backend/src/antseed-funding-vault.ts b/backend/src/antseed-funding-vault.ts index 55ccb0a..2319a5a 100644 --- a/backend/src/antseed-funding-vault.ts +++ b/backend/src/antseed-funding-vault.ts @@ -6,11 +6,15 @@ const FUNDING_VAULT_ABI = [ "function depositFor(address buyer, uint256 principal, uint256 bonus)", "function depositForWithId(address buyer, uint256 principal, uint256 bonus, string id)", "function acceptBuyerOperator(address buyer, uint256 nonce, bytes buyerSig)", - "function withdrawPrincipal(address buyer, uint256 amount, address recipient, uint256 timestamp, bytes buyerSig)", - "function requestClose(bytes32 channelId, uint256 timestamp, bytes buyerSig)", - "function withdrawChannel(bytes32 channelId, uint256 timestamp, bytes buyerSig)", + "function revokeOperator(address buyer, uint256 nonce, bytes buyerSig)", + "function withdrawPrincipal(address buyer, uint256 amount, address recipient, uint256 nonce, bytes buyerSig)", + "function requestClose(bytes32 channelId, uint256 nonce, bytes buyerSig)", + "function withdrawChannel(bytes32 channelId, uint256 nonce, bytes buyerSig)", + "function registry() view returns (address)", "function usedDepositIds(bytes32 id) view returns (bool)" ] as const; +const REGISTRY_ABI = ["function deposits() view returns (address)"] as const; +const DEPOSITS_ABI = ["function getOperator(address buyer) view returns (address)"] as const; export type AntSeedFundingResult = { enabled: boolean; @@ -29,11 +33,7 @@ export class AntSeedFundingVaultClient { } constructor(private readonly cfg: RuntimeConfig) { - this.enabled = Boolean( - cfg.ANTSEED_FUNDING_RPC_URL && - cfg.ANTSEED_FUNDING_VAULT_ADDRESS && - cfg.ANTSEED_FUNDING_OPERATOR_PRIVATE_KEY - ); + this.enabled = Boolean(cfg.ANTSEED_FUNDING_RPC_URL && cfg.ANTSEED_FUNDING_VAULT_ADDRESS && cfg.ANTSEED_FUNDING_OPERATOR_PRIVATE_KEY); if (this.enabled) { const provider = new ethers.JsonRpcProvider(cfg.ANTSEED_FUNDING_RPC_URL); const signer = new ethers.Wallet(cfg.ANTSEED_FUNDING_OPERATOR_PRIVATE_KEY!, provider); @@ -46,11 +46,7 @@ export class AntSeedFundingVaultClient { }); } - async acceptBuyerOperator( - buyer: string, - nonce: bigint, - signature: string - ): Promise<{ enabled: boolean; buyer: string; nonce: string; txHash?: string }> { + async acceptBuyerOperator(buyer: string, nonce: bigint, signature: string): Promise<{ enabled: boolean; buyer: string; nonce: string; txHash?: string }> { const normalizedBuyer = buyer.toLowerCase(); if (!this.contract) { return { enabled: false, buyer: normalizedBuyer, nonce: nonce.toString() }; @@ -65,6 +61,21 @@ export class AntSeedFundingVaultClient { }; } + async revokeBuyerOperator(buyer: string, nonce: bigint, signature: string): Promise<{ enabled: boolean; buyer: string; nonce: string; txHash?: string }> { + const normalizedBuyer = buyer.toLowerCase(); + if (!this.contract) { + return { enabled: false, buyer: normalizedBuyer, nonce: nonce.toString() }; + } + const tx = await this.contract.revokeOperator(normalizedBuyer, nonce, signature); + const receipt = await tx.wait(); + return { + enabled: true, + buyer: normalizedBuyer, + nonce: nonce.toString(), + txHash: receipt?.hash + }; + } + async depositForBuyer(buyer: string, principalUsd: bigint, bonusUsd: bigint): Promise { const total = principalUsd + bonusUsd; if (!this.contract) return { enabled: false, buyer, amountUsd: total.toString() }; @@ -141,23 +152,46 @@ export class AntSeedFundingVaultClient { } } - async withdrawPrincipalForBuyer(buyer: string, amountUsd: bigint, recipient: string, timestamp: number, signature: string): Promise<{ enabled: boolean; txHash?: string }> { + async isBuyerOperator(buyer: string): Promise<{ enabled: boolean; buyer: string; isOperator: boolean }> { + const normalizedBuyer = buyer.toLowerCase(); + if (!this.contract) return { enabled: false, buyer: normalizedBuyer, isOperator: false }; + + const operatorAddress = await this.contract.getAddress(); + const registryAddress = await this.contract.registry(); + const registry = new ethers.Contract(registryAddress, REGISTRY_ABI, this.contract.runner); + const depositsAddress = await registry.deposits(); + const deposits = new ethers.Contract(depositsAddress, DEPOSITS_ABI, this.contract.runner); + const currentOperator = await deposits.getOperator(normalizedBuyer); + return { + enabled: true, + buyer: normalizedBuyer, + isOperator: String(currentOperator).toLowerCase() === String(operatorAddress).toLowerCase() + }; + } + + async withdrawPrincipalForBuyer( + buyer: string, + amountUsd: bigint, + recipient: string, + nonce: bigint, + signature: string + ): Promise<{ enabled: boolean; txHash?: string }> { if (!this.contract) return { enabled: false }; - const tx = await this.contract.withdrawPrincipal(buyer, amountUsd, recipient, timestamp, signature); + const tx = await this.contract.withdrawPrincipal(buyer, amountUsd, recipient, nonce, signature); const receipt = await tx.wait(); return { enabled: true, txHash: receipt?.hash }; } - async requestClose(channelId: string, timestamp?: number, buyerSig?: string): Promise<{ enabled: boolean; txHash?: string }> { + async requestClose(channelId: string, nonce?: bigint, buyerSig?: string): Promise<{ enabled: boolean; txHash?: string }> { if (!this.contract) return { enabled: false }; - const tx = await this.contract.requestClose(channelId, timestamp ?? 0, buyerSig ?? "0x"); + const tx = await this.contract.requestClose(channelId, nonce ?? 0n, buyerSig ?? "0x"); const receipt = await tx.wait(); return { enabled: true, txHash: receipt?.hash }; } - async withdrawFromChannel(channelId: string, timestamp?: number, buyerSig?: string): Promise<{ enabled: boolean; txHash?: string }> { + async withdrawFromChannel(channelId: string, nonce?: bigint, buyerSig?: string): Promise<{ enabled: boolean; txHash?: string }> { if (!this.contract) return { enabled: false }; - const tx = await this.contract.withdrawChannel(channelId, timestamp ?? 0, buyerSig ?? "0x"); + const tx = await this.contract.withdrawChannel(channelId, nonce ?? 0n, buyerSig ?? "0x"); const receipt = await tx.wait(); return { enabled: true, txHash: receipt?.hash }; } diff --git a/backend/src/kv-credit-store.ts b/backend/src/kv-credit-store.ts index 7bf71cf..3ab2fd0 100644 --- a/backend/src/kv-credit-store.ts +++ b/backend/src/kv-credit-store.ts @@ -115,7 +115,10 @@ export class KVCreditStore { return entry; } - async markFundingResult(entry: GdCreditEntry, result: { funded: boolean; id?: string; txHash?: string; error?: string }): Promise { + async markFundingResult( + entry: GdCreditEntry, + result: { funded: boolean; id?: string; txHash?: string; error?: string; credited?: boolean } + ): Promise { if (entry.fundingStatus === "funded" || entry.fundingStatus === "failed") { logWarn("kv.funding.already-terminal", { entryId: entry.id, @@ -132,6 +135,7 @@ export class KVCreditStore { if (result.funded) { const now = new Date().toISOString(); + const credited = result.credited !== false; await this.updateUser(entry.account, entry.rootAccount, (current) => { const outstanding = BigInt(current.totalOutstandingFundingUsd); const creditAmount = BigInt(entry.totalCreditUsd); @@ -139,8 +143,8 @@ export class KVCreditStore { ...current, updatedAt: now, lastStreamCreditAt: entry.source.startsWith("stream") ? now : current.lastStreamCreditAt, - totalPrincipalUsd: (BigInt(current.totalPrincipalUsd) + BigInt(entry.principalUsd)).toString(), - totalBonusUsd: (BigInt(current.totalBonusUsd) + BigInt(entry.bonusUsd)).toString(), + totalPrincipalUsd: (BigInt(current.totalPrincipalUsd) + (credited ? BigInt(entry.principalUsd) : 0n)).toString(), + totalBonusUsd: (BigInt(current.totalBonusUsd) + (credited ? BigInt(entry.bonusUsd) : 0n)).toString(), totalOutstandingFundingUsd: (outstanding > creditAmount ? outstanding - creditAmount : 0n).toString() }; }); diff --git a/backend/src/worker.ts b/backend/src/worker.ts index 1af2a1b..f5d3a71 100644 --- a/backend/src/worker.ts +++ b/backend/src/worker.ts @@ -46,7 +46,7 @@ const StreamUpdateSchema = z.object({ const WithdrawPrincipalSchema = z.object({ amount: z.string().regex(/^\d+$/), recipient: z.string().regex(/^0x[0-9a-fA-F]{40}$/), - timestamp: z.number().int().nonnegative(), + nonce: z.string().regex(/^\d+$/), signature: z.string().regex(/^0x[0-9a-fA-F]+$/) }); const OperatorConsentSchema = z.object({ @@ -68,7 +68,7 @@ const CreditHistoryQuerySchema = z.object({ .optional() }); const ChannelOpSchema = z.object({ - timestamp: z.number().int().nonnegative().optional(), + nonce: z.string().regex(/^\d+$/).optional(), signature: z .string() .regex(/^0x[0-9a-fA-F]+$/) @@ -175,6 +175,10 @@ export default { continue; } const rootAccount = await fetchGoodIdRoot(stream.account, cfg); + const buyerForOperatorCheck = stream.buyerAddress || stream.account; + const hasOperatorConsent = antseedFundingVault.enabled ? (await antseedFundingVault.isBuyerOperator(buyerForOperatorCheck)).isOperator : true; + const isValidForBonus = !!rootAccount && hasOperatorConsent; + const depositId = createStreamFundingId(stream.account, new Date(createdAt)); const entry = await store.recordGdCredit({ id: depositId, @@ -183,7 +187,7 @@ export default { source: "streamCron", gdAmountWei: BigInt(gdAmountWei), flowRate: BigInt(stream.flowRateWeiPerSecond), - isVerified: !!rootAccount, // if root acccount was found it is whitelisted + isVerified: isValidForBonus, // if root acccount was found it is whitelisted & operator set gdPrice, maxBonusCapUsd: cfg.MAX_BONUS_CAP_USD, regularBonusBps: cfg.REGULAR_BONUS_BPS, @@ -404,6 +408,7 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis const gdPrice = await fetchCurrentGdPrice(cfg); for (const event of events) { const rootAccount = await fetchGoodIdRoot(event.account, cfg); + if (event.kind === "deposit") { if (event.gdAmountWei === 0n) { logInfo("celo.events.record.deposit.skipped.zero-amount", { @@ -413,6 +418,9 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis }); continue; } + const buyerForOperatorCheck = event.buyer || event.account; + const hasOperatorConsent = antseedFundingVault.enabled ? (await antseedFundingVault.isBuyerOperator(buyerForOperatorCheck)).isOperator : true; + const isValidForBonus = !!rootAccount && hasOperatorConsent; const depositId = `${event.txHash}:${event.logIndex}`; const entry = await store.recordGdCredit({ id: depositId, @@ -422,7 +430,7 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis gdAmountWei: event.gdAmountWei, txHash: event.txHash, logIndex: event.logIndex, - isVerified: !!rootAccount, // if root acccount was found it is whitelisted + isVerified: isValidForBonus, // if root acccount was found it is whitelisted & operator set gdPrice, maxBonusCapUsd: cfg.MAX_BONUS_CAP_USD, regularBonusBps: cfg.REGULAR_BONUS_BPS, @@ -440,6 +448,10 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis recorded.push(res); } else { const depositId = `${event.txHash}:${event.logIndex}`; + const buyerForOperatorCheck = event.buyer || event.account; + const hasOperatorConsent = + antseedFundingVault.enabled && event.totalFlowWei > 0n ? (await antseedFundingVault.isBuyerOperator(buyerForOperatorCheck)).isOperator : true; + const isValidForBonus = !!rootAccount && hasOperatorConsent; const entry = await store.recordGdCredit({ id: depositId, account: event.account, @@ -449,7 +461,7 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis flowRate: event.flowRateWeiPerSecond, txHash: event.txHash, logIndex: event.logIndex, - isVerified: !!rootAccount, // if root acccount was found it is whitelisted + isVerified: isValidForBonus, gdPrice, maxBonusCapUsd: cfg.MAX_BONUS_CAP_USD, regularBonusBps: cfg.REGULAR_BONUS_BPS, @@ -498,13 +510,12 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis const account = decodeURIComponent(streamCreditsMatch[1]).toLowerCase(); const profile = await store.getUser(account); const rootAccount = await fetchGoodIdRoot(account, cfg); - const isVerified = !!rootAccount; const streams = await fetchSuperfluidStreamsForAccount(account, cfg); + logInfo("stream.credits.start", { account: redactAddress(account), rootAccount: redactAddress(rootAccount), - streamCount: streams.length, - isVerified + streamCount: streams.length }); if (streams.length === 0) { logInfo("stream.credits.empty", { @@ -534,6 +545,10 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis const recorded = []; let skippedMinAmount = 0; for (const stream of streams) { + const buyerForOperatorCheck = stream.buyerAddress || account; + const hasOperatorConsent = antseedFundingVault.enabled ? (await antseedFundingVault.isBuyerOperator(buyerForOperatorCheck)).isOperator : true; + const isValidForBonus = !!rootAccount && hasOperatorConsent; + const isVerified = isValidForBonus; const gdAmountWei = BigInt(stream.flowRateWeiPerSecond) * BigInt(elapsedSeconds); if (gdAmountWei <= cfg.MIN_STREAM_BONUS_WEI) { skippedMinAmount += 1; @@ -563,7 +578,8 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis entryId: entry.id, account: redactAddress(entry.account), rootAccount: redactAddress(entry.rootAccount), - buyer: redactAddress(entry.buyerAddress) + buyer: redactAddress(entry.buyerAddress), + isValidForBonus }); const res = await fundCredit(entry, store, antseedFundingVault); recorded.push(res); @@ -603,6 +619,25 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis return json({ buyer, bridge }); } + const operatorRevokeMatch = url.pathname.match(/^\/v1\/accounts\/([^/]+)\/operator-revoke$/); + if (request.method === "POST" && operatorRevokeMatch) { + const buyer = decodeURIComponent(operatorRevokeMatch[1]).toLowerCase(); + const body = await parseJson(request); + const parsed = OperatorConsentSchema.safeParse(body); + if (!parsed.success) return json({ error: parsed.error.flatten() }, 400); + logInfo("operator.revoke.request", { + buyer: redactAddress(buyer), + nonce: parsed.data.nonce + }); + const bridge = await antseedFundingVault.revokeBuyerOperator(buyer, BigInt(parsed.data.nonce), parsed.data.signature); + logInfo("operator.revoke.result", { + buyer: redactAddress(buyer), + enabled: bridge.enabled, + txHash: redactHash(bridge.txHash) + }); + return json({ buyer, bridge }); + } + const withdrawMatch = url.pathname.match(/^\/v1\/accounts\/([^/]+)\/withdraw$/); if (request.method === "POST" && withdrawMatch) { const account = decodeURIComponent(withdrawMatch[1]).toLowerCase(); @@ -618,7 +653,7 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis account, BigInt(parsed.data.amount), parsed.data.recipient, - parsed.data.timestamp, + BigInt(parsed.data.nonce), parsed.data.signature ); logInfo("withdraw.result", { @@ -636,17 +671,18 @@ async function route(request: Request, env: Env, _ctx: ExecutionContext): Promis const body = request.headers.get("content-length") !== "0" ? await parseJson(request) : {}; const parsed = ChannelOpSchema.safeParse(body); if (!parsed.success) return json({ error: parsed.error.flatten() }, 400); - const { timestamp, signature } = parsed.data; + const { nonce, signature } = parsed.data; logInfo("channel.request", { action, channelId: redactHash(channelId), - hasTimestamp: timestamp !== undefined, + hasNonce: nonce !== undefined, hasSignature: Boolean(signature) }); + const parsedNonce = nonce === undefined ? undefined : BigInt(nonce); const bridge = action === "close" - ? await antseedFundingVault.requestClose(channelId, timestamp, signature) - : await antseedFundingVault.withdrawFromChannel(channelId, timestamp, signature); + ? await antseedFundingVault.requestClose(channelId, parsedNonce, signature) + : await antseedFundingVault.withdrawFromChannel(channelId, parsedNonce, signature); logInfo("channel.result", { action, channelId: redactHash(channelId), @@ -767,7 +803,11 @@ function nextUtcDate(date: string): string | undefined { return parsed.toISOString().slice(0, 10); } -async function fundCredit(entry: GdCreditEntry, store: KVCreditStore, antseedFundingVault: AntSeedFundingVaultClient): Promise<{ [key: string]: unknown }> { +export async function fundCredit( + entry: GdCreditEntry, + store: KVCreditStore, + antseedFundingVault: AntSeedFundingVaultClient +): Promise<{ [key: string]: unknown }> { const buyer = entry.buyerAddress || entry.account; if (entry.fundingStatus === "funded") { logInfo("funding.already-funded", { @@ -800,11 +840,11 @@ async function fundCredit(entry: GdCreditEntry, store: KVCreditStore, antseedFun totalCreditUsd: entry.totalCreditUsd }); try { - const bridge = - principalUsd + bonusUsd > 0n - ? await antseedFundingVault.depositForBuyerWithId(buyer, principalUsd, bonusUsd, entry.id) - : { enabled: antseedFundingVault.enabled, buyer, amountUsd: "0" }; - if (principalUsd + bonusUsd === 0n) { + const shouldCredit = principalUsd + bonusUsd > 0n; + const bridge = shouldCredit + ? await antseedFundingVault.depositForBuyerWithId(buyer, principalUsd, bonusUsd, entry.id) + : { enabled: antseedFundingVault.enabled, buyer, amountUsd: "0" }; + if (!shouldCredit) { logInfo("funding.skipped.zero-amount", { entryId: entry.id, source: entry.source, @@ -821,7 +861,8 @@ async function fundCredit(entry: GdCreditEntry, store: KVCreditStore, antseedFun const updated = await store.markFundingResult(entry, { funded: true, txHash: bridge.txHash, - error: undefined + error: undefined, + credited: shouldCredit }); logInfo("funding.success", { entryId: entry.id, diff --git a/backend/test/worker.test.ts b/backend/test/worker.test.ts index 7a6e641..5ac5d1e 100644 --- a/backend/test/worker.test.ts +++ b/backend/test/worker.test.ts @@ -1,9 +1,12 @@ import test from "node:test"; import assert from "node:assert/strict"; -import { Interface } from "ethers"; -import worker from "../src/worker.js"; +import { Interface, Wallet } from "ethers"; +import worker, { fundCredit } from "../src/worker.js"; +import { AntSeedFundingVaultClient } from "../src/antseed-funding-vault.js"; import { Env } from "../src/env.js"; +import { KVCreditStore } from "../src/kv-credit-store.js"; import { encodeVaultEventLog } from "../src/celo-events.js"; +import { GdCreditEntry } from "../src/types.js"; class MemoryKV { private data = new Map(); @@ -1054,7 +1057,7 @@ test("POST /v1/channels/:channelId/close with optional sig fields passes validat new Request(`https://worker.test/v1/channels/${CHANNEL_ID}/close`, { method: "POST", headers: { "content-type": "application/json" }, - body: JSON.stringify({ timestamp: 1234567890, signature: `0x${"b".repeat(130)}` }) + body: JSON.stringify({ nonce: "0", signature: `0x${"b".repeat(130)}` }) }), env(), makeExecutionContext() @@ -1111,6 +1114,41 @@ test("POST /v1/accounts/:account/operator-consent returns enabled:false when vau assert.equal(body.bridge.enabled, false); }); +test("POST /v1/accounts/:account/operator-revoke returns 400 on missing body fields", async () => { + const buyer = "0x0000000000000000000000000000000000000abc"; + const res = await worker.fetch( + new Request(`https://worker.test/v1/accounts/${buyer}/operator-revoke`, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({}) + }), + env(), + makeExecutionContext() + ); + assert.equal(res.status, 400); +}); + +test("POST /v1/accounts/:account/operator-revoke returns enabled:false when vault not configured", async () => { + const buyer = "0x0000000000000000000000000000000000000abc"; + const res = await worker.fetch( + new Request(`https://worker.test/v1/accounts/${buyer}/operator-revoke`, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + nonce: "0", + signature: `0x${"a".repeat(130)}` + }) + }), + env(), + makeExecutionContext() + ); + assert.equal(res.status, 200); + const body = (await res.json()) as { buyer: string; bridge: { enabled: boolean; nonce: string } }; + assert.equal(body.buyer, buyer); + assert.equal(body.bridge.enabled, false); + assert.equal(body.bridge.nonce, "0"); +}); + test("POST /v1/accounts/:account/withdraw returns 400 on missing body fields", async () => { const account = "0x0000000000000000000000000000000000000abc"; const res = await worker.fetch( @@ -1134,7 +1172,7 @@ test("POST /v1/accounts/:account/withdraw returns 400 on invalid recipient addre body: JSON.stringify({ amount: "5000000", recipient: "not-an-address", - timestamp: 1234567890, + nonce: "0", signature: `0x${"b".repeat(130)}` }) }), @@ -1154,7 +1192,7 @@ test("POST /v1/accounts/:account/withdraw returns enabled:false when vault not c body: JSON.stringify({ amount: "5000000", recipient, - timestamp: 1234567890, + nonce: "0", signature: `0x${"b".repeat(130)}` }) }), @@ -1453,6 +1491,137 @@ test("GET /v1/accounts/:account/outstanding returns failed funding entries", asy assert.equal(body.failedFundingCredits[0].fundingError, "vault reverted"); }); +test("/v1/celo/events/record sets stream bonus to 0 when buyer revoked operator", { concurrency: false }, async () => { + const account = "0x0000000000000000000000000000000000000abc"; + const buyer = "0x0000000000000000000000000000000000000aaa"; + const txHash = `0x${"7".repeat(64)}`; + const celoVault = "0x0000000000000000000000000000000000000def"; + const goodIdAddr = "0x0000000000000000000000000000000000001234"; + const originalFetch = globalThis.fetch; + const originalIsBuyerOperator = AntSeedFundingVaultClient.prototype.isBuyerOperator; + const originalDepositForBuyerWithId = AntSeedFundingVaultClient.prototype.depositForBuyerWithId; + + let depositCalls = 0; + + try { + const testEnv = env({ + CELO_RPC_URL: "https://celo.rpc.local", + CELO_VAULT_ADDRESS: celoVault, + CELO_GOODID_ADDRESS: goodIdAddr, + ANTSEED_FUNDING_RPC_URL: "https://base.rpc.local", + ANTSEED_FUNDING_VAULT_ADDRESS: "0x0000000000000000000000000000000000000b01", + ANTSEED_FUNDING_OPERATOR_PRIVATE_KEY: Wallet.createRandom().privateKey + }); + + const streamLog = encodeVaultEventLog( + "StreamUpdated", + [account, buyer, 385_802_469_136n, 1_000_000_000_000_000_000n, 2_000_000_000_000_000_000n], + celoVault, + txHash, + 0 + ); + + AntSeedFundingVaultClient.prototype.isBuyerOperator = async function (operatorBuyer: string) { + return { enabled: true, buyer: operatorBuyer.toLowerCase(), isOperator: false }; + }; + + AntSeedFundingVaultClient.prototype.depositForBuyerWithId = async function (operatorBuyer: string, principalUsd: bigint, bonusUsd: bigint) { + depositCalls += 1; + assert.equal(operatorBuyer, buyer.toLowerCase()); + assert.equal(principalUsd, 200n); + assert.equal(bonusUsd, 0n); + return { enabled: true, buyer: operatorBuyer, amountUsd: "200", txHash: "0xfunded" }; + }; + + globalThis.fetch = (async (_url: string | URL | Request, init?: RequestInit) => { + const body = JSON.parse(String(init?.body)); + if (body.method === "eth_call") { + return Response.json({ + jsonrpc: "2.0", + id: body.id, + result: "0x000000000000000000000000abababababababababababababababababababab" + }); + } + return Response.json({ jsonrpc: "2.0", id: body.id, result: { logs: [streamLog] } }); + }) as typeof fetch; + + const res = await worker.fetch( + new Request("https://worker.test/v1/celo/events/record", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ txHash }) + }), + testEnv, + makeExecutionContext() + ); + + assert.equal(res.status, 200); + const body = (await res.json()) as { + events: Array<{ source: string; fundingStatus: string; principalUsd: string; bonusUsd: string; buyerAddress?: string }>; + }; + assert.equal(body.events.length, 1); + assert.equal(body.events[0].source, "streamUpdate"); + assert.equal(body.events[0].fundingStatus, "funded"); + assert.equal(body.events[0].principalUsd, "200"); + assert.equal(body.events[0].bonusUsd, "0"); + assert.equal(body.events[0].buyerAddress, buyer.toLowerCase()); + assert.equal(depositCalls, 1); + } finally { + AntSeedFundingVaultClient.prototype.isBuyerOperator = originalIsBuyerOperator; + AntSeedFundingVaultClient.prototype.depositForBuyerWithId = originalDepositForBuyerWithId; + globalThis.fetch = originalFetch; + } +}); + +test("fundCredit deposits bonus-only credits when buyer still uses operator", async () => { + const account = "0x0000000000000000000000000000000000000abc"; + const buyer = "0x0000000000000000000000000000000000000aaa"; + const kv = new MemoryKV(); + const store = new KVCreditStore(kv as never); + const entry: GdCreditEntry = { + id: "stream:bonus-only:operator:test", + account: account.toLowerCase(), + rootAccount: account.toLowerCase(), + source: "streamUpdate", + gdAmountWei: "0", + principalUsd: "0", + bonusUsd: "40", + totalCreditUsd: "40", + fundingStatus: "pending", + createdAt: new Date().toISOString(), + streamUpdateMonth: "2026-08", + buyerAddress: buyer.toLowerCase() + }; + await kv.put(`user:${account.toLowerCase()}`, JSON.stringify({ account: account.toLowerCase(), totalOutstandingFundingUsd: "40" })); + + let depositCalls = 0; + const vault = { + enabled: true, + async isBuyerOperator() { + return { enabled: true, buyer: buyer.toLowerCase(), isOperator: true }; + }, + async depositForBuyerWithId(_buyer: string, principalUsd: bigint, bonusUsd: bigint, id: string) { + depositCalls += 1; + assert.equal(_buyer, buyer.toLowerCase()); + assert.equal(principalUsd, 0n); + assert.equal(bonusUsd, 40n); + assert.equal(id, entry.id); + return { enabled: true, buyer: _buyer, amountUsd: "40", txHash: "0xfunded" }; + } + }; + + const result = await fundCredit(entry, store, vault as never); + const updatedEntry = (await kv.get("gd-credit:stream:bonus-only:operator:test", "json")) as GdCreditEntry; + const profile = (await kv.get(`user:${account.toLowerCase()}`, "json")) as { totalOutstandingFundingUsd: string; totalBonusUsd: string }; + + assert.equal(depositCalls, 1); + assert.equal(updatedEntry.fundingStatus, "funded"); + assert.equal(updatedEntry.fundingTxHash, "0xfunded"); + assert.equal(profile.totalOutstandingFundingUsd, "0"); + assert.equal(profile.totalBonusUsd, "40"); + assert.deepEqual(result.bridge, { enabled: true, buyer: buyer.toLowerCase(), amountUsd: "40", txHash: "0xfunded" }); +}); + test("POST /v1/accounts/:account/stream-credits rate-limits when credits issued within 24h", { concurrency: false }, async () => { const account = "0x0000000000000000000000000000000000000abc"; const celoVault = "0x0000000000000000000000000000000000000def"; diff --git a/backend/yarn.lock b/backend/yarn.lock index fbab769..a9d066b 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -12,25 +12,41 @@ __metadata: languageName: node linkType: hard -"@adraffy/ens-normalize@npm:^1.11.0": +"@adraffy/ens-normalize@npm:1.11.1, @adraffy/ens-normalize@npm:^1.11.0": version: 1.11.1 resolution: "@adraffy/ens-normalize@npm:1.11.1" checksum: e8b17fcc730ccc45a956e1fbb09edfe42be41c291079512082e9964f8ef4287e67913183cdd02fff71d2e215340d5b98a9bbbd9be32c5d36fad4ba2c1ec33ff2 languageName: node linkType: hard -"@antseed/api-adapter@npm:0.1.39": - version: 0.1.39 - resolution: "@antseed/api-adapter@npm:0.1.39" - checksum: 4fac33fa12a0d4127ef8a1a536ea7cb3b73c3d9523f6f8b26598e0f20a1e681612d8a74254a03390d6e172659b44156aee80e1c1f0600de69e62d0a427b8f085 +"@antseed/api-adapter@npm:0.1.45": + version: 0.1.45 + resolution: "@antseed/api-adapter@npm:0.1.45" + dependencies: + tokenx: ^1.3.0 + checksum: d459a501d0ccf890d668bc9166199316ff51b54f117cb967e6061be6ac7986b6c3bb391ac051bb27a46b9ea6f2142e512035d5d3b47589ff4818d11579e891c0 + languageName: node + linkType: hard + +"@antseed/buyer-core@npm:0.1.5": + version: 0.1.5 + resolution: "@antseed/buyer-core@npm:0.1.5" + dependencies: + "@antseed/api-adapter": 0.1.45 + "@antseed/protocol": 0.1.4 + ethers: ~6.16.0 + tokenx: ^1.3.0 + checksum: a03a7d617b3230b1582fd56c5f6b9656d98d20e74f14859bbd506909399884bd816bf4abf131a9f7d875933509f29fe0af33b7d399ce3bf1a2f337dccebdfcf1 languageName: node linkType: hard "@antseed/node@npm:^0.2.96": - version: 0.2.96 - resolution: "@antseed/node@npm:0.2.96" + version: 0.2.113 + resolution: "@antseed/node@npm:0.2.113" dependencies: - "@antseed/api-adapter": 0.1.39 + "@antseed/api-adapter": 0.1.45 + "@antseed/buyer-core": 0.1.5 + "@antseed/protocol": 0.1.4 "@silentbot1/nat-api": ^0.4.9 better-sqlite3: ^12.6.2 bittorrent-dht: ^11.0.11 @@ -41,7 +57,16 @@ __metadata: dependenciesMeta: keytar: optional: true - checksum: 0f85db96fda055bee426b149f337e7e30ad1205bf1eac73617b8c3c35f1a2bb92c6d0891de2c0ecb22d4b15242796742fca040d41027a8a4aa4581e58826a4cc + checksum: 73bb397c04c1a5101c04a4031b6d5a520033c23534771c1ca5638e32d232c11dbcf890f824558292a372b760408ece66f777017541d71b11a1af03a9ae95fe19 + languageName: node + linkType: hard + +"@antseed/protocol@npm:0.1.4": + version: 0.1.4 + resolution: "@antseed/protocol@npm:0.1.4" + dependencies: + ethers: ~6.16.0 + checksum: 57bfbcbebec462be5d1f90c625637fd83c25a5a000c0c065d48027ac8b4d46ff380f6702363f86b1a606a210730feeaac60cb70ba5ef84ed68828541498e1b1e languageName: node linkType: hard @@ -65,45 +90,45 @@ __metadata: languageName: node linkType: hard -"@cloudflare/workerd-darwin-64@npm:1.20260515.1": - version: 1.20260515.1 - resolution: "@cloudflare/workerd-darwin-64@npm:1.20260515.1" +"@cloudflare/workerd-darwin-64@npm:1.20260815.1": + version: 1.20260815.1 + resolution: "@cloudflare/workerd-darwin-64@npm:1.20260815.1" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@cloudflare/workerd-darwin-arm64@npm:1.20260515.1": - version: 1.20260515.1 - resolution: "@cloudflare/workerd-darwin-arm64@npm:1.20260515.1" +"@cloudflare/workerd-darwin-arm64@npm:1.20260815.1": + version: 1.20260815.1 + resolution: "@cloudflare/workerd-darwin-arm64@npm:1.20260815.1" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@cloudflare/workerd-linux-64@npm:1.20260515.1": - version: 1.20260515.1 - resolution: "@cloudflare/workerd-linux-64@npm:1.20260515.1" +"@cloudflare/workerd-linux-64@npm:1.20260815.1": + version: 1.20260815.1 + resolution: "@cloudflare/workerd-linux-64@npm:1.20260815.1" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@cloudflare/workerd-linux-arm64@npm:1.20260515.1": - version: 1.20260515.1 - resolution: "@cloudflare/workerd-linux-arm64@npm:1.20260515.1" +"@cloudflare/workerd-linux-arm64@npm:1.20260815.1": + version: 1.20260815.1 + resolution: "@cloudflare/workerd-linux-arm64@npm:1.20260815.1" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@cloudflare/workerd-windows-64@npm:1.20260515.1": - version: 1.20260515.1 - resolution: "@cloudflare/workerd-windows-64@npm:1.20260515.1" +"@cloudflare/workerd-windows-64@npm:1.20260815.1": + version: 1.20260815.1 + resolution: "@cloudflare/workerd-windows-64@npm:1.20260815.1" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@cloudflare/workers-types@npm:^4.20260518.0": - version: 4.20260518.1 - resolution: "@cloudflare/workers-types@npm:4.20260518.1" - checksum: b4a41dfc6e55ceaef1d6bb05cdad25bb1ebb5393a966e8fc0bc5ba380a2455388484e9f831db36741623358fa5fbb2efc8ca458fd134c37391d813ce0b1ae928 + version: 4.20260702.1 + resolution: "@cloudflare/workers-types@npm:4.20260702.1" + checksum: 6233d5c284da49103e795cc7e57ccd0a779416aa5bcb8dfac139aa7e23a70a0f4a946a5149d0ec7bd4b6c76aaede5202bcee9b09aa5c9bc0d553f3fb9be0d6b8 languageName: node linkType: hard @@ -116,7 +141,7 @@ __metadata: languageName: node linkType: hard -"@emnapi/runtime@npm:^1.7.0": +"@emnapi/runtime@npm:^1.11.1": version: 1.11.3 resolution: "@emnapi/runtime@npm:1.11.3" dependencies: @@ -125,366 +150,366 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/aix-ppc64@npm:0.27.3" +"@esbuild/aix-ppc64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/aix-ppc64@npm:0.28.1" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/aix-ppc64@npm:0.28.0" +"@esbuild/aix-ppc64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/aix-ppc64@npm:0.28.2" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/android-arm64@npm:0.27.3" +"@esbuild/android-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/android-arm64@npm:0.28.1" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/android-arm64@npm:0.28.0" +"@esbuild/android-arm64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/android-arm64@npm:0.28.2" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/android-arm@npm:0.27.3" +"@esbuild/android-arm@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/android-arm@npm:0.28.1" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-arm@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/android-arm@npm:0.28.0" +"@esbuild/android-arm@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/android-arm@npm:0.28.2" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/android-x64@npm:0.27.3" +"@esbuild/android-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/android-x64@npm:0.28.1" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/android-x64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/android-x64@npm:0.28.0" +"@esbuild/android-x64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/android-x64@npm:0.28.2" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/darwin-arm64@npm:0.27.3" +"@esbuild/darwin-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/darwin-arm64@npm:0.28.1" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/darwin-arm64@npm:0.28.0" +"@esbuild/darwin-arm64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/darwin-arm64@npm:0.28.2" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/darwin-x64@npm:0.27.3" +"@esbuild/darwin-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/darwin-x64@npm:0.28.1" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/darwin-x64@npm:0.28.0" +"@esbuild/darwin-x64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/darwin-x64@npm:0.28.2" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/freebsd-arm64@npm:0.27.3" +"@esbuild/freebsd-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/freebsd-arm64@npm:0.28.1" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/freebsd-arm64@npm:0.28.0" +"@esbuild/freebsd-arm64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/freebsd-arm64@npm:0.28.2" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/freebsd-x64@npm:0.27.3" +"@esbuild/freebsd-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/freebsd-x64@npm:0.28.1" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/freebsd-x64@npm:0.28.0" +"@esbuild/freebsd-x64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/freebsd-x64@npm:0.28.2" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/linux-arm64@npm:0.27.3" +"@esbuild/linux-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-arm64@npm:0.28.1" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/linux-arm64@npm:0.28.0" +"@esbuild/linux-arm64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/linux-arm64@npm:0.28.2" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/linux-arm@npm:0.27.3" +"@esbuild/linux-arm@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-arm@npm:0.28.1" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/linux-arm@npm:0.28.0" +"@esbuild/linux-arm@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/linux-arm@npm:0.28.2" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/linux-ia32@npm:0.27.3" +"@esbuild/linux-ia32@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-ia32@npm:0.28.1" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/linux-ia32@npm:0.28.0" +"@esbuild/linux-ia32@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/linux-ia32@npm:0.28.2" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/linux-loong64@npm:0.27.3" +"@esbuild/linux-loong64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-loong64@npm:0.28.1" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/linux-loong64@npm:0.28.0" +"@esbuild/linux-loong64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/linux-loong64@npm:0.28.2" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/linux-mips64el@npm:0.27.3" +"@esbuild/linux-mips64el@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-mips64el@npm:0.28.1" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/linux-mips64el@npm:0.28.0" +"@esbuild/linux-mips64el@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/linux-mips64el@npm:0.28.2" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/linux-ppc64@npm:0.27.3" +"@esbuild/linux-ppc64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-ppc64@npm:0.28.1" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/linux-ppc64@npm:0.28.0" +"@esbuild/linux-ppc64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/linux-ppc64@npm:0.28.2" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/linux-riscv64@npm:0.27.3" +"@esbuild/linux-riscv64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-riscv64@npm:0.28.1" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/linux-riscv64@npm:0.28.0" +"@esbuild/linux-riscv64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/linux-riscv64@npm:0.28.2" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/linux-s390x@npm:0.27.3" +"@esbuild/linux-s390x@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-s390x@npm:0.28.1" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/linux-s390x@npm:0.28.0" +"@esbuild/linux-s390x@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/linux-s390x@npm:0.28.2" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/linux-x64@npm:0.27.3" +"@esbuild/linux-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-x64@npm:0.28.1" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/linux-x64@npm:0.28.0" +"@esbuild/linux-x64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/linux-x64@npm:0.28.2" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-arm64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/netbsd-arm64@npm:0.27.3" +"@esbuild/netbsd-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/netbsd-arm64@npm:0.28.1" conditions: os=netbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/netbsd-arm64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/netbsd-arm64@npm:0.28.0" +"@esbuild/netbsd-arm64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/netbsd-arm64@npm:0.28.2" conditions: os=netbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/netbsd-x64@npm:0.27.3" +"@esbuild/netbsd-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/netbsd-x64@npm:0.28.1" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/netbsd-x64@npm:0.28.0" +"@esbuild/netbsd-x64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/netbsd-x64@npm:0.28.2" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/openbsd-arm64@npm:0.27.3" +"@esbuild/openbsd-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/openbsd-arm64@npm:0.28.1" conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/openbsd-arm64@npm:0.28.0" +"@esbuild/openbsd-arm64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/openbsd-arm64@npm:0.28.2" conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/openbsd-x64@npm:0.27.3" +"@esbuild/openbsd-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/openbsd-x64@npm:0.28.1" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/openbsd-x64@npm:0.28.0" +"@esbuild/openbsd-x64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/openbsd-x64@npm:0.28.2" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openharmony-arm64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/openharmony-arm64@npm:0.27.3" +"@esbuild/openharmony-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/openharmony-arm64@npm:0.28.1" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@esbuild/openharmony-arm64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/openharmony-arm64@npm:0.28.0" +"@esbuild/openharmony-arm64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/openharmony-arm64@npm:0.28.2" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/sunos-x64@npm:0.27.3" +"@esbuild/sunos-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/sunos-x64@npm:0.28.1" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/sunos-x64@npm:0.28.0" +"@esbuild/sunos-x64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/sunos-x64@npm:0.28.2" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/win32-arm64@npm:0.27.3" +"@esbuild/win32-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/win32-arm64@npm:0.28.1" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/win32-arm64@npm:0.28.0" +"@esbuild/win32-arm64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/win32-arm64@npm:0.28.2" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/win32-ia32@npm:0.27.3" +"@esbuild/win32-ia32@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/win32-ia32@npm:0.28.1" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/win32-ia32@npm:0.28.0" +"@esbuild/win32-ia32@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/win32-ia32@npm:0.28.2" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.27.3": - version: 0.27.3 - resolution: "@esbuild/win32-x64@npm:0.27.3" +"@esbuild/win32-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/win32-x64@npm:0.28.1" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.28.0": - version: 0.28.0 - resolution: "@esbuild/win32-x64@npm:0.28.0" +"@esbuild/win32-x64@npm:0.28.2": + version: 0.28.2 + resolution: "@esbuild/win32-x64@npm:0.28.2" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -505,18 +530,18 @@ __metadata: languageName: unknown linkType: soft -"@img/colour@npm:^1.0.0": +"@img/colour@npm:^1.1.0": version: 1.1.0 resolution: "@img/colour@npm:1.1.0" checksum: 1572b4f154fe5987e02e107c32f64a9f50a18cab4a2015b7e53f48317b20c58e00cc2e09467378a2d4f06a6139cabd259b1b6d224e79a3bd6b66daea70a6613d languageName: node linkType: hard -"@img/sharp-darwin-arm64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-darwin-arm64@npm:0.34.5" +"@img/sharp-darwin-arm64@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-darwin-arm64@npm:0.35.2" dependencies: - "@img/sharp-libvips-darwin-arm64": 1.2.4 + "@img/sharp-libvips-darwin-arm64": 1.3.1 dependenciesMeta: "@img/sharp-libvips-darwin-arm64": optional: true @@ -524,11 +549,11 @@ __metadata: languageName: node linkType: hard -"@img/sharp-darwin-x64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-darwin-x64@npm:0.34.5" +"@img/sharp-darwin-x64@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-darwin-x64@npm:0.35.2" dependencies: - "@img/sharp-libvips-darwin-x64": 1.2.4 + "@img/sharp-libvips-darwin-x64": 1.3.1 dependenciesMeta: "@img/sharp-libvips-darwin-x64": optional: true @@ -536,81 +561,90 @@ __metadata: languageName: node linkType: hard -"@img/sharp-libvips-darwin-arm64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-darwin-arm64@npm:1.2.4" +"@img/sharp-freebsd-wasm32@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-freebsd-wasm32@npm:0.35.2" + dependencies: + "@img/sharp-wasm32": 0.35.2 + conditions: os=freebsd + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-arm64@npm:1.3.1": + version: 1.3.1 + resolution: "@img/sharp-libvips-darwin-arm64@npm:1.3.1" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@img/sharp-libvips-darwin-x64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-darwin-x64@npm:1.2.4" +"@img/sharp-libvips-darwin-x64@npm:1.3.1": + version: 1.3.1 + resolution: "@img/sharp-libvips-darwin-x64@npm:1.3.1" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@img/sharp-libvips-linux-arm64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-arm64@npm:1.2.4" +"@img/sharp-libvips-linux-arm64@npm:1.3.1": + version: 1.3.1 + resolution: "@img/sharp-libvips-linux-arm64@npm:1.3.1" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@img/sharp-libvips-linux-arm@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-arm@npm:1.2.4" +"@img/sharp-libvips-linux-arm@npm:1.3.1": + version: 1.3.1 + resolution: "@img/sharp-libvips-linux-arm@npm:1.3.1" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@img/sharp-libvips-linux-ppc64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-ppc64@npm:1.2.4" +"@img/sharp-libvips-linux-ppc64@npm:1.3.1": + version: 1.3.1 + resolution: "@img/sharp-libvips-linux-ppc64@npm:1.3.1" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@img/sharp-libvips-linux-riscv64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-riscv64@npm:1.2.4" +"@img/sharp-libvips-linux-riscv64@npm:1.3.1": + version: 1.3.1 + resolution: "@img/sharp-libvips-linux-riscv64@npm:1.3.1" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@img/sharp-libvips-linux-s390x@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-s390x@npm:1.2.4" +"@img/sharp-libvips-linux-s390x@npm:1.3.1": + version: 1.3.1 + resolution: "@img/sharp-libvips-linux-s390x@npm:1.3.1" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@img/sharp-libvips-linux-x64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-x64@npm:1.2.4" +"@img/sharp-libvips-linux-x64@npm:1.3.1": + version: 1.3.1 + resolution: "@img/sharp-libvips-linux-x64@npm:1.3.1" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@img/sharp-libvips-linuxmusl-arm64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.2.4" +"@img/sharp-libvips-linuxmusl-arm64@npm:1.3.1": + version: 1.3.1 + resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.3.1" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@img/sharp-libvips-linuxmusl-x64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.2.4" +"@img/sharp-libvips-linuxmusl-x64@npm:1.3.1": + version: 1.3.1 + resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.3.1" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@img/sharp-linux-arm64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-arm64@npm:0.34.5" +"@img/sharp-linux-arm64@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-linux-arm64@npm:0.35.2" dependencies: - "@img/sharp-libvips-linux-arm64": 1.2.4 + "@img/sharp-libvips-linux-arm64": 1.3.1 dependenciesMeta: "@img/sharp-libvips-linux-arm64": optional: true @@ -618,11 +652,11 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linux-arm@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-arm@npm:0.34.5" +"@img/sharp-linux-arm@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-linux-arm@npm:0.35.2" dependencies: - "@img/sharp-libvips-linux-arm": 1.2.4 + "@img/sharp-libvips-linux-arm": 1.3.1 dependenciesMeta: "@img/sharp-libvips-linux-arm": optional: true @@ -630,11 +664,11 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linux-ppc64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-ppc64@npm:0.34.5" +"@img/sharp-linux-ppc64@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-linux-ppc64@npm:0.35.2" dependencies: - "@img/sharp-libvips-linux-ppc64": 1.2.4 + "@img/sharp-libvips-linux-ppc64": 1.3.1 dependenciesMeta: "@img/sharp-libvips-linux-ppc64": optional: true @@ -642,11 +676,11 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linux-riscv64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-riscv64@npm:0.34.5" +"@img/sharp-linux-riscv64@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-linux-riscv64@npm:0.35.2" dependencies: - "@img/sharp-libvips-linux-riscv64": 1.2.4 + "@img/sharp-libvips-linux-riscv64": 1.3.1 dependenciesMeta: "@img/sharp-libvips-linux-riscv64": optional: true @@ -654,11 +688,11 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linux-s390x@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-s390x@npm:0.34.5" +"@img/sharp-linux-s390x@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-linux-s390x@npm:0.35.2" dependencies: - "@img/sharp-libvips-linux-s390x": 1.2.4 + "@img/sharp-libvips-linux-s390x": 1.3.1 dependenciesMeta: "@img/sharp-libvips-linux-s390x": optional: true @@ -666,11 +700,11 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linux-x64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-x64@npm:0.34.5" +"@img/sharp-linux-x64@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-linux-x64@npm:0.35.2" dependencies: - "@img/sharp-libvips-linux-x64": 1.2.4 + "@img/sharp-libvips-linux-x64": 1.3.1 dependenciesMeta: "@img/sharp-libvips-linux-x64": optional: true @@ -678,11 +712,11 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linuxmusl-arm64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linuxmusl-arm64@npm:0.34.5" +"@img/sharp-linuxmusl-arm64@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-linuxmusl-arm64@npm:0.35.2" dependencies: - "@img/sharp-libvips-linuxmusl-arm64": 1.2.4 + "@img/sharp-libvips-linuxmusl-arm64": 1.3.1 dependenciesMeta: "@img/sharp-libvips-linuxmusl-arm64": optional: true @@ -690,11 +724,11 @@ __metadata: languageName: node linkType: hard -"@img/sharp-linuxmusl-x64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linuxmusl-x64@npm:0.34.5" +"@img/sharp-linuxmusl-x64@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-linuxmusl-x64@npm:0.35.2" dependencies: - "@img/sharp-libvips-linuxmusl-x64": 1.2.4 + "@img/sharp-libvips-linuxmusl-x64": 1.3.1 dependenciesMeta: "@img/sharp-libvips-linuxmusl-x64": optional: true @@ -702,32 +736,41 @@ __metadata: languageName: node linkType: hard -"@img/sharp-wasm32@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-wasm32@npm:0.34.5" +"@img/sharp-wasm32@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-wasm32@npm:0.35.2" + dependencies: + "@emnapi/runtime": ^1.11.1 + checksum: e71022251df977c81675308a4eae78ffd2fec3b3320a104e0b2839900103fdf5dc441f0f75af4f10293cc75250d0fff86dade8638ffcb96e3b2a1b65577274e5 + languageName: node + linkType: hard + +"@img/sharp-webcontainers-wasm32@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-webcontainers-wasm32@npm:0.35.2" dependencies: - "@emnapi/runtime": ^1.7.0 + "@img/sharp-wasm32": 0.35.2 conditions: cpu=wasm32 languageName: node linkType: hard -"@img/sharp-win32-arm64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-win32-arm64@npm:0.34.5" +"@img/sharp-win32-arm64@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-win32-arm64@npm:0.35.2" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@img/sharp-win32-ia32@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-win32-ia32@npm:0.34.5" +"@img/sharp-win32-ia32@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-win32-ia32@npm:0.35.2" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@img/sharp-win32-x64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-win32-x64@npm:0.34.5" +"@img/sharp-win32-x64@npm:0.35.2": + version: 0.35.2 + resolution: "@img/sharp-win32-x64@npm:0.35.2" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -765,6 +808,13 @@ __metadata: languageName: node linkType: hard +"@napi-rs/lzma-linux-x64-gnu@npm:1.5.1": + version: 1.5.1 + resolution: "@napi-rs/lzma-linux-x64-gnu@npm:1.5.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@noble/ciphers@npm:^1.3.0": version: 1.3.0 resolution: "@noble/ciphers@npm:1.3.0" @@ -840,177 +890,177 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.62.2" +"@rollup/rollup-android-arm-eabi@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.62.4" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-android-arm64@npm:4.62.2" +"@rollup/rollup-android-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-android-arm64@npm:4.62.4" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-darwin-arm64@npm:4.62.2" +"@rollup/rollup-darwin-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-darwin-arm64@npm:4.62.4" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-darwin-x64@npm:4.62.2" +"@rollup/rollup-darwin-x64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-darwin-x64@npm:4.62.4" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.62.2" +"@rollup/rollup-freebsd-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.62.4" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-freebsd-x64@npm:4.62.2" +"@rollup/rollup-freebsd-x64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-freebsd-x64@npm:4.62.4" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.62.2" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.62.4" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.62.2" +"@rollup/rollup-linux-arm-musleabihf@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.62.4" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.62.2" +"@rollup/rollup-linux-arm64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.62.4" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.62.2" +"@rollup/rollup-linux-arm64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.62.4" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loong64-gnu@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.62.2" +"@rollup/rollup-linux-loong64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.62.4" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-loong64-musl@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-loong64-musl@npm:4.62.2" +"@rollup/rollup-linux-loong64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-loong64-musl@npm:4.62.4" conditions: os=linux & cpu=loong64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-ppc64-gnu@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.62.2" +"@rollup/rollup-linux-ppc64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.62.4" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-ppc64-musl@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.62.2" +"@rollup/rollup-linux-ppc64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.62.4" conditions: os=linux & cpu=ppc64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.62.2" +"@rollup/rollup-linux-riscv64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.62.4" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-musl@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.62.2" +"@rollup/rollup-linux-riscv64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.62.4" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.62.2" +"@rollup/rollup-linux-s390x-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.62.4" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.62.2" +"@rollup/rollup-linux-x64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.62.4" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.62.2" +"@rollup/rollup-linux-x64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.62.4" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-openbsd-x64@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-openbsd-x64@npm:4.62.2" +"@rollup/rollup-openbsd-x64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-openbsd-x64@npm:4.62.4" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-openharmony-arm64@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-openharmony-arm64@npm:4.62.2" +"@rollup/rollup-openharmony-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.62.4" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.62.2" +"@rollup/rollup-win32-arm64-msvc@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.62.4" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.62.2" +"@rollup/rollup-win32-ia32-msvc@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.62.4" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-gnu@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-win32-x64-gnu@npm:4.62.2" +"@rollup/rollup-win32-x64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.62.4" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.62.2": - version: 4.62.2 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.62.2" +"@rollup/rollup-win32-x64-msvc@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.62.4" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -1065,9 +1115,9 @@ __metadata: linkType: hard "@speed-highlight/core@npm:^1.2.7": - version: 1.2.15 - resolution: "@speed-highlight/core@npm:1.2.15" - checksum: 9644fcad2daa0d7cd1832b382ff7f0078a0bb3751e4eba29253612ad874b57658f6c28848fdaab8aa9bd0ada2aec9bb5392935f43c666e4caca4ddad267ac402 + version: 1.2.24 + resolution: "@speed-highlight/core@npm:1.2.24" + checksum: adb5914145969ff27c05508f082d5bdeaf44998e585a1c156a78334ec8003de1f3ebafa28555e83943b23460de56b5c2f89268e06d19c9b6bf7c7ba30b29d700 languageName: node linkType: hard @@ -1088,11 +1138,11 @@ __metadata: linkType: hard "@types/node@npm:^22.10.2": - version: 22.19.19 - resolution: "@types/node@npm:22.19.19" + version: 22.20.1 + resolution: "@types/node@npm:22.20.1" dependencies: undici-types: ~6.21.0 - checksum: 01bc720694f817a4f85af43ff6e93e80b9ec2e3bd1d0de2240e117152f61e2a4e6f19fe1a2632c2693d343ba0d157791581b34459b4e0110bca1ba5f9461ada3 + checksum: 03cc6d9941229b13fa9ab4e477d6550e85ed3e3d5f85734c03c84e0c18346d8a7c9f22b93570bb9cb4a44ffa176279f8a7ab3cd328fbdcf5d4e6ec541ce03f21 languageName: node linkType: hard @@ -1103,7 +1153,7 @@ __metadata: languageName: node linkType: hard -"abitype@npm:1.2.3, abitype@npm:^1.2.3": +"abitype@npm:1.2.3": version: 1.2.3 resolution: "abitype@npm:1.2.3" peerDependencies: @@ -1118,6 +1168,21 @@ __metadata: languageName: node linkType: hard +"abitype@npm:^1.2.3": + version: 1.3.0 + resolution: "abitype@npm:1.3.0" + peerDependencies: + typescript: ">=5.0.4" + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + checksum: d7a3139b883dd2c7fa109ef635d151219240c70b8fbec5a806265c47764ee9a77e9abf16f0464acf4aafec8df7a6c48511cb8e3d9df0bd6e7bd0e4f29746c5a0 + languageName: node + linkType: hard + "abort-controller@npm:^3.0.0": version: 3.0.0 resolution: "abort-controller@npm:3.0.0" @@ -1146,13 +1211,6 @@ __metadata: languageName: node linkType: hard -"base64-arraybuffer@npm:^1.0.2": - version: 1.0.2 - resolution: "base64-arraybuffer@npm:1.0.2" - checksum: 15e6400d2d028bf18be4ed97702b11418f8f8779fb8c743251c863b726638d52f69571d4cc1843224da7838abef0949c670bde46936663c45ad078e89fee5c62 - languageName: node - linkType: hard - "base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" @@ -1384,36 +1442,36 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:0.27.3": - version: 0.27.3 - resolution: "esbuild@npm:0.27.3" - dependencies: - "@esbuild/aix-ppc64": 0.27.3 - "@esbuild/android-arm": 0.27.3 - "@esbuild/android-arm64": 0.27.3 - "@esbuild/android-x64": 0.27.3 - "@esbuild/darwin-arm64": 0.27.3 - "@esbuild/darwin-x64": 0.27.3 - "@esbuild/freebsd-arm64": 0.27.3 - "@esbuild/freebsd-x64": 0.27.3 - "@esbuild/linux-arm": 0.27.3 - "@esbuild/linux-arm64": 0.27.3 - "@esbuild/linux-ia32": 0.27.3 - "@esbuild/linux-loong64": 0.27.3 - "@esbuild/linux-mips64el": 0.27.3 - "@esbuild/linux-ppc64": 0.27.3 - "@esbuild/linux-riscv64": 0.27.3 - "@esbuild/linux-s390x": 0.27.3 - "@esbuild/linux-x64": 0.27.3 - "@esbuild/netbsd-arm64": 0.27.3 - "@esbuild/netbsd-x64": 0.27.3 - "@esbuild/openbsd-arm64": 0.27.3 - "@esbuild/openbsd-x64": 0.27.3 - "@esbuild/openharmony-arm64": 0.27.3 - "@esbuild/sunos-x64": 0.27.3 - "@esbuild/win32-arm64": 0.27.3 - "@esbuild/win32-ia32": 0.27.3 - "@esbuild/win32-x64": 0.27.3 +"esbuild@npm:0.28.1": + version: 0.28.1 + resolution: "esbuild@npm:0.28.1" + dependencies: + "@esbuild/aix-ppc64": 0.28.1 + "@esbuild/android-arm": 0.28.1 + "@esbuild/android-arm64": 0.28.1 + "@esbuild/android-x64": 0.28.1 + "@esbuild/darwin-arm64": 0.28.1 + "@esbuild/darwin-x64": 0.28.1 + "@esbuild/freebsd-arm64": 0.28.1 + "@esbuild/freebsd-x64": 0.28.1 + "@esbuild/linux-arm": 0.28.1 + "@esbuild/linux-arm64": 0.28.1 + "@esbuild/linux-ia32": 0.28.1 + "@esbuild/linux-loong64": 0.28.1 + "@esbuild/linux-mips64el": 0.28.1 + "@esbuild/linux-ppc64": 0.28.1 + "@esbuild/linux-riscv64": 0.28.1 + "@esbuild/linux-s390x": 0.28.1 + "@esbuild/linux-x64": 0.28.1 + "@esbuild/netbsd-arm64": 0.28.1 + "@esbuild/netbsd-x64": 0.28.1 + "@esbuild/openbsd-arm64": 0.28.1 + "@esbuild/openbsd-x64": 0.28.1 + "@esbuild/openharmony-arm64": 0.28.1 + "@esbuild/sunos-x64": 0.28.1 + "@esbuild/win32-arm64": 0.28.1 + "@esbuild/win32-ia32": 0.28.1 + "@esbuild/win32-x64": 0.28.1 dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -1469,40 +1527,40 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 3a45334b00ca235ad96843738c4698970aacde92058aee28ab1fa57ad823c29667070af90b6071cc876e492bebdeed79f593a273c39b419097afd2a772296085 + checksum: 2ada56fe421ac0720f71968c0ceb56cb534588ae2fbbe5aef2c9dbe195f0f61773ef7838ad07d48c2141d9e8b7d3de5fd39d0bb880860f2f6f77bf67671ed235 languageName: node linkType: hard "esbuild@npm:~0.28.0": - version: 0.28.0 - resolution: "esbuild@npm:0.28.0" - dependencies: - "@esbuild/aix-ppc64": 0.28.0 - "@esbuild/android-arm": 0.28.0 - "@esbuild/android-arm64": 0.28.0 - "@esbuild/android-x64": 0.28.0 - "@esbuild/darwin-arm64": 0.28.0 - "@esbuild/darwin-x64": 0.28.0 - "@esbuild/freebsd-arm64": 0.28.0 - "@esbuild/freebsd-x64": 0.28.0 - "@esbuild/linux-arm": 0.28.0 - "@esbuild/linux-arm64": 0.28.0 - "@esbuild/linux-ia32": 0.28.0 - "@esbuild/linux-loong64": 0.28.0 - "@esbuild/linux-mips64el": 0.28.0 - "@esbuild/linux-ppc64": 0.28.0 - "@esbuild/linux-riscv64": 0.28.0 - "@esbuild/linux-s390x": 0.28.0 - "@esbuild/linux-x64": 0.28.0 - "@esbuild/netbsd-arm64": 0.28.0 - "@esbuild/netbsd-x64": 0.28.0 - "@esbuild/openbsd-arm64": 0.28.0 - "@esbuild/openbsd-x64": 0.28.0 - "@esbuild/openharmony-arm64": 0.28.0 - "@esbuild/sunos-x64": 0.28.0 - "@esbuild/win32-arm64": 0.28.0 - "@esbuild/win32-ia32": 0.28.0 - "@esbuild/win32-x64": 0.28.0 + version: 0.28.2 + resolution: "esbuild@npm:0.28.2" + dependencies: + "@esbuild/aix-ppc64": 0.28.2 + "@esbuild/android-arm": 0.28.2 + "@esbuild/android-arm64": 0.28.2 + "@esbuild/android-x64": 0.28.2 + "@esbuild/darwin-arm64": 0.28.2 + "@esbuild/darwin-x64": 0.28.2 + "@esbuild/freebsd-arm64": 0.28.2 + "@esbuild/freebsd-x64": 0.28.2 + "@esbuild/linux-arm": 0.28.2 + "@esbuild/linux-arm64": 0.28.2 + "@esbuild/linux-ia32": 0.28.2 + "@esbuild/linux-loong64": 0.28.2 + "@esbuild/linux-mips64el": 0.28.2 + "@esbuild/linux-ppc64": 0.28.2 + "@esbuild/linux-riscv64": 0.28.2 + "@esbuild/linux-s390x": 0.28.2 + "@esbuild/linux-x64": 0.28.2 + "@esbuild/netbsd-arm64": 0.28.2 + "@esbuild/netbsd-x64": 0.28.2 + "@esbuild/openbsd-arm64": 0.28.2 + "@esbuild/openbsd-x64": 0.28.2 + "@esbuild/openharmony-arm64": 0.28.2 + "@esbuild/sunos-x64": 0.28.2 + "@esbuild/win32-arm64": 0.28.2 + "@esbuild/win32-ia32": 0.28.2 + "@esbuild/win32-x64": 0.28.2 dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -1558,11 +1616,26 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: eeedcd8631138525908c185a6f987ca502ab2a523054f0305f458814caeb5ead8f51481e23b995b56326d8f232f09a7663182e0041a13f65d7f589d8a4ee76a4 + checksum: 724788c38454e29cd2dc930f02e593dd9c21ef1c977bba89664b6be16c80c83494d367961b8425a65d41d5a2245d2b1b3e5d21ed41333f6e2dbe1bc83526a62b + languageName: node + linkType: hard + +"ethers@npm:^6.13.5": + version: 6.17.0 + resolution: "ethers@npm:6.17.0" + dependencies: + "@adraffy/ens-normalize": 1.11.1 + "@noble/curves": 1.2.0 + "@noble/hashes": 1.3.2 + "@types/node": 22.7.5 + aes-js: 4.0.0-beta.5 + tslib: 2.7.0 + ws: 8.21.0 + checksum: 0ba314af2ae25622c60886caf83d825ce543262685961667d166b825c9dbfc66f905e0d7a2e3d8d4ccfa58b6ac20326e7f9a897b5580879efa758a50067ad082 languageName: node linkType: hard -"ethers@npm:^6.13.5, ethers@npm:~6.16.0": +"ethers@npm:~6.16.0": version: 6.16.0 resolution: "ethers@npm:6.16.0" dependencies: @@ -1667,7 +1740,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": +"fsevents@npm:2.3.3, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -1677,7 +1750,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@~2.3.2#~builtin, fsevents@patch:fsevents@~2.3.3#~builtin": +"fsevents@patch:fsevents@2.3.3#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin, fsevents@patch:fsevents@~2.3.3#~builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=df0bf1" dependencies: @@ -1852,19 +1925,17 @@ __metadata: languageName: node linkType: hard -"miniflare@npm:4.20260515.0": - version: 4.20260515.0 - resolution: "miniflare@npm:4.20260515.0" +"miniflare@npm:5.20260815.0-alpha": + version: 5.20260815.0-alpha + resolution: "miniflare@npm:5.20260815.0-alpha" dependencies: "@cspotcode/source-map-support": 0.8.1 - sharp: ^0.34.5 - undici: 7.24.8 - workerd: 1.20260515.1 - ws: 8.18.0 + sharp: 0.35.2 + undici: 7.29.0 + workerd: 1.20260815.1 + ws: 8.21.0 youch: 4.1.0-beta.10 - bin: - miniflare: bootstrap.js - checksum: 7293667957d634d776c5f7792589e224450b362c497b2d87dd096bd47096716c69427a0ac42bccbb6faf427ab0b25eb1eaa9bca093504a1ae2ae36f77cab92ab + checksum: dc2d4114f0242cb8b8bf4fc085e1cf0e135c31f018b643d03c68dd36e587964cdcde414843290e17052066930c0cf3536da05ce392c16e4c57e5a68e61d7c9b4 languageName: node linkType: hard @@ -1913,11 +1984,11 @@ __metadata: linkType: hard "node-abi@npm:^3.3.0": - version: 3.93.0 - resolution: "node-abi@npm:3.93.0" + version: 3.94.0 + resolution: "node-abi@npm:3.94.0" dependencies: semver: ^7.3.5 - checksum: b0f4c97e418419893a93a019033559d6f2add72c7e92460ca166907b86afaa907365178587ee787da44e960d97a3d0c9744e0107613465a407543a38a64ce845 + checksum: 0d79587a609fb2e4d152b4d648b32a89b42c9963399ca62c88b0f4d91c7bb4dd1f806c5cd771bd925380561923df5e4cd6e30bbc8133b02442136ec4afebc726 languageName: node linkType: hard @@ -2164,37 +2235,40 @@ __metadata: linkType: hard "rollup@npm:^4.14.1": - version: 4.62.2 - resolution: "rollup@npm:4.62.2" - dependencies: - "@rollup/rollup-android-arm-eabi": 4.62.2 - "@rollup/rollup-android-arm64": 4.62.2 - "@rollup/rollup-darwin-arm64": 4.62.2 - "@rollup/rollup-darwin-x64": 4.62.2 - "@rollup/rollup-freebsd-arm64": 4.62.2 - "@rollup/rollup-freebsd-x64": 4.62.2 - "@rollup/rollup-linux-arm-gnueabihf": 4.62.2 - "@rollup/rollup-linux-arm-musleabihf": 4.62.2 - "@rollup/rollup-linux-arm64-gnu": 4.62.2 - "@rollup/rollup-linux-arm64-musl": 4.62.2 - "@rollup/rollup-linux-loong64-gnu": 4.62.2 - "@rollup/rollup-linux-loong64-musl": 4.62.2 - "@rollup/rollup-linux-ppc64-gnu": 4.62.2 - "@rollup/rollup-linux-ppc64-musl": 4.62.2 - "@rollup/rollup-linux-riscv64-gnu": 4.62.2 - "@rollup/rollup-linux-riscv64-musl": 4.62.2 - "@rollup/rollup-linux-s390x-gnu": 4.62.2 - "@rollup/rollup-linux-x64-gnu": 4.62.2 - "@rollup/rollup-linux-x64-musl": 4.62.2 - "@rollup/rollup-openbsd-x64": 4.62.2 - "@rollup/rollup-openharmony-arm64": 4.62.2 - "@rollup/rollup-win32-arm64-msvc": 4.62.2 - "@rollup/rollup-win32-ia32-msvc": 4.62.2 - "@rollup/rollup-win32-x64-gnu": 4.62.2 - "@rollup/rollup-win32-x64-msvc": 4.62.2 + version: 4.62.4 + resolution: "rollup@npm:4.62.4" + dependencies: + "@napi-rs/lzma-linux-x64-gnu": 1.5.1 + "@rollup/rollup-android-arm-eabi": 4.62.4 + "@rollup/rollup-android-arm64": 4.62.4 + "@rollup/rollup-darwin-arm64": 4.62.4 + "@rollup/rollup-darwin-x64": 4.62.4 + "@rollup/rollup-freebsd-arm64": 4.62.4 + "@rollup/rollup-freebsd-x64": 4.62.4 + "@rollup/rollup-linux-arm-gnueabihf": 4.62.4 + "@rollup/rollup-linux-arm-musleabihf": 4.62.4 + "@rollup/rollup-linux-arm64-gnu": 4.62.4 + "@rollup/rollup-linux-arm64-musl": 4.62.4 + "@rollup/rollup-linux-loong64-gnu": 4.62.4 + "@rollup/rollup-linux-loong64-musl": 4.62.4 + "@rollup/rollup-linux-ppc64-gnu": 4.62.4 + "@rollup/rollup-linux-ppc64-musl": 4.62.4 + "@rollup/rollup-linux-riscv64-gnu": 4.62.4 + "@rollup/rollup-linux-riscv64-musl": 4.62.4 + "@rollup/rollup-linux-s390x-gnu": 4.62.4 + "@rollup/rollup-linux-x64-gnu": 4.62.4 + "@rollup/rollup-linux-x64-musl": 4.62.4 + "@rollup/rollup-openbsd-x64": 4.62.4 + "@rollup/rollup-openharmony-arm64": 4.62.4 + "@rollup/rollup-win32-arm64-msvc": 4.62.4 + "@rollup/rollup-win32-ia32-msvc": 4.62.4 + "@rollup/rollup-win32-x64-gnu": 4.62.4 + "@rollup/rollup-win32-x64-msvc": 4.62.4 "@types/estree": 1.0.9 fsevents: ~2.3.2 dependenciesMeta: + "@napi-rs/lzma-linux-x64-gnu": + optional: true "@rollup/rollup-android-arm-eabi": optional: true "@rollup/rollup-android-arm64": @@ -2249,7 +2323,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 9fb4b08e135db5968e1763a3f95ece6f78e64f135159a59bfc678d3f8ab80a7a0080022611a9ccec73346a71b82661d36f55ea7ccdc638bdad0255d96ff8e7ba + checksum: bf310620a92b608ea884de9353c974132edd099a547028f8b0ae4fb11705d590539054aa455affece154f259d05fadd11dd0596278a1d04f1af93657bc0eb3d5 languageName: node linkType: hard @@ -2268,57 +2342,60 @@ __metadata: linkType: hard "sax@npm:>=0.6.0": - version: 1.6.0 - resolution: "sax@npm:1.6.0" - checksum: 83ae2a17f524bd35b1b7d1c867700b1fab41e4cbb4f7635b7e66398421e06ff2cd43ec651c151cb99c67c3681ec7d0493cb6a98fd2e7799ea15b5d0a4615f870 + version: 1.6.1 + resolution: "sax@npm:1.6.1" + checksum: be78ded08c77db1644a8d32c93266615f51b925c8b6b6f3f689aed10eae57f307f8fbd7bcbf502041903edcfec17ea7d07c7bb4960e076faa92fc6773b621f2a languageName: node linkType: hard -"semver@npm:^7.3.5, semver@npm:^7.7.3": - version: 7.8.0 - resolution: "semver@npm:7.8.0" +"semver@npm:^7.3.5, semver@npm:^7.8.4": + version: 7.8.5 + resolution: "semver@npm:7.8.5" bin: semver: bin/semver.js - checksum: 68e38bc26ed1191d7c78d2b711bdffc2f8b1d05a1caadda41a1d7e1a9d32e1da5ae5b645de5c5f2b27bde830d7e9c1cbeeafcb8fda091830411df7d40be405b1 - languageName: node - linkType: hard - -"sharp@npm:^0.34.5": - version: 0.34.5 - resolution: "sharp@npm:0.34.5" - dependencies: - "@img/colour": ^1.0.0 - "@img/sharp-darwin-arm64": 0.34.5 - "@img/sharp-darwin-x64": 0.34.5 - "@img/sharp-libvips-darwin-arm64": 1.2.4 - "@img/sharp-libvips-darwin-x64": 1.2.4 - "@img/sharp-libvips-linux-arm": 1.2.4 - "@img/sharp-libvips-linux-arm64": 1.2.4 - "@img/sharp-libvips-linux-ppc64": 1.2.4 - "@img/sharp-libvips-linux-riscv64": 1.2.4 - "@img/sharp-libvips-linux-s390x": 1.2.4 - "@img/sharp-libvips-linux-x64": 1.2.4 - "@img/sharp-libvips-linuxmusl-arm64": 1.2.4 - "@img/sharp-libvips-linuxmusl-x64": 1.2.4 - "@img/sharp-linux-arm": 0.34.5 - "@img/sharp-linux-arm64": 0.34.5 - "@img/sharp-linux-ppc64": 0.34.5 - "@img/sharp-linux-riscv64": 0.34.5 - "@img/sharp-linux-s390x": 0.34.5 - "@img/sharp-linux-x64": 0.34.5 - "@img/sharp-linuxmusl-arm64": 0.34.5 - "@img/sharp-linuxmusl-x64": 0.34.5 - "@img/sharp-wasm32": 0.34.5 - "@img/sharp-win32-arm64": 0.34.5 - "@img/sharp-win32-ia32": 0.34.5 - "@img/sharp-win32-x64": 0.34.5 + checksum: 0c580f17e88e2b45806dc5cf3d824f719c946999d3554bf30307c2b68b3300ab3c8bfcd84d8f489b93b4cbb5362f5fc8de4d2858954f18d834253c4450fc9f6b + languageName: node + linkType: hard + +"sharp@npm:0.35.2": + version: 0.35.2 + resolution: "sharp@npm:0.35.2" + dependencies: + "@img/colour": ^1.1.0 + "@img/sharp-darwin-arm64": 0.35.2 + "@img/sharp-darwin-x64": 0.35.2 + "@img/sharp-freebsd-wasm32": 0.35.2 + "@img/sharp-libvips-darwin-arm64": 1.3.1 + "@img/sharp-libvips-darwin-x64": 1.3.1 + "@img/sharp-libvips-linux-arm": 1.3.1 + "@img/sharp-libvips-linux-arm64": 1.3.1 + "@img/sharp-libvips-linux-ppc64": 1.3.1 + "@img/sharp-libvips-linux-riscv64": 1.3.1 + "@img/sharp-libvips-linux-s390x": 1.3.1 + "@img/sharp-libvips-linux-x64": 1.3.1 + "@img/sharp-libvips-linuxmusl-arm64": 1.3.1 + "@img/sharp-libvips-linuxmusl-x64": 1.3.1 + "@img/sharp-linux-arm": 0.35.2 + "@img/sharp-linux-arm64": 0.35.2 + "@img/sharp-linux-ppc64": 0.35.2 + "@img/sharp-linux-riscv64": 0.35.2 + "@img/sharp-linux-s390x": 0.35.2 + "@img/sharp-linux-x64": 0.35.2 + "@img/sharp-linuxmusl-arm64": 0.35.2 + "@img/sharp-linuxmusl-x64": 0.35.2 + "@img/sharp-webcontainers-wasm32": 0.35.2 + "@img/sharp-win32-arm64": 0.35.2 + "@img/sharp-win32-ia32": 0.35.2 + "@img/sharp-win32-x64": 0.35.2 detect-libc: ^2.1.2 - semver: ^7.7.3 + semver: ^7.8.4 dependenciesMeta: "@img/sharp-darwin-arm64": optional: true "@img/sharp-darwin-x64": optional: true + "@img/sharp-freebsd-wasm32": + optional: true "@img/sharp-libvips-darwin-arm64": optional: true "@img/sharp-libvips-darwin-x64": @@ -2355,7 +2432,7 @@ __metadata: optional: true "@img/sharp-linuxmusl-x64": optional: true - "@img/sharp-wasm32": + "@img/sharp-webcontainers-wasm32": optional: true "@img/sharp-win32-arm64": optional: true @@ -2363,7 +2440,7 @@ __metadata: optional: true "@img/sharp-win32-x64": optional: true - checksum: b86972729697af7e37c96714cd9c5c2470c6b503a79d5b38f6fd3eb4d5a46b20d7c15dae1a73db3d0e0aa605d517f2f66d4f52de7496bfb037dd7feb930c1899 + checksum: fb286642ed5865cdeaf3f8878f2cab82f7621535f128d43571f73849a371e6196fc647c5562c0ecc7c4869ca6cd36ce942d3e8e21e2d2d8bcfb2d6e2e4258571 languageName: node linkType: hard @@ -2487,9 +2564,9 @@ __metadata: linkType: hard "tokenx@npm:^1.3.0": - version: 1.3.0 - resolution: "tokenx@npm:1.3.0" - checksum: b89896b25de631bcc6f0e2215ba7a8a726bb6f654a19ad578ebc897880811c279c5824644447ff2c95c1f6a6164a3dd1109c38a046883e24bccf3a80e3bcdaf9 + version: 1.6.0 + resolution: "tokenx@npm:1.6.0" + checksum: 9104986109f65a04bc3c148b442df5095abfd9786b1d8d218545cd1e3718c70f09f947757668c21f4b3318f30a6a3d9963ce60bae80348abf51cb12f9b19185e languageName: node linkType: hard @@ -2508,8 +2585,8 @@ __metadata: linkType: hard "tsx@npm:^4.22.4": - version: 4.22.4 - resolution: "tsx@npm:4.22.4" + version: 4.23.12 + resolution: "tsx@npm:4.23.12" dependencies: esbuild: ~0.28.0 fsevents: ~2.3.3 @@ -2518,7 +2595,7 @@ __metadata: optional: true bin: tsx: dist/cli.mjs - checksum: 21848c642032680c525d322d7e6b82fdf2bebfaa8b2911c413eb98a834fce89295ee315fb42de5597f4c2ba1ea06c4b71c2321ca47ecf1de065604324266c554 + checksum: f895395574f25ec987470944070828475ba6f5cb2ff565d203408bb60d4b0e62da6c223071c565f87687dc461b38a50886399feca1cf9b250bcfabd1ada20938 languageName: node linkType: hard @@ -2552,11 +2629,9 @@ __metadata: linkType: hard "uint8-util@npm:^2.2.2": - version: 2.2.6 - resolution: "uint8-util@npm:2.2.6" - dependencies: - base64-arraybuffer: ^1.0.2 - checksum: 77147e22051c25eca6822a0c3e79800bdd11324bd0611a3741d832b16bb4e37252d064bacae165ae0eff574d3ab68bb230a65007de5965362dda06a30f437499 + version: 2.3.2 + resolution: "uint8-util@npm:2.3.2" + checksum: 5d13a2cd3b42c29740ff29cbd83281e0ddbe2e520276d349a3c7a2a93261e2fc0365927a18eaa1d7633f2f37bdb59edd1ce246ac4c00298aa93dd9b98c01fa8a languageName: node linkType: hard @@ -2574,10 +2649,10 @@ __metadata: languageName: node linkType: hard -"undici@npm:7.24.8": - version: 7.24.8 - resolution: "undici@npm:7.24.8" - checksum: f691321cad3589e069bb0282b3862f581e4b692efde54857c4492f701380372fbd4f77f6a579674a133c5ca5c20efb44c3461803d16886beef489ac8690bbea4 +"undici@npm:7.29.0": + version: 7.29.0 + resolution: "undici@npm:7.29.0" + checksum: b3327e05259e66c61d3e05242bf63899c68d277302208f4fc1c7c0b880a9ba82651b8b3215584ffd424d8c8410f0114b6c3a89e6af604c703dc33009daa99ed3 languageName: node linkType: hard @@ -2612,8 +2687,8 @@ __metadata: linkType: hard "viem@npm:^2.38.3": - version: 2.55.11 - resolution: "viem@npm:2.55.11" + version: 2.55.18 + resolution: "viem@npm:2.55.18" dependencies: "@noble/curves": 1.9.1 "@noble/hashes": 1.8.0 @@ -2628,7 +2703,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 8afa0167e8238fa1cb11dba3de2a69fb308fa2b11378ab69ef81ab4b7cda65d9f2c2aabc67861aad39091ee819f6701cd2f60dc46adda877bb5b17eb98cac105 + checksum: c602ffbecf5e3d3eec2e63f4a833f90b8c184ef16d7aa09435ab250cc20ae1a4d601b2e37731ccb7179fb803dd1bca224ac97fe2221a1f30b828ac4ddd448c66 languageName: node linkType: hard @@ -2661,15 +2736,15 @@ __metadata: languageName: node linkType: hard -"workerd@npm:1.20260515.1": - version: 1.20260515.1 - resolution: "workerd@npm:1.20260515.1" +"workerd@npm:1.20260815.1": + version: 1.20260815.1 + resolution: "workerd@npm:1.20260815.1" dependencies: - "@cloudflare/workerd-darwin-64": 1.20260515.1 - "@cloudflare/workerd-darwin-arm64": 1.20260515.1 - "@cloudflare/workerd-linux-64": 1.20260515.1 - "@cloudflare/workerd-linux-arm64": 1.20260515.1 - "@cloudflare/workerd-windows-64": 1.20260515.1 + "@cloudflare/workerd-darwin-64": 1.20260815.1 + "@cloudflare/workerd-darwin-arm64": 1.20260815.1 + "@cloudflare/workerd-linux-64": 1.20260815.1 + "@cloudflare/workerd-linux-arm64": 1.20260815.1 + "@cloudflare/workerd-windows-64": 1.20260815.1 dependenciesMeta: "@cloudflare/workerd-darwin-64": optional: true @@ -2683,25 +2758,25 @@ __metadata: optional: true bin: workerd: bin/workerd - checksum: d8dcb084b74c3eea7841af3fcf32d95fc979d1c951b1a560711a0f4729ad4e234883d09395e937b6310726cfe14493106ed917381f7e9f98cc068bbeda69fb67 + checksum: 4b19b816bfa2ed2a76837bfbd47b19e5a8a8543023b9cc9832884d8b7bf78f612940a8707d6720238b32e4962fcb077ad3ce17a7e4c375914a68910188d272fc languageName: node linkType: hard "wrangler@npm:^4.18.0": - version: 4.92.0 - resolution: "wrangler@npm:4.92.0" + version: 4.124.0 + resolution: "wrangler@npm:4.124.0" dependencies: "@cloudflare/kv-asset-handler": 0.5.0 "@cloudflare/unenv-preset": 2.16.1 blake3-wasm: 2.1.5 - esbuild: 0.27.3 - fsevents: ~2.3.2 - miniflare: 4.20260515.0 + esbuild: 0.28.1 + fsevents: 2.3.3 + miniflare: 5.20260815.0-alpha path-to-regexp: 6.3.0 unenv: 2.0.0-rc.24 - workerd: 1.20260515.1 + workerd: 1.20260815.1 peerDependencies: - "@cloudflare/workers-types": ^4.20260515.1 + "@cloudflare/workers-types": ^5.20260815.1 dependenciesMeta: fsevents: optional: true @@ -2709,9 +2784,10 @@ __metadata: "@cloudflare/workers-types": optional: true bin: + cf-wrangler: bin/cf-wrangler.js wrangler: bin/wrangler.js wrangler2: bin/wrangler.js - checksum: a6fb117186700f0530645dcab917947b1bc3d27ee0fcd33fd7c5a2578f05ae3617799233750feca82906fe0440ca6c86d4869ce6e79c325d2d3172cd809480d8 + checksum: dff9d707e32414d84931a07288264dacc7d0f18c8be28a9470217b99a3a33e664249edd027a6b996baa768290d359ba785c8774e7235e5f16d6228a58e7ae9d4 languageName: node linkType: hard @@ -2737,21 +2813,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:8.18.0": - version: 8.18.0 - resolution: "ws@npm:8.18.0" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 91d4d35bc99ff6df483bdf029b9ea4bfd7af1f16fc91231a96777a63d263e1eabf486e13a2353970efc534f9faa43bdbf9ee76525af22f4752cbc5ebda333975 - languageName: node - linkType: hard - "ws@npm:8.21.0": version: 8.21.0 resolution: "ws@npm:8.21.0" diff --git a/contracts/DEPLOY.md b/contracts/DEPLOY.md index 7cd7e71..61ed188 100644 --- a/contracts/DEPLOY.md +++ b/contracts/DEPLOY.md @@ -123,12 +123,13 @@ The `AntseedBuyerOperator` calls `IAntseedDeposits.deposit` on behalf of buyers. cast call "balanceOf(address)(uint256)" ``` -### 5.2 Set the operator `owner` (optional) -Owner is the day to day operator. Admin has funds and upgrade permissions. -By default the deployer `owner` is the admin. To designate a separate hot-wallet admin: +### 5.2 Set the operator `admin` (optional) + +Admin is the day to day operator. Owner has funds and upgrade permissions. +By default the deployer owner is also the admin. To designate a separate hot-wallet admin: ```bash -cast send "transferOwnership(address)" \ +cast send "transferAdmin(address)" \ --rpc-url "$BASE_RPC_URL" \ --private-key "$DEPLOYER_PRIVATE_KEY" ``` diff --git a/contracts/src/AntseedBuyerOperator.sol b/contracts/src/AntseedBuyerOperator.sol index 949b320..e2dfdb0 100644 --- a/contracts/src/AntseedBuyerOperator.sol +++ b/contracts/src/AntseedBuyerOperator.sol @@ -3,40 +3,50 @@ pragma solidity ^0.8.24; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; interface IERC20 { function transfer(address to, uint256 amount) external returns (bool); + function transferFrom(address from, address to, uint256 amount) external returns (bool); + function approve(address spender, uint256 amount) external returns (bool); + function balanceOf(address account) external view returns (uint256); } -import { IAntseedChannels } from "./interfaces/IAntseedChannels.sol"; -import { IAntseedDeposits } from "./interfaces/IAntseedDeposits.sol"; -import { IAntseedRegistry } from "./interfaces/IAntseedRegistry.sol"; +import {IAntseedChannels} from "./interfaces/IAntseedChannels.sol"; +import {IAntseedDeposits} from "./interfaces/IAntseedDeposits.sol"; +import {IAntseedRegistry} from "./interfaces/IAntseedRegistry.sol"; contract AntseedBuyerOperator is Initializable, UUPSUpgradeable { IAntseedRegistry public immutable registry; IERC20 public immutable usdc; - address public owner; address public admin; + address public owner; bool private locked; mapping(bytes32 => bool) public usedDepositIds; mapping(address => uint256) public totalPrincipalDeposited; mapping(address => uint256) public totalBonusDeposited; - mapping(address => uint256) public totalWithdrawn; + mapping(address => uint256) public totalPrincipalWithdrawn; bytes32 public DOMAIN_SEPARATOR; - bytes32 public constant WITHDRAW_TYPEHASH = - keccak256("WithdrawPrincipal(address buyer,uint256 amount,address recipient,uint256 timestamp)"); - bytes32 public constant REQUEST_CLOSE_TYPEHASH = - keccak256("RequestClose(bytes32 channelId,uint256 timestamp)"); - bytes32 public constant WITHDRAW_CHANNEL_TYPEHASH = - keccak256("WithdrawChannel(bytes32 channelId,uint256 timestamp)"); + + mapping(address => uint256) public totalBonusWithdrawn; + mapping(address => uint256) public principalRemaining; + mapping(address => uint256) public bonusRemaining; + mapping(address => uint256) public lastAccountedBalance; + mapping(address => bool) public buyerAccountingMigrated; + mapping(address => uint256) public usedNonces; uint256[50] private __gap; + bytes32 public constant WITHDRAW_TYPEHASH = keccak256("WithdrawPrincipal(address buyer,uint256 amount,address recipient,uint256 nonce)"); + bytes32 public constant REQUEST_CLOSE_TYPEHASH = keccak256("RequestClose(bytes32 channelId,uint256 nonce)"); + bytes32 public constant WITHDRAW_CHANNEL_TYPEHASH = keccak256("WithdrawChannel(bytes32 channelId,uint256 nonce)"); + bytes32 public constant REVOKE_OPERATOR_TYPEHASH = keccak256("RevokeOperator(address buyer,uint256 nonce)"); + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); event AdminTransferred(address indexed previousAdmin, address indexed newAdmin); event BuyerOperatorAccepted(address indexed buyer, uint256 nonce); @@ -44,6 +54,9 @@ contract AntseedBuyerOperator is Initializable, UUPSUpgradeable { event BuyerDepositFundedWithId(address indexed buyer, uint256 principal, uint256 bonus, string id); event BuyerDepositWithdrawn(address indexed buyer, address indexed recipient, uint256 amount); event BuyerPrincipalWithdrawn(address indexed buyer, address indexed recipient, uint256 amount); + event BuyerBonusWithdrawn(address indexed buyer, uint256 amount); + event BuyerAccountingMigrated(address indexed buyer, uint256 principalRemaining, uint256 bonusRemaining, uint256 accountedBalance); + event BuyerOperatorRevoked(address indexed buyer); event BuyerOperatorTransferred(address indexed buyer, address indexed newOperator); event ChannelCloseRequested(bytes32 indexed channelId, address indexed buyer, address indexed caller); event ChannelWithdrawn(bytes32 indexed channelId, address indexed buyer, address indexed caller); @@ -52,22 +65,24 @@ contract AntseedBuyerOperator is Initializable, UUPSUpgradeable { error NotOwner(); error InvalidAddress(); error InvalidAmount(); - error NotBuyerOrOwner(); + error NotBuyerOrAdmin(); error NotDepositsOperator(); error TransferFailed(); error ApproveFailed(); error DuplicateDepositId(); error InsufficientPrincipal(); error InvalidSignature(); - error ExpiredSignature(); + error InvalidNonce(); + error AlreadyMigrated(); + error CloseChannelsBeforeRevoke(uint256 reserved); - modifier onlyOwner() { - if (msg.sender != owner && msg.sender != admin) revert NotOwner(); + modifier onlyAdmin() { + if (msg.sender != admin && msg.sender != owner) revert NotOwner(); _; } - modifier onlyAdmin() { - if (msg.sender != admin) revert NotOwner(); + modifier onlyOwner() { + if (msg.sender != owner) revert NotOwner(); _; } @@ -93,23 +108,26 @@ contract AntseedBuyerOperator is Initializable, UUPSUpgradeable { function initialize(address owner_) external initializer { if (owner_ == address(0)) revert InvalidAddress(); - owner = owner_; admin = owner_; + owner = owner_; + emit AdminTransferred(address(0), owner_); emit OwnershipTransferred(address(0), owner_); address depositsAddress = registry.deposits(); _forceApprove(usdc, depositsAddress, type(uint256).max); - DOMAIN_SEPARATOR = keccak256(abi.encode( - keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), - keccak256("AntseedBuyerOperator"), - keccak256("1"), - block.chainid, - address(this) - )); + DOMAIN_SEPARATOR = keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256("AntseedBuyerOperator"), + keccak256("1"), + block.chainid, + address(this) + ) + ); } - function _authorizeUpgrade(address) internal override onlyAdmin {} + function _authorizeUpgrade(address) internal override onlyOwner {} function transferOwnership(address newOwner) external onlyOwner { if (newOwner == address(0)) revert InvalidAddress(); @@ -123,35 +141,63 @@ contract AntseedBuyerOperator is Initializable, UUPSUpgradeable { admin = newAdmin; } - function acceptBuyerOperator(address buyer, uint256 nonce, bytes calldata buyerSig) external nonReentrant onlyOwner { + function acceptBuyerOperator(address buyer, uint256 nonce, bytes calldata buyerSig) external nonReentrant onlyAdmin { if (buyer == address(0)) revert InvalidAddress(); _deposits().setOperator(buyer, address(this), nonce, buyerSig); emit BuyerOperatorAccepted(buyer, nonce); } - function depositFor(address buyer, uint256 principal, uint256 bonus) external nonReentrant onlyOwner { + function _accountForUsage(address buyer) internal { + (uint256 available, uint256 reserved, ) = _deposits().getBuyerBalance(buyer); + uint256 currentBalance = available + reserved; + uint256 previousBalance = lastAccountedBalance[buyer]; + + if (previousBalance > currentBalance) { + uint256 used = previousBalance - currentBalance; + uint256 principalUsed = _min(used, principalRemaining[buyer]); + principalRemaining[buyer] -= principalUsed; + used -= principalUsed; + + if (used > 0) { + bonusRemaining[buyer] -= _min(used, bonusRemaining[buyer]); + } + } + + lastAccountedBalance[buyer] = currentBalance; + } + + function _recordDeposit(address buyer, uint256 principal, uint256 bonus) internal { + _accountForUsage(buyer); + totalPrincipalDeposited[buyer] += principal; + totalBonusDeposited[buyer] += bonus; + principalRemaining[buyer] += principal; + bonusRemaining[buyer] += bonus; + lastAccountedBalance[buyer] += principal + bonus; + } + + function depositFor(address buyer, uint256 principal, uint256 bonus) external nonReentrant onlyAdmin { if (buyer == address(0)) revert InvalidAddress(); + //revoke bonus if we are not operators + if (_deposits().getOperator(buyer) != address(this)) bonus = 0; uint256 total = principal + bonus; if (total == 0) revert InvalidAmount(); - _requireDepositsOperator(buyer); - totalPrincipalDeposited[buyer] += principal; - totalBonusDeposited[buyer] += bonus; + _recordDeposit(buyer, principal, bonus); _deposits().deposit(buyer, total); emit BuyerDepositFunded(buyer, principal, bonus); } - function depositForWithId(address buyer, uint256 principal, uint256 bonus, string calldata id) external nonReentrant onlyOwner { + function depositForWithId(address buyer, uint256 principal, uint256 bonus, string calldata id) external nonReentrant onlyAdmin { if (buyer == address(0)) revert InvalidAddress(); + //revoke bonus if we are not operators + if (_deposits().getOperator(buyer) != address(this)) bonus = 0; uint256 total = principal + bonus; if (total == 0) revert InvalidAmount(); bytes32 idHash = keccak256(bytes(id)); if (usedDepositIds[idHash]) revert DuplicateDepositId(); usedDepositIds[idHash] = true; - _requireDepositsOperator(buyer); - totalPrincipalDeposited[buyer] += principal; - totalBonusDeposited[buyer] += bonus; + _recordDeposit(buyer, principal, bonus); _deposits().deposit(buyer, total); emit BuyerDepositFundedWithId(buyer, principal, bonus, id); } @@ -161,94 +207,201 @@ contract AntseedBuyerOperator is Initializable, UUPSUpgradeable { /// @param amount The amount in USDC micro-units to withdraw. /// @param recipient The address to receive the withdrawn USDC. /// @param buyerSig The buyer's EIP-712 signature authorizing this withdrawal. - function withdrawPrincipal(address buyer, uint256 amount, address recipient, uint256 timestamp, bytes calldata buyerSig) external nonReentrant { + function withdrawPrincipal(address buyer, uint256 amount, address recipient, uint256 nonce, bytes calldata buyerSig) external nonReentrant { if (buyer == address(0) || recipient == address(0)) revert InvalidAddress(); if (amount == 0) revert InvalidAmount(); - if (timestamp > block.timestamp || block.timestamp - timestamp > 5 minutes) revert ExpiredSignature(); + if (nonce != usedNonces[buyer]) revert InvalidNonce(); - bytes32 structHash = keccak256(abi.encode(WITHDRAW_TYPEHASH, buyer, amount, recipient, timestamp)); + bytes32 structHash = keccak256(abi.encode(WITHDRAW_TYPEHASH, buyer, amount, recipient, nonce)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash)); - address signer = _recoverSigner(digest, buyerSig); - if (signer != buyer) revert InvalidSignature(); + address signer = ECDSA.recoverCalldata(digest, buyerSig); + if (signer == address(0) || signer != buyer) revert InvalidSignature(); + usedNonces[buyer] = nonce + 1; _requireDepositsOperator(buyer); + _accountForUsage(buyer); if (amount > withdrawablePrincipal(buyer)) revert InsufficientPrincipal(); - totalWithdrawn[buyer] += amount; - uint256 beforeBalance = usdc.balanceOf(address(this)); _deposits().withdraw(buyer, amount); uint256 received = usdc.balanceOf(address(this)) - beforeBalance; if (received < amount) revert InvalidAmount(); + principalRemaining[buyer] -= amount; + totalPrincipalWithdrawn[buyer] += amount; + lastAccountedBalance[buyer] -= amount; + _safeTransfer(usdc, recipient, amount); emit BuyerPrincipalWithdrawn(buyer, recipient, amount); } /// @notice Returns the amount of principal a buyer can still withdraw. function withdrawablePrincipal(address buyer) public view returns (uint256) { - return totalPrincipalDeposited[buyer] > totalWithdrawn[buyer] - ? totalPrincipalDeposited[buyer] - totalWithdrawn[buyer] - : 0; + (uint256 available, uint256 reserved, ) = _deposits().getBuyerBalance(buyer); + uint256 remaining = principalRemaining[buyer]; + uint256 currentBalance = available + reserved; + uint256 previousBalance = lastAccountedBalance[buyer]; + + if (previousBalance > currentBalance) { + uint256 used = previousBalance - currentBalance; + remaining = used > remaining ? 0 : remaining - used; + } + + return _min(remaining, available); + } + + function _withdrawUnusedBonus(address buyer) internal returns (uint256 amount) { + _accountForUsage(buyer); + (uint256 available, , ) = _deposits().getBuyerBalance(buyer); + if (available <= principalRemaining[buyer]) return 0; + + amount = _min(available - principalRemaining[buyer], bonusRemaining[buyer]); + if (amount == 0) return 0; + + uint256 beforeBalance = usdc.balanceOf(address(this)); + _deposits().withdraw(buyer, amount); + uint256 received = usdc.balanceOf(address(this)) - beforeBalance; + if (received < amount) revert InvalidAmount(); + + bonusRemaining[buyer] -= amount; + totalBonusWithdrawn[buyer] += amount; + lastAccountedBalance[buyer] -= amount; + + emit BuyerBonusWithdrawn(buyer, amount); + } + + function _revokeOperator(address buyer) internal { + _requireDepositsOperator(buyer); + _withdrawUnusedBonus(buyer); + (, uint256 reserved, ) = _deposits().getBuyerBalance(buyer); + if (bonusRemaining[buyer] != 0 && reserved > 0) revert CloseChannelsBeforeRevoke(reserved); + + _deposits().transferOperator(buyer, address(0)); + emit BuyerOperatorRevoked(buyer); + } + + function revokeOperator(address buyer, uint256 nonce, bytes memory buyerSig) public nonReentrant { + if (buyerSig.length > 0) { + if (nonce != usedNonces[buyer]) revert InvalidNonce(); + bytes32 structHash = keccak256(abi.encode(REVOKE_OPERATOR_TYPEHASH, buyer, nonce)); + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash)); + address signer = ECDSA.recover(digest, buyerSig); + if (signer == address(0) || signer != buyer) revert InvalidSignature(); + usedNonces[buyer] = nonce + 1; + } else { + _requireBuyerOrAdmin(buyer); + } + _revokeOperator(buyer); } - function transferBuyerOperator(address buyer, address newOperator) external nonReentrant onlyOwner { + function revokeOperator(address buyer) external { + revokeOperator(buyer, 0, ""); + } + + function _migrateBuyerAccounting(address buyer) internal { if (buyer == address(0)) revert InvalidAddress(); + if (buyerAccountingMigrated[buyer]) revert AlreadyMigrated(); + + (uint256 available, uint256 reserved, ) = _deposits().getBuyerBalance(buyer); + uint256 currentBalance = available + reserved; + + uint256 principal = totalPrincipalDeposited[buyer] - totalPrincipalWithdrawn[buyer]; + uint256 bonus = totalBonusDeposited[buyer] - totalBonusWithdrawn[buyer]; + uint256 totalTracked = principal + bonus; + + if (totalTracked > currentBalance) { + uint256 used = totalTracked - currentBalance; + uint256 principalUsed = _min(used, principal); + principal -= principalUsed; + used -= principalUsed; + + if (used > 0) { + bonus -= _min(used, bonus); + } + } + + principalRemaining[buyer] = principal; + bonusRemaining[buyer] = bonus; + lastAccountedBalance[buyer] = currentBalance; + buyerAccountingMigrated[buyer] = true; + + emit BuyerAccountingMigrated(buyer, principal, bonus, currentBalance); + } + + /// @notice One-time migration helper for a single buyer funded before remaining-balance accounting existed. + /// @dev Computes remaining principal/bonus from tracked totals and current deposit balance. + function migrateBuyerAccounting(address buyer) external onlyAdmin { + _migrateBuyerAccounting(buyer); + } + + /// @notice One-time migration helper for multiple buyers funded before remaining-balance accounting existed. + /// @dev Reverts if any buyer is invalid or already migrated. + function migrateBuyerAccounting(address[] calldata buyers) external onlyAdmin { + uint256 len = buyers.length; + for (uint256 i = 0; i < len; i++) { + _migrateBuyerAccounting(buyers[i]); + } + } + + /// @notice Transfers the operator role for a buyer to a new operator address. without enforcing any bonus withdrawal or channel closure. This function is intended for administrative use only. + /// @param buyer The address of the buyer whose operator role is being transferred. + /// @param newOperator The address of the new operator to be assigned to the buyer. + function transferBuyerOperator(address buyer, address newOperator) external nonReentrant onlyAdmin { + if (buyer == address(0)) revert InvalidAddress(); + _withdrawUnusedBonus(buyer); _deposits().transferOperator(buyer, newOperator); emit BuyerOperatorTransferred(buyer, newOperator); } - function requestClose(bytes32 channelId, uint256 timestamp, bytes calldata buyerSig) public nonReentrant { + function requestClose(bytes32 channelId, uint256 nonce, bytes memory buyerSig) public nonReentrant { address buyer = _channelBuyer(channelId); if (buyerSig.length > 0) { - if (timestamp > block.timestamp || block.timestamp - timestamp > 5 minutes) revert ExpiredSignature(); - bytes32 structHash = keccak256(abi.encode(REQUEST_CLOSE_TYPEHASH, channelId, timestamp)); + if (nonce != usedNonces[buyer]) revert InvalidNonce(); + bytes32 structHash = keccak256(abi.encode(REQUEST_CLOSE_TYPEHASH, channelId, nonce)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash)); - if (_recoverSigner(digest, buyerSig) != buyer) revert InvalidSignature(); + address signer = ECDSA.recover(digest, buyerSig); + if (signer == address(0) || signer != buyer) revert InvalidSignature(); + usedNonces[buyer] = nonce + 1; } else { - _requireBuyerOrOwner(buyer); + _requireBuyerOrAdmin(buyer); } _channels().requestClose(channelId); emit ChannelCloseRequested(channelId, buyer, msg.sender); } - function requestClose(bytes32 channelId) external nonReentrant { - address buyer = _channelBuyer(channelId); - _requireBuyerOrOwner(buyer); - _channels().requestClose(channelId); - emit ChannelCloseRequested(channelId, buyer, msg.sender); + function requestClose(bytes32 channelId) external { + requestClose(channelId, 0, ""); } - function withdrawChannel(bytes32 channelId, uint256 timestamp, bytes calldata buyerSig) external nonReentrant { + function withdrawChannel(bytes32 channelId, uint256 nonce, bytes memory buyerSig) public nonReentrant { address buyer = _channelBuyer(channelId); if (buyerSig.length > 0) { - if (timestamp > block.timestamp || block.timestamp - timestamp > 5 minutes) revert ExpiredSignature(); - bytes32 structHash = keccak256(abi.encode(WITHDRAW_CHANNEL_TYPEHASH, channelId, timestamp)); + if (nonce != usedNonces[buyer]) revert InvalidNonce(); + bytes32 structHash = keccak256(abi.encode(WITHDRAW_CHANNEL_TYPEHASH, channelId, nonce)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash)); - if (_recoverSigner(digest, buyerSig) != buyer) revert InvalidSignature(); + address signer = ECDSA.recover(digest, buyerSig); + if (signer == address(0) || signer != buyer) revert InvalidSignature(); + usedNonces[buyer] = nonce + 1; } else { - _requireBuyerOrOwner(buyer); + _requireBuyerOrAdmin(buyer); } _channels().withdraw(channelId); emit ChannelWithdrawn(channelId, buyer, msg.sender); } - function withdrawChannel(bytes32 channelId) external nonReentrant { - address buyer = _channelBuyer(channelId); - _requireBuyerOrOwner(buyer); - _channels().withdraw(channelId); - emit ChannelWithdrawn(channelId, buyer, msg.sender); + function withdrawChannel(bytes32 channelId) external { + withdrawChannel(channelId, 0, ""); } - function sweepToken(address token, address recipient, uint256 amount) external onlyAdmin { + function sweepToken(address token, address recipient, uint256 amount) external onlyOwner { if (token == address(0) || recipient == address(0)) revert InvalidAddress(); if (amount == 0) revert InvalidAmount(); _safeTransfer(IERC20(token), recipient, amount); emit TokenSwept(token, recipient, amount); } - function approveCurrentDeposits() external onlyOwner { + function approveCurrentDeposits() external onlyAdmin { _forceApprove(usdc, address(_deposits()), type(uint256).max); } @@ -256,13 +409,13 @@ contract AntseedBuyerOperator is Initializable, UUPSUpgradeable { if (_deposits().getOperator(buyer) != address(this)) revert NotDepositsOperator(); } - function _requireBuyerOrOwner(address buyer) internal view { - if (msg.sender == owner || msg.sender == buyer) return; - revert NotBuyerOrOwner(); + function _requireBuyerOrAdmin(address buyer) internal view { + if (msg.sender == admin || msg.sender == owner || msg.sender == buyer) return; + revert NotBuyerOrAdmin(); } function _channelBuyer(bytes32 channelId) internal view returns (address buyer) { - (buyer,,,,,,,,) = IAntseedChannelsState(address(_channels())).channels(channelId); + (buyer, , , , , , , , ) = IAntseedChannelsState(address(_channels())).channels(channelId); if (buyer == address(0)) revert InvalidAddress(); } @@ -293,24 +446,15 @@ contract AntseedBuyerOperator is Initializable, UUPSUpgradeable { _safeApprove(token, spender, amount); } - function _recoverSigner(bytes32 digest, bytes calldata sig) internal pure returns (address) { - if (sig.length != 65) return address(0); - bytes32 r; - bytes32 s; - uint8 v; - assembly { - r := calldataload(sig.offset) - s := calldataload(add(sig.offset, 32)) - v := byte(0, calldataload(add(sig.offset, 64))) - } - if (v < 27) v += 27; - if (v != 27 && v != 28) return address(0); - return ecrecover(digest, v, r, s); + function _min(uint256 a, uint256 b) private pure returns (uint256) { + return a < b ? a : b; } } interface IAntseedChannelsState { - function channels(bytes32 channelId) + function channels( + bytes32 channelId + ) external view returns ( diff --git a/contracts/src/interfaces/IAntseedDeposits.sol b/contracts/src/interfaces/IAntseedDeposits.sol index 541d5b5..6cfa389 100644 --- a/contracts/src/interfaces/IAntseedDeposits.sol +++ b/contracts/src/interfaces/IAntseedDeposits.sol @@ -6,6 +6,7 @@ interface IAntseedDeposits { function setOperator(address buyer, address operator, uint256 nonce, bytes calldata buyerSig) external; function deposit(address buyer, uint256 amount) external; function withdraw(address buyer, uint256 amount) external; + function getBuyerBalance(address buyer) external view returns (uint256 available, uint256 reserved, uint256 lastActivity); function transferOperator(address buyer, address newOperator) external; function getOperator(address buyer) external view returns (address); } diff --git a/contracts/test/AntseedBuyerOperator.t.sol b/contracts/test/AntseedBuyerOperator.t.sol index 987a1d7..4e16004 100644 --- a/contracts/test/AntseedBuyerOperator.t.sol +++ b/contracts/test/AntseedBuyerOperator.t.sol @@ -9,7 +9,9 @@ import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.s interface Vm { function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + function addr(uint256 privateKey) external pure returns (address); + function warp(uint256 newTimestamp) external; } @@ -47,6 +49,7 @@ contract MockDeposits is IAntseedDeposits { IERC20 public immutable token; mapping(address => address) public operators; mapping(address => uint256) public available; + mapping(address => uint256) public reserved; constructor(IERC20 token_) { token = token_; @@ -71,6 +74,22 @@ contract MockDeposits is IAntseedDeposits { require(token.transfer(msg.sender, amount), "TRANSFER"); } + function getBuyerBalance(address buyer) external view override returns (uint256, uint256, uint256) { + return (available[buyer], reserved[buyer], 0); + } + + function consume(address buyer, uint256 amount) external { + require(available[buyer] >= amount, "INSUFFICIENT"); + available[buyer] -= amount; + require(token.transfer(address(0xD00D), amount), "TRANSFER"); + } + + function reserve(address buyer, uint256 amount) external { + require(available[buyer] >= amount, "INSUFFICIENT"); + available[buyer] -= amount; + reserved[buyer] += amount; + } + function transferOperator(address buyer, address newOperator) external override { operators[buyer] = newOperator; } @@ -101,7 +120,9 @@ contract MockChannels is IAntseedChannels { _channels[channelId].buyer = buyer; } - function channels(bytes32 channelId) + function channels( + bytes32 channelId + ) external view returns ( @@ -170,8 +191,16 @@ contract BuyerCaller { operator = operator_; } - function callWithdrawPrincipal(uint256 amount, address recipient, uint256 timestamp, bytes calldata buyerSig) external returns (bool) { - try operator.withdrawPrincipal(address(this), amount, recipient, timestamp, buyerSig) { + function callWithdrawPrincipal(uint256 amount, address recipient, uint256 nonce, bytes calldata buyerSig) external returns (bool) { + try operator.withdrawPrincipal(address(this), amount, recipient, nonce, buyerSig) { + return true; + } catch { + return false; + } + } + + function callRevokeOperator(address buyer) external returns (bool) { + try operator.revokeOperator(buyer) { return true; } catch { return false; @@ -198,43 +227,33 @@ contract AntseedBuyerOperatorTest { channels = new MockChannels(); registry = new MockRegistry(address(deposits), address(channels)); AntseedBuyerOperator impl = new AntseedBuyerOperator(address(registry)); - ERC1967Proxy proxy = new ERC1967Proxy( - address(impl), - abi.encodeCall(AntseedBuyerOperator.initialize, (address(this))) - ); + ERC1967Proxy proxy = new ERC1967Proxy(address(impl), abi.encodeCall(AntseedBuyerOperator.initialize, (address(this)))); operator = AntseedBuyerOperator(address(proxy)); } - function _signWithdraw(uint256 pk, address buyerAddr, uint256 amount, address to, uint256 timestamp) internal view returns (bytes memory) { - bytes32 structHash = keccak256(abi.encode( - operator.WITHDRAW_TYPEHASH(), - buyerAddr, - amount, - to, - timestamp - )); + function _signWithdraw(uint256 pk, address buyerAddr, uint256 amount, address to, uint256 nonce) internal view returns (bytes memory) { + bytes32 structHash = keccak256(abi.encode(operator.WITHDRAW_TYPEHASH(), buyerAddr, amount, to, nonce)); + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", operator.DOMAIN_SEPARATOR(), structHash)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, digest); + return abi.encodePacked(r, s, v); + } + + function _signRequestClose(uint256 pk, bytes32 channelId, uint256 nonce) internal view returns (bytes memory) { + bytes32 structHash = keccak256(abi.encode(operator.REQUEST_CLOSE_TYPEHASH(), channelId, nonce)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", operator.DOMAIN_SEPARATOR(), structHash)); (uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, digest); return abi.encodePacked(r, s, v); } - function _signRequestClose(uint256 pk, bytes32 channelId, uint256 timestamp) internal view returns (bytes memory) { - bytes32 structHash = keccak256(abi.encode( - operator.REQUEST_CLOSE_TYPEHASH(), - channelId, - timestamp - )); + function _signWithdrawChannel(uint256 pk, bytes32 channelId, uint256 nonce) internal view returns (bytes memory) { + bytes32 structHash = keccak256(abi.encode(operator.WITHDRAW_CHANNEL_TYPEHASH(), channelId, nonce)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", operator.DOMAIN_SEPARATOR(), structHash)); (uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, digest); return abi.encodePacked(r, s, v); } - function _signWithdrawChannel(uint256 pk, bytes32 channelId, uint256 timestamp) internal view returns (bytes memory) { - bytes32 structHash = keccak256(abi.encode( - operator.WITHDRAW_CHANNEL_TYPEHASH(), - channelId, - timestamp - )); + function _signRevokeOperator(uint256 pk, address buyerAddr, uint256 nonce) internal view returns (bytes memory) { + bytes32 structHash = keccak256(abi.encode(operator.REVOKE_OPERATOR_TYPEHASH(), buyerAddr, nonce)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", operator.DOMAIN_SEPARATOR(), structHash)); (uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, digest); return abi.encodePacked(r, s, v); @@ -272,26 +291,67 @@ contract AntseedBuyerOperatorTest { require(!ok, "duplicate id rejected"); } - function testDepositRevertsIfOperatorNotSet() public { + function testDepositForWithoutOperatorZeroesBonus() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + + operator.depositFor(buyer, 900_000, 100_000); + + require(deposits.available(buyer) == 900_000, "only principal funded"); + require(operator.totalPrincipalDeposited(buyer) == 900_000, "principal tracked"); + require(operator.totalBonusDeposited(buyer) == 0, "bonus forced to zero"); + } + + function testDepositForWithIdWithoutOperatorZeroesBonusAndKeepsIdempotency() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + + operator.depositForWithId(buyer, 800_000, 200_000, "tx:no-operator"); + + require(deposits.available(buyer) == 800_000, "only principal funded"); + require(operator.totalPrincipalDeposited(buyer) == 800_000, "principal tracked"); + require(operator.totalBonusDeposited(buyer) == 0, "bonus forced to zero"); + + bool ok; + try operator.depositForWithId(buyer, 800_000, 200_000, "tx:no-operator") { + ok = true; + } catch { + ok = false; + } + require(!ok, "duplicate id rejected"); + } + + function testDepositWithoutOperatorRejectsZeroTotalAfterBonusWipe() public { setUp(); usdc.mint(address(operator), 100_000_000); bool ok; - try operator.depositFor(buyer, 900_000, 100_000) { + try operator.depositFor(buyer, 0, 100_000) { ok = true; } catch { ok = false; } - require(!ok, "must reject without operator"); + require(!ok, "zero total rejected after bonus wipe"); + + try operator.depositForWithId(buyer, 0, 100_000, "tx:zero-total") { + ok = true; + } catch { + ok = false; + } + require(!ok, "zero total rejected after bonus wipe with id"); } - function testChannelActionsAllowedForOwnerAndBuyerOnly() public { + function testChannelActionsAllowedForAdminOwnerAndBuyerOnly() public { setUp(); bytes32 channelId = keccak256("channel-1"); channels.setChannelBuyer(channelId, buyer); + OperatorCaller ownerCaller = new OperatorCaller(operator); + operator.transferOwnership(address(ownerCaller)); operator.requestClose(channelId, 0, ""); operator.withdrawChannel(channelId, 0, ""); + require(ownerCaller.callRequestClose(channelId), "owner can request close"); + require(ownerCaller.callWithdrawChannel(channelId), "owner can withdraw"); OperatorCaller buyerCaller = new OperatorCaller(operator); channels.setChannelBuyer(channelId, address(buyerCaller)); @@ -331,27 +391,26 @@ contract AntseedBuyerOperatorTest { require(operator.withdrawablePrincipal(buyerAddr) == 8_000_000, "full principal withdrawable"); // Withdraw part of principal - uint256 ts1 = block.timestamp; - bytes memory sig1 = _signWithdraw(BUYER_PK, buyerAddr, 3_000_000, recipient, ts1); - operator.withdrawPrincipal(buyerAddr, 3_000_000, recipient, ts1, sig1); + uint256 nonce1 = operator.usedNonces(buyerAddr); + bytes memory sig1 = _signWithdraw(BUYER_PK, buyerAddr, 3_000_000, recipient, nonce1); + operator.withdrawPrincipal(buyerAddr, 3_000_000, recipient, nonce1, sig1); require(usdc.balanceOf(recipient) == 3_000_000, "recipient received funds"); - require(operator.totalWithdrawn(buyerAddr) == 3_000_000, "withdrawn tracked"); + require(operator.totalPrincipalWithdrawn(buyerAddr) == 3_000_000, "withdrawn tracked"); require(operator.withdrawablePrincipal(buyerAddr) == 5_000_000, "remaining withdrawable"); + require(operator.usedNonces(buyerAddr) == nonce1 + 1, "nonce incremented after withdraw"); // Withdraw rest of principal - vm.warp(block.timestamp + 1); - uint256 ts2 = block.timestamp; - bytes memory sig2 = _signWithdraw(BUYER_PK, buyerAddr, 5_000_000, recipient, ts2); - operator.withdrawPrincipal(buyerAddr, 5_000_000, recipient, ts2, sig2); + uint256 nonce2 = operator.usedNonces(buyerAddr); + bytes memory sig2 = _signWithdraw(BUYER_PK, buyerAddr, 5_000_000, recipient, nonce2); + operator.withdrawPrincipal(buyerAddr, 5_000_000, recipient, nonce2, sig2); require(usdc.balanceOf(recipient) == 8_000_000, "recipient received all principal"); require(operator.withdrawablePrincipal(buyerAddr) == 0, "nothing left"); // Cannot withdraw more than principal (bonus not withdrawable) - vm.warp(block.timestamp + 1); - uint256 ts3 = block.timestamp; - bytes memory sig3 = _signWithdraw(BUYER_PK, buyerAddr, 1, recipient, ts3); + uint256 nonce3 = operator.usedNonces(buyerAddr); + bytes memory sig3 = _signWithdraw(BUYER_PK, buyerAddr, 1, recipient, nonce3); bool ok; - try operator.withdrawPrincipal(buyerAddr, 1, recipient, ts3, sig3) { + try operator.withdrawPrincipal(buyerAddr, 1, recipient, nonce3, sig3) { ok = true; } catch { ok = false; @@ -371,9 +430,9 @@ contract AntseedBuyerOperatorTest { require(deposits.available(buyerAddr) == 7_000_000, "full deposit in vault"); require(operator.withdrawablePrincipal(buyerAddr) == 5_000_000, "only principal withdrawable"); - uint256 ts = block.timestamp; - bytes memory sig = _signWithdraw(BUYER_PK, buyerAddr, 5_000_000, recipient, ts); - operator.withdrawPrincipal(buyerAddr, 5_000_000, recipient, ts, sig); + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory sig = _signWithdraw(BUYER_PK, buyerAddr, 5_000_000, recipient, nonce); + operator.withdrawPrincipal(buyerAddr, 5_000_000, recipient, nonce, sig); // Recipient received only the principal require(usdc.balanceOf(recipient) == 5_000_000, "recipient got principal"); @@ -382,6 +441,202 @@ contract AntseedBuyerOperatorTest { require(operator.withdrawablePrincipal(buyerAddr) == 0, "nothing left to withdraw"); } + function testUsageConsumesPrincipalBeforeBonusAcrossNewDeposits() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + operator.acceptBuyerOperator(buyer, 1, ""); + + operator.depositFor(buyer, 10_000_000, 2_000_000); + deposits.consume(buyer, 3_000_000); + require(operator.withdrawablePrincipal(buyer) == 7_000_000, "view accounts for pending usage"); + + deposits.consume(buyer, 9_000_000); + + operator.depositForWithId(buyer, 5_000_000, 1_000_000, "tx:after-usage"); + + require(operator.principalRemaining(buyer) == 5_000_000, "new principal remains"); + require(operator.bonusRemaining(buyer) == 1_000_000, "new bonus remains"); + require(operator.withdrawablePrincipal(buyer) == 5_000_000, "new principal withdrawable"); + } + + function testUsageConsumesPrincipalBeforeBonusAcrossNewDepositsWhenFullyConsumedAtOnce() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + operator.acceptBuyerOperator(buyer, 1, ""); + + operator.depositFor(buyer, 10_000_000, 2_000_000); + deposits.consume(buyer, 12_000_000); + + operator.depositForWithId(buyer, 5_000_000, 1_000_000, "tx:after-usage"); + + require(operator.principalRemaining(buyer) == 5_000_000, "new principal remains"); + require(operator.bonusRemaining(buyer) == 1_000_000, "new bonus remains"); + require(operator.withdrawablePrincipal(buyer) == 5_000_000, "new principal withdrawable"); + } + + function testRevokeOperatorWithdrawsUnusedAvailableBonus() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + + BuyerCaller buyerCaller = new BuyerCaller(operator); + operator.acceptBuyerOperator(address(buyerCaller), 1, ""); + operator.depositFor(address(buyerCaller), 5_000_000, 2_000_000); + + require(buyerCaller.callRevokeOperator(address(buyerCaller)), "buyer can revoke"); + + require(deposits.getOperator(address(buyerCaller)) == address(0), "operator revoked"); + require(deposits.available(address(buyerCaller)) == 5_000_000, "only principal left"); + require(usdc.balanceOf(address(operator)) == 95_000_000, "bonus returned to operator"); + require(operator.bonusRemaining(address(buyerCaller)) == 0, "bonus remaining cleared"); + require(operator.totalBonusWithdrawn(address(buyerCaller)) == 2_000_000, "bonus withdrawal tracked"); + } + + function testRevokeOperatorWithBuyerSig() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + + address buyerAddr = vm.addr(BUYER_PK); + operator.acceptBuyerOperator(buyerAddr, 1, ""); + operator.depositFor(buyerAddr, 4_000_000, 1_000_000); + + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory sig = _signRevokeOperator(BUYER_PK, buyerAddr, nonce); + + operator.revokeOperator(buyerAddr, nonce, sig); + + require(deposits.getOperator(buyerAddr) == address(0), "operator revoked"); + require(deposits.available(buyerAddr) == 4_000_000, "bonus reclaimed before revoke"); + require(operator.totalBonusWithdrawn(buyerAddr) == 1_000_000, "bonus withdrawal tracked"); + require(operator.usedNonces(buyerAddr) == nonce + 1, "nonce incremented after revoke"); + } + + function testRevokeOperatorRejectsWrongSigner() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + + address buyerAddr = vm.addr(BUYER_PK); + operator.acceptBuyerOperator(buyerAddr, 1, ""); + operator.depositFor(buyerAddr, 4_000_000, 1_000_000); + + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory badSig = _signRevokeOperator(0xDEAD, buyerAddr, nonce); + + bool ok; + try operator.revokeOperator(buyerAddr, nonce, badSig) { + ok = true; + } catch { + ok = false; + } + require(!ok, "wrong signer rejected"); + } + + function testRevokeOperatorRejectsInvalidNonce() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + + address buyerAddr = vm.addr(BUYER_PK); + operator.acceptBuyerOperator(buyerAddr, 1, ""); + operator.depositFor(buyerAddr, 4_000_000, 1_000_000); + + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory sig = _signRevokeOperator(BUYER_PK, buyerAddr, nonce); + + bool ok; + try operator.revokeOperator(buyerAddr, nonce + 1, sig) { + ok = true; + } catch { + ok = false; + } + require(!ok, "invalid nonce rejected"); + } + + function testMigrateBuyerAccountingComputesRemainingFromTrackedTotals() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + + operator.acceptBuyerOperator(buyer, 1, ""); + operator.depositFor(buyer, 10_000_000, 2_000_000); + deposits.consume(buyer, 3_000_000); + + operator.migrateBuyerAccounting(buyer); + + require(operator.principalRemaining(buyer) == 7_000_000, "principal recomputed"); + require(operator.bonusRemaining(buyer) == 2_000_000, "bonus recomputed"); + require(operator.lastAccountedBalance(buyer) == 9_000_000, "accounted balance set"); + require(operator.buyerAccountingMigrated(buyer), "migration flagged"); + + bool ok; + try operator.migrateBuyerAccounting(buyer) { + ok = true; + } catch { + ok = false; + } + require(!ok, "double migration rejected"); + } + + function testMigrateBuyerAccountingBatch() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + + address buyer2 = address(0xB0C); + + operator.acceptBuyerOperator(buyer, 1, ""); + operator.acceptBuyerOperator(buyer2, 1, ""); + + operator.depositFor(buyer, 10_000_000, 2_000_000); + operator.depositFor(buyer2, 6_000_000, 1_000_000); + + deposits.consume(buyer, 3_000_000); + deposits.consume(buyer2, 1_500_000); + + address[] memory buyers = new address[](2); + buyers[0] = buyer; + buyers[1] = buyer2; + operator.migrateBuyerAccounting(buyers); + + require(operator.principalRemaining(buyer) == 7_000_000, "buyer1 principal recomputed"); + require(operator.bonusRemaining(buyer) == 2_000_000, "buyer1 bonus recomputed"); + require(operator.lastAccountedBalance(buyer) == 9_000_000, "buyer1 accounted balance set"); + + require(operator.principalRemaining(buyer2) == 4_500_000, "buyer2 principal recomputed"); + require(operator.bonusRemaining(buyer2) == 1_000_000, "buyer2 bonus recomputed"); + require(operator.lastAccountedBalance(buyer2) == 5_500_000, "buyer2 accounted balance set"); + + require(operator.buyerAccountingMigrated(buyer), "buyer1 migration flagged"); + require(operator.buyerAccountingMigrated(buyer2), "buyer2 migration flagged"); + } + + function testTransferBuyerOperatorWithdrawsOnlyAvailableBonus() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + operator.acceptBuyerOperator(buyer, 1, ""); + operator.depositFor(buyer, 5_000_000, 2_000_000); + deposits.reserve(buyer, 2_000_000); + + address newOp = address(0xC0DE); + operator.transferBuyerOperator(buyer, newOp); + + require(deposits.getOperator(buyer) == newOp, "operator transferred"); + require(deposits.available(buyer) == 5_000_000, "available principal preserved"); + require(deposits.reserved(buyer) == 2_000_000, "reserved funds untouched"); + require(operator.totalBonusWithdrawn(buyer) == 0, "reserved bonus not withdrawn"); + } + + function testTransferBuyerOperatorAfterNonOperatorFundingKeepsPrincipalIntact() public { + setUp(); + usdc.mint(address(operator), 100_000_000); + + operator.depositFor(buyer, 3_000_000, 1_000_000); + + address newOp = address(0xA11CE); + operator.transferBuyerOperator(buyer, newOp); + + require(deposits.getOperator(buyer) == newOp, "operator transferred"); + require(deposits.available(buyer) == 3_000_000, "principal untouched"); + require(operator.totalBonusDeposited(buyer) == 0, "bonus never credited"); + require(operator.totalBonusWithdrawn(buyer) == 0, "no bonus withdrawal"); + } + function testWithdrawPrincipalRejectsWrongSigner() public { setUp(); usdc.mint(address(operator), 100_000_000); @@ -392,10 +647,10 @@ contract AntseedBuyerOperatorTest { // Sign with a different private key (not the buyer) uint256 wrongPk = 0xDEAD; - uint256 ts = block.timestamp; - bytes memory badSig = _signWithdraw(wrongPk, buyerAddr, 1_000_000, recipient, ts); + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory badSig = _signWithdraw(wrongPk, buyerAddr, 1_000_000, recipient, nonce); bool ok; - try operator.withdrawPrincipal(buyerAddr, 1_000_000, recipient, ts, badSig) { + try operator.withdrawPrincipal(buyerAddr, 1_000_000, recipient, nonce, badSig) { ok = true; } catch { ok = false; @@ -403,7 +658,7 @@ contract AntseedBuyerOperatorTest { require(!ok, "wrong signer rejected"); } - function testWithdrawPrincipalRejectsExpiredTimestamp() public { + function testWithdrawPrincipalRejectsInvalidNonce() public { setUp(); usdc.mint(address(operator), 100_000_000); @@ -411,19 +666,16 @@ contract AntseedBuyerOperatorTest { operator.acceptBuyerOperator(buyerAddr, 1, ""); operator.depositFor(buyerAddr, 10_000_000, 0); - uint256 ts = block.timestamp; - bytes memory sig = _signWithdraw(BUYER_PK, buyerAddr, 1_000_000, recipient, ts); - - // Warp 6 minutes into the future so the timestamp is expired - vm.warp(ts + 6 minutes); + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory sig = _signWithdraw(BUYER_PK, buyerAddr, 1_000_000, recipient, nonce); bool ok; - try operator.withdrawPrincipal(buyerAddr, 1_000_000, recipient, ts, sig) { + try operator.withdrawPrincipal(buyerAddr, 1_000_000, recipient, nonce + 1, sig) { ok = true; } catch { ok = false; } - require(!ok, "expired timestamp rejected"); + require(!ok, "invalid nonce rejected"); } function testRequestCloseWithBuyerSig() public { @@ -432,10 +684,11 @@ contract AntseedBuyerOperatorTest { address buyerAddr = vm.addr(BUYER_PK); channels.setChannelBuyer(channelId, buyerAddr); - uint256 ts = block.timestamp; - bytes memory sig = _signRequestClose(BUYER_PK, channelId, ts); - operator.requestClose(channelId, ts, sig); + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory sig = _signRequestClose(BUYER_PK, channelId, nonce); + operator.requestClose(channelId, nonce, sig); require(channels.requestCloseCalls() == 1, "requestClose forwarded"); + require(operator.usedNonces(buyerAddr) == nonce + 1, "nonce incremented after requestClose"); } function testRequestCloseRejectsWrongSigner() public { @@ -444,25 +697,32 @@ contract AntseedBuyerOperatorTest { address buyerAddr = vm.addr(BUYER_PK); channels.setChannelBuyer(channelId, buyerAddr); - uint256 ts = block.timestamp; - bytes memory badSig = _signRequestClose(0xDEAD, channelId, ts); + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory badSig = _signRequestClose(0xDEAD, channelId, nonce); bool ok; - try operator.requestClose(channelId, ts, badSig) { ok = true; } catch { ok = false; } + try operator.requestClose(channelId, nonce, badSig) { + ok = true; + } catch { + ok = false; + } require(!ok, "wrong signer rejected"); } - function testRequestCloseRejectsExpiredTimestamp() public { + function testRequestCloseRejectsInvalidNonce() public { setUp(); bytes32 channelId = keccak256("channel-sig"); address buyerAddr = vm.addr(BUYER_PK); channels.setChannelBuyer(channelId, buyerAddr); - uint256 ts = block.timestamp; - bytes memory sig = _signRequestClose(BUYER_PK, channelId, ts); - vm.warp(ts + 6 minutes); + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory sig = _signRequestClose(BUYER_PK, channelId, nonce); bool ok; - try operator.requestClose(channelId, ts, sig) { ok = true; } catch { ok = false; } - require(!ok, "expired timestamp rejected"); + try operator.requestClose(channelId, nonce + 1, sig) { + ok = true; + } catch { + ok = false; + } + require(!ok, "invalid nonce rejected"); } function testWithdrawChannelWithBuyerSig() public { @@ -471,10 +731,11 @@ contract AntseedBuyerOperatorTest { address buyerAddr = vm.addr(BUYER_PK); channels.setChannelBuyer(channelId, buyerAddr); - uint256 ts = block.timestamp; - bytes memory sig = _signWithdrawChannel(BUYER_PK, channelId, ts); - operator.withdrawChannel(channelId, ts, sig); + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory sig = _signWithdrawChannel(BUYER_PK, channelId, nonce); + operator.withdrawChannel(channelId, nonce, sig); require(channels.withdrawCalls() == 1, "withdrawChannel forwarded"); + require(operator.usedNonces(buyerAddr) == nonce + 1, "nonce incremented after withdrawChannel"); } function testWithdrawChannelRejectsWrongSigner() public { @@ -483,58 +744,59 @@ contract AntseedBuyerOperatorTest { address buyerAddr = vm.addr(BUYER_PK); channels.setChannelBuyer(channelId, buyerAddr); - uint256 ts = block.timestamp; - bytes memory badSig = _signWithdrawChannel(0xDEAD, channelId, ts); + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory badSig = _signWithdrawChannel(0xDEAD, channelId, nonce); bool ok; - try operator.withdrawChannel(channelId, ts, badSig) { ok = true; } catch { ok = false; } + try operator.withdrawChannel(channelId, nonce, badSig) { + ok = true; + } catch { + ok = false; + } require(!ok, "wrong signer rejected"); } - function testWithdrawChannelRejectsExpiredTimestamp() public { + function testWithdrawChannelRejectsInvalidNonce() public { setUp(); bytes32 channelId = keccak256("channel-sig"); address buyerAddr = vm.addr(BUYER_PK); channels.setChannelBuyer(channelId, buyerAddr); - uint256 ts = block.timestamp; - bytes memory sig = _signWithdrawChannel(BUYER_PK, channelId, ts); - vm.warp(ts + 6 minutes); + uint256 nonce = operator.usedNonces(buyerAddr); + bytes memory sig = _signWithdrawChannel(BUYER_PK, channelId, nonce); bool ok; - try operator.withdrawChannel(channelId, ts, sig) { ok = true; } catch { ok = false; } - require(!ok, "expired timestamp rejected"); + try operator.withdrawChannel(channelId, nonce + 1, sig) { + ok = true; + } catch { + ok = false; + } + require(!ok, "invalid nonce rejected"); } function testCannotReinitialize() public { setUp(); - (bool ok,) = address(operator).call( - abi.encodeCall(AntseedBuyerOperator.initialize, (address(this))) - ); + (bool ok, ) = address(operator).call(abi.encodeCall(AntseedBuyerOperator.initialize, (address(this)))); require(!ok, "double init rejected"); } - function testOnlyAdminCanUpgrade() public { + function testOnlyOwnerCanUpgrade() public { setUp(); AntseedBuyerOperator newImpl = new AntseedBuyerOperator(address(registry)); - // admin (equals owner at init) can upgrade + // owner (equals admin at init) can upgrade operator.upgradeToAndCall(address(newImpl), ""); // outsider cannot upgrade OperatorUpgradeHelper outsider = new OperatorUpgradeHelper(); - (bool ok,) = address(outsider).call( - abi.encodeWithSignature("upgrade(address,address)", address(operator), address(newImpl)) - ); + (bool ok, ) = address(outsider).call(abi.encodeWithSignature("upgrade(address,address)", address(operator), address(newImpl))); require(!ok, "outsider upgrade rejected"); - // transfer admin away; address(this) remains owner but loses admin role - AdminActor newAdminActor = new AdminActor(operator); - operator.transferAdmin(address(newAdminActor)); + // transfer ownership away; address(this) remains admin but loses owner role + AdminActor newOwnerActor = new AdminActor(operator); + operator.transferOwnership(address(newOwnerActor)); - // owner-without-admin is now blocked by onlyAdmin - (ok,) = address(operator).call( - abi.encodeWithSignature("upgradeToAndCall(address,bytes)", address(newImpl), bytes("")) - ); - require(!ok, "owner-without-admin upgrade rejected"); + // admin-without-owner is now blocked by onlyOwner + (ok, ) = address(operator).call(abi.encodeWithSignature("upgradeToAndCall(address,bytes)", address(newImpl), bytes(""))); + require(!ok, "admin-without-owner upgrade rejected"); } // ─── transferOwnership ─── @@ -548,9 +810,7 @@ contract AntseedBuyerOperatorTest { function testTransferOwnershipRejectsZeroAddress() public { setUp(); - (bool ok,) = address(operator).call( - abi.encodeWithSignature("transferOwnership(address)", address(0)) - ); + (bool ok, ) = address(operator).call(abi.encodeWithSignature("transferOwnership(address)", address(0))); require(!ok, "zero-address transferOwnership rejected"); } @@ -558,9 +818,7 @@ contract AntseedBuyerOperatorTest { setUp(); AdminActor outsider = new AdminActor(operator); // outsider is neither owner nor admin - (bool ok,) = address(outsider).call( - abi.encodeWithSignature("callTransferOwnership(address)", address(outsider)) - ); + (bool ok, ) = address(outsider).call(abi.encodeWithSignature("callTransferOwnership(address)", address(outsider))); require(!ok, "outsider cannot transferOwnership"); } @@ -571,104 +829,82 @@ contract AntseedBuyerOperatorTest { AdminActor newAdminActor = new AdminActor(operator); operator.transferAdmin(address(newAdminActor)); require(operator.admin() == address(newAdminActor), "admin updated"); - // new admin can exercise onlyAdmin — sweep a token + // new admin can exercise operational functions usdc.mint(address(operator), 1_000_000); - newAdminActor.callSweepToken(address(usdc), recipient, 1_000_000); - require(usdc.balanceOf(recipient) == 1_000_000, "new admin swept token"); + newAdminActor.callAcceptBuyerOperator(buyer, 1); + newAdminActor.callDepositFor(buyer, 500_000, 100_000); + require(deposits.available(buyer) == 600_000, "new admin funded buyer"); } function testTransferAdminRejectsZeroAddress() public { setUp(); - (bool ok,) = address(operator).call( - abi.encodeWithSignature("transferAdmin(address)", address(0)) - ); + (bool ok, ) = address(operator).call(abi.encodeWithSignature("transferAdmin(address)", address(0))); require(!ok, "zero-address transferAdmin rejected"); } - function testTransferAdminOnlyCallableByAdmin() public { + function testTransferAdminOnlyCallableByAdminOrOwner() public { setUp(); AdminActor outsider = new AdminActor(operator); // outsider (neither owner nor admin) cannot call transferAdmin - (bool ok,) = address(outsider).call( - abi.encodeWithSignature("callTransferAdmin(address)", address(outsider)) - ); + (bool ok, ) = address(outsider).call(abi.encodeWithSignature("callTransferAdmin(address)", address(outsider))); require(!ok, "outsider cannot transferAdmin"); } - function testOwnerAfterAdminTransferCannotCallOnlyAdmin() public { + function testAdminAfterOwnershipTransferCannotCallOnlyOwner() public { setUp(); - // Transfer admin away; address(this) remains owner but is no longer admin. - AdminActor newAdminActor = new AdminActor(operator); - operator.transferAdmin(address(newAdminActor)); + // Transfer ownership away; address(this) remains admin but is no longer owner. + AdminActor newOwnerActor = new AdminActor(operator); + operator.transferOwnership(address(newOwnerActor)); usdc.mint(address(operator), 1_000_000); - // address(this) can no longer call onlyAdmin functions - (bool ok,) = address(operator).call( - abi.encodeWithSignature( - "sweepToken(address,address,uint256)", - address(usdc), recipient, uint256(1_000_000) - ) - ); - require(!ok, "owner-without-admin cannot sweepToken"); + // address(this) can no longer call onlyOwner functions + (bool ok, ) = address(operator).call(abi.encodeWithSignature("sweepToken(address,address,uint256)", address(usdc), recipient, uint256(1_000_000))); + require(!ok, "admin-without-owner cannot sweepToken"); - (ok,) = address(operator).call( - abi.encodeWithSignature("transferAdmin(address)", address(this)) - ); - require(!ok, "owner-without-admin cannot transferAdmin"); + operator.transferAdmin(address(this)); + require(operator.admin() == address(this), "admin-without-owner can transferAdmin"); } - // ─── onlyOwner: admin can also call ─── + // ─── onlyAdmin: owner can also call ─── - function testAdminCanCallOnlyOwnerFunctions() public { + function testOwnerCanCallOnlyAdminFunctions() public { setUp(); - AdminActor adminActor = new AdminActor(operator); - operator.transferAdmin(address(adminActor)); usdc.mint(address(operator), 100_000_000); - // acceptBuyerOperator via admin - adminActor.callAcceptBuyerOperator(buyer, 1); - // depositFor via admin - adminActor.callDepositFor(buyer, 500_000, 100_000); - require(deposits.available(buyer) == 600_000, "admin funded buyer"); - require(operator.totalPrincipalDeposited(buyer) == 500_000, "principal tracked via admin"); - require(operator.totalBonusDeposited(buyer) == 100_000, "bonus tracked via admin"); + operator.acceptBuyerOperator(buyer, 1, ""); + operator.depositFor(buyer, 500_000, 100_000); + require(deposits.available(buyer) == 600_000, "owner funded buyer"); + require(operator.totalPrincipalDeposited(buyer) == 500_000, "principal tracked via owner"); + require(operator.totalBonusDeposited(buyer) == 100_000, "bonus tracked via owner"); } - function testAdminCanUpgrade() public { + function testAdminCannotUpgrade() public { setUp(); AntseedBuyerOperator newImpl = new AntseedBuyerOperator(address(registry)); AdminActor adminActor = new AdminActor(operator); operator.transferAdmin(address(adminActor)); - // admin (not owner) should be able to trigger upgradeToAndCall - adminActor.callUpgrade(address(operator), address(newImpl)); - require(operator.admin() == address(adminActor), "admin preserved after admin-initiated upgrade"); + // admin (not owner) cannot trigger upgradeToAndCall + (bool ok, ) = address(adminActor).call(abi.encodeWithSignature("callUpgrade(address,address)", address(operator), address(newImpl))); + require(!ok, "admin cannot upgrade"); } - // ─── onlyOwner: outsider rejected ─── + // ─── onlyAdmin: outsider rejected ─── - function testOnlyOwnerFunctionsRejectOutsider() public { + function testOnlyAdminFunctionsRejectOutsider() public { setUp(); AdminActor outsider = new AdminActor(operator); - (bool ok,) = address(outsider).call( - abi.encodeWithSignature("callAcceptBuyerOperator(address,uint256)", buyer, uint256(1)) - ); + (bool ok, ) = address(outsider).call(abi.encodeWithSignature("callAcceptBuyerOperator(address,uint256)", buyer, uint256(1))); require(!ok, "outsider cannot acceptBuyerOperator"); - (ok,) = address(outsider).call( - abi.encodeWithSignature("callDepositFor(address,uint256,uint256)", buyer, uint256(1), uint256(0)) - ); + (ok, ) = address(outsider).call(abi.encodeWithSignature("callDepositFor(address,uint256,uint256)", buyer, uint256(1), uint256(0))); require(!ok, "outsider cannot depositFor"); - (ok,) = address(outsider).call( - abi.encodeWithSignature("callApproveCurrentDeposits()") - ); + (ok, ) = address(outsider).call(abi.encodeWithSignature("callApproveCurrentDeposits()")); require(!ok, "outsider cannot approveCurrentDeposits"); - (ok,) = address(outsider).call( - abi.encodeWithSignature("callTransferBuyerOperator(address,address)", buyer, address(outsider)) - ); + (ok, ) = address(outsider).call(abi.encodeWithSignature("callTransferBuyerOperator(address,address)", buyer, address(outsider))); require(!ok, "outsider cannot transferBuyerOperator"); } @@ -685,34 +921,26 @@ contract AntseedBuyerOperatorTest { setUp(); usdc.mint(address(operator), 1_000_000); - (bool ok,) = address(operator).call( - abi.encodeWithSignature("sweepToken(address,address,uint256)", address(0), recipient, uint256(1)) - ); + (bool ok, ) = address(operator).call(abi.encodeWithSignature("sweepToken(address,address,uint256)", address(0), recipient, uint256(1))); require(!ok, "zero token address rejected"); - (ok,) = address(operator).call( - abi.encodeWithSignature("sweepToken(address,address,uint256)", address(usdc), address(0), uint256(1)) - ); + (ok, ) = address(operator).call(abi.encodeWithSignature("sweepToken(address,address,uint256)", address(usdc), address(0), uint256(1))); require(!ok, "zero recipient rejected"); - (ok,) = address(operator).call( - abi.encodeWithSignature("sweepToken(address,address,uint256)", address(usdc), recipient, uint256(0)) - ); + (ok, ) = address(operator).call(abi.encodeWithSignature("sweepToken(address,address,uint256)", address(usdc), recipient, uint256(0))); require(!ok, "zero amount rejected"); } // ─── approveCurrentDeposits ─── - function testApproveCurrentDepositsOnlyOwner() public { + function testApproveCurrentDepositsOnlyAdmin() public { setUp(); - // owner can call + // owner can call admin operations too operator.approveCurrentDeposits(); // outsider cannot AdminActor outsider = new AdminActor(operator); - (bool ok,) = address(outsider).call( - abi.encodeWithSignature("callApproveCurrentDeposits()") - ); + (bool ok, ) = address(outsider).call(abi.encodeWithSignature("callApproveCurrentDeposits()")); require(!ok, "outsider cannot approveCurrentDeposits"); } @@ -726,13 +954,11 @@ contract AntseedBuyerOperatorTest { require(deposits.getOperator(buyer) == newOp, "operator transferred"); } - function testTransferBuyerOperatorOnlyOwner() public { + function testTransferBuyerOperatorOnlyAdmin() public { setUp(); operator.acceptBuyerOperator(buyer, 1, ""); AdminActor outsider = new AdminActor(operator); - (bool ok,) = address(outsider).call( - abi.encodeWithSignature("callTransferBuyerOperator(address,address)", buyer, address(outsider)) - ); + (bool ok, ) = address(outsider).call(abi.encodeWithSignature("callTransferBuyerOperator(address,address)", buyer, address(outsider))); require(!ok, "outsider cannot transferBuyerOperator"); } } @@ -742,23 +968,38 @@ contract AntseedBuyerOperatorTest { contract AdminActor { AntseedBuyerOperator public operator; - constructor(AntseedBuyerOperator op) { operator = op; } + constructor(AntseedBuyerOperator op) { + operator = op; + } + + function callTransferOwnership(address to) external { + operator.transferOwnership(to); + } + + function callTransferAdmin(address to) external { + operator.transferAdmin(to); + } - function callTransferOwnership(address to) external { operator.transferOwnership(to); } - function callTransferAdmin(address to) external { operator.transferAdmin(to); } function callAcceptBuyerOperator(address buyer_, uint256 nonce) external { operator.acceptBuyerOperator(buyer_, nonce, ""); } + function callDepositFor(address buyer_, uint256 principal, uint256 bonus) external { operator.depositFor(buyer_, principal, bonus); } + function callSweepToken(address token_, address recipient_, uint256 amount) external { operator.sweepToken(token_, recipient_, amount); } - function callApproveCurrentDeposits() external { operator.approveCurrentDeposits(); } + + function callApproveCurrentDeposits() external { + operator.approveCurrentDeposits(); + } + function callTransferBuyerOperator(address buyer_, address newOp) external { operator.transferBuyerOperator(buyer_, newOp); } + function callUpgrade(address proxy, address newImpl) external { AntseedBuyerOperator(proxy).upgradeToAndCall(newImpl, ""); } diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 257b3bc..687c9fb 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -14,7 +14,7 @@ A UUPS-upgradeable contract deployed on Base. It acts as the on-chain operator f - `depositFor(buyer, principal, bonus)` — pulls USDC from contract balance, calls `deposits.deposit(buyer, principal + bonus)` - `depositForWithId(buyer, principal, bonus, id)` — same but idempotent via `usedDepositIds[keccak256(id)]`; duplicate IDs are silently skipped - tracks `totalPrincipalDeposited[buyer]` and `totalBonusDeposited[buyer]` separately; `withdrawablePrincipal(buyer) = totalPrincipalDeposited - totalWithdrawn` -- `withdrawPrincipal(buyer, amount, recipient, timestamp, buyerSig)` — buyer EIP-712 signed principal-only withdrawal; 5-minute timestamp window; bonus is not withdrawable by buyer +- `withdrawPrincipal(buyer, amount, recipient, nonce, buyerSig)` — buyer EIP-712 signed principal-only withdrawal using the per-address `usedNonces[buyer]` counter; bonus is not withdrawable by buyer - `withdrawDepositedFor(buyer, amount, recipient)` — owner-only full withdrawal from deposits - `requestClose(channelId)` / `withdrawChannel(channelId)` — callable by owner or the channel's buyer - `sweepToken(token, recipient, amount)` — owner-only token rescue @@ -44,44 +44,59 @@ The backend reads `buyer` directly from on-chain events (log topics) for deposit The backend is a Cloudflare Worker managed by Wrangler. Its current scope is G$ credit ingestion, accounting, and AntSeed deposit funding. It does **not** proxy AI requests. **Event ingestion** (`POST /v1/celo/events/record`): + - fetches a Celo transaction receipt by `txHash` (or a log range by `account + fromBlock`) - parses `GdDeposited` and `StreamUpdated` events from `CeloGdAntSeedVault` - resolves `getWhitelistedRoot(account)` to determine GoodID verification and root-account aggregation - records a `GdCreditEntry` in KV and calls `fundCredit` immediately **Stream credit issuance** (`POST /v1/accounts/:account/stream-credits`): + - reads active Superfluid streams for the account from the subgraph - computes elapsed seconds since last credit (24-hour cooldown enforced) - records a `GdCreditEntry` per stream and calls `fundCredit` **Cron (every minute)**: + - fetches all active incoming streams from the Superfluid subgraph - issues stream credits for each streamer and funds them **Profile** (`GET /v1/accounts/:account/profile`): + - returns the user's `UserCreditProfile` only **Credit history** (`GET /v1/accounts/:account/credit-history`): + - returns paginated `GdCreditEntry` records newest-first - query params: `limit` (default 20, max 100), `offset` (default 0), optional `source`, `fundingStatus`, `from` / `to` (ISO `createdAt` range, inclusive) - response: `{ account, items, total, limit, offset, hasMore }` **Outstanding funding** (`GET /v1/accounts/:account/outstanding`): + - returns `totalOutstandingFundingUsd` and all `GdCreditEntry` records with `fundingStatus = "pending"` or `"failed"` **Principal withdraw** (`POST /v1/accounts/:account/withdraw`): -- body: `amount` (USDC micro-units), `recipient`, `timestamp`, buyer EIP-712 `signature` -- calls `AntseedBuyerOperator.withdrawPrincipal(buyer, amount, recipient, timestamp, buyerSig)` + +- body: `amount` (USDC micro-units), `recipient`, `nonce`, buyer EIP-712 `signature` +- calls `AntseedBuyerOperator.withdrawPrincipal(buyer, amount, recipient, nonce, buyerSig)` + +**Operator revoke** (`POST /v1/accounts/:account/operator-revoke`): + +- body: `nonce`, buyer EIP-712 `signature` +- calls `AntseedBuyerOperator.revokeOperator(buyer, nonce, buyerSig)` **Channel close** (`POST /v1/channels/:channelId/close`): -- optional buyer EIP-712 `RequestClose` (`timestamp`, `signature`) or operator-as-owner when unsigned + +- optional buyer EIP-712 `RequestClose` (`nonce`, `signature`) or operator-as-owner when unsigned - calls `AntseedBuyerOperator.requestClose(channelId, …)` **Channel withdraw** (`POST /v1/channels/:channelId/withdraw`): -- optional buyer EIP-712 `WithdrawChannel` (`timestamp`, `signature`) or operator-as-owner when unsigned + +- optional buyer EIP-712 `WithdrawChannel` (`nonce`, `signature`) or operator-as-owner when unsigned - calls `AntseedBuyerOperator.withdrawChannel(channelId, …)` **Funding path** (`fundCredit`): + - calls `AntSeedFundingVaultClient.depositForBuyerWithId(buyer, principal, bonus, id)` — uses the `buyer` from the credit entry, or falls back to `account` - on success: marks entry `funded`, decrements `totalOutstandingFundingUsd` - on failure: marks entry `failed`, preserves `fundingError` @@ -109,7 +124,6 @@ Future payment mechanisms (sponsorships, org budgets, subscriptions, multi-buyer - no wallet UI - no model hosting logic - ## Cloudflare KV persistence The Worker binds `ANTSEED_KV` and persists: