mirror of
https://github.com/C4illin/ConvertX.git
synced 2026-10-31 10:03:43 +01:00
Merge remote-tracking branch 'origin/main' into test/add-converter-tests
This commit is contained in:
Vendored
+2
-2
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||
"js/ts.tsdk.path": "node_modules/typescript/lib",
|
||||
"js/ts.tsdk.promptToUseWorkspaceVersion": true
|
||||
}
|
||||
|
||||
@@ -11,14 +11,13 @@
|
||||
"@kitajs/html": "^4.2.13",
|
||||
"elysia": "1.4.30",
|
||||
"sanitize-filename": "^1.6.4",
|
||||
"tar": "^7.5.22",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@kitajs/ts-html-plugin": "^4.1.4",
|
||||
"@tailwindcss/cli": "^4.3.3",
|
||||
"@tailwindcss/postcss": "^4.3.3",
|
||||
"@types/bun": "1.4.3",
|
||||
"@types/bun": "1.4.4",
|
||||
"@types/node": "^24.19.0",
|
||||
"eslint": "^10.11.0",
|
||||
"eslint-plugin-better-tailwindcss": "^4.7.0",
|
||||
@@ -26,7 +25,6 @@
|
||||
"knip": "^6.38.0",
|
||||
"npm-run-all2": "^9.0.3",
|
||||
"postcss": "^8.5.28",
|
||||
"prettier": "^3.9.9",
|
||||
"tailwind-scrollbar": "^4.0.2",
|
||||
"tailwindcss": "^4.3.3",
|
||||
"typescript": "^5.9.3",
|
||||
@@ -90,8 +88,6 @@
|
||||
|
||||
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
|
||||
|
||||
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
|
||||
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
||||
@@ -110,47 +106,47 @@
|
||||
|
||||
"@kitajs/ts-html-plugin": ["@kitajs/ts-html-plugin@4.1.4", "", { "dependencies": { "chalk": "^5.6.2", "tslib": "^2.8.1", "yargs": "^18.0.0" }, "peerDependencies": { "@kitajs/html": "^4.2.10", "typescript": "^5.9.3" }, "bin": { "xss-scan": "dist/cli.js", "ts-html-plugin": "dist/cli.js" } }, "sha512-xK5mNrhnIy73kJFKx5yVGChJyWFRGmIaE0sjlVxVYllk5dyaEYVCrIh1N8AfnseEHka8gAqzPGW95HlkhDvnJA=="],
|
||||
|
||||
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA=="],
|
||||
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || 2.0.0-beta.2", "@emnapi/runtime": "^1.7.1 || 2.0.0-beta.2" } }, "sha512-mRyDmEw9/fCDXCGfL1sbgIw/GUK0PVxRW4YwgPN61F3LQ+fSyoBFarJVzgGyhF6kRzEQZ0FejDqm4WLXSeqQmw=="],
|
||||
|
||||
"@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.154.0", "", { "os": "android", "cpu": "arm" }, "sha512-sDdEtDl7vKdCvf54j72RJbowE3jCmyRz/+oOB6IAwQxAHZ0eI+Dcj4hvVnm0b9Dy31plUkdmfds9C+/Zt895Tg=="],
|
||||
"@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.155.0", "", { "os": "android", "cpu": "arm" }, "sha512-A6xv7hDtnTm+xlZ7utn6rRQpRMJHRhVr3gjRGqlx0RUX84mNk0pAsy6YN/wWhuOTkaZhRrrzaLxf0NfbH77j2w=="],
|
||||
|
||||
"@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.154.0", "", { "os": "android", "cpu": "arm64" }, "sha512-UHrDPELzvWZoVkIDdSycj4bzcTMCJG3IbN++mSUgVBaUtNtWHjQ98U6Vz5bpF/1Ic3FYJyYhMr74huO5tVvpZw=="],
|
||||
"@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.155.0", "", { "os": "android", "cpu": "arm64" }, "sha512-T1wWwH9/JI5g7Z4kEQwDOwhToxdDhRyOTklH+uuNpJ16m3MZFmGl+l2rKc0NHQdbVRG2LTOBsNjpW3h1BWytPA=="],
|
||||
|
||||
"@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.154.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mokYzajOSXxtSRDWCdHARGdntrKH+rZZ24Jzo8AtafyNzz0NARmpMm26Tc5B6qiGrr6UliWibHCOif1qRN2vaA=="],
|
||||
"@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.155.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ZoRB3qJxJ8DWA41jHja+YeB0lLfjBy4T+Kr15vnN1k65X3zbJt3rPZftEwN4Ju4tmA4K/T9dWWD7Z8ewQLnrVA=="],
|
||||
|
||||
"@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.154.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-WbtUBrclOVItWfLRSvs+Z/WLtXxJ2Ctv50PyuX894HzDN5/e0qzxVpTNPIVMzOerBhgKtFsSMcfxlYIAbvdVgg=="],
|
||||
"@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.155.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-vxtL86BtM+IgrpejA86nbTk5j0HKTIMeuaJ1fQciw6p9RfavPtIPjI7gN34owap0yG9txXBaAWpGdxokNwdqIw=="],
|
||||
|
||||
"@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.154.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-YooHZSLawOe2fqm+lDdG8oAaQh2NYV/RMYTYzWRLy72stm2BgE9O/8Al6kFENjkmzyyBccDLLBirGxVtpzQfrw=="],
|
||||
"@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.155.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tN6Ru5e0UVnWaIuiH8jEwnvxuxg7FvhWwSd3oe5oDhOD4ObsSr9/N6WfHLjilUWlPPj65ptwrSDH0Y7lzwTzmw=="],
|
||||
|
||||
"@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.154.0", "", { "os": "linux", "cpu": "arm" }, "sha512-hKOwhZbrXdTwc4bGVfbLCXl9f2swl6zWdISocLQSNX9MgPmwHE3qGzOUkCrkuGpwdCVHPnkfOwsqTuYsrP5uNg=="],
|
||||
"@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.155.0", "", { "os": "linux", "cpu": "arm" }, "sha512-h4ozA5n6L6lwolsz9iwunEhKWnIVbmFRots5QxEix0H6nJ5ICpuDa7PuShuhfpIDFe3+Qvyscioyiv+9g+4Syg=="],
|
||||
|
||||
"@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.154.0", "", { "os": "linux", "cpu": "arm" }, "sha512-tnjiooXEU013349O/yxKbF5Cusp1CfHWQ8kYR8tGeRzR/P4sOpQGQo21fsS71M0fMD6ESLq+lbvXFWi43PuKeQ=="],
|
||||
"@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.155.0", "", { "os": "linux", "cpu": "arm" }, "sha512-058/+LardpfuUlsKIvBGk/CYoakEVcMgqYx8GgyUZeOxFWTojYLlCc1Gb60/y21v3esDhHidgiY/Zbq9LpBhaQ=="],
|
||||
|
||||
"@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.154.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Cao2kj+8d7BT6XJU1gV9eVQjV+Cr+e8vQm3tddDRZiM2hHrMDxwy3j6t+ofaSl0idyuPPCZ4AlpmQoj8yOT1QA=="],
|
||||
"@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.155.0", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-nrOt2Y3xIAzu+lSPzH0864ieO+iCCXgoo9qFlGANE8Xh0cQ+RP8Wstfp+/wXN2YCyb98cAGzX0VruKYw7it/jw=="],
|
||||
|
||||
"@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.154.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-uiwA0V3q8llWA7/8r+a9BBjk4j5YMDmi6wfOsyQfGOJMQSLHEiZ3HI8ulea766ykUa9wJFWk9XWEl4uJrZLQqw=="],
|
||||
"@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.155.0", "", { "os": "linux", "cpu": "arm64", "libc": "musl" }, "sha512-KYAayyN5hQbJPtGKtRxlyc8XYmyntOplyXSQzTDrmbz7l/GCrzQbSswvyJFBTH1LGtsZrbXOAfN52i/Kz6kLKg=="],
|
||||
|
||||
"@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.154.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-LICfN0Xs4Zdko+bJy6eOAEQojDuIR26suF2JtOsMaXjgbCrpRSH7/NCvJhY13YvYBx12V6hnwrL8n0lk0rbNJQ=="],
|
||||
"@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.155.0", "", { "os": "linux", "cpu": "ppc64", "libc": "glibc" }, "sha512-CSuSY5hfjtsBnHXydOj8jiNfS1qHbdPZuPz1YL1cSgK7VmNYP+QlZIbG0BBYYBgX/vYEgZwbG9mBdW4YairZ5w=="],
|
||||
|
||||
"@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.154.0", "", { "os": "linux", "cpu": "none" }, "sha512-gbbSYxLF8ssRbQ2qQPy+2EhGNwNH1bAoRdkk6cnWaKHqmCikpSIPtpXjFbCCtjTi0uojqOM3ghFQwQPbDQsU0Q=="],
|
||||
"@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.155.0", "", { "os": "linux", "cpu": "none", "libc": "glibc" }, "sha512-7KCfOQm+Nz2N8trAXbQkal4TQ5756WVEmhm35y816YHvyFnEfVsICsiV5k0pEszNf/fRm4cm2i6i18SJ6/iCWg=="],
|
||||
|
||||
"@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.154.0", "", { "os": "linux", "cpu": "none" }, "sha512-nSnRYYDLCcRVjSQzF3g6rKqCNYwo5o+aQgnn8BBXfe+ofCgMGlGqkfRyvXm6ptZvoxNkkWtLlqM8W7Xc3j6ZnQ=="],
|
||||
"@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.155.0", "", { "os": "linux", "cpu": "none", "libc": "musl" }, "sha512-JSlhgoK+/g1TGJI5NuADx2+6syhxnQNLCWLXyO5QLFyetomcr/vIxSdiNlmyAv963YXUzCuwAwRG6npZ5xyJ1A=="],
|
||||
|
||||
"@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.154.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-BxBQoJKtzRQgZEKQIt6CDUm8RGKC5T8Qo4576yDa5/xgc10X3fBDItMbRabzLtbUBfTqKLl+8AVr/H6CF7W22g=="],
|
||||
"@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.155.0", "", { "os": "linux", "cpu": "s390x", "libc": "glibc" }, "sha512-WFIX+dPokWp64mi434Md3U3lJaTwNxAphvGjpltoyQjGUsdXavOIRrnp9dOS34Hd75HOAwDxAI+YwWOwqmJbtg=="],
|
||||
|
||||
"@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.154.0", "", { "os": "linux", "cpu": "x64" }, "sha512-/whkust2vYy+GjRUVL5cWaJmEu6jkdFfo5mkxgckyeOX61eMwo4iBoiwzeJZeMWAdzb/XOtQyLApHhFht3sOWA=="],
|
||||
"@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.155.0", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-g6xSDC/JpbnVOz5uafMGyK3txBVRFMQTx8opv/yHXGxqV3ZMVl3bf7W8XrSnF68dmy3gM4dgReNryuE53+WkeQ=="],
|
||||
|
||||
"@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.154.0", "", { "os": "linux", "cpu": "x64" }, "sha512-EXURTyW9riw4B/kZnnE+58emAtw6+3VEszQfXUZkRqGaKIcmWDYkZtKB+xY/blHvuZ+Qy/fDclc31nmUCgtkSA=="],
|
||||
"@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.155.0", "", { "os": "linux", "cpu": "x64", "libc": "musl" }, "sha512-6/4xlxKlZJWrQ0uwDFPc0H9+xLu7068CKhX3vIDW3SbvP/lVgnVuT5v6dyugeWskWpuxqF/WJ4WKwhxjU3pG2w=="],
|
||||
|
||||
"@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.154.0", "", { "os": "none", "cpu": "arm64" }, "sha512-ZRFooyH3qsR6vuR4jFGlG3XM36490SvvXtNaUahBK4zHpooMdTHNaOMtGGJI0EW38m5hi4rOco9kw7ZwCIp28w=="],
|
||||
"@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.155.0", "", { "os": "none", "cpu": "arm64" }, "sha512-tltklL0J0XjDxIRTBXWOBhvc2mitcmES45pIxhwDWfxRyqz7Vkeu0NekTZEIxGE4f/lXgq3vZcjjffteQOVorg=="],
|
||||
|
||||
"@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.154.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-U0Vp+4lvwUa/PnOCJTZOjydj1rX2+VLHz4Y2vSFqlN8/7LTiURgD7z4uQ9yNv9O/NlU3mELBnPDlu7aaSYG1zQ=="],
|
||||
"@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.155.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-alAb9TzjatUEsOeoncAziUnfdTDxfyswhalFZ9sC6plUgATIUx2NIZ0+bMn6aJ28AduS1OpG/OAisr/YISn4Ig=="],
|
||||
|
||||
"@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.154.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-Hc8QgsFY5eUUP25we8TISUruibG2cDt0H4IcPG9RKdabb6odkCzIqjV6Gk9beGWGuOwMVCr81H/Su1q363LCCg=="],
|
||||
"@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.155.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-yc5cbSfcGmRv/KpxDFuyk8adEBaWd/9HilWvBbQ4bFbus1V2PUh2mGB2Cfq9rqZTqLeiMT8x0skV+LKp9hOMgQ=="],
|
||||
|
||||
"@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.154.0", "", { "os": "win32", "cpu": "x64" }, "sha512-hD7judkUMA/hZPoamvKADs6+an1smp8UTK0aMYRijkvi00K/1vl7vEtmyn2JyQ9S+vibtnfcNzxqTLGyJUZCRQ=="],
|
||||
"@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.155.0", "", { "os": "win32", "cpu": "x64" }, "sha512-8heq6jGq+rfpTDRDjoQiBHw0maQZf3IXkS99pdHQZPoTL5kyF5qyPS0RidUlSdnWDIqxXb5nux7GBD9cT+imUw=="],
|
||||
|
||||
"@oxc-project/types": ["@oxc-project/types@0.154.0", "", {}, "sha512-KYOUGQFlLWR+s4QMV2Q9ko38TZm7EdO87Qm7rvZLqk/webse/cDjtyxKhg/47l0byCbs/k46LT8qc4PKjAikzA=="],
|
||||
"@oxc-project/types": ["@oxc-project/types@0.155.0", "", {}, "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q=="],
|
||||
|
||||
"@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA=="],
|
||||
|
||||
@@ -166,21 +162,21 @@
|
||||
|
||||
"@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA=="],
|
||||
|
||||
"@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA=="],
|
||||
"@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.24.2", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA=="],
|
||||
|
||||
"@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw=="],
|
||||
"@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.24.2", "", { "os": "linux", "cpu": "arm64", "libc": "musl" }, "sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw=="],
|
||||
|
||||
"@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.24.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA=="],
|
||||
"@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.24.2", "", { "os": "linux", "cpu": "ppc64", "libc": "glibc" }, "sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA=="],
|
||||
|
||||
"@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw=="],
|
||||
"@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.24.2", "", { "os": "linux", "cpu": "none", "libc": "glibc" }, "sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw=="],
|
||||
|
||||
"@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w=="],
|
||||
"@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.24.2", "", { "os": "linux", "cpu": "none", "libc": "musl" }, "sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w=="],
|
||||
|
||||
"@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.24.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ=="],
|
||||
"@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.24.2", "", { "os": "linux", "cpu": "s390x", "libc": "glibc" }, "sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ=="],
|
||||
|
||||
"@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg=="],
|
||||
"@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.24.2", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg=="],
|
||||
|
||||
"@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw=="],
|
||||
"@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.24.2", "", { "os": "linux", "cpu": "x64", "libc": "musl" }, "sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw=="],
|
||||
|
||||
"@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.24.2", "", { "os": "none", "cpu": "arm64" }, "sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg=="],
|
||||
|
||||
@@ -190,7 +186,7 @@
|
||||
|
||||
"@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw=="],
|
||||
|
||||
"@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="],
|
||||
"@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" }, "hasInstallScript": true }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="],
|
||||
|
||||
"@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="],
|
||||
|
||||
@@ -200,17 +196,17 @@
|
||||
|
||||
"@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="],
|
||||
|
||||
"@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="],
|
||||
"@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm", "libc": "glibc" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="],
|
||||
|
||||
"@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="],
|
||||
"@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm", "libc": "musl" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="],
|
||||
|
||||
"@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="],
|
||||
"@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="],
|
||||
|
||||
"@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="],
|
||||
"@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64", "libc": "musl" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="],
|
||||
|
||||
"@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="],
|
||||
"@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="],
|
||||
|
||||
"@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="],
|
||||
"@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64", "libc": "musl" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="],
|
||||
|
||||
"@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="],
|
||||
|
||||
@@ -238,13 +234,13 @@
|
||||
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3", "", { "os": "linux", "cpu": "arm" }, "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w=="],
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.3", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA=="],
|
||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.3", "", { "os": "linux", "cpu": "arm64", "libc": "musl" }, "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w=="],
|
||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.3", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img=="],
|
||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.3", "", { "os": "linux", "cpu": "x64", "libc": "musl" }, "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.3", "", { "dependencies": { "@emnapi/core": "^1.11.1", "@emnapi/runtime": "^1.11.1", "@emnapi/wasi-threads": "^1.2.2", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.2", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ=="],
|
||||
|
||||
@@ -254,13 +250,13 @@
|
||||
|
||||
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.3.3", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.3.3", "@tailwindcss/oxide": "4.3.3", "postcss": "^8.5.16", "tailwindcss": "4.3.3" } }, "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg=="],
|
||||
|
||||
"@tokenizer/inflate": ["@tokenizer/inflate@0.5.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.2" } }, "sha512-56U2O6fDLFtqokwWh597IdeUgtM7j+TT9tb1soybhgA6cy163gAcVmoQr8H4Ud/CkgCkViwcuLyqtn6wYqw59Q=="],
|
||||
"@tokenizer/inflate": ["@tokenizer/inflate@0.5.2", "", { "dependencies": { "debug": "^4.4.3", "strtok3": "^10.6.2", "token-types": "^6.1.2" } }, "sha512-3AZIuReWQ7i916s/UWAzy4V4k2wrkAZLW2sTi448W3w7Hz5uoc+Y7h+cnwzr0cwrwf3PsC5xKsH8MOl0NRltlg=="],
|
||||
|
||||
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
|
||||
|
||||
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.4", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.4.3", "", { "dependencies": { "bun-types": "1.4.3" } }, "sha512-N67Pqy8JXbAY/j0tNraS3V5mubGvc6rrrNDmDCtZLlFzccbUJPDb0tvgUBC5q4m8ybkP93Jcn1QB+RYQ6PvBhw=="],
|
||||
"@types/bun": ["@types/bun@1.4.4", "", { "dependencies": { "bun-types": "1.4.4" } }, "sha512-9wkRDXUXK124pEnAutE6n/l18j+i9GC5IAHK8TmX/2nlySETmky0OU6yL5U8pW1AoKh++AN9auDCr647BfurjQ=="],
|
||||
|
||||
"@types/esrecurse": ["@types/esrecurse@4.3.1", "", {}, "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw=="],
|
||||
|
||||
@@ -272,25 +268,25 @@
|
||||
|
||||
"@types/prismjs": ["@types/prismjs@1.26.6", "", {}, "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw=="],
|
||||
|
||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.71.2", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.71.2", "@typescript-eslint/type-utils": "8.71.2", "@typescript-eslint/utils": "8.71.2", "@typescript-eslint/visitor-keys": "8.71.2", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.71.2", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-K72/pvT7qpm8q3k8G5u93NCSN1RcLxX5h7Gw0bQpbMXviBHeY6Nx1WEwmk9wP+eKTSQ8ecxvcgt/ZX/rB938xQ=="],
|
||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.72.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.72.0", "@typescript-eslint/type-utils": "8.72.0", "@typescript-eslint/utils": "8.72.0", "@typescript-eslint/visitor-keys": "8.72.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.72.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-aysKgysPX9XOv/dk95UkvUDe++Q3n3dJPG9CEWT3RUccxfkPJ+Qn6nhKPDhZXU6Ofo9kgwGWwKyQCnZIXTgngg=="],
|
||||
|
||||
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.71.2", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.71.2", "@typescript-eslint/types": "8.71.2", "@typescript-eslint/typescript-estree": "8.71.2", "@typescript-eslint/visitor-keys": "8.71.2", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-aTtmZjp/x3gsGHkDs04/1I8kNogBJkpQaeGaN0PfiG43NzDEmW2n+OP5im9wfsvyX0yP1UZWBrAGtDBfH9jEVw=="],
|
||||
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.72.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.72.0", "@typescript-eslint/types": "8.72.0", "@typescript-eslint/typescript-estree": "8.72.0", "@typescript-eslint/visitor-keys": "8.72.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-0O+x3ynciD6zuXb1CKSu165haQV6ey53DKhHHUnujP7U+XlltJG+/keT0Xhd1HXCze+IHf7Tvt39ovyepX/LNw=="],
|
||||
|
||||
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.71.2", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.71.2", "@typescript-eslint/types": "^8.71.2", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Pd68GsLVh5ZXlcEccFPdhSOvtHZ/2WU0XsA8zmXOS3F158lVlcTLhfQ6qvtL1RzbMie0Kp8xtbVwAg4nejKPHw=="],
|
||||
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.72.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.72.0", "@typescript-eslint/types": "^8.72.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-bzHngBbmIgzj6TsTjVUCntGx6FFLgE7mPjpO0PzHycOaZHXqS43XnrkFIHRS16LLr/xO6FHSXG3GJFo/F4bSBQ=="],
|
||||
|
||||
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.71.2", "", { "dependencies": { "@typescript-eslint/types": "8.71.2", "@typescript-eslint/visitor-keys": "8.71.2" } }, "sha512-YF4wgg5iUX5Obywoac27B56FhozMNFhdJSbh11H5GBAwmBtfyRhmgTQqW9tRNNmHDvsZ2CX6UGzoz+YfYn2Leg=="],
|
||||
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.72.0", "", { "dependencies": { "@typescript-eslint/types": "8.72.0", "@typescript-eslint/visitor-keys": "8.72.0" } }, "sha512-JewPyJOYcXBSAS7PIgufscHOwZqhTGyBRiQJhhuDln66tMchxvvt7nJ90JKKIoOelmdHA3kAQbm9cEUHc4JSEA=="],
|
||||
|
||||
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.71.2", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-jz49TAWokm/7yWD9/o837nYax9DyALxIPOImdImvVzo6canBCZYzin8zJyqNR5k1j9K1DE0bVvr0XYB+99uAdg=="],
|
||||
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.72.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-0vbxCf7xLVPSjcOdm6eQbgViH8EDJ8xnl1laLT9yoqSz2YmcSfSg5Vdl0JUvZf6rcuJ0ZivJIuMD4edTg8obaA=="],
|
||||
|
||||
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.71.2", "", { "dependencies": { "@typescript-eslint/types": "8.71.2", "@typescript-eslint/typescript-estree": "8.71.2", "@typescript-eslint/utils": "8.71.2", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-cC8UaalCViJkb3rH/xLIvidEwoFRtMZMUqDjjJMGEKaTFwYRHYBcoczlEGHuvkHEO8svRDrgZ0yQgOArFmwang=="],
|
||||
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.72.0", "", { "dependencies": { "@typescript-eslint/types": "8.72.0", "@typescript-eslint/typescript-estree": "8.72.0", "@typescript-eslint/utils": "8.72.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-gEXxmmbSTSOVTC37IYYvremOM31v+UN2W772bJxmVYPhAOPSUxtacyb7wkm1EhkYKU6KzFJsdU44DCV4to0LWw=="],
|
||||
|
||||
"@typescript-eslint/types": ["@typescript-eslint/types@8.71.2", "", {}, "sha512-y5Ukl3oVp7e/VGxqIoEXoeb/Roj71PAJ4WG/N/RGj+eeDvKRLM15kGr9MijLbN0i03S52zxu31Z98E5gWChJKw=="],
|
||||
"@typescript-eslint/types": ["@typescript-eslint/types@8.72.0", "", {}, "sha512-Adfoy59kxNEjT5E5fnyrp7GpHYuWs8ONbdohu4ez6IU46qDq8LltG90tLmkucZB2uhYL8mqBjtXqGd8yhfjXqQ=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.71.2", "", { "dependencies": { "@typescript-eslint/project-service": "8.71.2", "@typescript-eslint/tsconfig-utils": "8.71.2", "@typescript-eslint/types": "8.71.2", "@typescript-eslint/visitor-keys": "8.71.2", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-DgNOEsl4pdYzwSL+N/Cl33tX1Hlw3FvId73LnKXfq7jnrF2viOEn7X+P7RBkkSWCVm92gnWd28GIC5vJuLREeA=="],
|
||||
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.72.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.72.0", "@typescript-eslint/tsconfig-utils": "8.72.0", "@typescript-eslint/types": "8.72.0", "@typescript-eslint/visitor-keys": "8.72.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-gwLfFgWcw15tN2KXDCJvxEOQjPn+P3j/n3eSqkZ5sX4VpW9Cosodr+tWwBZRvJT3TcKx6HnPRGZMCNAiP1Xhug=="],
|
||||
|
||||
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.71.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.71.2", "@typescript-eslint/types": "8.71.2", "@typescript-eslint/typescript-estree": "8.71.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-RyKa1G1M9rKHDhrk+HJtiF1MvLD5Ux2JW3TSkzw+02pRALdpJb+QzG1Y5em+LvCgzGwgg8H7mBRFKljNz7ImPw=="],
|
||||
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.72.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.72.0", "@typescript-eslint/types": "8.72.0", "@typescript-eslint/typescript-estree": "8.72.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-0up3oArJZBYnzOaEXKo8DmI43QvMZyPoFEt9LWzRJcyl/RcJjfKKPebknN1VbTgXBf3M/KggUh5uUMdURLnseg=="],
|
||||
|
||||
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.71.2", "", { "dependencies": { "@typescript-eslint/types": "8.71.2", "eslint-visitor-keys": "^5.0.0" } }, "sha512-zozlN0UA32bSG2zkKAgQyRYSbEISVoyU6vvkKYo2aSny74D8Jh4e+POkJ6Lk0dlezZi5x7TtD+88Xb06IB8nhg=="],
|
||||
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.72.0", "", { "dependencies": { "@typescript-eslint/types": "8.72.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-E2mroviasaWecDzTGiGMtuEguuLVOeRggnrIn93CJuxYJzQBHbyymlT08aVQydbBal5538o+JkBKXh2sRuCyIA=="],
|
||||
|
||||
"@valibot/to-json-schema": ["@valibot/to-json-schema@1.8.0", "", { "peerDependencies": { "valibot": "^1.5.0" } }, "sha512-a0M+uwCuQZEPAo65NYkFSJ14O5c213KoSZmPdoCfuFvUhfULi4T2Z6Tpjv6lTVMW9RoLm74RpRAjNEa43KcN+g=="],
|
||||
|
||||
@@ -310,14 +306,12 @@
|
||||
|
||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||
|
||||
"bun-types": ["bun-types@1.4.3", "", { "dependencies": { "@types/node": "*", "undici-types": "*" } }, "sha512-tinRJNGOmUN+tEAsn2y2e942n9JHRHR42iUYzDH75NmhJqVBokGSQkkfSFdNWwsANIdrK6ACH9t01M452YyTwg=="],
|
||||
"bun-types": ["bun-types@1.4.4", "", { "dependencies": { "@types/node": "*", "undici-types": "*" } }, "sha512-yjrJh5oGX7mMPKGd19YXyIjmEuj4G4zNC30bs7PM9Az7NQ3ndF3j6hbeRdvJTRQEhJ/FYQwW0a2moweEi2hMxQ=="],
|
||||
|
||||
"cacheable": ["cacheable@2.5.0", "", { "dependencies": { "@cacheable/memory": "^2.2.0", "@cacheable/utils": "^2.5.0", "hookified": "^1.15.0", "keyv": "^5.6.0", "qified": "^0.10.1" } }, "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g=="],
|
||||
|
||||
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
|
||||
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||
|
||||
"cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="],
|
||||
|
||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||
@@ -350,7 +344,7 @@
|
||||
|
||||
"eslint": ["eslint@10.13.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.7.0", "@eslint/core": "^1.2.1", "@eslint/plugin-kit": "^0.7.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "11.1.5 || >11.1.6 <12", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-UohDjD4zSzEwhf58M3O7vc/ycc8O1I7dNlhtD0WxE8Px8EHNJKtUwzBqrzeGhisRuv2ag4sAYswszCJRgKXYUg=="],
|
||||
|
||||
"eslint-plugin-better-tailwindcss": ["eslint-plugin-better-tailwindcss@4.9.1", "", { "dependencies": { "@eslint/css-tree": "^4.0.4", "@valibot/to-json-schema": "^1.7.1", "enhanced-resolve": "^5.24.1", "jiti": "^2.7.0", "synckit": "^0.12.3", "tailwind-csstree": "^0.3.3", "tsconfig-paths-webpack-plugin": "^4.2.0", "valibot": "^1.4.2" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", "oxlint": "^1.35.0", "tailwindcss": "^3.3.0 || ^4.1.17" }, "optionalPeers": ["eslint", "oxlint"] }, "sha512-WOuUOlc27Ib3tcYNt6qhRpvQUie5Y/pNTkwO779QGdfF1tu0k51avWtmvfPv++7/1oVjntoFHcUK4+5a6SPZvA=="],
|
||||
"eslint-plugin-better-tailwindcss": ["eslint-plugin-better-tailwindcss@4.10.0", "", { "dependencies": { "@eslint/css-tree": "^4.0.4", "@valibot/to-json-schema": "^1.7.1", "enhanced-resolve": "^5.24.1", "jiti": "^2.7.0", "synckit": "^0.12.3", "tailwind-csstree": "^0.3.3", "tsconfig-paths-webpack-plugin": "^4.2.0", "valibot": "^1.4.2" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", "oxlint": "^1.35.0", "tailwindcss": "^3.3.0 || ^4.1.17" }, "optionalPeers": ["eslint", "oxlint"] }, "sha512-EvcfEScF7N39LXuqX8fDnDsgylhbBZe5bbNb+6oN8ht06ou3MvwfPQ5hVgm2LWIPLOB5LBwNDCY6gBQGW4KHGA=="],
|
||||
|
||||
"eslint-scope": ["eslint-scope@9.1.2", "", { "dependencies": { "@types/esrecurse": "^4.3.1", "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ=="],
|
||||
|
||||
@@ -428,7 +422,7 @@
|
||||
|
||||
"jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
|
||||
|
||||
"jose": ["jose@6.2.12", "", {}, "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw=="],
|
||||
"jose": ["jose@6.2.13", "", {}, "sha512-7TIg10ZE1x82YediN+lcrPNvGMKge9yFHQD+Qho/b8y2adfugU3AsvvHfxV0fzyFllT6l9xCjf4RWY9g/Z9PJQ=="],
|
||||
|
||||
"json-parse-even-better-errors": ["json-parse-even-better-errors@6.0.0", "", {}, "sha512-2/8adwnK1/+Fdjyts4r6wSpfANWw8zdNhU9U/Llk59c6O+DjSisPWPykwoL8gZmocP9Dy64S7oie2g+Mia123A=="],
|
||||
|
||||
@@ -440,7 +434,7 @@
|
||||
|
||||
"keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="],
|
||||
|
||||
"knip": ["knip@6.42.0", "", { "dependencies": { "formatly": "^0.11.4", "get-tsconfig": "4.14.3", "jiti": "^2.7.0", "oxc-parser": "^0.154.0", "oxc-resolver": "11.24.2", "picomatch": "^4.0.7", "smol-toml": "^1.9.0", "strip-json-comments": "5.0.3", "tinyglobby": "^0.2.17", "unbash": "^6.0.0", "yaml": "^2.9.1", "zod": "^4.6.5" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-lNypqHwi38RJQG8pVuItqzCDPMOfPbBExyFh8aM4yMJRHVU7t5OQAtEK4tDkaB3rLHetOcVMhRFAgv5Vn2CM0A=="],
|
||||
"knip": ["knip@6.43.0", "", { "dependencies": { "formatly": "^0.11.4", "get-tsconfig": "4.14.3", "jiti": "^2.7.0", "oxc-parser": "^0.155.0", "oxc-resolver": "11.24.2", "picomatch": "^4.0.7", "smol-toml": "^1.9.0", "strip-json-comments": "5.0.3", "tinyglobby": "^0.2.17", "unbash": "^6.0.1", "yaml": "^2.9.1", "zod": "^4.6.5" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-8l3cCOg/EXoILO0qcSoMra49yQM91+lEIR4fu5Ko8rrArGX8xKdKZiGI9psPiY6rhLmfLERcMfFEByF0wli5CA=="],
|
||||
|
||||
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
||||
|
||||
@@ -456,13 +450,13 @@
|
||||
|
||||
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="],
|
||||
|
||||
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="],
|
||||
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="],
|
||||
|
||||
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="],
|
||||
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64", "libc": "musl" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="],
|
||||
|
||||
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="],
|
||||
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="],
|
||||
|
||||
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="],
|
||||
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64", "libc": "musl" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="],
|
||||
|
||||
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="],
|
||||
|
||||
@@ -484,10 +478,6 @@
|
||||
|
||||
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||
|
||||
"minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
|
||||
|
||||
"minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="],
|
||||
|
||||
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
@@ -500,13 +490,13 @@
|
||||
|
||||
"npm-normalize-package-bin": ["npm-normalize-package-bin@6.0.0", "", {}, "sha512-tdt4aFn9QamlhdN3HV2D2ccpBwO5/fyjjbXUxYA6uBjyekMZcZvDq0aSj9t5Jo+tih6AYFnt/cuIRn9013e0Uw=="],
|
||||
|
||||
"npm-run-all2": ["npm-run-all2@9.0.3", "", { "dependencies": { "ansi-styles": "^7.0.0", "cross-spawn": "^7.0.6", "memorystream": "^0.3.1", "picomatch": "^4.0.2", "pidtree": "^1.0.0", "read-package-json-fast": "^6.0.0", "shell-quote": "^1.8.4", "which": "^7.0.0" }, "bin": { "run-p": "bin/run-p/index.js", "run-s": "bin/run-s/index.js", "npm-run-all": "bin/npm-run-all/index.js", "npm-run-all2": "bin/npm-run-all/index.js" } }, "sha512-BQAEdU1PtYc48qYRdghW2BVTQT3VqWCoFQmO87NlM1h1PYwMCKQpUWaNyB20V26caNzFsXQDfyOdznLlHCih6g=="],
|
||||
"npm-run-all2": ["npm-run-all2@9.0.4", "", { "dependencies": { "ansi-styles": "^7.0.0", "cross-spawn": "^7.0.6", "memorystream": "^0.3.1", "picomatch": "^4.0.2", "pidtree": "^1.0.0", "read-package-json-fast": "^6.0.0", "shell-quote": "^1.12.0", "which": "^7.0.0" }, "bin": { "run-p": "bin/run-p/index.js", "run-s": "bin/run-s/index.js", "npm-run-all": "bin/npm-run-all/index.js", "npm-run-all2": "bin/npm-run-all/index.js" } }, "sha512-GuGRF8MddEKavyUzjy0k2z2pA76/N+eT8lHlypx0/AhShLKD2FOerQxHhpFhcqnQmAqCkunUCYlf6Z9RKh/4zg=="],
|
||||
|
||||
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
||||
|
||||
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||
|
||||
"oxc-parser": ["oxc-parser@0.154.0", "", { "dependencies": { "@oxc-project/types": "^0.154.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.154.0", "@oxc-parser/binding-android-arm64": "0.154.0", "@oxc-parser/binding-darwin-arm64": "0.154.0", "@oxc-parser/binding-darwin-x64": "0.154.0", "@oxc-parser/binding-freebsd-x64": "0.154.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.154.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.154.0", "@oxc-parser/binding-linux-arm64-gnu": "0.154.0", "@oxc-parser/binding-linux-arm64-musl": "0.154.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.154.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.154.0", "@oxc-parser/binding-linux-riscv64-musl": "0.154.0", "@oxc-parser/binding-linux-s390x-gnu": "0.154.0", "@oxc-parser/binding-linux-x64-gnu": "0.154.0", "@oxc-parser/binding-linux-x64-musl": "0.154.0", "@oxc-parser/binding-openharmony-arm64": "0.154.0", "@oxc-parser/binding-win32-arm64-msvc": "0.154.0", "@oxc-parser/binding-win32-ia32-msvc": "0.154.0", "@oxc-parser/binding-win32-x64-msvc": "0.154.0" } }, "sha512-Gr/6fkjZwi937c4Tsz8y0iO4U0FLPkZI6JSVucLAIvQyqh379px7RS8ORIc0HOORbFjXZ6zyqWLl53qxhSeofw=="],
|
||||
"oxc-parser": ["oxc-parser@0.155.0", "", { "dependencies": { "@oxc-project/types": "^0.155.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.155.0", "@oxc-parser/binding-android-arm64": "0.155.0", "@oxc-parser/binding-darwin-arm64": "0.155.0", "@oxc-parser/binding-darwin-x64": "0.155.0", "@oxc-parser/binding-freebsd-x64": "0.155.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.155.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.155.0", "@oxc-parser/binding-linux-arm64-gnu": "0.155.0", "@oxc-parser/binding-linux-arm64-musl": "0.155.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.155.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.155.0", "@oxc-parser/binding-linux-riscv64-musl": "0.155.0", "@oxc-parser/binding-linux-s390x-gnu": "0.155.0", "@oxc-parser/binding-linux-x64-gnu": "0.155.0", "@oxc-parser/binding-linux-x64-musl": "0.155.0", "@oxc-parser/binding-openharmony-arm64": "0.155.0", "@oxc-parser/binding-win32-arm64-msvc": "0.155.0", "@oxc-parser/binding-win32-ia32-msvc": "0.155.0", "@oxc-parser/binding-win32-x64-msvc": "0.155.0" } }, "sha512-C/ReSf1JUFukK/zvk6jhcNibSssvas5+ktIzK7fbKVd3CedWe59C3QwHEOrEZj/4Rt9+xg0Jeis/Jv1F/KM1mw=="],
|
||||
|
||||
"oxc-resolver": ["oxc-resolver@11.24.2", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.24.2", "@oxc-resolver/binding-android-arm64": "11.24.2", "@oxc-resolver/binding-darwin-arm64": "11.24.2", "@oxc-resolver/binding-darwin-x64": "11.24.2", "@oxc-resolver/binding-freebsd-x64": "11.24.2", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.24.2", "@oxc-resolver/binding-linux-arm-musleabihf": "11.24.2", "@oxc-resolver/binding-linux-arm64-gnu": "11.24.2", "@oxc-resolver/binding-linux-arm64-musl": "11.24.2", "@oxc-resolver/binding-linux-ppc64-gnu": "11.24.2", "@oxc-resolver/binding-linux-riscv64-gnu": "11.24.2", "@oxc-resolver/binding-linux-riscv64-musl": "11.24.2", "@oxc-resolver/binding-linux-s390x-gnu": "11.24.2", "@oxc-resolver/binding-linux-x64-gnu": "11.24.2", "@oxc-resolver/binding-linux-x64-musl": "11.24.2", "@oxc-resolver/binding-openharmony-arm64": "11.24.2", "@oxc-resolver/binding-wasm32-wasi": "11.24.2", "@oxc-resolver/binding-win32-arm64-msvc": "11.24.2", "@oxc-resolver/binding-win32-x64-msvc": "11.24.2" } }, "sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw=="],
|
||||
|
||||
@@ -530,8 +520,6 @@
|
||||
|
||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||
|
||||
"prettier": ["prettier@3.9.10", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA=="],
|
||||
|
||||
"prism-react-renderer": ["prism-react-renderer@2.4.1", "", { "dependencies": { "@types/prismjs": "^1.26.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": ">=16.0.0" } }, "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig=="],
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
@@ -580,8 +568,6 @@
|
||||
|
||||
"tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="],
|
||||
|
||||
"tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="],
|
||||
|
||||
"tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
@@ -602,11 +588,11 @@
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"typescript-eslint": ["typescript-eslint@8.71.2", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.71.2", "@typescript-eslint/parser": "8.71.2", "@typescript-eslint/typescript-estree": "8.71.2", "@typescript-eslint/utils": "8.71.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Rz4effbMy2g9wnvOJZG6SbVavX313Lap1vNEbk1RUochzickvzP8P4HB+bkNg5e50eVz1hQGjh9K1omI1xB4Bw=="],
|
||||
"typescript-eslint": ["typescript-eslint@8.72.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.72.0", "@typescript-eslint/parser": "8.72.0", "@typescript-eslint/typescript-estree": "8.72.0", "@typescript-eslint/utils": "8.72.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-r26Fkc8As+mZvqp7SLsMmNFyYUup/6CjK7/eHBHmhOw6GH6n6YFxHVFrG0jN1c5CMpDzelLPxvgeCOzx7BjN+A=="],
|
||||
|
||||
"uint8array-extras": ["uint8array-extras@1.6.0", "", {}, "sha512-8iAasVS4wUx0gPLjH8Xtz2PeDzTSiy8QiLGu2DT3X5GU+egFEQhpnbtkehbAwjvDcxIERmCYcysiODFmE3Ud0Q=="],
|
||||
|
||||
"unbash": ["unbash@6.0.0", "", {}, "sha512-vD5CvvFLVQDhXdNyNEPPa/tHPCK3HLySddOine+OZLDYIH1cMImGNgnw9+NkizToaPsFsQlwiyPGMiK+uwtYVw=="],
|
||||
"unbash": ["unbash@6.0.1", "", {}, "sha512-0db9eS5iqybux41zLkX69nk90KTci7F7eZ+gXzEG/Q7E0tAqEBhRh5fkZvk1N7jT7QkGWqq34i8SFGPFEe1V8A=="],
|
||||
|
||||
"undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
|
||||
|
||||
@@ -626,8 +612,6 @@
|
||||
|
||||
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||
|
||||
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||
|
||||
"yaml": ["yaml@2.9.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw=="],
|
||||
|
||||
"yargs": ["yargs@18.2.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^8.2.1", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-9OpKOLeaoNFecEp7P6iYbzze/5CqWoH7N3SMs/6y1XF4nMvFMspEGZzJ6uFi9MmQwXhyzqYoSEKO3tvA3Z/o2w=="],
|
||||
@@ -646,17 +630,13 @@
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" }, "bundled": true }, "sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA=="],
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || 2.0.0-beta.2", "@emnapi/runtime": "^1.7.1 || 2.0.0-beta.2" }, "bundled": true }, "sha512-mRyDmEw9/fCDXCGfL1sbgIw/GUK0PVxRW4YwgPN61F3LQ+fSyoBFarJVzgGyhF6kRzEQZ0FejDqm4WLXSeqQmw=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.4", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.12", "", {}, "sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg=="],
|
||||
|
||||
"bun-types/@types/node": ["@types/node@26.6.5", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg=="],
|
||||
|
||||
"bun-types/undici-types": ["undici-types@8.12.2", "", {}, "sha512-VoMeD2O0KdHhcn+oPqOrpivN+7aDOklVSwOLD7JNjbzV1CboAFek9IFOXnreoufTUtAsCsOK0iETiERPNR/fDA=="],
|
||||
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.14", "", {}, "sha512-wCBiZ77u1tuWde6G/nfOtLaCTYcFDU5yCzARzK10y+rLhzYoL7a7yEemcopcc2Mzow7gZOIjnV2ym1NYmdiJOQ=="],
|
||||
|
||||
"cliui/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
@@ -674,8 +654,6 @@
|
||||
|
||||
"wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
"bun-types/@types/node/undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="],
|
||||
|
||||
"cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"tsconfig-paths-webpack-plugin/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
+11
@@ -7,3 +7,14 @@ coveragePathIgnorePatterns = [
|
||||
pathIgnorePatterns = [
|
||||
"**/integration/**"
|
||||
]
|
||||
|
||||
[fmt]
|
||||
arrowParens = "always"
|
||||
printWidth = 100
|
||||
singleQuote = false
|
||||
semi = true
|
||||
tabWidth = 2
|
||||
sortImports = true
|
||||
sortTailwindcss = false
|
||||
sortPackageJson = true
|
||||
jsdoc = true
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
"potrace",
|
||||
"soffice",
|
||||
"perl",
|
||||
"markitdown"
|
||||
"markitdown",
|
||||
"fmt"
|
||||
],
|
||||
"tailwind": {
|
||||
"entry": ["src/main.css"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tools]
|
||||
bun = "1.4.4"
|
||||
|
||||
[env]
|
||||
JWT_SECRET = "aLongAndSecretStringUsedToSignTheJSONWebToken1234"
|
||||
FFMPEG_OUTPUT_ARGS = "-preset veryfast -threads 2"
|
||||
[tools]
|
||||
bun = "1.4.4"
|
||||
|
||||
[env]
|
||||
JWT_SECRET = "aLongAndSecretStringUsedToSignTheJSONWebToken1234"
|
||||
FFMPEG_OUTPUT_ARGS = "-preset veryfast -threads 2"
|
||||
|
||||
+10
-12
@@ -1,22 +1,24 @@
|
||||
{
|
||||
"name": "convertx-frontend",
|
||||
"version": "0.20.0",
|
||||
"type": "module",
|
||||
"module": "src/index.tsx",
|
||||
"scripts": {
|
||||
"dev": "bun run --watch src/index.tsx",
|
||||
"hot": "bun run --hot src/index.tsx",
|
||||
"format": "npm-run-all 'format:*'",
|
||||
"format:eslint": "eslint --fix .",
|
||||
"format:prettier": "prettier --write .",
|
||||
"format:prettier": "bun fmt",
|
||||
"build:css": "bun x @tailwindcss/cli -i ./src/main.css -o ./public/generated.css",
|
||||
"build:js": "tsc",
|
||||
"build:bin": "bun run build:css && bun build --compile --minify --sourcemap --bytecode --format=esm --define 'process.env.NODE_ENV=\"production\"' src/index.tsx --outfile dist/convertx",
|
||||
"build:docker": "docker compose build",
|
||||
"build": "bun run build:css && bun run build:js",
|
||||
"lint": "npm-run-all 'lint:*'",
|
||||
"lint:tsc": "tsc --noEmit",
|
||||
"lint:tsc": "bun check",
|
||||
"lint:knip": "knip",
|
||||
"lint:eslint": "eslint .",
|
||||
"lint:prettier": "prettier --check .",
|
||||
"lint:prettier": "bun fmt --check",
|
||||
"lint:xss": "xss-scan",
|
||||
"test": "bun test",
|
||||
"test:integration": "docker build --target test -t convertx:test . && docker run --rm -t -v ./tests:/app/tests -v ./src:/app/src -v ./package.json:/app/package.json convertx:test bun test tests/integration"
|
||||
@@ -27,20 +29,14 @@
|
||||
"@elysiajs/static": "^1.4.10",
|
||||
"@kitajs/html": "^4.2.13",
|
||||
"elysia": "1.4.30",
|
||||
"sanitize-filename": "^1.6.4",
|
||||
"tar": "^7.5.22"
|
||||
},
|
||||
"module": "src/index.tsx",
|
||||
"type": "module",
|
||||
"bun-create": {
|
||||
"start": "bun run src/index.tsx"
|
||||
"sanitize-filename": "^1.6.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@kitajs/ts-html-plugin": "^4.1.4",
|
||||
"@tailwindcss/cli": "^4.3.3",
|
||||
"@tailwindcss/postcss": "^4.3.3",
|
||||
"@types/bun": "1.4.3",
|
||||
"@types/bun": "1.4.4",
|
||||
"@types/node": "^24.19.0",
|
||||
"eslint": "^10.11.0",
|
||||
"eslint-plugin-better-tailwindcss": "^4.7.0",
|
||||
@@ -48,12 +44,14 @@
|
||||
"knip": "^6.38.0",
|
||||
"npm-run-all2": "^9.0.3",
|
||||
"postcss": "^8.5.28",
|
||||
"prettier": "^3.9.9",
|
||||
"tailwind-scrollbar": "^4.0.2",
|
||||
"tailwindcss": "^4.3.3",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.70.1"
|
||||
},
|
||||
"bun-create": {
|
||||
"start": "bun run src/index.tsx"
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"@parcel/watcher",
|
||||
"@tailwindcss/oxide",
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
/**
|
||||
* @type {import('prettier').Config}
|
||||
*/
|
||||
/** @type {import("prettier").Config} */
|
||||
const config = {
|
||||
arrowParens: "always",
|
||||
printWidth: 100,
|
||||
|
||||
+2
-1
@@ -39,11 +39,12 @@ function handleFile(file) {
|
||||
|
||||
const row = document.createElement("tr");
|
||||
row.innerHTML = `
|
||||
<td>${file.name}</td>
|
||||
<td></td>
|
||||
<td><progress max="100" class="inline-block h-2 appearance-none overflow-hidden rounded-full border-0 bg-neutral-700 bg-none text-accent-500 accent-accent-500 [&::-moz-progress-bar]:bg-accent-500 [&::-webkit-progress-value]:rounded-full [&::-webkit-progress-value]:[background:none] [&[value]::-webkit-progress-value]:bg-accent-500 [&[value]::-webkit-progress-value]:transition-[inline-size]"></progress></td>
|
||||
<td>${(file.size / 1024).toFixed(2)} kB</td>
|
||||
<td><button type="button" class="text-accent-500 hover:underline" onclick="deleteRow(this)">Remove</button></td>
|
||||
`;
|
||||
row.firstElementChild.textContent = file.name;
|
||||
|
||||
if (!fileType) {
|
||||
fileType = file.name.split(".").pop();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from "fs";
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import type { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
execFile as execFileOriginal,
|
||||
type ChildProcess,
|
||||
execFile as execFileOriginal,
|
||||
type ExecFileOptions,
|
||||
} from "node:child_process";
|
||||
|
||||
@@ -770,9 +770,15 @@ export async function convert(
|
||||
}
|
||||
|
||||
// Parse FFMPEG_ARGS environment variable into array
|
||||
const ffmpegArgs = process.env.FFMPEG_ARGS ? process.env.FFMPEG_ARGS.split(/\s+/) : [];
|
||||
const ffmpegArgs = process.env.FFMPEG_ARGS
|
||||
? process.env.FFMPEG_ARGS.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.map((arg) => arg.trim())
|
||||
: [];
|
||||
const ffmpegOutputArgs = process.env.FFMPEG_OUTPUT_ARGS
|
||||
? process.env.FFMPEG_OUTPUT_ARGS.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.map((arg) => arg.trim())
|
||||
: [];
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
// declare possible conversions
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
// declare possible conversions
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
+31
-23
@@ -1,7 +1,9 @@
|
||||
import { Cookie } from "elysia";
|
||||
import db from "../db/db";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import { Cookie } from "elysia";
|
||||
|
||||
import db from "../db/db";
|
||||
import { MAX_CONVERT_PROCESS } from "../helpers/env";
|
||||
import { normalizeFiletype, normalizeOutputFiletype } from "../helpers/normalizeFiletype";
|
||||
import { convert as convertassimp, properties as propertiesassimp } from "./assimp";
|
||||
@@ -19,16 +21,16 @@ import { convert as convertInkscape, properties as propertiesInkscape } from "./
|
||||
import { convert as convertLibheif, properties as propertiesLibheif } from "./libheif";
|
||||
import { convert as convertLibjxl, properties as propertiesLibjxl } from "./libjxl";
|
||||
import { convert as convertLibreOffice, properties as propertiesLibreOffice } from "./libreoffice";
|
||||
import { convert as convertMarkitdown, properties as propertiesMarkitdown } from "./markitdown";
|
||||
import { convert as convertMsgconvert, properties as propertiesMsgconvert } from "./msgconvert";
|
||||
import { convert as convertPandoc, properties as propertiesPandoc } from "./pandoc";
|
||||
import { convert as convertPdftops, properties as propertiesPdftops } from "./pdftops";
|
||||
import { convert as convertPotrace, properties as propertiesPotrace } from "./potrace";
|
||||
import { convert as convertresvg, properties as propertiesresvg } from "./resvg";
|
||||
import { convert as convertVcf, properties as propertiesVcf } from "./vcf";
|
||||
import { convert as convertImage, properties as propertiesImage } from "./vips";
|
||||
import { convert as convertVtracer, properties as propertiesVtracer } from "./vtracer";
|
||||
import { convert as convertVcf, properties as propertiesVcf } from "./vcf";
|
||||
import { convert as convertxelatex, properties as propertiesxelatex } from "./xelatex";
|
||||
import { convert as convertMarkitdown, properties as propertiesMarkitdown } from "./markitdown";
|
||||
|
||||
// This should probably be reconstructed so that the functions are not imported instead the functions hook into this to make the converters more modular
|
||||
|
||||
@@ -85,6 +87,11 @@ const properties: Record<
|
||||
properties: propertiesxelatex,
|
||||
converter: convertxelatex,
|
||||
},
|
||||
// djvu before calibre so the dedicated ddjvu converter wins for DjVu files
|
||||
djvu: {
|
||||
properties: propertiesDjvu,
|
||||
converter: convertDjvu,
|
||||
},
|
||||
calibre: {
|
||||
properties: propertiesCalibre,
|
||||
converter: convertCalibre,
|
||||
@@ -93,10 +100,6 @@ const properties: Record<
|
||||
properties: propertiesDasel,
|
||||
converter: convertDasel,
|
||||
},
|
||||
djvu: {
|
||||
properties: propertiesDjvu,
|
||||
converter: convertDjvu,
|
||||
},
|
||||
libreoffice: {
|
||||
properties: propertiesLibreOffice,
|
||||
converter: convertLibreOffice,
|
||||
@@ -246,8 +249,8 @@ async function mainConverter(
|
||||
converterFunc = properties[converterName]?.converter;
|
||||
} else {
|
||||
// Iterate over each converter in properties
|
||||
for (converterName in properties) {
|
||||
const converterObj = properties[converterName];
|
||||
for (const name in properties) {
|
||||
const converterObj = properties[name];
|
||||
|
||||
if (!converterObj) {
|
||||
break;
|
||||
@@ -259,9 +262,13 @@ async function mainConverter(
|
||||
converterObj?.properties?.to[key]?.includes(convertTo)
|
||||
) {
|
||||
converterFunc = converterObj.converter;
|
||||
converterName = name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (converterFunc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,6 +303,7 @@ const possibleTargets: Record<string, Record<string, string[]>> = {};
|
||||
|
||||
for (const converterName in properties) {
|
||||
const converterProperties = properties[converterName]?.properties;
|
||||
|
||||
if (!converterProperties) continue;
|
||||
|
||||
for (const key in converterProperties.from) {
|
||||
@@ -307,7 +315,7 @@ for (const converterName in properties) {
|
||||
for (const ext of fromList) {
|
||||
if (!possibleTargets[ext]) possibleTargets[ext] = {};
|
||||
|
||||
possibleTargets[ext][converterName] = toList;
|
||||
possibleTargets[ext][converterName] = [...toList];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,9 +330,7 @@ const possibleInputs: string[] = [];
|
||||
for (const converterName in properties) {
|
||||
const converterProperties = properties[converterName]?.properties;
|
||||
|
||||
if (!converterProperties) {
|
||||
continue;
|
||||
}
|
||||
if (!converterProperties) continue;
|
||||
|
||||
for (const key in converterProperties.from) {
|
||||
for (const extension of converterProperties.from[key] ?? []) {
|
||||
@@ -341,15 +347,16 @@ const allTargets: Record<string, string[]> = {};
|
||||
for (const converterName in properties) {
|
||||
const converterProperties = properties[converterName]?.properties;
|
||||
|
||||
if (!converterProperties) {
|
||||
continue;
|
||||
}
|
||||
if (!converterProperties) continue;
|
||||
|
||||
for (const key in converterProperties.to) {
|
||||
if (allTargets[converterName]) {
|
||||
allTargets[converterName].push(...(converterProperties.to[key] || []));
|
||||
allTargets[converterName] = [
|
||||
...allTargets[converterName],
|
||||
...(converterProperties.to[key] || []),
|
||||
];
|
||||
} else {
|
||||
allTargets[converterName] = converterProperties.to[key] || [];
|
||||
allTargets[converterName] = [...(converterProperties.to[key] || [])];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -362,13 +369,14 @@ const allInputs: Record<string, string[]> = {};
|
||||
for (const converterName in properties) {
|
||||
const converterProperties = properties[converterName]?.properties;
|
||||
|
||||
if (!converterProperties) {
|
||||
continue;
|
||||
}
|
||||
if (!converterProperties) continue;
|
||||
|
||||
for (const key in converterProperties.from) {
|
||||
if (allInputs[converterName]) {
|
||||
allInputs[converterName].push(...(converterProperties.from[key] || []));
|
||||
allInputs[converterName] = [
|
||||
...allInputs[converterName],
|
||||
...(converterProperties.from[key] || []),
|
||||
];
|
||||
} else {
|
||||
allInputs[converterName] = converterProperties.from[key] || [];
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -46,12 +46,14 @@ export function parseVCF(data: string): Record<string, string>[] {
|
||||
|
||||
export function toCSV(data: Record<string, string>[]): string {
|
||||
if (!data.length) return "";
|
||||
const first = data[0];
|
||||
if (!first) return "";
|
||||
const headers = Object.keys(first);
|
||||
const headers = new Set<string>();
|
||||
for (const row of data) {
|
||||
Object.keys(row).forEach((key) => headers.add(key));
|
||||
}
|
||||
const headerArray = Array.from(headers);
|
||||
const escape = (str: string) => `"${str.replace(/"/g, '""')}"`;
|
||||
const rows = data.map((row) => headers.map((h) => escape(row[h] || "")).join(","));
|
||||
return [headers.join(","), ...rows].join("\n");
|
||||
const rows = data.map((row) => headerArray.map((h) => escape(row[h] || "")).join(","));
|
||||
return [headerArray.join(","), ...rows].join("\n");
|
||||
}
|
||||
|
||||
export async function convert(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
// declare possible conversions
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
|
||||
import { ExecFileFn } from "./types";
|
||||
|
||||
export const properties = {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { exec } from "node:child_process";
|
||||
import { readFile } from "node:fs";
|
||||
|
||||
import { version } from "../../package.json";
|
||||
|
||||
console.log(`ConvertX v${version}`);
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/** SetTimeout delays above this overflow a signed 32-bit integer and fire immediately. */
|
||||
const MAX_TIMEOUT_DELAY_MS = 2 ** 31 - 1;
|
||||
|
||||
type ArmTimer = (callback: () => void, delayMs: number) => ReturnType<typeof setTimeout>;
|
||||
|
||||
const armNativeTimer: ArmTimer = (callback, delayMs) => setTimeout(callback, delayMs);
|
||||
|
||||
export type ScheduledTask = {
|
||||
/** Stops the task. Works across chunk boundaries, unlike a raw timer handle. */
|
||||
cancel: () => void;
|
||||
};
|
||||
|
||||
export function scheduleDelayed(
|
||||
delayMs: number,
|
||||
task: () => void,
|
||||
armTimer: ArmTimer = armNativeTimer,
|
||||
): ScheduledTask {
|
||||
let handle: ReturnType<typeof setTimeout> | undefined;
|
||||
let cancelled = false;
|
||||
|
||||
const arm = (remainingMs: number) => {
|
||||
const chunkMs = Math.min(remainingMs, MAX_TIMEOUT_DELAY_MS);
|
||||
handle = armTimer(() => {
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const restMs = remainingMs - chunkMs;
|
||||
if (restMs > 0) {
|
||||
arm(restMs);
|
||||
return;
|
||||
}
|
||||
|
||||
task();
|
||||
}, chunkMs);
|
||||
};
|
||||
|
||||
arm(delayMs);
|
||||
|
||||
return {
|
||||
cancel: () => {
|
||||
cancelled = true;
|
||||
if (handle !== undefined) {
|
||||
clearTimeout(handle);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
+11
-5
@@ -1,11 +1,14 @@
|
||||
import { rmSync } from "node:fs";
|
||||
|
||||
import { html } from "@elysiajs/html";
|
||||
import { staticPlugin } from "@elysiajs/static";
|
||||
import { Elysia } from "elysia";
|
||||
import { rmSync } from "node:fs";
|
||||
|
||||
import db from "./db/db";
|
||||
import { Jobs } from "./db/types";
|
||||
import { AUTO_DELETE_EVERY_N_HOURS, WEBROOT } from "./helpers/env";
|
||||
import "./helpers/printVersions";
|
||||
import { scheduleDelayed, ScheduledTask } from "./helpers/scheduleDelayed";
|
||||
import { chooseConverter } from "./pages/chooseConverter";
|
||||
import { convert } from "./pages/convert";
|
||||
import { deleteFile } from "./pages/deleteFile";
|
||||
@@ -73,12 +76,15 @@ app.listen(process.env.PORT || 3000);
|
||||
|
||||
console.log(`🦊 Elysia is running at http://${app.server?.hostname}:${app.server?.port}${WEBROOT}`);
|
||||
|
||||
let clearJobsTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
const MILLISECONDS_PER_HOUR = 60 * 60 * 1000;
|
||||
const autoDeleteIntervalMs = AUTO_DELETE_EVERY_N_HOURS * MILLISECONDS_PER_HOUR;
|
||||
let clearJobsTimer: ScheduledTask;
|
||||
|
||||
const clearJobs = () => {
|
||||
const jobs = db
|
||||
.query("SELECT * FROM jobs WHERE date_created < ?")
|
||||
.as(Jobs)
|
||||
.all(new Date(Date.now() - AUTO_DELETE_EVERY_N_HOURS * 60 * 60 * 1000).toISOString());
|
||||
.all(new Date(Date.now() - autoDeleteIntervalMs).toISOString());
|
||||
|
||||
for (const job of jobs) {
|
||||
// delete the directories
|
||||
@@ -95,7 +101,7 @@ const clearJobs = () => {
|
||||
db.query("DELETE FROM jobs WHERE id = ?").run(job.id);
|
||||
}
|
||||
|
||||
clearJobsTimer = setTimeout(clearJobs, AUTO_DELETE_EVERY_N_HOURS * 60 * 60 * 1000);
|
||||
clearJobsTimer = scheduleDelayed(autoDeleteIntervalMs, clearJobs);
|
||||
};
|
||||
|
||||
if (AUTO_DELETE_EVERY_N_HOURS > 0) {
|
||||
@@ -107,7 +113,7 @@ const handleShutdown = async () => {
|
||||
if (isShuttingDown) return;
|
||||
isShuttingDown = true;
|
||||
if (clearJobsTimer) {
|
||||
clearTimeout(clearJobsTimer);
|
||||
clearJobsTimer.cancel();
|
||||
}
|
||||
try {
|
||||
await app.stop(true);
|
||||
|
||||
+3
-3
@@ -20,13 +20,13 @@
|
||||
}
|
||||
|
||||
@utility article {
|
||||
@apply px-2 sm:px-4 py-4 mb-4 bg-neutral-800/40 w-full mx-auto max-w-4xl rounded-sm;
|
||||
@apply mx-auto mb-4 w-full max-w-4xl rounded-sm bg-neutral-800/40 px-2 py-4 sm:px-4;
|
||||
}
|
||||
|
||||
@utility btn-primary {
|
||||
@apply bg-accent-500 text-contrast rounded-sm p-2 sm:p-4 hover:bg-accent-400 cursor-pointer transition-colors;
|
||||
@apply bg-accent-500 text-contrast hover:bg-accent-400 cursor-pointer rounded-sm p-2 transition-colors sm:p-4;
|
||||
}
|
||||
|
||||
@utility btn-secondary {
|
||||
@apply bg-neutral-400 text-contrast rounded-sm p-2 sm:p-4 hover:bg-neutral-300 cursor-pointer transition-colors;
|
||||
@apply text-contrast cursor-pointer rounded-sm bg-neutral-400 p-2 transition-colors hover:bg-neutral-300 sm:p-4;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Elysia, { t } from "elysia";
|
||||
|
||||
import { getPossibleTargets } from "../converters/main";
|
||||
import { userService } from "./user";
|
||||
|
||||
|
||||
+15
-4
@@ -1,6 +1,8 @@
|
||||
import { mkdir } from "node:fs/promises";
|
||||
|
||||
import { Elysia, t } from "elysia";
|
||||
import sanitize from "sanitize-filename";
|
||||
|
||||
import { outputDir, uploadsDir } from "..";
|
||||
import { handleConvert } from "../converters/main";
|
||||
import db from "../db/db";
|
||||
@@ -56,16 +58,25 @@ export const convert = new Elysia().use(userService).post(
|
||||
return redirect(`${WEBROOT}/`, 302);
|
||||
}
|
||||
|
||||
const fileNames = JSON.parse(body.file_names) as string[];
|
||||
|
||||
for (let i = 0; i < fileNames.length; i++) {
|
||||
fileNames[i] = sanitize(fileNames[i] || "");
|
||||
let fileNames: string[];
|
||||
try {
|
||||
fileNames = JSON.parse(body.file_names) as string[];
|
||||
} catch {
|
||||
return redirect(`${WEBROOT}/`, 302);
|
||||
}
|
||||
|
||||
if (!Array.isArray(fileNames) || fileNames.length === 0) {
|
||||
return redirect(`${WEBROOT}/`, 302);
|
||||
}
|
||||
|
||||
if (!fileNames.every((name) => typeof name === "string")) {
|
||||
return redirect(`${WEBROOT}/`, 302);
|
||||
}
|
||||
|
||||
for (let i = 0; i < fileNames.length; i++) {
|
||||
fileNames[i] = sanitize(fileNames[i] || "");
|
||||
}
|
||||
|
||||
db.query("UPDATE jobs SET num_files = ?1, status = 'pending' WHERE id = ?2").run(
|
||||
fileNames.length,
|
||||
jobId.value,
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { unlink } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
import { Elysia, t } from "elysia";
|
||||
import sanitize from "sanitize-filename";
|
||||
|
||||
import { uploadsDir } from "..";
|
||||
import db from "../db/db";
|
||||
import { WEBROOT } from "../helpers/env";
|
||||
import { userService } from "./user";
|
||||
import sanitize from "sanitize-filename";
|
||||
import path from "node:path";
|
||||
|
||||
export const deleteFile = new Elysia().use(userService).post(
|
||||
"/delete",
|
||||
async ({ body, redirect, cookie: { jobId }, user }) => {
|
||||
async ({ body, redirect, set, cookie: { jobId }, user }) => {
|
||||
if (!jobId?.value) {
|
||||
return redirect(`${WEBROOT}/`, 302);
|
||||
}
|
||||
@@ -27,7 +29,15 @@ export const deleteFile = new Elysia().use(userService).post(
|
||||
const sanitized = sanitize(body.filename);
|
||||
const targetPath = path.join(userUploadsDir, sanitized);
|
||||
|
||||
await unlink(targetPath);
|
||||
try {
|
||||
await unlink(targetPath);
|
||||
} catch (e) {
|
||||
if ((e as NodeJS.ErrnoException).code === "ENOENT") {
|
||||
set.status = 404;
|
||||
return { message: "File not found." };
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
return {
|
||||
message: "File deleted successfully.",
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { rmSync } from "node:fs";
|
||||
|
||||
import { Elysia, t } from "elysia";
|
||||
|
||||
import { outputDir, uploadsDir } from "..";
|
||||
import db from "../db/db";
|
||||
import { Jobs } from "../db/types";
|
||||
import { WEBROOT } from "../helpers/env";
|
||||
import { userService } from "./user";
|
||||
import { Jobs } from "../db/types";
|
||||
|
||||
export const deleteJob = new Elysia()
|
||||
.use(userService)
|
||||
|
||||
+41
-13
@@ -1,12 +1,17 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { rename, unlink } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
import { Elysia } from "elysia";
|
||||
import sanitize from "sanitize-filename";
|
||||
import * as tar from "tar";
|
||||
|
||||
import { outputDir } from "..";
|
||||
import db from "../db/db";
|
||||
import { WEBROOT } from "../helpers/env";
|
||||
import { userService } from "./user";
|
||||
|
||||
const archiveBuilds = new Map<string, Promise<void>>();
|
||||
|
||||
export const download = new Elysia()
|
||||
.use(userService)
|
||||
.get(
|
||||
@@ -21,8 +26,8 @@ export const download = new Elysia()
|
||||
return redirect(`${WEBROOT}/results`, 302);
|
||||
}
|
||||
// parse from URL encoded string
|
||||
const jobId = decodeURIComponent(params.jobId);
|
||||
const fileName = sanitize(decodeURIComponent(params.fileName));
|
||||
const jobId = params.jobId;
|
||||
const fileName = sanitize(params.fileName);
|
||||
|
||||
const filePath = `${outputDir}${userId}/${jobId}/${fileName}`;
|
||||
const file = Bun.file(filePath);
|
||||
@@ -53,16 +58,39 @@ export const download = new Elysia()
|
||||
const outputPath = `${outputDir}${userId}/${jobId}`;
|
||||
const outputTar = path.join(outputPath, `converted_files_${jobId}.tar`);
|
||||
|
||||
await tar.create(
|
||||
{
|
||||
file: outputTar,
|
||||
cwd: outputPath,
|
||||
filter: (path) => {
|
||||
return !path.match(".*\\.tar");
|
||||
},
|
||||
},
|
||||
["."],
|
||||
);
|
||||
const archiveKey = `${userId}/${jobId}`;
|
||||
let archiveBuild = archiveBuilds.get(archiveKey);
|
||||
if (!archiveBuild) {
|
||||
const build = async () => {
|
||||
const outputTarName = path.basename(outputTar);
|
||||
const outputTarTempName = `${outputTarName}.tmp-${randomUUID()}`;
|
||||
const outputTarTemp = path.join(outputPath, outputTarTempName);
|
||||
|
||||
try {
|
||||
const files: Record<string, Uint8Array> = {};
|
||||
const glob = new Bun.Glob("**/*");
|
||||
for await (const file of glob.scan({ cwd: outputPath, onlyFiles: true, dot: true })) {
|
||||
if (file !== outputTarName && !file.startsWith(`${outputTarName}.tmp-`)) {
|
||||
files[file] = new Uint8Array(
|
||||
await Bun.file(path.join(outputPath, file)).arrayBuffer(),
|
||||
);
|
||||
}
|
||||
}
|
||||
await Bun.Archive.write(outputTarTemp, files);
|
||||
await rename(outputTarTemp, outputTar);
|
||||
} finally {
|
||||
if (await Bun.file(outputTarTemp).exists()) {
|
||||
await unlink(outputTarTemp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
archiveBuild = build().finally(() => {
|
||||
archiveBuilds.delete(archiveKey);
|
||||
});
|
||||
archiveBuilds.set(archiveKey, archiveBuild);
|
||||
}
|
||||
await archiveBuild;
|
||||
return Bun.file(outputTar);
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Elysia from "elysia";
|
||||
|
||||
import { userService } from "./user";
|
||||
|
||||
export const healthcheck = new Elysia().use(userService).get(
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import { Elysia } from "elysia";
|
||||
|
||||
import { BaseHtml } from "../components/base";
|
||||
import { Header } from "../components/header";
|
||||
import db from "../db/db";
|
||||
import { Filename, Jobs } from "../db/types";
|
||||
import {
|
||||
ALLOW_UNAUTHENTICATED,
|
||||
BRANDING,
|
||||
HIDE_HISTORY,
|
||||
LANGUAGE,
|
||||
TIMEZONE,
|
||||
WEBROOT,
|
||||
BRANDING,
|
||||
} from "../helpers/env";
|
||||
import { userService } from "./user";
|
||||
import { EyeIcon } from "../icons/eye";
|
||||
import { DeleteIcon } from "../icons/delete";
|
||||
import { EyeIcon } from "../icons/eye";
|
||||
import { userService } from "./user";
|
||||
|
||||
export const history = new Elysia().use(userService).get(
|
||||
"/history",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import Elysia from "elysia";
|
||||
|
||||
import { BaseHtml } from "../components/base";
|
||||
import { Header } from "../components/header";
|
||||
import { getAllInputs, getAllTargets } from "../converters/main";
|
||||
import { ALLOW_UNAUTHENTICATED, WEBROOT, BRANDING } from "../helpers/env";
|
||||
import { ALLOW_UNAUTHENTICATED, BRANDING, WEBROOT } from "../helpers/env";
|
||||
import { userService } from "./user";
|
||||
|
||||
export const listConverters = new Elysia().use(userService).get(
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Elysia } from "elysia";
|
||||
|
||||
import { BaseHtml } from "../components/base";
|
||||
import { Header } from "../components/header";
|
||||
import db from "../db/db";
|
||||
import { Filename, Jobs } from "../db/types";
|
||||
import { buildDownloadUrl } from "../helpers/buildDownloadUrl";
|
||||
import { ALLOW_UNAUTHENTICATED, WEBROOT, BRANDING } from "../helpers/env";
|
||||
import { DownloadIcon } from "../icons/download";
|
||||
import { ALLOW_UNAUTHENTICATED, BRANDING, WEBROOT } from "../helpers/env";
|
||||
import { DeleteIcon } from "../icons/delete";
|
||||
import { DownloadIcon } from "../icons/download";
|
||||
import { EyeIcon } from "../icons/eye";
|
||||
import { userService } from "./user";
|
||||
|
||||
|
||||
+49
-23
@@ -1,6 +1,8 @@
|
||||
import { randomInt } from "node:crypto";
|
||||
|
||||
import { JWTPayloadSpec } from "@elysiajs/jwt";
|
||||
import { Elysia, t } from "elysia";
|
||||
|
||||
import { BaseHtml } from "../components/base";
|
||||
import { Header } from "../components/header";
|
||||
import { getAllTargets } from "../converters/main";
|
||||
@@ -9,11 +11,11 @@ import { User } from "../db/types";
|
||||
import {
|
||||
ACCOUNT_REGISTRATION,
|
||||
ALLOW_UNAUTHENTICATED,
|
||||
BRANDING,
|
||||
HIDE_HISTORY,
|
||||
HTTP_ALLOWED,
|
||||
UNAUTHENTICATED_USER_SHARING,
|
||||
WEBROOT,
|
||||
BRANDING,
|
||||
} from "../helpers/env";
|
||||
import { FIRST_RUN, userService } from "./user";
|
||||
|
||||
@@ -33,30 +35,54 @@ export const root = new Elysia().use(userService).get(
|
||||
// validate jwt
|
||||
let user: ({ id: string } & JWTPayloadSpec) | false = false;
|
||||
if (ALLOW_UNAUTHENTICATED) {
|
||||
const newUserId = String(
|
||||
UNAUTHENTICATED_USER_SHARING
|
||||
? 0
|
||||
: randomInt(2 ** 24, Math.min(2 ** 48 + 2 ** 24 - 1, Number.MAX_SAFE_INTEGER)),
|
||||
);
|
||||
const accessToken = await jwt.sign({
|
||||
id: newUserId,
|
||||
});
|
||||
|
||||
user = { id: newUserId };
|
||||
if (!auth) {
|
||||
return {
|
||||
message: "No auth cookie, perhaps your browser is blocking cookies.",
|
||||
};
|
||||
// Check if the current cookie is already a valid session
|
||||
if (auth?.value) {
|
||||
try {
|
||||
const verifiedUser = await jwt.verify(auth.value);
|
||||
if (verifiedUser && verifiedUser.id) {
|
||||
const numericId = Number.parseInt(verifiedUser.id);
|
||||
// IDs below the anonymous range (excluding shared 0) are registered users
|
||||
const isRegistered = numericId > 0 && numericId < 2 ** 24;
|
||||
if (
|
||||
!isRegistered ||
|
||||
db.query("SELECT * FROM users WHERE id = ?").as(User).get(verifiedUser.id)
|
||||
) {
|
||||
user = verifiedUser;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Invalid cookie, fall through to anonymous creation
|
||||
}
|
||||
}
|
||||
|
||||
// set cookie
|
||||
auth.set({
|
||||
value: accessToken,
|
||||
httpOnly: true,
|
||||
secure: !HTTP_ALLOWED,
|
||||
maxAge: 24 * 60 * 60,
|
||||
sameSite: "strict",
|
||||
});
|
||||
// If no valid session found, create an anonymous user
|
||||
if (!user) {
|
||||
const newUserId = String(
|
||||
UNAUTHENTICATED_USER_SHARING
|
||||
? 0
|
||||
: randomInt(2 ** 24, Math.min(2 ** 48 + 2 ** 24 - 1, Number.MAX_SAFE_INTEGER)),
|
||||
);
|
||||
const accessToken = await jwt.sign({
|
||||
id: newUserId,
|
||||
});
|
||||
|
||||
user = { id: newUserId };
|
||||
|
||||
// Use existing cookie if it exists, otherwise set a new one
|
||||
if (auth) {
|
||||
auth.set({
|
||||
value: accessToken,
|
||||
httpOnly: true,
|
||||
secure: !HTTP_ALLOWED,
|
||||
maxAge: 24 * 60 * 60,
|
||||
sameSite: "strict",
|
||||
});
|
||||
} else {
|
||||
return {
|
||||
message: "No auth cookie, perhaps your browser is blocking cookies.",
|
||||
};
|
||||
}
|
||||
}
|
||||
} else if (auth?.value) {
|
||||
user = await jwt.verify(auth.value);
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Elysia, t } from "elysia";
|
||||
import sanitize from "sanitize-filename";
|
||||
|
||||
import db from "../db/db";
|
||||
import { WEBROOT } from "../helpers/env";
|
||||
import { uploadsDir } from "../index";
|
||||
import { userService } from "./user";
|
||||
import sanitize from "sanitize-filename";
|
||||
|
||||
export const upload = new Elysia().use(userService).post(
|
||||
"/upload",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Elysia, t } from "elysia";
|
||||
|
||||
import { BaseHtml } from "../components/base";
|
||||
import { Header } from "../components/header";
|
||||
import db from "../db/db";
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
|
||||
import { jwt } from "@elysiajs/jwt";
|
||||
import { Elysia, t } from "elysia";
|
||||
|
||||
import { WEBROOT } from "../helpers/env";
|
||||
import { isHtmlPageRequest } from "../helpers/isHtmlPageRequest";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/assimp";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/calibre";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
||||
import fs from "fs";
|
||||
import { beforeEach, afterEach, expect, test, describe } from "bun:test";
|
||||
|
||||
import { buildDaselArgs, convert } from "../../src/converters/dasel";
|
||||
import type { ExecFileFn } from "../../src/converters/types";
|
||||
import { captureConsole } from "./helpers/converters";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ExecFileException } from "node:child_process";
|
||||
import { expect, test } from "bun:test";
|
||||
import type { ExecFileException } from "node:child_process";
|
||||
|
||||
import { convert, properties } from "../../src/converters/djvu";
|
||||
import type { ExecFileFn } from "../../src/converters/types";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/dvisvgm";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { afterAll, afterEach, beforeEach, expect, test } from "bun:test";
|
||||
import { convert } from "../../src/converters/ffmpeg";
|
||||
import type { ExecFileOptions } from "node:child_process";
|
||||
|
||||
import { convert } from "../../src/converters/ffmpeg";
|
||||
import { captureConsole } from "./helpers/converters";
|
||||
|
||||
let calls: string[][] = [];
|
||||
@@ -181,10 +182,7 @@ test("splits FFMPEG_ARGS on any whitespace", async () => {
|
||||
expect(calls[0]?.slice(0, 3)).toEqual(["-hide_banner", "-y", "-nostdin"]);
|
||||
});
|
||||
|
||||
// BUG: split(/\s+/) keeps empty strings for leading/trailing whitespace
|
||||
// (" -y ".split(/\s+/) is ["", "-y", ""]), so ffmpeg receives "" as an argument
|
||||
// and fails. Remove `.failing` once src/converters/ffmpeg.ts drops empty entries.
|
||||
test.failing("ignores leading and trailing whitespace in FFMPEG_ARGS", async () => {
|
||||
test("ignores leading and trailing whitespace in FFMPEG_ARGS", async () => {
|
||||
process.env.FFMPEG_ARGS = " -y ";
|
||||
process.env.FFMPEG_OUTPUT_ARGS = " -preset veryfast ";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/graphicsmagick";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { test } from "bun:test";
|
||||
|
||||
import { ConvertFnWithExecFile } from "../../../src/converters/types";
|
||||
import {
|
||||
runConvertFailTest,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { expect } from "bun:test";
|
||||
|
||||
import type { ConvertFnWithExecFile, ExecFileFn } from "../../../src/converters/types";
|
||||
|
||||
type ExecFileCall = { cmd: string; args: string[] };
|
||||
|
||||
/**
|
||||
* Creates an execFile replacement that records every invocation and answers with the
|
||||
* given error/stdout/stderr, so converter tests never spawn real binaries.
|
||||
* Creates an execFile replacement that records every invocation and answers with the given
|
||||
* error/stdout/stderr, so converter tests never spawn real binaries.
|
||||
*/
|
||||
export function createMockExecFile({
|
||||
error = null,
|
||||
@@ -21,8 +22,8 @@ export function createMockExecFile({
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects console.log/error/warn into arrays so tests can assert on them without
|
||||
* printing to the terminal. Always call restore() afterwards (e.g. in afterEach).
|
||||
* Redirects console.log/error/warn into arrays so tests can assert on them without printing to the
|
||||
* terminal. Always call restore() afterwards (e.g. in afterEach).
|
||||
*/
|
||||
export function captureConsole() {
|
||||
const original = { log: console.log, error: console.error, warn: console.warn };
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/imagemagick";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/inkscape";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/libheif";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/libjxl";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { afterEach, beforeEach, expect, test } from "bun:test";
|
||||
import { convert } from "../../src/converters/libreoffice";
|
||||
|
||||
import { convert, filters, getFilters } from "../../src/converters/libreoffice";
|
||||
import type { ExecFileFn } from "../../src/converters/types";
|
||||
import { filters, getFilters } from "../../src/converters/libreoffice";
|
||||
|
||||
function requireDefined<T>(value: T, msg: string): NonNullable<T> {
|
||||
if (value === undefined || value === null) throw new Error(msg);
|
||||
|
||||
@@ -3,7 +3,9 @@ import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
|
||||
import type { Cookie } from "elysia";
|
||||
|
||||
import { properties as libreofficeProperties } from "../../src/converters/libreoffice";
|
||||
import { captureConsole } from "./helpers/converters";
|
||||
|
||||
@@ -148,11 +150,7 @@ describe("converter registry", () => {
|
||||
expect(getAllInputs("doesnotexist")).toEqual([]);
|
||||
});
|
||||
|
||||
// BUG: building allTargets/allInputs stores the first category's array by
|
||||
// reference and then pushes the other categories into it. That mutates the
|
||||
// converters' own properties, so e.g. LibreOffice offers docx -> xlsx and
|
||||
// libjxl offers jxl -> jxl. Remove `.failing` once main.ts copies the arrays.
|
||||
test.failing("listing all targets and inputs does not leak formats across categories", () => {
|
||||
test("listing all targets and inputs does not leak formats across categories", () => {
|
||||
expect(getPossibleTargets("docx").libreoffice).not.toContain("xlsx");
|
||||
expect(getPossibleTargets("jxl").libjxl).not.toContain("jxl");
|
||||
expect(libreofficeProperties.from.text).not.toContain("xlsx");
|
||||
@@ -251,10 +249,7 @@ describe("mainConverter", () => {
|
||||
},
|
||||
);
|
||||
|
||||
// BUG: discovery loops with `for (converterName in properties)` and only breaks
|
||||
// the inner loop, so the variable always ends on the last registered converter.
|
||||
// Remove `.failing` once mainConverter stops at the first match.
|
||||
test.failing("logs the name of the auto-discovered converter", async () => {
|
||||
test("logs the name of the auto-discovered converter", async () => {
|
||||
const inputPath = `${uploadsDir}named.vcf`;
|
||||
await writeFile(inputPath, vcard("Named"));
|
||||
|
||||
@@ -263,11 +258,7 @@ describe("mainConverter", () => {
|
||||
expect(output.logs.join("\n")).toContain("successfully using vcf");
|
||||
});
|
||||
|
||||
// BUG: same root cause - later matches overwrite earlier ones, so emf -> png
|
||||
// uses ImageMagick even though Inkscape is registered first on purpose
|
||||
// ("Prioritize Inkscape for EMF files"). The input does not exist, so whichever
|
||||
// converter is picked fails fast; only the logged converter name matters.
|
||||
test.failing("auto-discovery prefers the first registered converter", async () => {
|
||||
test("auto-discovery prefers the first registered converter", async () => {
|
||||
await mainConverter(`${uploadsDir}missing.emf`, "emf", "png", `${outputDir}missing.png`);
|
||||
|
||||
expect(output.errors.join("\n")).toContain("using inkscape");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { afterEach, beforeEach, expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/markitdown";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { captureConsole, createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { afterEach, beforeEach, expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/msgconvert";
|
||||
import { captureConsole, createMockExecFile } from "./helpers/converters";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test, describe } from "bun:test";
|
||||
import { describe, expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/pandoc";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { afterEach, beforeEach, expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/pdftops";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { captureConsole, createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/potrace";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/resvg";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { afterAll, beforeAll, expect, test, describe } from "bun:test";
|
||||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { convert, parseVCF, toCSV } from "../../src/converters/vcf";
|
||||
|
||||
describe("parseVCF", () => {
|
||||
@@ -181,10 +182,7 @@ describe("toCSV", () => {
|
||||
expect(toCSV(contacts)).toBe('Full Name,Email\n"John Doe","john@example.com"\n"Jane Smith",""');
|
||||
});
|
||||
|
||||
// BUG: the header is built from the first contact only, so fields that only
|
||||
// later contacts have are silently dropped from the export. Remove `.failing`
|
||||
// once toCSV builds the header from all contacts.
|
||||
test.failing("should not drop fields that only later contacts have", () => {
|
||||
test("should not drop fields that only later contacts have", () => {
|
||||
const contacts = [{ "Full Name": "John Doe" }, { "Full Name": "Jane Smith", Email: "j@x.com" }];
|
||||
|
||||
expect(toCSV(contacts)).toContain("j@x.com");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/vips";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { afterEach, beforeEach, expect, test, describe } from "bun:test";
|
||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/vtracer";
|
||||
import { captureConsole, createMockExecFile } from "./helpers/converters";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { convert } from "../../src/converters/xelatex";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
import { createMockExecFile } from "./helpers/converters";
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { test, expect, beforeEach, afterEach } from "bun:test";
|
||||
import { Database } from "bun:sqlite";
|
||||
import { unlinkSync, existsSync } from "node:fs";
|
||||
import { afterEach, beforeEach, expect, test } from "bun:test";
|
||||
import { existsSync, unlinkSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
const testRoot = process.env.CONVERTX_TEST_ROOT;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { test, expect } from "bun:test";
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { normalizeFiletype, normalizeOutputFiletype } from "../../src/helpers/normalizeFiletype";
|
||||
|
||||
test("normalizeFiletype maps known inputs", () => {
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { scheduleDelayed } from "../../src/helpers/scheduleDelayed";
|
||||
|
||||
/** Largest delay setTimeout accepts before a 32-bit overflow. */
|
||||
const MAX_TIMEOUT_DELAY_MS = 2 ** 31 - 1;
|
||||
/** Delay reported in the TimeoutOverflowWarning: 30 days in milliseconds. */
|
||||
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
||||
|
||||
type ArmedTimer = {
|
||||
delayMs: number;
|
||||
fire: () => void;
|
||||
};
|
||||
|
||||
function captureTimers(): {
|
||||
armed: ArmedTimer[];
|
||||
armTimer: (callback: () => void, delayMs: number) => ReturnType<typeof setTimeout>;
|
||||
} {
|
||||
const armed: ArmedTimer[] = [];
|
||||
const armTimer = (callback: () => void, delayMs: number) => {
|
||||
armed.push({ delayMs, fire: callback });
|
||||
return 0 as unknown as ReturnType<typeof setTimeout>;
|
||||
};
|
||||
return { armed, armTimer };
|
||||
}
|
||||
|
||||
test("runs a one day delay as a single timer", () => {
|
||||
const { armed, armTimer } = captureTimers();
|
||||
let runs = 0;
|
||||
const oneDayMs = 24 * 60 * 60 * 1000;
|
||||
|
||||
scheduleDelayed(
|
||||
oneDayMs,
|
||||
() => {
|
||||
runs += 1;
|
||||
},
|
||||
armTimer,
|
||||
);
|
||||
|
||||
expect(armed).toHaveLength(1);
|
||||
const timer = armed.shift();
|
||||
expect(timer?.delayMs).toBe(oneDayMs);
|
||||
expect(runs).toBe(0);
|
||||
|
||||
timer?.fire();
|
||||
expect(runs).toBe(1);
|
||||
expect(armed).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("runs a 30 day delay in timer-sized chunks that add up to 30 days", () => {
|
||||
expect(THIRTY_DAYS_MS).toBe(2_592_000_000);
|
||||
|
||||
const { armed, armTimer } = captureTimers();
|
||||
let runs = 0;
|
||||
scheduleDelayed(
|
||||
THIRTY_DAYS_MS,
|
||||
() => {
|
||||
runs += 1;
|
||||
},
|
||||
armTimer,
|
||||
);
|
||||
|
||||
let elapsedMs = 0;
|
||||
let chunks = 0;
|
||||
while (runs === 0) {
|
||||
chunks += 1;
|
||||
expect(chunks).toBeLessThanOrEqual(3);
|
||||
|
||||
const next = armed.shift();
|
||||
if (!next) {
|
||||
throw new Error("timer chain ended before the task ran");
|
||||
}
|
||||
|
||||
expect(next.delayMs).toBeGreaterThan(0);
|
||||
expect(next.delayMs).toBeLessThanOrEqual(MAX_TIMEOUT_DELAY_MS);
|
||||
elapsedMs += next.delayMs;
|
||||
next.fire();
|
||||
}
|
||||
|
||||
expect(runs).toBe(1);
|
||||
expect(elapsedMs).toBe(THIRTY_DAYS_MS);
|
||||
expect(armed).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("cancelling before the first chunk fires prevents the task", () => {
|
||||
const { armed, armTimer } = captureTimers();
|
||||
let runs = 0;
|
||||
const scheduled = scheduleDelayed(
|
||||
THIRTY_DAYS_MS,
|
||||
() => {
|
||||
runs += 1;
|
||||
},
|
||||
armTimer,
|
||||
);
|
||||
|
||||
scheduled.cancel();
|
||||
armed.shift()?.fire();
|
||||
expect(runs).toBe(0);
|
||||
expect(armed).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("cancelling after a chunk fired still stops the remaining chain", () => {
|
||||
const { armed, armTimer } = captureTimers();
|
||||
let runs = 0;
|
||||
const scheduled = scheduleDelayed(
|
||||
THIRTY_DAYS_MS,
|
||||
() => {
|
||||
runs += 1;
|
||||
},
|
||||
armTimer,
|
||||
);
|
||||
|
||||
armed.shift()?.fire();
|
||||
expect(armed).toHaveLength(1);
|
||||
expect(runs).toBe(0);
|
||||
|
||||
scheduled.cancel();
|
||||
armed.shift()?.fire();
|
||||
expect(runs).toBe(0);
|
||||
expect(armed).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("does not emit a timeout overflow warning for a 30 day delay", async () => {
|
||||
const warnings: string[] = [];
|
||||
const onWarning = (warning: Error) => {
|
||||
warnings.push(warning.message);
|
||||
};
|
||||
process.on("warning", onWarning);
|
||||
|
||||
let ran = false;
|
||||
const scheduled = scheduleDelayed(THIRTY_DAYS_MS, () => {
|
||||
ran = true;
|
||||
});
|
||||
|
||||
try {
|
||||
await new Promise((resolve) => setTimeout(resolve, 40));
|
||||
expect(ran).toBe(false);
|
||||
expect(warnings.join("\n")).not.toContain("TimeoutOverflowWarning");
|
||||
expect(warnings.join("\n")).not.toContain("2592000000");
|
||||
} finally {
|
||||
scheduled.cancel();
|
||||
process.off("warning", onWarning);
|
||||
}
|
||||
});
|
||||
@@ -1,5 +1,7 @@
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
import { Elysia } from "elysia";
|
||||
|
||||
import { isHtmlPageRequest } from "../../src/helpers/isHtmlPageRequest";
|
||||
import { userService } from "../../src/services/user";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
|
||||
import { request } from "./helpers/app";
|
||||
|
||||
async function conversionsFor(fileType: string) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { mkdirSync } from "node:fs";
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
|
||||
import { createJob, createUser, db, jobDirs, request, waitFor } from "./helpers/app";
|
||||
|
||||
type JobRow = { status: string; num_files: number };
|
||||
@@ -154,10 +155,7 @@ describe("POST /convert", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
// BUG: file_names is parsed and indexed before it is validated, so a value that is not a
|
||||
// JSON array ends in a 500 instead of the redirect used for every other invalid input.
|
||||
// Remove `.failing` once convert.tsx validates the parsed value first.
|
||||
test.failing.each([
|
||||
test.each([
|
||||
["is not JSON", "not json"],
|
||||
["is a JSON string", '"a.vcf"'],
|
||||
])("redirects home when file_names %s", async (_, fileNames) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
||||
|
||||
import { createJob, createUser, jobDirs, request, uploadsDir } from "./helpers/app";
|
||||
|
||||
async function userWithUploads(...fileNames: string[]) {
|
||||
@@ -79,11 +80,7 @@ describe("POST /delete", () => {
|
||||
expect(existsSync(`${other.dirs.uploads}keep.txt`)).toBe(true);
|
||||
});
|
||||
|
||||
// BUG: unlink errors are not handled, so deleting a file that does not exist answers
|
||||
// with a 500 whose body contains the absolute upload path on the server. This also
|
||||
// happens for every sanitized traversal attempt. Remove `.failing` once deleteFile.tsx
|
||||
// handles the missing file.
|
||||
test.failing.each(["missing.txt", "../../1/1/keep.txt"])(
|
||||
test.each(["missing.txt", "../../1/1/keep.txt"])(
|
||||
"answers a missing file (%s) without a server error or server paths",
|
||||
async (filename) => {
|
||||
const { user, job } = await userWithUploads();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
||||
|
||||
import { createJob, createUser, db, jobDirs, request } from "./helpers/app";
|
||||
|
||||
async function userWithJobs(count = 1) {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import * as tar from "tar";
|
||||
import { mkdirSync, writeFileSync } from "node:fs";
|
||||
|
||||
import { createJob, createUser, jobDirs, request } from "./helpers/app";
|
||||
|
||||
async function userWithOutputs(files: Record<string, string>) {
|
||||
async function userWithOutputs(files: Record<string, string | Uint8Array>) {
|
||||
const user = await createUser();
|
||||
const job = createJob(user.id);
|
||||
const dirs = jobDirs(user.id, job);
|
||||
@@ -17,16 +15,8 @@ async function userWithOutputs(files: Record<string, string>) {
|
||||
}
|
||||
|
||||
async function tarEntries(response: Response) {
|
||||
const dir = mkdtempSync(join(tmpdir(), "convertx-archive-"));
|
||||
try {
|
||||
const file = join(dir, "archive.tar");
|
||||
writeFileSync(file, Buffer.from(await response.arrayBuffer()));
|
||||
const entries: string[] = [];
|
||||
await tar.list({ file, onReadEntry: (entry) => entries.push(entry.path) });
|
||||
return entries.sort();
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
const archive = new Bun.Archive(await response.arrayBuffer());
|
||||
return [...(await archive.files()).keys()].sort();
|
||||
}
|
||||
|
||||
describe("GET /download/:userId/:jobId/:fileName", () => {
|
||||
@@ -111,11 +101,7 @@ describe("GET /download/:userId/:jobId/:fileName", () => {
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
|
||||
// BUG: Elysia already decodes path parameters and download.tsx decodes them a second
|
||||
// time, so file names containing "%" fail with a 500 "URI error" (and a literal "%20"
|
||||
// would be turned into a space). The results page links to such files. Remove
|
||||
// `.failing` once the second decodeURIComponent is dropped.
|
||||
test.failing("serves file names containing a percent sign", async () => {
|
||||
test("serves file names containing a percent sign", async () => {
|
||||
const { user, job } = await userWithOutputs({ "100%.csv": "percent" });
|
||||
|
||||
const response = await request(`/download/${user.id}/${job}/100%25.csv`, {
|
||||
@@ -144,7 +130,18 @@ describe("GET /archive/:jobId", () => {
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get("content-type")).toBe("application/x-tar");
|
||||
expect(await tarEntries(response)).toEqual(["./", "./a.csv", "./b.csv"]);
|
||||
expect(await tarEntries(response)).toEqual(["a.csv", "b.csv"]);
|
||||
});
|
||||
|
||||
test("preserves binary file contents", async () => {
|
||||
const { user, job } = await userWithOutputs({ "image.png": new Uint8Array([0, 1, 2, 255]) });
|
||||
|
||||
const response = await request(`/archive/${job}`, { cookies: { auth: user.token } });
|
||||
const archive = new Bun.Archive(await response.arrayBuffer());
|
||||
const image = (await archive.files()).get("image.png");
|
||||
|
||||
expect(image).toBeDefined();
|
||||
expect(await image?.arrayBuffer()).toEqual(new Uint8Array([0, 1, 2, 255]).buffer);
|
||||
});
|
||||
|
||||
test("does not include earlier archives in a new archive", async () => {
|
||||
@@ -153,7 +150,7 @@ describe("GET /archive/:jobId", () => {
|
||||
await request(`/archive/${job}`, { cookies: { auth: user.token } });
|
||||
const response = await request(`/archive/${job}`, { cookies: { auth: user.token } });
|
||||
|
||||
expect(await tarEntries(response)).toEqual(["./", "./a.csv"]);
|
||||
expect(await tarEntries(response)).toEqual(["a.csv"]);
|
||||
});
|
||||
|
||||
test("refuses another user's job", async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
|
||||
import type { User } from "../../src/db/types";
|
||||
import { db, FIRST_ACCOUNT, firstRun as recordedFirstRun, SECOND_ACCOUNT } from "./helpers/app";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
|
||||
import { request } from "./helpers/app";
|
||||
|
||||
describe("GET /healthcheck", () => {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { mock } from "bun:test";
|
||||
|
||||
import { html } from "@elysiajs/html";
|
||||
import { Elysia } from "elysia";
|
||||
|
||||
import * as realEnvModule from "../../../src/helpers/env";
|
||||
|
||||
if (!process.env.CONVERTX_TEST_ROOT) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { afterEach, describe, expect, test } from "bun:test";
|
||||
|
||||
import { createJob, createUser, request, resetEnv, setEnv } from "./helpers/app";
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
|
||||
import { getAllInputs, getAllTargets } from "../../src/converters/main";
|
||||
import { createUser, request } from "./helpers/app";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { afterEach, describe, expect, test } from "bun:test";
|
||||
|
||||
import { buildDownloadUrl } from "../../src/helpers/buildDownloadUrl";
|
||||
import { createJob, createUser, request, resetEnv, setCookie, setEnv } from "./helpers/app";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { afterEach, describe, expect, test } from "bun:test";
|
||||
|
||||
import {
|
||||
app,
|
||||
createUser,
|
||||
@@ -142,12 +143,7 @@ describe("GET / without accounts (ALLOW_UNAUTHENTICATED)", () => {
|
||||
expect(body).not.toContain('href="/logoff"');
|
||||
});
|
||||
|
||||
// BUG: the ALLOW_UNAUTHENTICATED branch runs before the session check, so every visit
|
||||
// replaces the existing session (even a registered account's) with a new anonymous id
|
||||
// and the user loses access to their previous jobs. This regressed the fix for #114
|
||||
// ("keep unauthenticated user logged in if allowed", bc4ad49) in 538c5b6. Remove
|
||||
// `.failing` once root.tsx verifies an existing session first.
|
||||
test.failing("keeps an existing session", async () => {
|
||||
test("keeps an existing session", async () => {
|
||||
setEnv({ ALLOW_UNAUTHENTICATED: true });
|
||||
const user = await createUser();
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test";
|
||||
import { existsSync, readdirSync } from "node:fs";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
import { createJob, createUser, jobDirs, request } from "./helpers/app";
|
||||
|
||||
function uploadForm(...files: File[]) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { afterEach, describe, expect, test } from "bun:test";
|
||||
|
||||
import type { User } from "../../src/db/types";
|
||||
import {
|
||||
app,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { randomUUID } from "node:crypto";
|
||||
|
||||
import { jwt } from "@elysiajs/jwt";
|
||||
import { Elysia } from "elysia";
|
||||
|
||||
import { WEBROOT } from "../../src/helpers/env";
|
||||
import { userService } from "../../src/services/user";
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
"noEmit": false,
|
||||
"composite": true,
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "@kitajs/html",
|
||||
|
||||
Reference in New Issue
Block a user