diff --git a/bunfig.toml b/bunfig.toml deleted file mode 100644 index 0614006..0000000 --- a/bunfig.toml +++ /dev/null @@ -1,7 +0,0 @@ -[test] -preload = [ - "./testSetup.ts", - "./src/mocks/consumet.ts", - "./src/mocks/getGoogleAuthToken.ts", - "./src/mocks/cloudflare.ts", -] diff --git a/package.json b/package.json index 232fe34..ff4a662 100644 --- a/package.json +++ b/package.json @@ -5,17 +5,15 @@ "main": "src/index.ts", "type": "module", "scripts": { - "dev:cloudflare": "wrangler dev src/index.ts --port 8080", - "dev:server": "TURSO_URL=http://127.0.0.1:3000 TURSO_AUTH_TOKEN=123 bun run --watch src/index.ts", - "prod:server": "bun run src/index.ts", + "dev": "wrangler dev src/index.ts --port 8080", "deploy": "wrangler deploy --minify src/index.ts", - "env:generate": "bun src/scripts/generateEnv.ts", - "env:verify": "bun src/scripts/verifyEnv.ts", + "env:generate": "tsx src/scripts/generateEnv.ts", + "env:verify": "tsx src/scripts/verifyEnv.ts", "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate", - "test": "bun src/testRunner.ts", - "prepare": "husky", - "tsx": "tsx" + "test": "vitest", + "coverage": "vitest run --coverage", + "prepare": "husky" }, "dependencies": { "@consumet/extensions": "github:consumet/consumet.ts#3dd0ccb", @@ -43,11 +41,10 @@ "@cloudflare/vitest-pool-workers": "^0.10.7", "@cloudflare/workers-types": "^4.20250423.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@types/bun": "^1.2.10", "@types/lodash.isequal": "^4.5.8", "@types/lodash.mapkeys": "^4.6.9", "@types/luxon": "^3.6.2", - "@types/node": "^24.10.1", + "@types/node": "^22.10.1", "@types/pngjs": "^6.0.5", "@vitest/coverage-v8": "^3.2.4", "@vitest/runner": "^3.2.4", @@ -60,13 +57,13 @@ "husky": "^9.1.7", "lint-staged": "^15.5.1", "miniflare": "^4.20251109.1", - "msw": "2.4.3", "prettier": "^3.5.3", "prettier-plugin-toml": "^2.0.4", "ts-morph": "^22.0.0", - "tsx": "^4.20.6", + "tsx": "^4.19.2", "typescript": "^5.8.3", "util": "^0.12.5", + "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.2.4", "wrangler": "^4.51.0", "zx": "8.1.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 35273d0..20259df 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -75,16 +75,13 @@ importers: version: 1.15.0(graphql@16.12.0)(typescript@5.9.3) "@cloudflare/vitest-pool-workers": specifier: ^0.10.7 - version: 0.10.7(@cloudflare/workers-types@4.20251014.0)(@vitest/runner@3.2.4)(@vitest/snapshot@3.2.4)(vitest@3.2.4(@types/node@24.10.1)(msw@2.4.3(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 0.10.7(@cloudflare/workers-types@4.20251014.0)(@vitest/runner@3.2.4)(@vitest/snapshot@3.2.4)(vitest@3.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) "@cloudflare/workers-types": specifier: ^4.20250423.0 version: 4.20251014.0 "@trivago/prettier-plugin-sort-imports": specifier: ^4.3.0 version: 4.3.0(prettier@3.6.2) - "@types/bun": - specifier: ^1.2.10 - version: 1.3.1(@types/react@19.2.2) "@types/lodash.isequal": specifier: ^4.5.8 version: 4.5.8 @@ -95,14 +92,14 @@ importers: specifier: ^3.6.2 version: 3.7.1 "@types/node": - specifier: ^24.10.1 - version: 24.10.1 + specifier: ^22.10.1 + version: 22.18.13 "@types/pngjs": specifier: ^6.0.5 version: 6.0.5 "@vitest/coverage-v8": specifier: ^3.2.4 - version: 3.2.4(vitest@3.2.4(@types/node@24.10.1)(msw@2.4.3(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 3.2.4(vitest@3.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) "@vitest/runner": specifier: ^3.2.4 version: 3.2.4 @@ -133,9 +130,6 @@ importers: miniflare: specifier: ^4.20251109.1 version: 4.20251109.1 - msw: - specifier: 2.4.3 - version: 2.4.3(typescript@5.9.3) prettier: specifier: ^3.5.3 version: 3.6.2 @@ -146,7 +140,7 @@ importers: specifier: ^22.0.0 version: 22.0.0 tsx: - specifier: ^4.20.6 + specifier: ^4.19.2 version: 4.20.6 typescript: specifier: ^5.8.3 @@ -154,9 +148,12 @@ importers: util: specifier: ^0.12.5 version: 0.12.5 + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.9.3)(vite@7.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.10.1)(msw@2.4.3(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + version: 3.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) wrangler: specifier: ^4.51.0 version: 4.51.0(@cloudflare/workers-types@4.20251014.0) @@ -306,24 +303,6 @@ packages: } engines: { node: ">=18" } - "@bundled-es-modules/cookie@2.0.1": - resolution: - { - integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==, - } - - "@bundled-es-modules/statuses@1.0.1": - resolution: - { - integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==, - } - - "@bundled-es-modules/tough-cookie@0.1.6": - resolution: - { - integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==, - } - "@cloudflare/kv-asset-handler@0.4.0": resolution: { @@ -1723,41 +1702,6 @@ packages: cpu: [x64] os: [win32] - "@inquirer/confirm@3.2.0": - resolution: - { - integrity: sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw==, - } - engines: { node: ">=18" } - - "@inquirer/core@9.2.1": - resolution: - { - integrity: sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==, - } - engines: { node: ">=18" } - - "@inquirer/figures@1.0.14": - resolution: - { - integrity: sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==, - } - engines: { node: ">=18" } - - "@inquirer/type@1.5.5": - resolution: - { - integrity: sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==, - } - engines: { node: ">=18" } - - "@inquirer/type@2.0.0": - resolution: - { - integrity: sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==, - } - engines: { node: ">=18" } - "@isaacs/cliui@8.0.2": resolution: { @@ -1912,13 +1856,6 @@ packages: cpu: [x64] os: [win32] - "@mswjs/interceptors@0.29.1": - resolution: - { - integrity: sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==, - } - engines: { node: ">=18" } - "@neon-rs/load@0.0.4": resolution: { @@ -1946,24 +1883,6 @@ packages: } engines: { node: ">= 8" } - "@open-draft/deferred-promise@2.2.0": - resolution: - { - integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==, - } - - "@open-draft/logger@0.3.0": - resolution: - { - integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==, - } - - "@open-draft/until@2.1.0": - resolution: - { - integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==, - } - "@pkgjs/parseargs@0.11.0": resolution: { @@ -2214,24 +2133,12 @@ packages: integrity: sha512-m7Lllj9n/S6sOkCkRftpM7L24uvmfXQFedlW/4hENcuJH1HHm9u5EgxZb9uVjQSCGrbBWBkOGgcTxNg36r6ywA==, } - "@types/bun@1.3.1": - resolution: - { - integrity: sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ==, - } - "@types/chai@5.2.3": resolution: { integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==, } - "@types/cookie@0.6.0": - resolution: - { - integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==, - } - "@types/deep-eql@4.0.2": resolution: { @@ -2280,12 +2187,6 @@ packages: integrity: sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==, } - "@types/mute-stream@0.0.4": - resolution: - { - integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==, - } - "@types/node-fetch@2.6.13": resolution: { @@ -2304,18 +2205,6 @@ packages: integrity: sha512-Bo45YKIjnmFtv6I1TuC8AaHBbqXtIo+Om5fE4QiU1Tj8QR/qt+8O3BAtOimG5IFmwaWiPmB3Mv3jtYzBA4Us2A==, } - "@types/node@24.10.1": - resolution: - { - integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==, - } - - "@types/node@24.9.2": - resolution: - { - integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==, - } - "@types/pngjs@6.0.5": resolution: { @@ -2328,24 +2217,6 @@ packages: integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==, } - "@types/statuses@2.0.6": - resolution: - { - integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==, - } - - "@types/tough-cookie@4.0.5": - resolution: - { - integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==, - } - - "@types/wrap-ansi@3.0.0": - resolution: - { - integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==, - } - "@types/ws@8.18.1": resolution: { @@ -2500,13 +2371,6 @@ packages: } engines: { node: ">= 8.0.0" } - ansi-escapes@4.3.2: - resolution: - { - integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==, - } - engines: { node: ">=8" } - ansi-escapes@7.1.1: resolution: { @@ -2678,13 +2542,6 @@ packages: } engines: { node: ">=18" } - chalk@4.1.2: - resolution: - { - integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, - } - engines: { node: ">=10" } - chalk@5.6.2: resolution: { @@ -2732,20 +2589,6 @@ packages: } engines: { node: ">=18" } - cli-width@4.1.0: - resolution: - { - integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==, - } - engines: { node: ">= 12" } - - cliui@8.0.1: - resolution: - { - integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==, - } - engines: { node: ">=12" } - cloudflare@5.2.0: resolution: { @@ -2810,13 +2653,6 @@ packages: integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, } - cookie@0.7.2: - resolution: - { - integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==, - } - engines: { node: ">= 0.6" } - cookie@1.0.2: resolution: { @@ -3201,13 +3037,6 @@ packages: engines: { node: ">=18" } hasBin: true - escalade@3.2.0: - resolution: - { - integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, - } - engines: { node: ">=6" } - estree-walker@3.0.3: resolution: { @@ -3374,13 +3203,6 @@ packages: } engines: { node: ">= 0.4" } - get-caller-file@2.0.5: - resolution: - { - integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, - } - engines: { node: 6.* || 8.* || >= 10.* } - get-east-asian-width@1.4.0: resolution: { @@ -3442,6 +3264,12 @@ packages: } engines: { node: ">=4" } + globrex@0.1.2: + resolution: + { + integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==, + } + gopd@1.2.0: resolution: { @@ -3523,12 +3351,6 @@ packages: } engines: { node: ">= 0.4" } - headers-polyfill@4.0.3: - resolution: - { - integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==, - } - hono@4.10.4: resolution: { @@ -3651,12 +3473,6 @@ packages: } engines: { node: ">=0.10.0" } - is-node-process@1.2.0: - resolution: - { - integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==, - } - is-number@7.0.0: resolution: { @@ -4004,26 +3820,6 @@ packages: integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, } - msw@2.4.3: - resolution: - { - integrity: sha512-PXK3wOQHwDtz6JYVyAVlQtzrLr6bOAJxggw5UHm3CId79+W7238aNBD1zJVkFY53o/DMacuIfgesW2nv9yCO3Q==, - } - engines: { node: ">=18" } - hasBin: true - peerDependencies: - typescript: ">= 4.8.x" - peerDependenciesMeta: - typescript: - optional: true - - mute-stream@1.0.0: - resolution: - { - integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==, - } - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } - nanoid@3.3.11: resolution: { @@ -4092,12 +3888,6 @@ packages: integrity: sha512-jaL+HgTq2Gj5jRcfdutgRGLosCy/hT8sQf6VOy+P+g36cZOjI1iukdPnijC+4CmeRzg/jEllJUboEic2FhxhtQ==, } - outvariant@1.4.3: - resolution: - { - integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==, - } - package-json-from-dist@1.0.1: resolution: { @@ -4240,44 +4030,12 @@ packages: integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==, } - psl@1.15.0: - resolution: - { - integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==, - } - - punycode@2.3.1: - resolution: - { - integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, - } - engines: { node: ">=6" } - - querystringify@2.2.0: - resolution: - { - integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==, - } - queue-microtask@1.2.3: resolution: { integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, } - require-directory@2.1.1: - resolution: - { - integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, - } - engines: { node: ">=0.10.0" } - - requires-port@1.0.0: - resolution: - { - integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==, - } - resolve-pkg-maps@1.0.0: resolution: { @@ -4439,13 +4197,6 @@ packages: integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==, } - statuses@2.0.2: - resolution: - { - integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==, - } - engines: { node: ">= 0.8" } - std-env@3.10.0: resolution: { @@ -4459,12 +4210,6 @@ packages: } engines: { node: ">=4", npm: ">=6" } - strict-event-emitter@0.5.1: - resolution: - { - integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==, - } - string-argv@0.3.2: resolution: { @@ -4603,13 +4348,6 @@ packages: } engines: { node: ">=8.0" } - tough-cookie@4.1.4: - resolution: - { - integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==, - } - engines: { node: ">=6" } - tr46@0.0.3: resolution: { @@ -4622,6 +4360,19 @@ packages: integrity: sha512-M9MqFGZREyeb5fTl6gNHKZLqBQA0TjA1lea+CR48R8EBTDuWrNqW6ccC5QvjNR4s6wDumD3LTCjOFSp9iwlzaw==, } + tsconfck@3.1.6: + resolution: + { + integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==, + } + engines: { node: ^18 || >=20 } + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + tslib@2.8.1: resolution: { @@ -4636,20 +4387,6 @@ packages: engines: { node: ">=18.0.0" } hasBin: true - type-fest@0.21.3: - resolution: - { - integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==, - } - engines: { node: ">=10" } - - type-fest@4.41.0: - resolution: - { - integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==, - } - engines: { node: ">=16" } - typescript@5.9.3: resolution: { @@ -4670,12 +4407,6 @@ packages: integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==, } - undici-types@7.16.0: - resolution: - { - integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==, - } - undici@7.14.0: resolution: { @@ -4696,19 +4427,6 @@ packages: integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==, } - universalify@0.2.0: - resolution: - { - integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==, - } - engines: { node: ">= 4.0.0" } - - url-parse@1.5.10: - resolution: - { - integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==, - } - urlpattern-polyfill@10.1.0: resolution: { @@ -4736,6 +4454,17 @@ packages: engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 } hasBin: true + vite-tsconfig-paths@5.1.4: + resolution: + { + integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==, + } + peerDependencies: + vite: "*" + peerDependenciesMeta: + vite: + optional: true + vite@7.2.4: resolution: { @@ -4916,13 +4645,6 @@ packages: "@cloudflare/workers-types": optional: true - wrap-ansi@6.2.0: - resolution: - { - integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==, - } - engines: { node: ">=8" } - wrap-ansi@7.0.0: resolution: { @@ -4974,13 +4696,6 @@ packages: utf-8-validate: optional: true - y18n@5.0.8: - resolution: - { - integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, - } - engines: { node: ">=10" } - yaml@2.8.1: resolution: { @@ -4989,27 +4704,6 @@ packages: engines: { node: ">= 14.6" } hasBin: true - yargs-parser@21.1.1: - resolution: - { - integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, - } - engines: { node: ">=12" } - - yargs@17.7.2: - resolution: - { - integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==, - } - engines: { node: ">=12" } - - yoctocolors-cjs@2.1.3: - resolution: - { - integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==, - } - engines: { node: ">=18" } - youch-core@0.3.3: resolution: { @@ -5141,19 +4835,6 @@ snapshots: "@bcoe/v8-coverage@1.0.2": {} - "@bundled-es-modules/cookie@2.0.1": - dependencies: - cookie: 0.7.2 - - "@bundled-es-modules/statuses@1.0.1": - dependencies: - statuses: 2.0.2 - - "@bundled-es-modules/tough-cookie@0.1.6": - dependencies: - "@types/tough-cookie": 4.0.5 - tough-cookie: 4.1.4 - "@cloudflare/kv-asset-handler@0.4.0": dependencies: mime: 3.0.0 @@ -5174,7 +4855,7 @@ snapshots: optionalDependencies: workerd: 1.20251125.0 - "@cloudflare/vitest-pool-workers@0.10.7(@cloudflare/workers-types@4.20251014.0)(@vitest/runner@3.2.4)(@vitest/snapshot@3.2.4)(vitest@3.2.4(@types/node@24.10.1)(msw@2.4.3(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))": + "@cloudflare/vitest-pool-workers@0.10.7(@cloudflare/workers-types@4.20251014.0)(@vitest/runner@3.2.4)(@vitest/snapshot@3.2.4)(vitest@3.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))": dependencies: "@vitest/runner": 3.2.4 "@vitest/snapshot": 3.2.4 @@ -5183,7 +4864,7 @@ snapshots: devalue: 5.5.0 miniflare: 4.20251109.1 semver: 7.7.3 - vitest: 3.2.4(@types/node@24.10.1)(msw@2.4.3(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vitest: 3.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) wrangler: 4.48.0(@cloudflare/workers-types@4.20251014.0) zod: 3.25.76 transitivePeerDependencies: @@ -5736,36 +5417,6 @@ snapshots: "@img/sharp-win32-x64@0.33.5": optional: true - "@inquirer/confirm@3.2.0": - dependencies: - "@inquirer/core": 9.2.1 - "@inquirer/type": 1.5.5 - - "@inquirer/core@9.2.1": - dependencies: - "@inquirer/figures": 1.0.14 - "@inquirer/type": 2.0.0 - "@types/mute-stream": 0.0.4 - "@types/node": 22.18.13 - "@types/wrap-ansi": 3.0.0 - ansi-escapes: 4.3.2 - cli-width: 4.1.0 - mute-stream: 1.0.0 - signal-exit: 4.1.0 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.3 - - "@inquirer/figures@1.0.14": {} - - "@inquirer/type@1.5.5": - dependencies: - mute-stream: 1.0.0 - - "@inquirer/type@2.0.0": - dependencies: - mute-stream: 1.0.0 - "@isaacs/cliui@8.0.2": dependencies: string-width: 5.1.2 @@ -5869,15 +5520,6 @@ snapshots: "@libsql/win32-x64-msvc@0.5.22": optional: true - "@mswjs/interceptors@0.29.1": - dependencies: - "@open-draft/deferred-promise": 2.2.0 - "@open-draft/logger": 0.3.0 - "@open-draft/until": 2.1.0 - is-node-process: 1.2.0 - outvariant: 1.4.3 - strict-event-emitter: 0.5.1 - "@neon-rs/load@0.0.4": optional: true @@ -5893,15 +5535,6 @@ snapshots: "@nodelib/fs.scandir": 2.1.5 fastq: 1.19.1 - "@open-draft/deferred-promise@2.2.0": {} - - "@open-draft/logger@0.3.0": - dependencies: - is-node-process: 1.2.0 - outvariant: 1.4.3 - - "@open-draft/until@2.1.0": {} - "@pkgjs/parseargs@0.11.0": optional: true @@ -6014,19 +5647,11 @@ snapshots: mkdirp: 3.0.1 path-browserify: 1.0.1 - "@types/bun@1.3.1(@types/react@19.2.2)": - dependencies: - bun-types: 1.3.1(@types/react@19.2.2) - transitivePeerDependencies: - - "@types/react" - "@types/chai@5.2.3": dependencies: "@types/deep-eql": 4.0.2 assertion-error: 2.0.1 - "@types/cookie@0.6.0": {} - "@types/deep-eql@4.0.2": {} "@types/estree@1.0.8": {} @@ -6034,12 +5659,12 @@ snapshots: "@types/fs-extra@11.0.4": dependencies: "@types/jsonfile": 6.1.4 - "@types/node": 24.10.1 + "@types/node": 22.18.13 optional: true "@types/jsonfile@6.1.4": dependencies: - "@types/node": 24.10.1 + "@types/node": 22.18.13 optional: true "@types/lodash.isequal@4.5.8": @@ -6054,13 +5679,9 @@ snapshots: "@types/luxon@3.7.1": {} - "@types/mute-stream@0.0.4": - dependencies: - "@types/node": 24.10.1 - "@types/node-fetch@2.6.13": dependencies: - "@types/node": 24.10.1 + "@types/node": 22.18.13 form-data: 4.0.4 "@types/node@18.19.130": @@ -6071,35 +5692,21 @@ snapshots: dependencies: undici-types: 6.21.0 - "@types/node@24.10.1": - dependencies: - undici-types: 7.16.0 - - "@types/node@24.9.2": - dependencies: - undici-types: 7.16.0 - optional: true - "@types/pngjs@6.0.5": dependencies: - "@types/node": 24.10.1 + "@types/node": 22.18.13 "@types/react@19.2.2": dependencies: csstype: 3.2.3 - - "@types/statuses@2.0.6": {} - - "@types/tough-cookie@4.0.5": {} - - "@types/wrap-ansi@3.0.0": {} + optional: true "@types/ws@8.18.1": dependencies: - "@types/node": 24.9.2 + "@types/node": 22.18.13 optional: true - "@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@24.10.1)(msw@2.4.3(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))": + "@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))": dependencies: "@ampproject/remapping": 2.3.0 "@bcoe/v8-coverage": 1.0.2 @@ -6114,7 +5721,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@24.10.1)(msw@2.4.3(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vitest: 3.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -6126,14 +5733,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - "@vitest/mocker@3.2.4(msw@2.4.3(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))": + "@vitest/mocker@3.2.4(vite@7.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))": dependencies: "@vitest/spy": 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.4.3(typescript@5.9.3) - vite: 7.2.4(@types/node@24.10.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) "@vitest/pretty-format@3.2.4": dependencies: @@ -6211,10 +5817,6 @@ snapshots: dependencies: humanize-ms: 1.2.1 - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - ansi-escapes@7.1.1: dependencies: environment: 1.1.0 @@ -6277,8 +5879,9 @@ snapshots: bun-types@1.3.1(@types/react@19.2.2): dependencies: - "@types/node": 24.10.1 + "@types/node": 22.18.13 "@types/react": 19.2.2 + optional: true cac@6.7.14: {} @@ -6307,11 +5910,6 @@ snapshots: loupe: 3.2.1 pathval: 2.0.1 - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - chalk@5.6.2: {} check-error@2.1.1: {} @@ -6350,14 +5948,6 @@ snapshots: slice-ansi: 5.0.0 string-width: 7.2.0 - cli-width@4.1.0: {} - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - cloudflare@5.2.0: dependencies: "@types/node": 18.19.130 @@ -6399,8 +5989,6 @@ snapshots: commander@2.20.3: optional: true - cookie@0.7.2: {} - cookie@1.0.2: {} cross-inspect@1.0.1: @@ -6425,7 +6013,8 @@ snapshots: css-what@6.2.2: {} - csstype@3.2.3: {} + csstype@3.2.3: + optional: true data-uri-to-buffer@4.0.1: optional: true @@ -6652,8 +6241,6 @@ snapshots: "@esbuild/win32-ia32": 0.27.0 "@esbuild/win32-x64": 0.27.0 - escalade@3.2.0: {} - estree-walker@3.0.3: dependencies: "@types/estree": 1.0.8 @@ -6755,8 +6342,6 @@ snapshots: generator-function@2.0.1: {} - get-caller-file@2.0.5: {} - get-east-asian-width@1.4.0: {} get-intrinsic@1.3.0: @@ -6800,6 +6385,8 @@ snapshots: globals@11.12.0: {} + globrex@0.1.2: {} + gopd@1.2.0: {} gql.tada@1.8.13(graphql@16.12.0)(typescript@5.9.3): @@ -6861,8 +6448,6 @@ snapshots: dependencies: function-bind: 1.1.2 - headers-polyfill@4.0.3: {} - hono@4.10.4: {} html-escaper@2.0.2: {} @@ -6926,8 +6511,6 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-node-process@1.2.0: {} - is-number@7.0.0: {} is-regex@1.2.1: @@ -7149,30 +6732,6 @@ snapshots: ms@2.1.3: {} - msw@2.4.3(typescript@5.9.3): - dependencies: - "@bundled-es-modules/cookie": 2.0.1 - "@bundled-es-modules/statuses": 1.0.1 - "@bundled-es-modules/tough-cookie": 0.1.6 - "@inquirer/confirm": 3.2.0 - "@mswjs/interceptors": 0.29.1 - "@open-draft/until": 2.1.0 - "@types/cookie": 0.6.0 - "@types/statuses": 2.0.6 - chalk: 4.1.2 - graphql: 16.12.0 - headers-polyfill: 4.0.3 - is-node-process: 1.2.0 - outvariant: 1.4.3 - path-to-regexp: 6.3.0 - strict-event-emitter: 0.5.1 - type-fest: 4.41.0 - yargs: 17.7.2 - optionalDependencies: - typescript: 5.9.3 - - mute-stream@1.0.0: {} - nanoid@3.3.11: {} node-domexception@1.0.0: {} @@ -7208,8 +6767,6 @@ snapshots: dependencies: yaml: 2.8.1 - outvariant@1.4.3: {} - package-json-from-dist@1.0.1: {} parse5-htmlparser2-tree-adapter@7.1.0: @@ -7270,20 +6827,8 @@ snapshots: promise-limit@2.7.0: optional: true - psl@1.15.0: - dependencies: - punycode: 2.3.1 - - punycode@2.3.1: {} - - querystringify@2.2.0: {} - queue-microtask@1.2.3: {} - require-directory@2.1.1: {} - - requires-port@1.0.0: {} - resolve-pkg-maps@1.0.0: {} restore-cursor@5.1.0: @@ -7411,14 +6956,10 @@ snapshots: stackback@0.0.2: {} - statuses@2.0.2: {} - std-env@3.10.0: {} stoppable@1.1.0: {} - strict-event-emitter@0.5.1: {} - string-argv@0.3.2: {} string-width@4.2.3: @@ -7494,13 +7035,6 @@ snapshots: dependencies: is-number: 7.0.0 - tough-cookie@4.1.4: - dependencies: - psl: 1.15.0 - punycode: 2.3.1 - universalify: 0.2.0 - url-parse: 1.5.10 - tr46@0.0.3: {} ts-morph@22.0.0: @@ -7508,27 +7042,25 @@ snapshots: "@ts-morph/common": 0.23.0 code-block-writer: 13.0.3 + tsconfck@3.1.6(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + tslib@2.8.1: {} tsx@4.20.6: dependencies: - esbuild: 0.25.4 + esbuild: 0.25.12 get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 - type-fest@0.21.3: {} - - type-fest@4.41.0: {} - typescript@5.9.3: {} undici-types@5.26.5: {} undici-types@6.21.0: {} - undici-types@7.16.0: {} - undici@7.14.0: {} undici@7.16.0: {} @@ -7537,13 +7069,6 @@ snapshots: dependencies: pathe: 2.0.3 - universalify@0.2.0: {} - - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - urlpattern-polyfill@10.1.0: {} util@0.12.5: @@ -7556,13 +7081,13 @@ snapshots: uuid@9.0.1: {} - vite-node@3.2.4(@types/node@24.10.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): + vite-node@3.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.2.4(@types/node@24.10.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - "@types/node" - jiti @@ -7577,7 +7102,18 @@ snapshots: - tsx - yaml - vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): + vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)): + dependencies: + debug: 4.4.3 + globrex: 0.1.2 + tsconfck: 3.1.6(typescript@5.9.3) + optionalDependencies: + vite: 7.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + - typescript + + vite@7.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -7586,17 +7122,17 @@ snapshots: rollup: 4.53.3 tinyglobby: 0.2.15 optionalDependencies: - "@types/node": 24.10.1 + "@types/node": 22.18.13 fsevents: 2.3.3 terser: 5.44.1 tsx: 4.20.6 yaml: 2.8.1 - vitest@3.2.4(@types/node@24.10.1)(msw@2.4.3(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): + vitest@3.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: "@types/chai": 5.2.3 "@vitest/expect": 3.2.4 - "@vitest/mocker": 3.2.4(msw@2.4.3(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + "@vitest/mocker": 3.2.4(vite@7.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) "@vitest/pretty-format": 3.2.4 "@vitest/runner": 3.2.4 "@vitest/snapshot": 3.2.4 @@ -7614,11 +7150,11 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.2.4(@types/node@24.10.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) - vite-node: 3.2.4(@types/node@24.10.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@22.18.13)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: - "@types/node": 24.10.1 + "@types/node": 22.18.13 transitivePeerDependencies: - jiti - less @@ -7720,12 +7256,6 @@ snapshots: - bufferutil - utf-8-validate - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -7749,24 +7279,8 @@ snapshots: ws@8.18.3: optional: true - y18n@5.0.8: {} - yaml@2.8.1: {} - yargs-parser@21.1.1: {} - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yoctocolors-cjs@2.1.3: {} - youch-core@0.3.3: dependencies: "@poppinss/exception": 1.2.2 @@ -7787,4 +7301,4 @@ snapshots: zx@8.1.5: optionalDependencies: "@types/fs-extra": 11.0.4 - "@types/node": 24.10.1 + "@types/node": 22.18.13 diff --git a/src/index.ts b/src/index.ts index 17ee82f..57cce87 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,7 @@ import { maybeUpdateLastConnectedAt } from "~/middleware/maybeUpdateLastConnecte import type { QueueBody } from "./libs/tasks/queueTask"; -const app = new Hono(); +export const app = new Hono(); app.use(maybeUpdateLastConnectedAt); diff --git a/src/libs/changeStringCase.spec.ts b/src/libs/changeStringCase.spec.ts index b2c25e6..3604bce 100644 --- a/src/libs/changeStringCase.spec.ts +++ b/src/libs/changeStringCase.spec.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from "bun:test"; +import { describe, expect, it } from "vitest"; import { Case, changeStringCase } from "./changeStringCase"; diff --git a/src/libs/fetchFromMultipleSources.spec.ts b/src/libs/fetchFromMultipleSources.spec.ts index decaebc..0a8bcc2 100644 --- a/src/libs/fetchFromMultipleSources.spec.ts +++ b/src/libs/fetchFromMultipleSources.spec.ts @@ -1,10 +1,10 @@ -import { describe, expect, it } from "bun:test"; +import { describe, expect, it } from "vitest"; import { fetchFromMultipleSources } from "./fetchFromMultipleSources"; describe("fetchFromMultipleSources", () => { - it("no promises, throws exception", () => { - expect(() => fetchFromMultipleSources([])).toThrow( + it("no promises, throws exception", async () => { + await expect(fetchFromMultipleSources([])).rejects.toThrow( "fetchPromises cannot be empty", ); }); @@ -30,7 +30,7 @@ describe("fetchFromMultipleSources", () => { () => Promise.resolve(3), ]); - expect(errorOccurred).toBeFalse(); + expect(errorOccurred).toBe(false); }); it("has promises that all throw, returns null", async () => { @@ -48,7 +48,7 @@ describe("fetchFromMultipleSources", () => { () => Promise.reject(new Error("error")), ]); - expect(errorOccurred).toBeTrue(); + expect(errorOccurred).toBe(true); }); it("has promises but cache has value, returns cached value", async () => { @@ -80,7 +80,7 @@ describe("fetchFromMultipleSources", () => { }, ); - expect(errorOccurred).toBeFalse(); + expect(errorOccurred).toBe(false); }); it("has promises, no cached value, no valid response, should not save in cache", async () => { diff --git a/src/libs/gcloud/verifyFcmToken.spec.ts b/src/libs/gcloud/verifyFcmToken.spec.ts index c563a40..3a8737c 100644 --- a/src/libs/gcloud/verifyFcmToken.spec.ts +++ b/src/libs/gcloud/verifyFcmToken.spec.ts @@ -1,12 +1,8 @@ -import { describe, expect, it } from "bun:test"; - -import { server } from "~/mocks"; +import { describe, expect, it } from "vitest"; import type { AdminSdkCredentials } from "./getAdminSdkCredentials"; import { verifyFcmToken } from "./verifyFcmToken"; -server.listen(); - const FAKE_ADMIN_SDK_JSON: AdminSdkCredentials = { type: "service_account", projectId: "test-26g38", @@ -28,14 +24,14 @@ describe("verifyFcmToken", () => { // "7v8sy43aq0re4r8xe7rmr0cn1fsmh6phehnfla2pa73z899zmhyarivmkt4sj6pyv0py43u6p2sim6wz2vg9ypjp9rug1keoth7f6ll3gdvas4q020u3ah51r6bjgn51j6bd92ztmtof3ljpcm8q31njvndy65enm68"; // const res = await verifyFcmToken(token, FAKE_ADMIN_SDK_JSON); - // expect(res).toBeTrue(); + // expect(res).toBe(true); // }); it("invalid token, returns false", async () => { const token = "abc123"; const res = await verifyFcmToken(token, FAKE_ADMIN_SDK_JSON); - expect(res).toBeFalse(); + expect(res).toBe(false); }); it("invalid ADMIN_SDK_JSON, returns false", async () => { @@ -46,6 +42,6 @@ describe("verifyFcmToken", () => { clientEmail: "", }); - expect(res).toBeFalse(); + expect(res).toBe(false); }); }); diff --git a/src/libs/getCurrentAndNextSeason.spec.ts b/src/libs/getCurrentAndNextSeason.spec.ts index 14ffcc3..c5f1f93 100644 --- a/src/libs/getCurrentAndNextSeason.spec.ts +++ b/src/libs/getCurrentAndNextSeason.spec.ts @@ -1,6 +1,5 @@ import { DateTime } from "luxon"; - -import { describe, expect, it } from "bun:test"; +import { describe, expect, it } from "vitest"; import { getCurrentAndNextSeason } from "./getCurrentAndNextSeason"; diff --git a/src/libs/lazy.spec.ts b/src/libs/lazy.spec.ts index 9810047..ae94d2f 100644 --- a/src/libs/lazy.spec.ts +++ b/src/libs/lazy.spec.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from "bun:test"; +import { describe, expect, it } from "vitest"; import { lazy } from "./lazy"; @@ -16,7 +16,7 @@ describe("lazy", () => { return "value"; }); - expect(setValue).toBeFalse(); + expect(setValue).toBe(false); }); it("lazy function called if get is called", () => { @@ -26,7 +26,7 @@ describe("lazy", () => { return "value"; }).get(); - expect(setValue).toBeTrue(); + expect(setValue).toBe(true); }); it("lazy function called only once if get is called multiple times", () => { diff --git a/src/libs/promiseTimeout.spec.ts b/src/libs/promiseTimeout.spec.ts index 56dcd2d..e94f7ed 100644 --- a/src/libs/promiseTimeout.spec.ts +++ b/src/libs/promiseTimeout.spec.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from "bun:test"; +import { describe, expect, it } from "vitest"; import { PromiseTimedOutError, promiseTimeout } from "./promiseTimeout"; diff --git a/src/libs/readEnvVariable.spec.ts b/src/libs/readEnvVariable.spec.ts index 6c3044c..f889987 100644 --- a/src/libs/readEnvVariable.spec.ts +++ b/src/libs/readEnvVariable.spec.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from "bun:test"; +import { describe, expect, it } from "vitest"; import { readEnvVariable } from "./readEnvVariable"; diff --git a/src/libs/sortByProperty.spec.ts b/src/libs/sortByProperty.spec.ts index 6b2686b..0a97927 100644 --- a/src/libs/sortByProperty.spec.ts +++ b/src/libs/sortByProperty.spec.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from "bun:test"; +import { describe, expect, it } from "vitest"; import { sortByProperty } from "./sortByProperty"; diff --git a/src/libs/tasks/delayedTask.spec.ts b/src/libs/tasks/delayedTask.spec.ts index c342555..825f39c 100644 --- a/src/libs/tasks/delayedTask.spec.ts +++ b/src/libs/tasks/delayedTask.spec.ts @@ -1,6 +1,5 @@ import { DateTime } from "luxon"; - -import { beforeEach, describe, expect, it, mock } from "bun:test"; +import { beforeEach, describe, expect, it, mock } from "vitest"; import type { DelayedTaskMetadata } from "./delayedTask"; import { diff --git a/src/libs/tasks/processDelayedTasks.spec.ts b/src/libs/tasks/processDelayedTasks.spec.ts index 1febe14..1e6f14b 100644 --- a/src/libs/tasks/processDelayedTasks.spec.ts +++ b/src/libs/tasks/processDelayedTasks.spec.ts @@ -1,28 +1,28 @@ -import { beforeEach, describe, expect, it, mock } from "bun:test"; +import { type Mock, beforeEach, describe, expect, it, vi } from "vitest"; import { processDelayedTasks } from "./processDelayedTasks"; describe("processDelayedTasks", () => { let mockEnv: Cloudflare.Env; let mockCtx: ExecutionContext; - let kvGetSpy: ReturnType; - let kvDeleteSpy: ReturnType; - let kvPutSpy: ReturnType; - let queueSendSpy: ReturnType; + let kvGetSpy: ReturnType; + let kvDeleteSpy: ReturnType; + let kvPutSpy: ReturnType; + let queueSendSpy: ReturnType; beforeEach(() => { - kvGetSpy = mock(() => Promise.resolve(null)); - kvDeleteSpy = mock(() => Promise.resolve()); - kvPutSpy = mock(() => Promise.resolve()); - queueSendSpy = mock(() => Promise.resolve()); + kvGetSpy = vi.fn(() => Promise.resolve(null)); + kvDeleteSpy = vi.fn(() => Promise.resolve()); + kvPutSpy = vi.fn(() => Promise.resolve()); + queueSendSpy = vi.fn(() => Promise.resolve()); mockEnv = { DELAYED_TASKS: { get: kvGetSpy, delete: kvDeleteSpy, put: kvPutSpy, - list: mock(() => Promise.resolve({ keys: [], list_complete: true })), - getWithMetadata: mock(() => + list: vi.fn(() => Promise.resolve({ keys: [], list_complete: true })), + getWithMetadata: vi.fn(() => Promise.resolve({ value: null, metadata: null }), ), } as any, @@ -30,13 +30,13 @@ describe("processDelayedTasks", () => { send: queueSendSpy, } as any, ANILIST_UPDATES: { - send: mock(() => Promise.resolve()), + send: vi.fn(() => Promise.resolve()), } as any, } as any; mockCtx = { - waitUntil: mock(() => {}), - passThroughOnException: mock(() => {}), + waitUntil: vi.fn(() => {}), + passThroughOnException: vi.fn(() => {}), } as any; }); @@ -61,7 +61,7 @@ describe("processDelayedTasks", () => { retryCount: 0, }; - mockEnv.DELAYED_TASKS.list = mock(() => + mockEnv.DELAYED_TASKS.list = vi.fn(() => Promise.resolve({ keys: [{ name: `delayed-task:${scheduledTime}:task-1` }], list_complete: true, @@ -93,7 +93,7 @@ describe("processDelayedTasks", () => { retryCount: 0, }; - mockEnv.DELAYED_TASKS.list = mock(() => + mockEnv.DELAYED_TASKS.list = vi.fn(() => Promise.resolve({ keys: [{ name: `delayed-task:${scheduledTime}:task-2` }], list_complete: true, @@ -122,7 +122,7 @@ describe("processDelayedTasks", () => { retryCount: 0, }; - mockEnv.DELAYED_TASKS.list = mock(() => + mockEnv.DELAYED_TASKS.list = vi.fn(() => Promise.resolve({ keys: [{ name: `delayed-task:${scheduledTime}:task-3` }], list_complete: true, @@ -141,7 +141,7 @@ describe("processDelayedTasks", () => { }); it("logs alert after 3 failed attempts", async () => { - const consoleErrorSpy = mock(() => {}); + const consoleErrorSpy = vi.fn(() => {}); const originalConsoleError = console.error; console.error = consoleErrorSpy as any; @@ -158,7 +158,7 @@ describe("processDelayedTasks", () => { retryCount: 2, // Will become 3 after this failure }; - mockEnv.DELAYED_TASKS.list = mock(() => + mockEnv.DELAYED_TASKS.list = vi.fn(() => Promise.resolve({ keys: [{ name: `delayed-task:${scheduledTime}:task-4` }], list_complete: true, @@ -202,7 +202,7 @@ describe("processDelayedTasks", () => { retryCount: 0, }; - mockEnv.DELAYED_TASKS.list = mock(() => + mockEnv.DELAYED_TASKS.list = vi.fn(() => Promise.resolve({ keys: [ { name: `delayed-task:${task1Metadata.scheduledEpochTime}:task-1` }, @@ -223,7 +223,7 @@ describe("processDelayedTasks", () => { }); it("skips tasks with null values in KV", async () => { - mockEnv.DELAYED_TASKS.list = mock(() => + mockEnv.DELAYED_TASKS.list = vi.fn(() => Promise.resolve({ keys: [{ name: "delayed-task:123:invalid" }], list_complete: true, diff --git a/src/libs/tasks/queueTask.spec.ts b/src/libs/tasks/queueTask.spec.ts index a623ae1..322a3c0 100644 --- a/src/libs/tasks/queueTask.spec.ts +++ b/src/libs/tasks/queueTask.spec.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, mock, spyOn } from "bun:test"; +import { type Mock, beforeEach, describe, expect, it, spyOn, vi } from "vitest"; import { queueTask } from "./queueTask"; @@ -6,20 +6,20 @@ describe("queueTask - delayed task handling", () => { const MAX_DELAY_SECONDS = 12 * 60 * 60; // 43,200 seconds let mockEnv: Cloudflare.Env; - let kvPutSpy: ReturnType; - let queueSendSpy: ReturnType; + let kvPutSpy: ReturnType; + let queueSendSpy: ReturnType; beforeEach(() => { - kvPutSpy = mock(() => Promise.resolve()); - queueSendSpy = mock(() => Promise.resolve()); + kvPutSpy = vi.fn(() => Promise.resolve()); + queueSendSpy = vi.fn(() => Promise.resolve()); mockEnv = { DELAYED_TASKS: { put: kvPutSpy, - get: mock(() => Promise.resolve(null)), - delete: mock(() => Promise.resolve()), - list: mock(() => Promise.resolve({ keys: [], list_complete: true })), - getWithMetadata: mock(() => + get: vi.fn(() => Promise.resolve(null)), + delete: vi.fn(() => Promise.resolve()), + list: vi.fn(() => Promise.resolve({ keys: [], list_complete: true })), + getWithMetadata: vi.fn(() => Promise.resolve({ value: null, metadata: null }), ), } as any, @@ -27,12 +27,12 @@ describe("queueTask - delayed task handling", () => { send: queueSendSpy, } as any, ANILIST_UPDATES: { - send: mock(() => Promise.resolve()), + send: vi.fn(() => Promise.resolve()), } as any, } as any; // Mock crypto.randomUUID - globalThis.crypto.randomUUID = mock(() => "test-uuid-123"); + globalThis.crypto.randomUUID = vi.fn(() => "test-uuid-123"); }); describe("tasks with delay <= 12 hours", () => { diff --git a/src/mocks/anilist/deleteMediaListEntry.ts b/src/mocks/anilist/deleteMediaListEntry.ts deleted file mode 100644 index 3a289cf..0000000 --- a/src/mocks/anilist/deleteMediaListEntry.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { HttpResponse, graphql } from "msw"; - -export function deleteAnilistMediaListEntry() { - return graphql.mutation( - "DeleteMediaListEntry", - ({ variables: { entryId } }) => - HttpResponse.json({ - data: { - DeleteMediaListEntry: { - deleted: entryId > 0, - }, - }, - }), - ); -} diff --git a/src/mocks/anilist/mediaListEntry.ts b/src/mocks/anilist/mediaListEntry.ts deleted file mode 100644 index 05843ea..0000000 --- a/src/mocks/anilist/mediaListEntry.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { HttpResponse, graphql } from "msw"; - -export function getAnilistMediaListEntry() { - return graphql.query("GetMediaListEntry", ({ variables: { titleId } }) => { - if (titleId === 10) { - return HttpResponse.json({ - data: { - Media: { - mediaListEntry: { - id: 123456, - }, - }, - }, - }); - } else if (titleId === 139518) { - return HttpResponse.json({ - data: { - Media: { - mediaListEntry: { - id: 123457, - }, - }, - }, - }); - } - - return HttpResponse.json({ - data: { - Media: { - mediaListEntry: null, - }, - }, - }); - }); -} diff --git a/src/mocks/anilist/nextAiringEpisode.ts b/src/mocks/anilist/nextAiringEpisode.ts deleted file mode 100644 index 4f86683..0000000 --- a/src/mocks/anilist/nextAiringEpisode.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { HttpResponse, graphql } from "msw"; - -export function getAnilistNextAiringEpisode() { - return graphql.query( - "GetNextEpisodeAiringAt", - ({ variables: { titleId } }) => { - return HttpResponse.json({ - data: { - Media: { - nextAiringEpisode: null, - }, - }, - }); - }, - ); -} diff --git a/src/mocks/anilist/search.ts b/src/mocks/anilist/search.ts deleted file mode 100644 index 242a4d8..0000000 --- a/src/mocks/anilist/search.ts +++ /dev/null @@ -1,575 +0,0 @@ -import { HttpResponse, graphql } from "msw"; - -export function getAnilistSearchResults() { - return graphql.query("Search", ({ variables: { query, page } }) => { - console.log(`Intercepting Search query with ${query} and page ${page}`); - - if (!query || query === "a" || query === "aniwatch") { - return HttpResponse.json({ - data: { - Page: { - media: [], - pageInfo: { - hasNextPage: false, - }, - }, - }, - }); - } - - return HttpResponse.json({ - data: { - Page: { - media: [ - { - id: 151807, - title: { - userPreferred: "Ore dake Level Up na Ken", - english: "Solo Leveling", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx151807-yxY3olrjZH4k.png", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx151807-yxY3olrjZH4k.png", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx151807-yxY3olrjZH4k.png", - }, - }, - { - id: 2759, - title: { - userPreferred: "Evangelion Shin Movie: Jo", - english: "Evangelion: 1.0 You Are (Not) Alone", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx2759-z07kq8Pnw5B1.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx2759-z07kq8Pnw5B1.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx2759-z07kq8Pnw5B1.jpg", - }, - }, - { - id: 139589, - title: { - userPreferred: "Kotarou wa Hitorigurashi", - english: "Kotaro Lives Alone", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx139589-oFz7JwpwRkQV.png", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx139589-oFz7JwpwRkQV.png", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx139589-oFz7JwpwRkQV.png", - }, - }, - { - id: 145815, - title: { - userPreferred: - "Noumin Kanren no Skill Bakka Agetetara Naze ka Tsuyoku Natta.", - english: - "I've Somehow Gotten Stronger When I Improved My Farm-Related Skills", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx145815-XsgcXy7WzgtK.png", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx145815-XsgcXy7WzgtK.png", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx145815-XsgcXy7WzgtK.png", - }, - }, - { - id: 176496, - title: { - userPreferred: - "Ore dake Level Up na Ken: Season 2 - Arise from the Shadow", - english: "Solo Leveling Season 2 -Arise from the Shadow-", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx176496-r6oXxEqdZL0n.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx176496-r6oXxEqdZL0n.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx176496-r6oXxEqdZL0n.jpg", - }, - }, - { - id: 1965, - title: { - userPreferred: "sola", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx1965-lWBpcTni9PS9.png", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx1965-lWBpcTni9PS9.png", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx1965-lWBpcTni9PS9.png", - }, - }, - { - id: 118123, - title: { - userPreferred: "Holo no Graffiti", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx118123-xqn5fYsjKXJU.png", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx118123-xqn5fYsjKXJU.png", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx118123-xqn5fYsjKXJU.png", - }, - }, - { - id: 2582, - title: { - userPreferred: "Soukou Kihei Votoms", - english: "Armored Trooper Votoms", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx2582-aB1Vh1jDobQ3.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx2582-aB1Vh1jDobQ3.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx2582-aB1Vh1jDobQ3.jpg", - }, - }, - { - id: 116384, - title: { - userPreferred: "Sol Levante", - english: "Sol Levante", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx116384-xn0nQAKGFSd7.png", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx116384-xn0nQAKGFSd7.png", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx116384-xn0nQAKGFSd7.png", - }, - }, - { - id: 104073, - title: { - userPreferred: "Sono Toki, Kanojo wa.", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/nx104073-OQ8YBTy7zmKf.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/nx104073-OQ8YBTy7zmKf.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/nx104073-OQ8YBTy7zmKf.jpg", - }, - }, - { - id: 15313, - title: { - userPreferred: "Wooser no Sono Higurashi", - english: "Wooser's Hand-to-Mouth Life", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/15313.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/15313.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/15313.jpg", - }, - }, - { - id: 8068, - title: { - userPreferred: "Kuroshitsuji Picture Drama", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/8068.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/8068.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/8068.jpg", - }, - }, - { - id: 3174, - title: { - userPreferred: "sola Specials", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/3174.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/3174.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/3174.jpg", - }, - }, - { - id: 1443, - title: { - userPreferred: "SOL BIANCA", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/1443.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/1443.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/1443.jpg", - }, - }, - { - id: 153431, - title: { - userPreferred: "Onna no Sono no Hoshi", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx153431-DMBYQxagH3Uu.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx153431-DMBYQxagH3Uu.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx153431-DMBYQxagH3Uu.jpg", - }, - }, - { - id: 1444, - title: { - userPreferred: "Sol Bianca: Taiyou no Fune", - english: "Sol Bianca: The Legacy", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx1444-7Yn6hmQ2bk9D.png", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx1444-7Yn6hmQ2bk9D.png", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx1444-7Yn6hmQ2bk9D.png", - }, - }, - { - id: 4138, - title: { - userPreferred: "Chiisana Pengin: Lolo no Bouken", - english: "The Adventures of Scamper the Penguin", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/4138.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/4138.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/4138.jpg", - }, - }, - { - id: 164192, - title: { - userPreferred: "Planetarium", - english: "Planetarium", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx164192-KQ8sYXbaAl6i.png", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx164192-KQ8sYXbaAl6i.png", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx164192-KQ8sYXbaAl6i.png", - }, - }, - { - id: 5838, - title: { - userPreferred: "Furudera no Obake-soudou", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/b5838-QTe07RRZylUm.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/b5838-QTe07RRZylUm.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/b5838-QTe07RRZylUm.jpg", - }, - }, - { - id: 162882, - title: { - userPreferred: "P.E.T.", - english: "P.E.T.", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx162882-OQENM5pXn7QQ.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx162882-OQENM5pXn7QQ.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx162882-OQENM5pXn7QQ.jpg", - }, - }, - { - id: 102710, - title: { - userPreferred: "Kairaku no Sono", - english: "The Garden of Pleasure", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/102710-dVayaOkzATwa.png", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/102710-dVayaOkzATwa.png", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/102710-dVayaOkzATwa.png", - }, - }, - { - id: 162881, - title: { - userPreferred: "Mosh Race", - english: "Mosh Race", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx162881-c7xmNA6DlHFZ.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx162881-c7xmNA6DlHFZ.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx162881-c7xmNA6DlHFZ.jpg", - }, - }, - { - id: 5935, - title: { - userPreferred: "Marco Polo no Boken", - english: "Marco Polo's Adventures", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/5935.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/5935.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/5935.jpg", - }, - }, - { - id: 103449, - title: { - userPreferred: "SOL", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/103449-FxDK8eJuMAKg.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/103449-FxDK8eJuMAKg.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/103449-FxDK8eJuMAKg.jpg", - }, - }, - { - id: 12993, - title: { - userPreferred: "Sono Mukou no Mukougawa", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/12993.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/12993.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/12993.jpg", - }, - }, - { - id: 20459, - title: { - userPreferred: "Ganbare! Lulu Lolo", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/20459.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/20459.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/20459.jpg", - }, - }, - { - id: 137760, - title: { - userPreferred: "Soko ni wa Mata Meikyuu", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/b137760-CleNdfmuKRy7.png", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/b137760-CleNdfmuKRy7.png", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/b137760-CleNdfmuKRy7.png", - }, - }, - { - id: 7473, - title: { - userPreferred: "Rennyo to Sono Haha", - english: "Rennyo and His Mother", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/7473.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/7473.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/7473.jpg", - }, - }, - { - id: 21418, - title: { - userPreferred: "Ganbare! Lulu Lolo 3rd Season", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/21418-TZYwdItidowx.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/21418-TZYwdItidowx.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/21418-TZYwdItidowx.jpg", - }, - }, - { - id: 103517, - title: { - userPreferred: "Toute wa Sono Kotae", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/103517-XgOUryeFaPDW.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/103517-XgOUryeFaPDW.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/103517-XgOUryeFaPDW.jpg", - }, - }, - { - id: 113572, - title: { - userPreferred: "Sono Saki no Taniji", - english: "Journey to the beyond", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/b113572-hP9x1SkRJXvA.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/b113572-hP9x1SkRJXvA.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/b113572-hP9x1SkRJXvA.jpg", - }, - }, - { - id: 20864, - title: { - userPreferred: "Ganbare! Lulu Lolo 2nd Season", - english: null, - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/20864.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/20864.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/20864.jpg", - }, - }, - { - id: 15129, - title: { - userPreferred: "Tanpen Animation Junpei Fujita", - english: "Short Animations of Junpei Fujita", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/15129.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/15129.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/15129.jpg", - }, - }, - { - id: 106557, - title: { - userPreferred: "Sono Ie no Namae", - english: "A Place to Name", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/nx106557-TPLmwa2EccB9.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/nx106557-TPLmwa2EccB9.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/nx106557-TPLmwa2EccB9.jpg", - }, - }, - { - id: 118133, - title: { - userPreferred: "Guzu no Soko", - english: "In Inertia", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/b118133-y7RvDFmr30hZ.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/b118133-y7RvDFmr30hZ.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/b118133-y7RvDFmr30hZ.jpg", - }, - }, - { - id: 169686, - title: { - userPreferred: "Soto ni Denai hi", - english: "Indoor Days", - }, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx169686-exScHzB5UX2D.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx169686-exScHzB5UX2D.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx169686-exScHzB5UX2D.jpg", - }, - }, - ], - pageInfo: { - hasNextPage: false, - }, - }, - }, - }); - }); -} diff --git a/src/mocks/anilist/title.ts b/src/mocks/anilist/title.ts deleted file mode 100644 index 9a9b0e1..0000000 --- a/src/mocks/anilist/title.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { HttpResponse, graphql } from "msw"; - -export function getAnilistTitle() { - return graphql.query( - "GetTitle", - ({ variables: { id }, request: { headers } }) => { - console.log( - `Intercepting GetTitle query with ID ${id} and Authorization header ${headers.get("authorization")}`, - ); - - if (id === -1 || id === 50) { - return HttpResponse.json({ - errors: [ - { - message: "Not Found.", - status: 404, - locations: [ - { - line: 2, - column: 2, - }, - ], - }, - ], - data: { - Media: null, - }, - }); - } - - return HttpResponse.json({ - data: { - Media: { - id: 135643, - idMal: 49210, - title: { - english: "The Grimm Variations", - userPreferred: "The Grimm Variations", - }, - description: - 'Once upon a time, brothers Jacob and Wilhelm collected fairy tales from across the land and made them into a book. They also had a much younger sister, the innocent and curious Charlotte, who they loved very much. One day, while the brothers were telling Charlotte a fairy tale like usual, they saw that she had a somewhat melancholy look on her face. She asked them, "Do you suppose they really lived happily ever after?"\n

\nThe pages of Grimms\' Fairy Tales, written by Jacob and Wilhelm, are now presented from the unique perspective of Charlotte, who sees the stories quite differently from her brothers.\n

\n(Source: Netflix Anime)', - episodes: 6, - genres: ["Fantasy", "Thriller"], - status: "FINISHED", - bannerImage: - "https://s4.anilist.co/file/anilistcdn/media/anime/banner/135643-cmQZCR3z9dB5.jpg", - averageScore: 66, - coverImage: { - extraLarge: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx135643-2kJt86K9Db9P.jpg", - large: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx135643-2kJt86K9Db9P.jpg", - medium: - "https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx135643-2kJt86K9Db9P.jpg", - }, - countryOfOrigin: "JP", - mediaListEntry: headers.has("authorization") - ? { - id: 402665918, - progress: 1, - status: "CURRENT", - } - : null, - nextAiringEpisode: null, - }, - }, - }); - }, - ); -} diff --git a/src/mocks/anilist/updateWatchStatus.ts b/src/mocks/anilist/updateWatchStatus.ts deleted file mode 100644 index 9affb44..0000000 --- a/src/mocks/anilist/updateWatchStatus.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { HttpResponse, graphql } from "msw"; - -export function updateAnilistWatchStatus() { - return graphql.mutation( - "UpdateWatchStatus", - ({ variables: { titleId, watchStatus }, request: { headers } }) => { - console.log( - `Intercepting UpdateWatchStatus mutation with ID ${titleId}, watch status ${watchStatus} and Authorization header ${headers.get("authorization")}`, - ); - - if (titleId === -1) { - return HttpResponse.json({ - errors: [ - { - message: "validation", - status: 400, - locations: [ - { - line: 2, - column: 2, - }, - ], - validation: { - mediaId: ["The selected media id is invalid."], - }, - }, - ], - data: { - SaveMediaListEntry: null, - }, - }); - } - - return HttpResponse.json({ data: { id: titleId } }); - }, - ); -} diff --git a/src/mocks/aniwatch/episodes.ts b/src/mocks/aniwatch/episodes.ts deleted file mode 100644 index 523fc2c..0000000 --- a/src/mocks/aniwatch/episodes.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { HttpResponse, http } from "msw"; - -export function getAniwatchEpisodes() { - return http.get( - "https://aniwatch.up.railway.app/api/v2/hianime/anime/:aniListId/episodes", - ({ params }) => { - const aniListId = Number(params["aniListId"]); - if (aniListId === 4) { - return HttpResponse.json({ - code: 200, - message: "success", - episodes: [ - { - id: "aniwatch-1", - episode: 1, - title: "EP 1", - isFiller: false, - isDub: false, - image: null, - }, - ], - }); - } - - return HttpResponse.json( - { code: 500, message: "Server error", episodes: [] }, - { status: 500 }, - ); - }, - ); -} diff --git a/src/mocks/aniwatch/search.ts b/src/mocks/aniwatch/search.ts deleted file mode 100644 index 7d86667..0000000 --- a/src/mocks/aniwatch/search.ts +++ /dev/null @@ -1,512 +0,0 @@ -import { HttpResponse, http } from "msw"; - -export function getAniwatchSearchResults() { - return http.get( - "https://aniwatch.up.railway.app/api/v2/hianime/search", - ({ request }) => { - const query = new URL(request.url).searchParams.get("query"); - - return HttpResponse.json({ - animes: [ - { - id: "naruto-shippuden-355", - name: "Naruto: Shippuden", - jname: "Naruto: Shippuuden", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/9cbcf87f54194742e7686119089478f8.jpg", - duration: "23m", - type: "TV", - rating: null, - episodes: { - sub: 500, - dub: 500, - }, - }, - { - id: "naruto-shippuden-the-movie-2306", - name: "Naruto: Shippuden the Movie", - jname: "Naruto: Shippuuden Movie 1", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/071ca93201eccc34a9e088013bc27807.jpg", - duration: "94m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "naruto-shippuden-the-movie-2-bonds-2346", - name: "Naruto: Shippuden the Movie 2 -Bonds-", - jname: "Naruto: Shippuuden Movie 2 - Kizuna", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/74a112674ab92212933e41cb532689a5.jpg", - duration: "92m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "naruto-x-ut-1840", - name: "Naruto x UT", - jname: "Naruto x UT", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/be66602efedb73c4688e302303b0a422.jpg", - duration: "6m", - type: "OVA", - rating: null, - episodes: { - sub: 1, - dub: null, - }, - }, - { - id: "naruto-677", - name: "Naruto", - jname: "Naruto", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/5db400c33f7494bc8ae96f9e634958d0.jpg", - duration: "23m", - type: "TV", - rating: null, - episodes: { - sub: 220, - dub: 220, - }, - }, - { - id: "naruto-the-movie-2-legend-of-the-stone-of-gelel-4004", - name: "Naruto the Movie 2: Legend of the Stone of Gelel", - jname: - "Naruto Movie 2: Dai Gekitotsu! Maboroshi no Chiteiiseki Dattebayo!", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/111f06edfffba5f46f5cac05db2a6bce.jpg", - duration: "97m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "road-of-naruto-18220", - name: "Road of Naruto", - jname: "Road of Naruto", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/fd414879634ea83ad2c4fc1c33e8ac43.jpg", - duration: "9m", - type: "ONA", - rating: null, - episodes: { - sub: 1, - dub: null, - }, - }, - { - id: "naruto-shippuuden-movie-5-blood-prison-1642", - name: "Naruto: Shippuuden Movie 5 - Blood Prison", - jname: "Naruto: Shippuuden Movie 5 - Blood Prison", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/23a436a4ae640fa191a587b5e417bf7d.jpg", - duration: "102m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "boruto-naruto-next-generations-8143", - name: "Boruto: Naruto Next Generations", - jname: "Boruto: Naruto Next Generations", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/32c83e2ad4a43229996356840db3982c.jpg", - duration: "23m", - type: "TV", - rating: null, - episodes: { - sub: 293, - dub: 273, - }, - }, - { - id: "boruto-naruto-the-movie-1391", - name: "Boruto: Naruto the Movie", - jname: "Boruto: Naruto the Movie", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/f0ad5b3ee01703cc817638973b535aa2.jpg", - duration: "95m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "naruto-shippuuden-movie-6-road-to-ninja-1066", - name: "Naruto: Shippuuden Movie 6: Road to Ninja", - jname: "Naruto: Shippuuden Movie 6 - Road to Ninja", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/dde4a8a8ddd19648711845448d02d6d8.jpg", - duration: "109m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "the-last-naruto-the-movie-882", - name: "The Last: Naruto the Movie", - jname: "The Last: Naruto the Movie", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/8d42031c8f566e744d84de02d42466bc.jpg", - duration: "112m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "naruto-shippuuden-movie-3-inheritors-of-will-of-fire-2044", - name: "Naruto Shippuuden Movie 3: Inheritors of Will of Fire", - jname: "Naruto: Shippuuden Movie 3 - Hi no Ishi wo Tsugu Mono", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/1b9aad793b15265876f479c53ca7bfe1.jpg", - duration: "95m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "naruto-shippuuden-movie-4-the-lost-tower-1821", - name: "Naruto: Shippuuden Movie 4 - The Lost Tower", - jname: "Naruto: Shippuuden Movie 4 - The Lost Tower", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/68c5ae4e5b496eb0474920659a9a85e2.jpg", - duration: "85m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "boruto-naruto-the-movie-the-day-naruto-became-the-hokage-1805", - name: "Boruto: Naruto the Movie - The Day Naruto Became the Hokage", - jname: "Boruto: Naruto the Movie - Naruto ga Hokage ni Natta Hi", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/b19c06fae70eab67b1f390ed3cd905d8.jpg", - duration: "10m", - type: "Special", - rating: null, - episodes: { - sub: 1, - dub: null, - }, - }, - { - id: "naruto-the-movie-3-guardians-of-the-crescent-moon-kingdom-4005", - name: "Naruto the Movie 3: Guardians of the Crescent Moon Kingdom", - jname: - "Naruto Movie 3: Dai Koufun! Mikazuki Jima no Animaru Panikku Dattebayo!", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/73d003618cd260df44e93a5baf9acb56.jpg", - duration: "94m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "naruto-find-the-crimson-four-leaf-clover-5694", - name: "Naruto: Find the Crimson Four-leaf Clover!", - jname: "Naruto: Akaki Yotsuba no Clover wo Sagase", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/da3a3d57e29aa0dba87cd6e1596b78e9.jpg", - duration: "17m", - type: "Special", - rating: null, - episodes: { - sub: 1, - dub: null, - }, - }, - { - id: "naruto-ova5-naruto-the-genie-and-the-three-wishes-3657", - name: "Naruto OVA5: Naruto, The Genie, and The Three Wishes!!", - jname: - "Naruto Soyokazeden Movie: Naruto to Mashin to Mitsu no Onegai Dattebayo!!", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/57935a347fb4328e0132c76afdd85822.jpg", - duration: "14m", - type: "OVA", - rating: null, - episodes: { - sub: 1, - dub: null, - }, - }, - { - id: "naruto-narutimate-hero-3-tsuini-gekitotsu-jounin-vs-genin-musabetsu-dairansen-taikai-kaisai-4485", - name: "Naruto Narutimate Hero 3: Tsuini Gekitotsu! Jounin vs. Genin!! Musabetsu Dairansen Taikai Kaisai!!", - jname: - "Naruto Narutimate Hero 3: Tsuini Gekitotsu! Jounin vs. Genin!! Musabetsu Dairansen Taikai Kaisai!!", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/939f107dc40ca24056b90c0b215bd475.jpg", - duration: "26m", - type: "OVA", - rating: null, - episodes: { - sub: 1, - dub: null, - }, - }, - { - id: "naruto-ova7-chunin-exam-on-fire-and-naruto-vs-konohamaru-2928", - name: "Naruto OVA7: Chunin Exam on Fire! and Naruto vs. Konohamaru!", - jname: "Naruto: Honoo no Chuunin Shiken! Naruto vs. Konohamaru!!", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/44246cdf24c85468599ff2b9496c27cb.jpg", - duration: "14m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "naruto-the-movie-ninja-clash-in-the-land-of-snow-3162", - name: "Naruto Movie 1: Ninja Clash in the Land of Snow", - jname: - "Naruto Movie 1: Dai Katsugeki!! Yuki Hime Shinobu Houjou Dattebayo!", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/a1ab85f1eb75ec0a986e4c9d5fe04b49.jpg", - duration: "82m", - type: "Movie", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "naruto-ova9-sunny-side-battle-1916", - name: "Naruto OVA9: Sunny Side Battle", - jname: "Naruto: Shippuuden - Sunny Side Battle", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/94c836b7aff106f515b53f8eb440ccdf.jpg", - duration: "11m", - type: "Special", - rating: null, - episodes: { - sub: 1, - dub: null, - }, - }, - { - id: "naruto-the-cross-roads-4291", - name: "Naruto: The Cross Roads", - jname: "Naruto: The Cross Roads", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/99d7c753d9535c0d91858e4dd2a8d939.jpg", - duration: "27m", - type: "Special", - rating: null, - episodes: { - sub: 1, - dub: null, - }, - }, - { - id: "naruto-ova2-the-lost-story-mission-protect-the-waterfall-village-4538", - name: "Naruto OVA2: The Lost Story - Mission: Protect the Waterfall Village", - jname: "Naruto: Takigakure no Shitou - Ore ga Eiyuu Dattebayo!", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/ed2ca489d8c438c880056ea507efc93c.jpg", - duration: "40m", - type: "Special", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "naruto-ova3-hidden-leaf-village-grand-sports-festival-4136", - name: "Naruto OVA3: Hidden Leaf Village Grand Sports Festival", - jname: - "Naruto: Dai Katsugeki!! Yuki Hime Shinobu Houjou Dattebayo! - Konoha no Sato no Dai Undoukai", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/b4bb0d2caaa9591fdb3c442738d7f87a.jpg", - duration: "11m", - type: "Special", - rating: null, - episodes: { - sub: 1, - dub: 1, - }, - }, - { - id: "naruto-spin-off-rock-lee-his-ninja-pals-2992", - name: "NARUTO Spin-Off: Rock Lee & His Ninja Pals", - jname: "Naruto SD: Rock Lee no Seishun Full-Power Ninden", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/37f8b16b0f693e433207117abe5daf44.jpg", - duration: "24m", - type: "TV", - rating: null, - episodes: { - sub: 51, - dub: 51, - }, - }, - ], - mostPopularAnimes: [ - { - id: "one-piece-100", - name: "One Piece", - jname: "One Piece", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/bcd84731a3eda4f4a306250769675065.jpg", - episodes: { - sub: 1116, - dub: 1085, - }, - type: "TV", - }, - { - id: "naruto-shippuden-355", - name: "Naruto: Shippuden", - jname: "Naruto: Shippuuden", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/9cbcf87f54194742e7686119089478f8.jpg", - episodes: { - sub: 500, - dub: 500, - }, - type: "TV", - }, - { - id: "jujutsu-kaisen-2nd-season-18413", - name: "Jujutsu Kaisen 2nd Season", - jname: "Jujutsu Kaisen 2nd Season", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/b51f863b05f30576cf9d85fa9b911bb5.png", - episodes: { - sub: 23, - dub: 23, - }, - type: "TV", - }, - { - id: "bleach-806", - name: "Bleach", - jname: "Bleach", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/bd5ae1d387a59c5abcf5e1a6a616728c.jpg", - episodes: { - sub: 366, - dub: 366, - }, - type: "TV", - }, - { - id: "black-clover-2404", - name: "Black Clover", - jname: "Black Clover", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/f58b0204c20ae3310f65ae7b8cb9987e.jpg", - episodes: { - sub: 170, - dub: 170, - }, - type: "TV", - }, - { - id: "demon-slayer-kimetsu-no-yaiba-swordsmith-village-arc-18056", - name: "Demon Slayer: Kimetsu no Yaiba Swordsmith Village Arc", - jname: "Kimetsu no Yaiba: Katanakaji no Sato-hen", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/db2f3ce7b9cab7fdc160b005bffb899a.png", - episodes: { - sub: 11, - dub: 11, - }, - type: "TV", - }, - { - id: "boruto-naruto-next-generations-8143", - name: "Boruto: Naruto Next Generations", - jname: "Boruto: Naruto Next Generations", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/32c83e2ad4a43229996356840db3982c.jpg", - episodes: { - sub: 293, - dub: 273, - }, - type: "TV", - }, - { - id: "naruto-677", - name: "Naruto", - jname: "Naruto", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/5db400c33f7494bc8ae96f9e634958d0.jpg", - episodes: { - sub: 220, - dub: 220, - }, - type: "TV", - }, - { - id: "jujutsu-kaisen-tv-534", - name: "Jujutsu Kaisen (TV)", - jname: "Jujutsu Kaisen (TV)", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/82402f796b7d84d7071ab1e03ff7747a.jpg", - episodes: { - sub: 24, - dub: 24, - }, - type: "TV", - }, - { - id: "spy-x-family-17977", - name: "Spy x Family", - jname: "Spy x Family", - poster: - "https://cdn.noitatnemucod.net/thumbnail/300x400/100/88bd17534dc4884f23027035d23d74e5.jpg", - episodes: { - sub: 12, - dub: 12, - }, - type: "TV", - }, - ], - currentPage: 1, - hasNextPage: false, - totalPages: 1, - searchQuery: "naruto-shippuden-355", - searchFilters: {}, - }); - }, - ); -} diff --git a/src/mocks/aniwatch/sources.ts b/src/mocks/aniwatch/sources.ts deleted file mode 100644 index 62f7e16..0000000 --- a/src/mocks/aniwatch/sources.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { HttpResponse, http } from "msw"; - -export function getAniwatchSources() { - return http.get( - "https://aniwatch.up.railway.app/api/v2/hianime/episode/sources", - ({ request }) => { - const url = new URL(request.url); - const id = url.searchParams.get("id"); - - if (id === "unknown") { - return HttpResponse.json( - { - code: 404, - message: - "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", - }, - { status: 404 }, - ); - } - - return HttpResponse.json({ - tracks: [ - { - file: "https://s.megastatics.com/subtitle/4ea42fb35b93b7a2d8e69ca8fe55c0e5/eng-2.vtt", - label: "English", - kind: "captions", - default: true, - }, - { - file: "https://s.megastatics.com/thumbnails/be7d997958cdf9b9444d910c2c28645e/thumbnails.vtt", - kind: "thumbnails", - }, - ], - intro: { - start: 258, - end: 347, - }, - outro: { - start: 1335, - end: 1424, - }, - sources: [ - { - url: "https://vd2.biananset.net/_v7/26c0c3f5b635f5b9153fca5d43037bb06875d79b3f1528ca69ac83f8e14c90a48cce237316cbf6fa12de243f1dca5118b8dbb767aff155b79ad687a75905004314bee838cdbd8bea083910d6f660f3e29ebb5bb3e48dd9b30816c31737fc8fdf9dd123a7ea937c5594fb9daf540e6a4e6aecef840e23f0fe9cfe20638e3467a2/master.m3u8", - type: "hls", - }, - ], - anilistID: 153406, - malID: 52635, - }); - }, - ); -} diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts deleted file mode 100644 index ce385e0..0000000 --- a/src/mocks/handlers.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { deleteAnilistMediaListEntry } from "./anilist/deleteMediaListEntry"; -import { getAnilistMediaListEntry } from "./anilist/mediaListEntry"; -import { getAnilistNextAiringEpisode } from "./anilist/nextAiringEpisode"; -import { getAnilistSearchResults } from "./anilist/search"; -import { getAnilistTitle } from "./anilist/title"; -import { updateAnilistWatchStatus } from "./anilist/updateWatchStatus"; -import { getAniwatchEpisodes } from "./aniwatch/episodes"; -import { getAniwatchSearchResults } from "./aniwatch/search"; -import { getAniwatchSources } from "./aniwatch/sources"; -import { - mockCreateGcloudTask, - mockDeleteGcloudTask, - mockFcmMessageResponse, -} from "./gcloud"; - -export const handlers = [ - deleteAnilistMediaListEntry(), - getAnilistMediaListEntry(), - getAnilistNextAiringEpisode(), - getAnilistSearchResults(), - getAnilistTitle(), - updateAnilistWatchStatus(), - getAniwatchEpisodes(), - getAniwatchSearchResults(), - getAniwatchSources(), - mockCreateGcloudTask(), - mockDeleteGcloudTask(), - mockFcmMessageResponse(), -]; diff --git a/src/mocks/index.ts b/src/mocks/index.ts deleted file mode 100644 index fa95245..0000000 --- a/src/mocks/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { setupServer } from "msw/node"; - -import { handlers } from "./handlers"; - -export const server = setupServer(...handlers); diff --git a/src/services/episodes/getEpisodeUrl/index.spec.ts b/src/services/episodes/getEpisodeUrl/index.spec.ts index adb69d3..cbf2fc6 100644 --- a/src/services/episodes/getEpisodeUrl/index.spec.ts +++ b/src/services/episodes/getEpisodeUrl/index.spec.ts @@ -1,47 +1,71 @@ -import { describe, expect, it } from "bun:test"; +import { beforeEach, describe, expect, it, vi } from "vitest"; -import app from "~/index"; -import { server } from "~/mocks"; +import { fetchEpisodeUrl } from "./index"; -server.listen(); +describe("fetchEpisodeUrl", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); -describe('requests the "/episodes/:id/url" route', () => { it("with sources from Aniwatch", async () => { - const response = await app.request( - "/episodes/4/url", - { - method: "POST", - body: JSON.stringify({ - episodeNumber: 1, - }), - headers: { "Content-Type": "application/json" }, - }, - { - ENABLE_ANIFY: "true", - }, - ); + (global.fetch as any).mockResolvedValue({ + ok: true, + json: async () => ({ + status: 200, + data: { + tracks: [], + intro: { start: 258, end: 347 }, + outro: { start: 1335, end: 1424 }, + sources: [ + { + url: "https://www032.vipanicdn.net/streamhls/aa804a2400535d84dd59454b28d329fb/ep.1.1712504065.m3u8", + type: "hls", + }, + ], + anilistID: 153406, + malID: 52635, + }, + }), + }); - expect(response.json()).resolves.toEqual({ + const result = await fetchEpisodeUrl({ + id: "4", + aniListId: 153406, + episodeNumber: 1, + }); + + expect(result).toEqual({ success: true, result: { source: "https://www032.vipanicdn.net/streamhls/aa804a2400535d84dd59454b28d329fb/ep.1.1712504065.m3u8", subtitles: [], audio: [], + intro: [258, 347], + outro: [1335, 1424], + headers: undefined, }, }); }); it("with no URL from Aniwatch source", async () => { - const response = await app.request("/episodes/-1/url", { - method: "POST", - body: JSON.stringify({ - episodeNumber: -1, + (global.fetch as any).mockResolvedValue({ + ok: true, + json: async () => ({ + status: 200, + data: { + sources: [], + sub: [], + }, }), - headers: { "Content-Type": "application/json" }, }); - expect(response.json()).resolves.toEqual({ success: false }); - expect(response.status).toBe(404); + const result = await fetchEpisodeUrl({ + id: "4", + aniListId: 153406, + episodeNumber: 1, + }); + + expect(result).toEqual({ success: false }); }); }); diff --git a/src/testRunner.ts b/src/testRunner.ts deleted file mode 100644 index 6f7ca7b..0000000 --- a/src/testRunner.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { formatCmd } from "node_modules/zx/build/util"; -import { $, minimist } from "zx"; - -import { getTestEnvVariables } from "./libs/test/getTestEnv"; - -const args = minimist(process.argv.slice(2)); -if (!args["dbCommand"]) { - throw new Error("dbCommand is required"); -} - -const filteredKeys = new Set(["_", "dbCommand", "db", "$0", "db-command"]); -const positionalArgs = Object.entries(args) - .filter(([key]) => !filteredKeys.has(key)) - .map(([key, value]) => { - if (typeof value === "boolean") { - return `--${key}`; - } - - return `--${key}=${value}`; - }) - .concat(args._); - -console.log(formatCmd(args["dbCommand"])); -const dbProcess = $({ quote: (arg) => arg })`${args["dbCommand"]}`; - -let exitCode = 0; -try { - $.env = { - ...getTestEnvVariables(), - PATH: process.env["PATH"], - HOME: process.env["HOME"], - SHOULD_LOG_ERRORS: process.env["SHOULD_LOG_ERRORS"] ?? "true", - }; - await $`bun db:migrate`; - const testProcess = await $({ - verbose: true, - quote: (arg) => arg, - })`FORCE_COLOR=1 bun test ${positionalArgs.join(" ")}`.nothrow(); - exitCode = (await testProcess.exitCode) ?? 0; -} finally { - await dbProcess.kill("SIGINT"); -} - -process.exit(exitCode); diff --git a/testSetup.ts b/testSetup.ts index 18ee416..b52bf4a 100644 --- a/testSetup.ts +++ b/testSetup.ts @@ -1,3 +1,26 @@ -if (process.env.SHOULD_LOG_ERRORS === "false") { - console.error = () => {}; +import { vi } from "vitest"; + +const shouldLogErrors = process.env["SHOULD_LOG_ERRORS"] === "true"; + +if (!shouldLogErrors) { + const originalConsoleError = console.error; + console.error = (...args) => { + // Suppress specific error messages + if ( + args[0]?.includes?.("Error: No email provided") || + args[0]?.includes?.('TypeError: "pkcs8" must be PKCS#8 formatted string') + ) { + return; + } + originalConsoleError(...args); + }; } + +global.fetch = vi.fn(); + +vi.mock("cloudflare:workers", () => { + return { + env: {}, + DurableObject: class DurableObject {}, + }; +}); diff --git a/tsconfig.json b/tsconfig.json index c17a10b..334dbd8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,32 +1,27 @@ { "compilerOptions": { - "types": ["@types/bun"], + "types": ["@cloudflare/workers-types"], "baseUrl": "./", "paths": { "~/*": ["src/*"] }, - // Enable latest features "lib": ["ESNext"], "target": "ESNext", "module": "ESNext", - // Bundler mode "moduleResolution": "bundler", "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, "noEmit": true, - // Best practices "strict": true, "skipLibCheck": true, "noFallthroughCasesInSwitch": true, - // Some stricter flags "noUnusedLocals": true, "noUnusedParameters": false, "noPropertyAccessFromIndexSignature": true, - // plugins "plugins": [ { diff --git a/vitest.config.ts b/vitest.config.ts index 2e0846f..04e8dd2 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,8 +1,11 @@ import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; +import tsconfigPaths from "vite-tsconfig-paths"; +import { configDefaults } from "vitest/config"; export default defineWorkersConfig({ + plugins: [tsconfigPaths()], test: { - globals: true, + globals: false, setupFiles: ["./testSetup.ts"], poolOptions: { workers: { @@ -10,14 +13,18 @@ export default defineWorkersConfig({ }, }, coverage: { + ...configDefaults.coverage, provider: "v8", reporter: ["text", "json", "html"], exclude: [ + ...configDefaults.coverage.exclude, "node_modules/**", "dist/**", "**/*.spec.ts", "**/*.d.ts", "**/mocks/**", + "drizzle.config.ts", + "src/schema.ts", ], }, },