ci: enforce oxc checks for worker
This commit is contained in:
parent
b4cd356443
commit
b528a765fc
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@ -70,6 +70,14 @@ jobs:
|
||||
run: npm ci
|
||||
working-directory: worker
|
||||
|
||||
- name: Format
|
||||
run: npm run format:check
|
||||
working-directory: worker
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
working-directory: worker
|
||||
|
||||
- name: Typecheck
|
||||
run: npm run check
|
||||
working-directory: worker
|
||||
|
||||
@ -97,6 +97,8 @@ Local checks:
|
||||
|
||||
```sh
|
||||
npm ci --prefix worker
|
||||
npm run format:check --prefix worker
|
||||
npm run lint --prefix worker
|
||||
npm run check --prefix worker
|
||||
npm test --prefix worker
|
||||
npm run build --prefix worker
|
||||
@ -178,6 +180,8 @@ go vet ./...
|
||||
go test -race ./...
|
||||
go build -trimpath -o bin/crabbox ./cmd/crabbox
|
||||
npm ci --prefix worker
|
||||
npm run format:check --prefix worker
|
||||
npm run lint --prefix worker
|
||||
npm run check --prefix worker
|
||||
npm test --prefix worker
|
||||
npm run build --prefix worker
|
||||
|
||||
16
worker/.oxfmtrc.json
Normal file
16
worker/.oxfmtrc.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||
"arrowParens": "always",
|
||||
"bracketSpacing": true,
|
||||
"endOfLine": "lf",
|
||||
"ignorePatterns": ["dist/**", "node_modules/**"],
|
||||
"insertFinalNewline": true,
|
||||
"printWidth": 100,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"sortImports": true,
|
||||
"sortPackageJson": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "all",
|
||||
"useTabs": false
|
||||
}
|
||||
22
worker/.oxlintrc.json
Normal file
22
worker/.oxlintrc.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"categories": {
|
||||
"correctness": "deny",
|
||||
"perf": "deny",
|
||||
"suspicious": "deny"
|
||||
},
|
||||
"env": {
|
||||
"builtin": true,
|
||||
"es2026": true,
|
||||
"node": true,
|
||||
"vitest": true,
|
||||
"worker": true
|
||||
},
|
||||
"ignorePatterns": ["dist/**", "node_modules/**"],
|
||||
"options": {
|
||||
"denyWarnings": true,
|
||||
"maxWarnings": 0,
|
||||
"reportUnusedDisableDirectives": "deny"
|
||||
},
|
||||
"plugins": ["typescript", "unicorn", "import", "vitest", "promise", "node"]
|
||||
}
|
||||
791
worker/package-lock.json
generated
791
worker/package-lock.json
generated
@ -9,6 +9,8 @@
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20260430.0",
|
||||
"oxfmt": "^0.47.0",
|
||||
"oxlint": "^1.62.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.10",
|
||||
"wrangler": "^4.50.0"
|
||||
@ -1216,6 +1218,700 @@
|
||||
"url": "https://github.com/sponsors/Boshen"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-android-arm-eabi": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.47.0.tgz",
|
||||
"integrity": "sha512-KrMQRdMi/upr81qT4ijK6X6BNp6jqpMY7FwILQnwIy9QLc3qpnhUx5rsCLGzn4ewsCQ0CNAspN2ogmP1GXLyLw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-android-arm64": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.47.0.tgz",
|
||||
"integrity": "sha512-r4ixS/PeUpAFKgrpDoZ5pSkthjZzVzKd95525Aazj+aOv9H4ulK5zYHGb7wFY5n5kZxHK8TbOJUZgoEb1ohddQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-darwin-arm64": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.47.0.tgz",
|
||||
"integrity": "sha512-CLWxiKpMl+195cm09CuaWEhJK0CirRkoMa07aR9+9AFPat2LfIKtwx1JqxZM0MTvcMe6+adlJNdVL6jdInvq3g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-darwin-x64": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.47.0.tgz",
|
||||
"integrity": "sha512-Xq5fjTYDC50faUeLSm0rZdBqoTgleXEdD7NpJdARtQIczkCJn3xNjMUSQQkUmh4CtxkKTNL68lytcOK3e/osgg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-freebsd-x64": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.47.0.tgz",
|
||||
"integrity": "sha512-QOU9ZIJ52p5askcEC0QJvvr8trHAWoonul8bgISo6gYUL3s50zkqafBYcNAr9LJZQbsZtPfIWHk9+5+nUp1qJQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-linux-arm-gnueabihf": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.47.0.tgz",
|
||||
"integrity": "sha512-oJxDM1aBhPvz9gmElBv8UpxyiqhwfjcbrSxT5F0xtuUzY6dQI27/AQPIt3eu3Z5Yvn0kQl5R7MA3Z+MbnRvCBw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-linux-arm-musleabihf": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.47.0.tgz",
|
||||
"integrity": "sha512-g8Lh50VS4ibGz2q6v7r9UZY4D0dM16SdrFYOMzhqIoCwGcai8VMIRUAcqn1/jlCsOOzUXJ741+kCeJt0cofakQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-linux-arm64-gnu": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.47.0.tgz",
|
||||
"integrity": "sha512-YrNT1vQ0asaXoRbrvYENPqmBfOQ9Xr8enPNOULeYfg44VjCcrUowFy5QZr+WawE0zyP8cH9e9Gxxg0fDEFzhcg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-linux-arm64-musl": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.47.0.tgz",
|
||||
"integrity": "sha512-IxtQC/sbBi4ubbY+MdwdanRWrG9InQJVZqyMsBa5IUaQcnSg86gQme574HxXMC1p4bo4YhV99zQ+wNnGCvEgzw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-linux-ppc64-gnu": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.47.0.tgz",
|
||||
"integrity": "sha512-EWXEhOMbWO0q6eJSbu0QLkU8cKi0ljlYLngeDs2Ocu/pm1rrLwyQiYzlFbdnMRURI4w9ndr1sI9rSbhlJ5o23Q==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-linux-riscv64-gnu": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.47.0.tgz",
|
||||
"integrity": "sha512-tZrjS11TUiDuEpRaqdk8K9F9xETRyKXfuZKmdeW+Gj7coBnm7+8sBEfyt033EAFEQSlkniAXvBLh+Qja2ioGBQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-linux-riscv64-musl": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.47.0.tgz",
|
||||
"integrity": "sha512-KBFy+2CFKUCZzYwX2ZOPQKck1vjQbz+hextuc19G4r0WRJwadfAeuQMQRQvB+Ivc8brlbOVg7et8K7E467440g==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-linux-s390x-gnu": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.47.0.tgz",
|
||||
"integrity": "sha512-REUPFKVGSiK99B+9eaPhluEVglzaoj/SMykNC5SUiV2RSsBfV5lWN7Y0iCIc251Wz3GaeAGZsJ/zj3gjarxdFg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-linux-x64-gnu": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.47.0.tgz",
|
||||
"integrity": "sha512-KVftVSVEDeIfRW3TIeLe3aNI/iY4m1fu5mDwHcisKMZSCMKLkrhFsjowC7o9RoqNPxbbglm2+/6KAKBIts2t0Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-linux-x64-musl": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.47.0.tgz",
|
||||
"integrity": "sha512-DTsmGEaA2860Aq5VUyDO8/MT9NFxwVL93RnRYmpMwK6DsSkThmvEpqoUDDljziEpAedMRG19SCogrNbINSbLUQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-openharmony-arm64": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.47.0.tgz",
|
||||
"integrity": "sha512-8r5BDro7fLOBoq1JXHLVSs55OlrxQhEso4HVo0TcY7OXJUPYfjPoOaYL5us+yIwqyP9rQwN+rxuiNFSmaxSuOQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-win32-arm64-msvc": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.47.0.tgz",
|
||||
"integrity": "sha512-qtz/gzm8IjSPUlseZ0ofW8zyHLoZsuP5HTfcGGkWkUblB89JT8GNYH3ICqjbDsqsGqXum0/ZndXTFplSdXFIcg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-win32-ia32-msvc": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.47.0.tgz",
|
||||
"integrity": "sha512-5vIcdcIDE7nCx+MXN6sm8kbC4zajDB31E86rez4i45iHNH/2NjdKlJ720xcHTr3eeiMcttCGPHPhE1TjtBDGZw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxfmt/binding-win32-x64-msvc": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.47.0.tgz",
|
||||
"integrity": "sha512-Sr59Y5ms54ONBjxFeWhVlGyQcHXxcl9DxC23f6yXlRkcos7LXBLoO+KDfxexjHIOZh7cWqrWduzvUjJ+pHp8cQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-android-arm-eabi": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.62.0.tgz",
|
||||
"integrity": "sha512-pKsthNECyvJh8lPTICz6VcwVy2jOqdhhsp1rlxCkhgZR47aKvXPmaRWQDv+zlXpRae4qm1MaaTnutkaOk5aofg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-android-arm64": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.62.0.tgz",
|
||||
"integrity": "sha512-b1AUNViByvgmR2xJDubvLIr+dSuu3uraG7bsAoKo+xrpspPvu6RIn6Fhr2JUhobfep3jwUTy18Huco6GkwdvGQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-darwin-arm64": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.62.0.tgz",
|
||||
"integrity": "sha512-iG+Tvf70UJ6otfwFYIHk36Sjq9cpPP5YLxkoggANNRtzgi3Tj3g8q6Ybqi6AtkU3+yg9QwF7bDCkCS6bbL4PCg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-darwin-x64": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.62.0.tgz",
|
||||
"integrity": "sha512-oOWI6YPPr5AJUx+yIDlxmuUbQjS5gZX3OH3QisawYvsZgLiQVvZtR0rPBcJTxLWqt2ClrWg0DlSrlUiG5SQNHg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-freebsd-x64": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.62.0.tgz",
|
||||
"integrity": "sha512-dLP33T7VLCmLVv4cvjkVX+rmkcwNk2UfxmsZPNur/7BQHoQR60zJ7XLiRvNUawlzn0u8ngCa3itjEG73MAMa/w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-linux-arm-gnueabihf": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.62.0.tgz",
|
||||
"integrity": "sha512-fl//LWNks6qo9chNY60UDYyIwtp7a5cEx4Y/rHPjaarhuwqx6jtbzEpD5V5AqmdL4a6Y5D8zeXg5HF2Cr0QmSQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-linux-arm-musleabihf": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.62.0.tgz",
|
||||
"integrity": "sha512-i5vkAuxvueTODV3J2dL61/TXewDHhMFKvtD156cIsk7GsdfiAu7zW7kY0NJXhKeFHeiMZIh7eFNjkPYH6J47HQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-linux-arm64-gnu": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.62.0.tgz",
|
||||
"integrity": "sha512-QwN19LLuIGuOjEflSeJkZmOTfBdBMlTmW8xbMf8TZhjd//cxVNYQPq75q7oKZBJc6hRx3gY7sX0Egc8cEIFZYg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-linux-arm64-musl": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.62.0.tgz",
|
||||
"integrity": "sha512-8eCy3FCDuWUM5hWujAv6heMvfZPbcCOU3SdQUAkixZLu5bSzOkNfirJiLGoQFO943xceOKkiQRMQNzH++jM3WA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-linux-ppc64-gnu": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.62.0.tgz",
|
||||
"integrity": "sha512-NjQ7K7tpTPDe9J+yq8p/s/J0E7lRCkK2uDBDqvT4XIT6f4Z0tlnr59OBg/WcrmVHER1AbrcfyxhGTXgcG8ytWg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-linux-riscv64-gnu": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.62.0.tgz",
|
||||
"integrity": "sha512-oKZed9gmSwze29dEt3/Wnsv6l/Ygw/FUst+8Kfpv2SGeS/glEoTGZAMQw37SVyzFV76UTHJN2snGgxK2t2+8ow==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-linux-riscv64-musl": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.62.0.tgz",
|
||||
"integrity": "sha512-gBjBxQ+9lGpAYq+ELqw0w8QXsBnkZclFc7GRX2r0LnEVn3ZTEqeIKpKcGjucmp76Q53bvJD0i4qBWBhcfhSfGA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-linux-s390x-gnu": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.62.0.tgz",
|
||||
"integrity": "sha512-Ew2Kxs9EQ9/mbAIJ2hvocMC0wsOu6YKzStI2eFBDt+Td5O8seVC/oxgRIHqCcl5sf5ratA1nozQBAuv7tphkHg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-linux-x64-gnu": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.62.0.tgz",
|
||||
"integrity": "sha512-5z25jcAA0gfKyVwz71A0VXgaPlocPoTAxhlv/hgoK6tlCrfoNuw7haWbDHvGMfjXhdic4EqVXGRv5XsTqFnbRQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-linux-x64-musl": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.62.0.tgz",
|
||||
"integrity": "sha512-IWpHmMB6ZDllPvqWDkG6AmXrN7JF5e/c4g/0PuURsmlK+vHoYZPB70rr4u1bn3I4LsKCSpqqfveyx6UCOC8wdg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-openharmony-arm64": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.62.0.tgz",
|
||||
"integrity": "sha512-fjlSxxrD5pA594vkyikCS9MnPRjQawW6/BLgyTYkO+73wwPlYjkcZ7LSd974l0Q2zkHQmu4DPvJFLYA7o8xrxQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-win32-arm64-msvc": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.62.0.tgz",
|
||||
"integrity": "sha512-EiFXr8loNS0Ul3Gu80+9nr1T8jRmnKocqmHHg16tj5ZqTgUXyb97l2rrspVHdDluyFn9JfR4PoJFdNzw4paHww==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-win32-ia32-msvc": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.62.0.tgz",
|
||||
"integrity": "sha512-IgOFvL73li1bFgab+hThXYA0N2Xms2kV2MvZN95cebV+fmrZ9AVui1JSxfeeqRLo3CpPxKZlzhyq4G0cnaAvIw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxlint/binding-win32-x64-msvc": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.62.0.tgz",
|
||||
"integrity": "sha512-6hMpyDWQ2zGA1OXFKBrdYMUveUCO8UJhkO6JdwZPd78xIdHZNhjx+pib+4fC2Cljuhjyl0QwA2F3df/bs4Bp6A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@poppinss/colors": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz",
|
||||
@ -2217,6 +2913,91 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/oxfmt": {
|
||||
"version": "0.47.0",
|
||||
"resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.47.0.tgz",
|
||||
"integrity": "sha512-OFbkbzxKCpooQEnRmpTDnuwTX8KHXzZTQ4Df/hz85fpS67Pl+lxPEFvUtin56HIIS0B1k4X8oIzTXRZPufA2CA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tinypool": "2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"oxfmt": "bin/oxfmt"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/Boshen"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@oxfmt/binding-android-arm-eabi": "0.47.0",
|
||||
"@oxfmt/binding-android-arm64": "0.47.0",
|
||||
"@oxfmt/binding-darwin-arm64": "0.47.0",
|
||||
"@oxfmt/binding-darwin-x64": "0.47.0",
|
||||
"@oxfmt/binding-freebsd-x64": "0.47.0",
|
||||
"@oxfmt/binding-linux-arm-gnueabihf": "0.47.0",
|
||||
"@oxfmt/binding-linux-arm-musleabihf": "0.47.0",
|
||||
"@oxfmt/binding-linux-arm64-gnu": "0.47.0",
|
||||
"@oxfmt/binding-linux-arm64-musl": "0.47.0",
|
||||
"@oxfmt/binding-linux-ppc64-gnu": "0.47.0",
|
||||
"@oxfmt/binding-linux-riscv64-gnu": "0.47.0",
|
||||
"@oxfmt/binding-linux-riscv64-musl": "0.47.0",
|
||||
"@oxfmt/binding-linux-s390x-gnu": "0.47.0",
|
||||
"@oxfmt/binding-linux-x64-gnu": "0.47.0",
|
||||
"@oxfmt/binding-linux-x64-musl": "0.47.0",
|
||||
"@oxfmt/binding-openharmony-arm64": "0.47.0",
|
||||
"@oxfmt/binding-win32-arm64-msvc": "0.47.0",
|
||||
"@oxfmt/binding-win32-ia32-msvc": "0.47.0",
|
||||
"@oxfmt/binding-win32-x64-msvc": "0.47.0"
|
||||
}
|
||||
},
|
||||
"node_modules/oxlint": {
|
||||
"version": "1.62.0",
|
||||
"resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.62.0.tgz",
|
||||
"integrity": "sha512-1uFkg6HakjsGIpW9wNdeW4/2LOHW9MEkoWjZUTUfQtIHyLIZPYt00w3Sg+H3lH+206FgBPHBbW5dVE5l2ExECQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"oxlint": "bin/oxlint"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/Boshen"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@oxlint/binding-android-arm-eabi": "1.62.0",
|
||||
"@oxlint/binding-android-arm64": "1.62.0",
|
||||
"@oxlint/binding-darwin-arm64": "1.62.0",
|
||||
"@oxlint/binding-darwin-x64": "1.62.0",
|
||||
"@oxlint/binding-freebsd-x64": "1.62.0",
|
||||
"@oxlint/binding-linux-arm-gnueabihf": "1.62.0",
|
||||
"@oxlint/binding-linux-arm-musleabihf": "1.62.0",
|
||||
"@oxlint/binding-linux-arm64-gnu": "1.62.0",
|
||||
"@oxlint/binding-linux-arm64-musl": "1.62.0",
|
||||
"@oxlint/binding-linux-ppc64-gnu": "1.62.0",
|
||||
"@oxlint/binding-linux-riscv64-gnu": "1.62.0",
|
||||
"@oxlint/binding-linux-riscv64-musl": "1.62.0",
|
||||
"@oxlint/binding-linux-s390x-gnu": "1.62.0",
|
||||
"@oxlint/binding-linux-x64-gnu": "1.62.0",
|
||||
"@oxlint/binding-linux-x64-musl": "1.62.0",
|
||||
"@oxlint/binding-openharmony-arm64": "1.62.0",
|
||||
"@oxlint/binding-win32-arm64-msvc": "1.62.0",
|
||||
"@oxlint/binding-win32-ia32-msvc": "1.62.0",
|
||||
"@oxlint/binding-win32-x64-msvc": "1.62.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"oxlint-tsgolint": ">=0.18.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"oxlint-tsgolint": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
|
||||
@ -2450,6 +3231,16 @@
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/tinypool": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-2.1.0.tgz",
|
||||
"integrity": "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^20.0.0 || >=22.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyrainbow": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz",
|
||||
|
||||
@ -7,10 +7,15 @@
|
||||
"build": "wrangler deploy --dry-run --outdir dist",
|
||||
"check": "tsc --noEmit",
|
||||
"deploy": "wrangler deploy",
|
||||
"format": "oxfmt --write .",
|
||||
"format:check": "oxfmt --check .",
|
||||
"lint": "oxlint --config .oxlintrc.json .",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20260430.0",
|
||||
"oxfmt": "^0.47.0",
|
||||
"oxlint": "^1.62.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.10",
|
||||
"wrangler": "^4.50.0"
|
||||
|
||||
@ -35,7 +35,7 @@ export function leaseConfig(input: LeaseRequest): LeaseConfig {
|
||||
workRoot: input.workRoot ?? "/work/crabbox",
|
||||
ttlSeconds,
|
||||
keep: input.keep ?? false,
|
||||
sshPublicKey
|
||||
sshPublicKey,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { leaseConfig } from "./config";
|
||||
import { errorMessage, json, pathParts, readJson, requestOwner } from "./http";
|
||||
import { HetznerClient } from "./hetzner";
|
||||
import { errorMessage, json, pathParts, readJson, requestOwner } from "./http";
|
||||
import type { Env, LeaseRecord, LeaseRequest } from "./types";
|
||||
|
||||
const fleetID = "default";
|
||||
@ -8,7 +8,7 @@ const fleetID = "default";
|
||||
export class FleetDurableObject implements DurableObject {
|
||||
constructor(
|
||||
private readonly state: DurableObjectState,
|
||||
private readonly env: Env
|
||||
private readonly env: Env,
|
||||
) {}
|
||||
|
||||
async fetch(request: Request): Promise<Response> {
|
||||
@ -65,7 +65,7 @@ export class FleetDurableObject implements DurableObject {
|
||||
state: "active",
|
||||
createdAt: now.toISOString(),
|
||||
updatedAt: now.toISOString(),
|
||||
expiresAt: new Date(now.getTime() + config.ttlSeconds * 1000).toISOString()
|
||||
expiresAt: new Date(now.getTime() + config.ttlSeconds * 1000).toISOString(),
|
||||
};
|
||||
await this.putLease(record);
|
||||
await this.scheduleAlarm();
|
||||
@ -118,17 +118,19 @@ export class FleetDurableObject implements DurableObject {
|
||||
const leases = await this.state.storage.list<LeaseRecord>({ prefix: "lease:" });
|
||||
const now = Date.now();
|
||||
const client = new HetznerClient(this.env);
|
||||
for (const lease of leases.values()) {
|
||||
if (lease.state !== "active" || Date.parse(lease.expiresAt) > now) {
|
||||
continue;
|
||||
}
|
||||
if (!lease.keep) {
|
||||
await client.deleteServer(lease.serverID).catch(() => undefined);
|
||||
}
|
||||
lease.state = "expired";
|
||||
lease.updatedAt = new Date().toISOString();
|
||||
await this.putLease(lease);
|
||||
}
|
||||
const expired = [...leases.values()].filter(
|
||||
(lease) => lease.state === "active" && Date.parse(lease.expiresAt) <= now,
|
||||
);
|
||||
await Promise.all(
|
||||
expired.map(async (lease) => {
|
||||
if (!lease.keep) {
|
||||
await client.deleteServer(lease.serverID).catch(() => undefined);
|
||||
}
|
||||
lease.state = "expired";
|
||||
lease.updatedAt = new Date().toISOString();
|
||||
await this.putLease(lease);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
private async scheduleAlarm(): Promise<void> {
|
||||
|
||||
@ -31,7 +31,7 @@ export class HetznerClient {
|
||||
async listCrabboxServers(): Promise<HetznerServer[]> {
|
||||
const query = new URLSearchParams({
|
||||
label_selector: "crabbox=true",
|
||||
per_page: "100"
|
||||
per_page: "100",
|
||||
});
|
||||
const response = await this.request<HetznerListServersResponse>("GET", `/servers?${query}`);
|
||||
return response.servers;
|
||||
@ -40,7 +40,7 @@ export class HetznerClient {
|
||||
async ensureSSHKey(name: string, publicKey: string): Promise<HetznerSSHKey> {
|
||||
const byName = await this.request<HetznerListSSHKeysResponse>(
|
||||
"GET",
|
||||
`/ssh_keys?${new URLSearchParams({ name })}`
|
||||
`/ssh_keys?${new URLSearchParams({ name })}`,
|
||||
);
|
||||
for (const key of byName.ssh_keys) {
|
||||
if (key.name === name) {
|
||||
@ -53,7 +53,7 @@ export class HetznerClient {
|
||||
|
||||
const all = await this.request<HetznerListSSHKeysResponse>(
|
||||
"GET",
|
||||
`/ssh_keys?${new URLSearchParams({ per_page: "100" })}`
|
||||
`/ssh_keys?${new URLSearchParams({ per_page: "100" })}`,
|
||||
);
|
||||
for (const key of all.ssh_keys) {
|
||||
if (key.public_key.trim() === publicKey.trim()) {
|
||||
@ -66,8 +66,8 @@ export class HetznerClient {
|
||||
public_key: publicKey,
|
||||
labels: {
|
||||
crabbox: "true",
|
||||
created_by: "crabbox"
|
||||
}
|
||||
created_by: "crabbox",
|
||||
},
|
||||
});
|
||||
return created.ssh_key;
|
||||
}
|
||||
@ -75,17 +75,18 @@ export class HetznerClient {
|
||||
async createServerWithFallback(
|
||||
config: LeaseConfig,
|
||||
leaseID: string,
|
||||
owner: string
|
||||
owner: string,
|
||||
): Promise<{ server: HetznerServer; serverType: string }> {
|
||||
const key = await this.ensureSSHKey(config.providerKey, config.sshPublicKey);
|
||||
const resolvedConfig = { ...config, providerKey: key.name };
|
||||
const candidates = prependUnique(
|
||||
resolvedConfig.serverType,
|
||||
serverTypeCandidatesForClass(resolvedConfig.class)
|
||||
serverTypeCandidatesForClass(resolvedConfig.class),
|
||||
);
|
||||
const failures: string[] = [];
|
||||
for (const serverType of candidates) {
|
||||
try {
|
||||
// oxlint-disable-next-line eslint/no-await-in-loop -- server-type fallback must stay sequential.
|
||||
const server = await this.createServer({ ...resolvedConfig, serverType }, leaseID, owner);
|
||||
return { server, serverType };
|
||||
} catch (error) {
|
||||
@ -106,10 +107,12 @@ export class HetznerClient {
|
||||
async waitForServerIP(id: number): Promise<HetznerServer> {
|
||||
const deadline = Date.now() + 60_000;
|
||||
while (Date.now() < deadline) {
|
||||
// oxlint-disable-next-line eslint/no-await-in-loop -- polling must wait between Hetzner API reads.
|
||||
const server = await this.getServer(id);
|
||||
if (server.public_net.ipv4.ip) {
|
||||
return server;
|
||||
}
|
||||
// oxlint-disable-next-line eslint/no-await-in-loop -- this delay is the polling interval.
|
||||
await sleep(2_000);
|
||||
}
|
||||
throw new Error(`timed out waiting for server IP: ${id}`);
|
||||
@ -126,14 +129,14 @@ export class HetznerClient {
|
||||
status: server.status,
|
||||
serverType: server.server_type.name,
|
||||
host: server.public_net.ipv4.ip,
|
||||
labels: server.labels
|
||||
labels: server.labels,
|
||||
};
|
||||
}
|
||||
|
||||
private async createServer(
|
||||
config: LeaseConfig,
|
||||
leaseID: string,
|
||||
owner: string
|
||||
owner: string,
|
||||
): Promise<HetznerServer> {
|
||||
const name = `crabbox-${leaseID}`.replaceAll("_", "-");
|
||||
const labels = {
|
||||
@ -145,7 +148,7 @@ export class HetznerClient {
|
||||
state: "leased",
|
||||
keep: String(config.keep),
|
||||
owner: sanitizeLabel(owner),
|
||||
created_by: "crabbox"
|
||||
created_by: "crabbox",
|
||||
};
|
||||
const response = await this.request<HetznerServerResponse>("POST", "/servers", {
|
||||
name,
|
||||
@ -158,8 +161,8 @@ export class HetznerClient {
|
||||
start_after_create: true,
|
||||
public_net: {
|
||||
enable_ipv4: true,
|
||||
enable_ipv6: false
|
||||
}
|
||||
enable_ipv6: false,
|
||||
},
|
||||
});
|
||||
return response.server.public_net.ipv4.ip
|
||||
? response.server
|
||||
@ -171,15 +174,17 @@ export class HetznerClient {
|
||||
method,
|
||||
headers: {
|
||||
authorization: `Bearer ${this.token}`,
|
||||
"content-type": "application/json"
|
||||
}
|
||||
"content-type": "application/json",
|
||||
},
|
||||
};
|
||||
if (body !== undefined) {
|
||||
init.body = JSON.stringify(body);
|
||||
}
|
||||
const response = await fetch(`https://api.hetzner.cloud/v1${path}`, init);
|
||||
if (!response.ok) {
|
||||
throw new Error(`hetzner ${method} ${path}: http ${response.status}: ${await safeBody(response)}`);
|
||||
throw new Error(
|
||||
`hetzner ${method} ${path}: http ${response.status}: ${await safeBody(response)}`,
|
||||
);
|
||||
}
|
||||
if (response.status === 204) {
|
||||
return undefined as T;
|
||||
|
||||
@ -7,7 +7,7 @@ export function json(data: unknown, init: ResponseInit = {}): Response {
|
||||
export function text(message: string, status = 200): Response {
|
||||
return new Response(message, {
|
||||
status,
|
||||
headers: { "content-type": "text/plain; charset=utf-8" }
|
||||
headers: { "content-type": "text/plain; charset=utf-8" },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ export default {
|
||||
}
|
||||
const id = env.FLEET.idFromName("default");
|
||||
return env.FLEET.get(id).fetch(request);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export function isAuthorized(request: Request, env: Pick<Env, "CRABBOX_SHARED_TOKEN">): boolean {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { leaseConfig, serverTypeCandidatesForClass, serverTypeForClass } from "../src/config";
|
||||
|
||||
describe("machine class config", () => {
|
||||
@ -9,7 +10,7 @@ describe("machine class config", () => {
|
||||
"ccx53",
|
||||
"ccx43",
|
||||
"cpx62",
|
||||
"cx53"
|
||||
"cx53",
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { isAuthorized } from "../src";
|
||||
|
||||
describe("coordinator auth", () => {
|
||||
@ -10,7 +11,7 @@ describe("coordinator auth", () => {
|
||||
it("requires the configured bearer token", () => {
|
||||
const denied = new Request("https://example.test/v1/pool");
|
||||
const allowed = new Request("https://example.test/v1/pool", {
|
||||
headers: { authorization: "Bearer secret" }
|
||||
headers: { authorization: "Bearer secret" },
|
||||
});
|
||||
expect(isAuthorized(denied, { CRABBOX_SHARED_TOKEN: "secret" })).toBe(false);
|
||||
expect(isAuthorized(allowed, { CRABBOX_SHARED_TOKEN: "secret" })).toBe(true);
|
||||
|
||||
@ -3,6 +3,6 @@ import { defineConfig } from "vitest/config";
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: "node",
|
||||
globals: false
|
||||
}
|
||||
globals: false,
|
||||
},
|
||||
});
|
||||
|
||||
@ -8,21 +8,21 @@
|
||||
"routes": [
|
||||
{
|
||||
"pattern": "crabbox.clawd.bot/*",
|
||||
"zone_name": "clawd.bot"
|
||||
}
|
||||
"zone_name": "clawd.bot",
|
||||
},
|
||||
],
|
||||
"durable_objects": {
|
||||
"bindings": [
|
||||
{
|
||||
"name": "FLEET",
|
||||
"class_name": "FleetDurableObject"
|
||||
}
|
||||
]
|
||||
"class_name": "FleetDurableObject",
|
||||
},
|
||||
],
|
||||
},
|
||||
"migrations": [
|
||||
{
|
||||
"tag": "v1",
|
||||
"new_sqlite_classes": ["FleetDurableObject"]
|
||||
}
|
||||
]
|
||||
"new_sqlite_classes": ["FleetDurableObject"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user