mirror of
https://github.com/ld3z/new-manga.git
synced 2026-11-09 21:13:46 -07:00
Compare commits
No commits in common. "600c3b0e1f6507e8be53a7151baf2444f316cc46" and "fd14c1a80ccc2f091ee2bcec668a88062b9a3f73" have entirely different histories.
600c3b0e1f
...
fd14c1a80c
5 changed files with 276 additions and 420 deletions
|
|
@ -14,13 +14,7 @@ export default defineConfig({
|
||||||
'process.env.PRIMARY_REDIS_URL': JSON.stringify(process.env.PRIMARY_REDIS_URL || process.env.REDIS_URL),
|
'process.env.PRIMARY_REDIS_URL': JSON.stringify(process.env.PRIMARY_REDIS_URL || process.env.REDIS_URL),
|
||||||
'process.env.REPLICA_REDIS_URL_1': JSON.stringify(process.env.REPLICA_REDIS_URL_1 || process.env.REPLICA_REDIS_URL),
|
'process.env.REPLICA_REDIS_URL_1': JSON.stringify(process.env.REPLICA_REDIS_URL_1 || process.env.REPLICA_REDIS_URL),
|
||||||
'process.env.REPLICA_REDIS_URL_2': JSON.stringify(process.env.REPLICA_REDIS_URL_2),
|
'process.env.REPLICA_REDIS_URL_2': JSON.stringify(process.env.REPLICA_REDIS_URL_2),
|
||||||
'process.env.REPLICA_REDIS_URL_3': JSON.stringify(process.env.REPLICA_REDIS_URL_3),
|
'process.env.REPLICA_REDIS_URL_3': JSON.stringify(process.env.REPLICA_REDIS_URL_3)
|
||||||
'process.env.VERCEL': JSON.stringify(process.env.VERCEL || false)
|
}
|
||||||
},
|
|
||||||
server: {
|
|
||||||
watch: {
|
|
||||||
usePolling: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
385
package-lock.json
generated
385
package-lock.json
generated
|
|
@ -10,14 +10,14 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/rss": "^4.0.11",
|
"@astrojs/rss": "^4.0.11",
|
||||||
"@astrojs/tailwind": "^6.0.0",
|
"@astrojs/tailwind": "^6.0.0",
|
||||||
"@astrojs/vercel": "^8.1.0",
|
"@astrojs/vercel": "^8.1.1",
|
||||||
"@floating-ui/dom": "^1.6.13",
|
"@floating-ui/dom": "^1.6.13",
|
||||||
"@types/node": "^22.13.9",
|
"@types/node": "^22.13.9",
|
||||||
"@vercel/analytics": "^1.5.0",
|
"@vercel/analytics": "^1.5.0",
|
||||||
"@vercel/kv": "^3.0.0",
|
"@vercel/kv": "^3.0.0",
|
||||||
"astro": "^5.4.1",
|
"astro": "^5.4.2",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"ioredis": "^5.5.0",
|
"ioredis": "^5.6.0",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -122,14 +122,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@astrojs/vercel": {
|
"node_modules/@astrojs/vercel": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@astrojs/vercel/-/vercel-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@astrojs/vercel/-/vercel-8.1.1.tgz",
|
||||||
"integrity": "sha512-qaztQ0WCg8epe9+3PS7+eTbukNcwDtfjgN/QeWk0+wmmWHpEBlhzUA17Vmk5OINBX/Tf0bzXgydDWrAVG+/irQ==",
|
"integrity": "sha512-4tTib9LkAtg7tqac4L+pnWEveUmYyWRXpHivaVV3lHKeQjB28KUZ+YXtR/VUG6/xpMduo+OCOOg0l1zOPq/e4w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/internal-helpers": "0.6.0",
|
"@astrojs/internal-helpers": "0.6.0",
|
||||||
"@vercel/analytics": "^1.4.1",
|
"@vercel/analytics": "^1.5.0",
|
||||||
"@vercel/edge": "^1.2.1",
|
"@vercel/edge": "^1.2.1",
|
||||||
"@vercel/nft": "^0.29.0",
|
"@vercel/nft": "^0.29.2",
|
||||||
"@vercel/routing-utils": "^5.0.4",
|
"@vercel/routing-utils": "^5.0.4",
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"tinyglobby": "^0.2.12"
|
"tinyglobby": "^0.2.12"
|
||||||
|
|
@ -1486,8 +1486,6 @@
|
||||||
"version": "1.34.3",
|
"version": "1.34.3",
|
||||||
"resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.34.3.tgz",
|
"resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.34.3.tgz",
|
||||||
"integrity": "sha512-VT25TyODGy/8ljl7GADnJoMmtmJ1F8d84UXfGonRRF8fWYJz7+2J6GzW+a6ETGtk4OyuRTt7FRSvFG5GvrfSdQ==",
|
"integrity": "sha512-VT25TyODGy/8ljl7GADnJoMmtmJ1F8d84UXfGonRRF8fWYJz7+2J6GzW+a6ETGtk4OyuRTt7FRSvFG5GvrfSdQ==",
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"crypto-js": "^4.2.0"
|
"crypto-js": "^4.2.0"
|
||||||
}
|
}
|
||||||
|
|
@ -1534,10 +1532,21 @@
|
||||||
"resolved": "https://registry.npmjs.org/@vercel/edge/-/edge-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@vercel/edge/-/edge-1.2.1.tgz",
|
||||||
"integrity": "sha512-1++yncEyIAi68D3UEOlytYb1IUcIulMWdoSzX2h9LuSeeyR7JtaIgR8DcTQ6+DmYOQn+5MCh6LY+UmK6QBByNA=="
|
"integrity": "sha512-1++yncEyIAi68D3UEOlytYb1IUcIulMWdoSzX2h9LuSeeyR7JtaIgR8DcTQ6+DmYOQn+5MCh6LY+UmK6QBByNA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@vercel/kv": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vercel/kv/-/kv-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-pKT8fRnfyYk2MgvyB6fn6ipJPCdfZwiKDdw7vB+HL50rjboEBHDVBEcnwfkEpVSp2AjNtoaOUH7zG+bVC/rvSg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@upstash/redis": "^1.34.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vercel/nft": {
|
"node_modules/@vercel/nft": {
|
||||||
"version": "0.29.1",
|
"version": "0.29.2",
|
||||||
"resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.29.1.tgz",
|
"resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.29.2.tgz",
|
||||||
"integrity": "sha512-6239JJM1V9b3OjvZIjbe+47/hGxMr44FEzlbTErrqzebCaoKAHK+yvahn3gdNacybDUbTxVF8Zuh0vqaeM8aKQ==",
|
"integrity": "sha512-A/Si4mrTkQqJ6EXJKv5EYCDQ3NL6nJXxG8VGXePsaiQigsomHYQC9xSpX8qGk7AEZk4b1ssbYIqJ0ISQQ7bfcA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/node-pre-gyp": "^2.0.0",
|
"@mapbox/node-pre-gyp": "^2.0.0",
|
||||||
"@rollup/pluginutils": "^5.1.3",
|
"@rollup/pluginutils": "^5.1.3",
|
||||||
|
|
@ -1546,7 +1555,7 @@
|
||||||
"async-sema": "^3.1.1",
|
"async-sema": "^3.1.1",
|
||||||
"bindings": "^1.4.0",
|
"bindings": "^1.4.0",
|
||||||
"estree-walker": "2.0.2",
|
"estree-walker": "2.0.2",
|
||||||
"glob": "^7.1.3",
|
"glob": "^10.4.5",
|
||||||
"graceful-fs": "^4.2.9",
|
"graceful-fs": "^4.2.9",
|
||||||
"node-gyp-build": "^4.2.2",
|
"node-gyp-build": "^4.2.2",
|
||||||
"picomatch": "^4.0.2",
|
"picomatch": "^4.0.2",
|
||||||
|
|
@ -1745,9 +1754,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/astro": {
|
"node_modules/astro": {
|
||||||
"version": "5.4.1",
|
"version": "5.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/astro/-/astro-5.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/astro/-/astro-5.4.2.tgz",
|
||||||
"integrity": "sha512-z9BiBz8pV7pZVn1evZv/9bJil3A9UZNyEjDFH3IjD87ioz95HHGLgbjRbbqF1EwSy8JOLKlMNyuQPqjrX8xqWw==",
|
"integrity": "sha512-9Z3fAniIRJaK/o43OroZA1wHUIU+qHiOR9ovlVT/2XQaN25QRXScIsKWlFp0G/zrx5OuuoJ+QnaoHHW061u26A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/compiler": "^2.10.4",
|
"@astrojs/compiler": "^2.10.4",
|
||||||
"@astrojs/internal-helpers": "0.6.0",
|
"@astrojs/internal-helpers": "0.6.0",
|
||||||
|
|
@ -1782,7 +1791,7 @@
|
||||||
"kleur": "^4.1.5",
|
"kleur": "^4.1.5",
|
||||||
"magic-string": "^0.30.17",
|
"magic-string": "^0.30.17",
|
||||||
"magicast": "^0.3.5",
|
"magicast": "^0.3.5",
|
||||||
"mrmime": "^2.0.0",
|
"mrmime": "^2.0.1",
|
||||||
"neotraverse": "^0.6.18",
|
"neotraverse": "^0.6.18",
|
||||||
"p-limit": "^6.2.0",
|
"p-limit": "^6.2.0",
|
||||||
"p-queue": "^8.1.0",
|
"p-queue": "^8.1.0",
|
||||||
|
|
@ -1794,19 +1803,19 @@
|
||||||
"shiki": "^1.29.2",
|
"shiki": "^1.29.2",
|
||||||
"tinyexec": "^0.3.2",
|
"tinyexec": "^0.3.2",
|
||||||
"tinyglobby": "^0.2.12",
|
"tinyglobby": "^0.2.12",
|
||||||
"tsconfck": "^3.1.4",
|
"tsconfck": "^3.1.5",
|
||||||
"ultrahtml": "^1.5.3",
|
"ultrahtml": "^1.5.3",
|
||||||
"unist-util-visit": "^5.0.0",
|
"unist-util-visit": "^5.0.0",
|
||||||
"unstorage": "^1.14.4",
|
"unstorage": "^1.15.0",
|
||||||
"vfile": "^6.0.3",
|
"vfile": "^6.0.3",
|
||||||
"vite": "^6.2.0",
|
"vite": "^6.2.0",
|
||||||
"vitefu": "^1.0.5",
|
"vitefu": "^1.0.6",
|
||||||
"which-pm": "^3.0.1",
|
"which-pm": "^3.0.1",
|
||||||
"xxhash-wasm": "^1.1.0",
|
"xxhash-wasm": "^1.1.0",
|
||||||
"yargs-parser": "^21.1.1",
|
"yargs-parser": "^21.1.1",
|
||||||
"yocto-spinner": "^0.2.0",
|
"yocto-spinner": "^0.2.1",
|
||||||
"zod": "^3.24.1",
|
"zod": "^3.24.2",
|
||||||
"zod-to-json-schema": "^3.24.1",
|
"zod-to-json-schema": "^3.24.3",
|
||||||
"zod-to-ts": "^1.2.0"
|
"zod-to-ts": "^1.2.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -1848,6 +1857,20 @@
|
||||||
"crypto-js": "^4.2.0"
|
"crypto-js": "^4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/astro/node_modules/chokidar": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||||
|
"dependencies": {
|
||||||
|
"readdirp": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.16.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/astro/node_modules/estree-walker": {
|
"node_modules/astro/node_modules/estree-walker": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
||||||
|
|
@ -1856,17 +1879,29 @@
|
||||||
"@types/estree": "^1.0.0"
|
"@types/estree": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/astro/node_modules/readdirp": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.18.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/astro/node_modules/unstorage": {
|
"node_modules/astro/node_modules/unstorage": {
|
||||||
"version": "1.14.4",
|
"version": "1.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.14.4.tgz",
|
"resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.15.0.tgz",
|
||||||
"integrity": "sha512-1SYeamwuYeQJtJ/USE1x4l17LkmQBzg7deBJ+U9qOBoHo15d1cDxG4jM31zKRgF7pG0kirZy4wVMX6WL6Zoscg==",
|
"integrity": "sha512-m40eHdGY/gA6xAPqo8eaxqXgBuzQTlAKfmB1iF7oCKXE1HfwHwzDJBywK+qQGn52dta+bPlZluPF7++yR3p/bg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"anymatch": "^3.1.3",
|
"anymatch": "^3.1.3",
|
||||||
"chokidar": "^3.6.0",
|
"chokidar": "^4.0.3",
|
||||||
"destr": "^2.0.3",
|
"destr": "^2.0.3",
|
||||||
"h3": "^1.13.0",
|
"h3": "^1.15.0",
|
||||||
"lru-cache": "^10.4.3",
|
"lru-cache": "^10.4.3",
|
||||||
"node-fetch-native": "^1.6.4",
|
"node-fetch-native": "^1.6.6",
|
||||||
"ofetch": "^1.4.1",
|
"ofetch": "^1.4.1",
|
||||||
"ufo": "^1.5.4"
|
"ufo": "^1.5.4"
|
||||||
},
|
},
|
||||||
|
|
@ -1874,21 +1909,21 @@
|
||||||
"@azure/app-configuration": "^1.8.0",
|
"@azure/app-configuration": "^1.8.0",
|
||||||
"@azure/cosmos": "^4.2.0",
|
"@azure/cosmos": "^4.2.0",
|
||||||
"@azure/data-tables": "^13.3.0",
|
"@azure/data-tables": "^13.3.0",
|
||||||
"@azure/identity": "^4.5.0",
|
"@azure/identity": "^4.6.0",
|
||||||
"@azure/keyvault-secrets": "^4.9.0",
|
"@azure/keyvault-secrets": "^4.9.0",
|
||||||
"@azure/storage-blob": "^12.26.0",
|
"@azure/storage-blob": "^12.26.0",
|
||||||
"@capacitor/preferences": "^6.0.3",
|
"@capacitor/preferences": "^6.0.3",
|
||||||
"@deno/kv": ">=0.8.4",
|
"@deno/kv": ">=0.9.0",
|
||||||
"@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0",
|
"@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0",
|
||||||
"@planetscale/database": "^1.19.0",
|
"@planetscale/database": "^1.19.0",
|
||||||
"@upstash/redis": "^1.34.3",
|
"@upstash/redis": "^1.34.3",
|
||||||
"@vercel/blob": ">=0.27.0",
|
"@vercel/blob": ">=0.27.1",
|
||||||
"@vercel/kv": "^1.0.1",
|
"@vercel/kv": "^1.0.1",
|
||||||
"aws4fetch": "^1.0.20",
|
"aws4fetch": "^1.0.20",
|
||||||
"db0": ">=0.2.1",
|
"db0": ">=0.2.1",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"ioredis": "^5.4.2",
|
"ioredis": "^5.4.2",
|
||||||
"uploadthing": "^7.4.1"
|
"uploadthing": "^7.4.4"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@azure/app-configuration": {
|
"@azure/app-configuration": {
|
||||||
|
|
@ -2056,12 +2091,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0"
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
|
|
@ -2324,11 +2358,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz",
|
||||||
"integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="
|
"integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="
|
||||||
},
|
},
|
||||||
"node_modules/concat-map": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
|
||||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
|
||||||
},
|
|
||||||
"node_modules/consola": {
|
"node_modules/consola": {
|
||||||
"version": "3.4.0",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz",
|
||||||
|
|
@ -2364,9 +2393,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/crossws": {
|
"node_modules/crossws": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.4.tgz",
|
||||||
"integrity": "sha512-/71DJT3xJlqSnBr83uGJesmVHSzZEvgxHt/fIKxBAAngqMHmnBWQNxCphVxxJ2XL3xleu5+hJD6IQ3TglBedcw==",
|
"integrity": "sha512-uj0O1ETYX1Bh6uSgktfPvwDiPYGQ3aI4qVsaC/LWpkIzGj1nUYm5FK3K+t11oOlpN01lGbprFCH4wBlKdJjVgw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"uncrypto": "^0.1.3"
|
"uncrypto": "^0.1.3"
|
||||||
}
|
}
|
||||||
|
|
@ -2374,9 +2403,7 @@
|
||||||
"node_modules/crypto-js": {
|
"node_modules/crypto-js": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
|
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
||||||
"optional": true,
|
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/cssesc": {
|
"node_modules/cssesc": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
|
|
@ -2789,11 +2816,6 @@
|
||||||
"url": "https://github.com/sponsors/rawify"
|
"url": "https://github.com/sponsors/rawify"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fs.realpath": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
|
||||||
},
|
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
|
@ -2832,20 +2854,19 @@
|
||||||
"integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="
|
"integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="
|
||||||
},
|
},
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "7.2.3",
|
"version": "10.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fs.realpath": "^1.0.0",
|
"foreground-child": "^3.1.0",
|
||||||
"inflight": "^1.0.4",
|
"jackspeak": "^3.1.2",
|
||||||
"inherits": "2",
|
"minimatch": "^9.0.4",
|
||||||
"minimatch": "^3.1.1",
|
"minipass": "^7.1.2",
|
||||||
"once": "^1.3.0",
|
"package-json-from-dist": "^1.0.0",
|
||||||
"path-is-absolute": "^1.0.0"
|
"path-scurry": "^1.11.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"bin": {
|
||||||
"node": "*"
|
"glob": "dist/esm/bin.mjs"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
|
@ -2868,20 +2889,19 @@
|
||||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
||||||
},
|
},
|
||||||
"node_modules/h3": {
|
"node_modules/h3": {
|
||||||
"version": "1.14.0",
|
"version": "1.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/h3/-/h3-1.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/h3/-/h3-1.15.1.tgz",
|
||||||
"integrity": "sha512-ao22eiONdgelqcnknw0iD645qW0s9NnrJHr5OBz4WOMdBdycfSas1EQf1wXRsm+PcB2Yoj43pjBPwqIpJQTeWg==",
|
"integrity": "sha512-+ORaOBttdUm1E2Uu/obAyCguiI7MbBvsLTndc3gyK3zU+SYLoZXlyCP9Xgy0gikkGufFLTZXCXD6+4BsufnmHA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cookie-es": "^1.2.2",
|
"cookie-es": "^1.2.2",
|
||||||
"crossws": "^0.3.2",
|
"crossws": "^0.3.3",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
"destr": "^2.0.3",
|
"destr": "^2.0.3",
|
||||||
"iron-webcrypto": "^1.2.1",
|
"iron-webcrypto": "^1.2.1",
|
||||||
"ohash": "^1.1.4",
|
"node-mock-http": "^1.0.0",
|
||||||
"radix3": "^1.1.2",
|
"radix3": "^1.1.2",
|
||||||
"ufo": "^1.5.4",
|
"ufo": "^1.5.4",
|
||||||
"uncrypto": "^0.1.3",
|
"uncrypto": "^0.1.3"
|
||||||
"unenv": "^1.10.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/hasown": {
|
"node_modules/hasown": {
|
||||||
|
|
@ -3102,25 +3122,10 @@
|
||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/inflight": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
|
||||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
|
||||||
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
|
|
||||||
"dependencies": {
|
|
||||||
"once": "^1.3.0",
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/inherits": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
|
||||||
},
|
|
||||||
"node_modules/ioredis": {
|
"node_modules/ioredis": {
|
||||||
"version": "5.5.0",
|
"version": "5.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.6.0.tgz",
|
||||||
"integrity": "sha512-7CutT89g23FfSa8MDoIFs2GYYa0PaNiW/OrT+nRyjRXHDZd17HmIgy+reOQ/yhh72NznNjGuS8kbCAcA4Ro4mw==",
|
"integrity": "sha512-tBZlIIWbndeWBWCXWZiqtOF/yxf6yZX3tAlTJ7nfo5jhd6dctNxF7QnYlZLZ1a0o0pDoen7CgZqO+zjNaFbJAg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ioredis/commands": "^1.1.1",
|
"@ioredis/commands": "^1.1.1",
|
||||||
"cluster-key-slot": "^1.1.0",
|
"cluster-key-slot": "^1.1.0",
|
||||||
|
|
@ -4220,26 +4225,18 @@
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mime": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
|
|
||||||
"bin": {
|
|
||||||
"mime": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "3.1.2",
|
"version": "9.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^2.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minipass": {
|
"node_modules/minipass": {
|
||||||
|
|
@ -4277,9 +4274,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mrmime": {
|
"node_modules/mrmime": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
||||||
"integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
|
"integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
|
|
@ -4370,6 +4367,11 @@
|
||||||
"node-gyp-build-test": "build-test.js"
|
"node-gyp-build-test": "build-test.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-mock-http": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ=="
|
||||||
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.19",
|
"version": "2.0.19",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
||||||
|
|
@ -4431,19 +4433,6 @@
|
||||||
"ufo": "^1.5.4"
|
"ufo": "^1.5.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ohash": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g=="
|
|
||||||
},
|
|
||||||
"node_modules/once": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
|
||||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
|
||||||
"dependencies": {
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/oniguruma-to-es": {
|
"node_modules/oniguruma-to-es": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-2.3.0.tgz",
|
||||||
|
|
@ -4568,14 +4557,6 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-is-absolute": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/path-key": {
|
"node_modules/path-key": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
|
|
@ -4615,11 +4596,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
|
||||||
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="
|
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="
|
||||||
},
|
},
|
||||||
"node_modules/pathe": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="
|
|
||||||
},
|
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
|
|
@ -5193,47 +5169,6 @@
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rimraf/node_modules/brace-expansion": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/rimraf/node_modules/glob": {
|
|
||||||
"version": "10.4.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
|
||||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
|
||||||
"dependencies": {
|
|
||||||
"foreground-child": "^3.1.0",
|
|
||||||
"jackspeak": "^3.1.2",
|
|
||||||
"minimatch": "^9.0.4",
|
|
||||||
"minipass": "^7.1.2",
|
|
||||||
"package-json-from-dist": "^1.0.0",
|
|
||||||
"path-scurry": "^1.11.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"glob": "dist/esm/bin.mjs"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/rimraf/node_modules/minimatch": {
|
|
||||||
"version": "9.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
|
||||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
|
||||||
"dependencies": {
|
|
||||||
"brace-expansion": "^2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16 || 14 >=14.17"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.32.1",
|
"version": "4.32.1",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.1.tgz",
|
||||||
|
|
@ -5580,47 +5515,6 @@
|
||||||
"node": ">=16 || 14 >=14.17"
|
"node": ">=16 || 14 >=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sucrase/node_modules/brace-expansion": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sucrase/node_modules/glob": {
|
|
||||||
"version": "10.4.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
|
||||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
|
||||||
"dependencies": {
|
|
||||||
"foreground-child": "^3.1.0",
|
|
||||||
"jackspeak": "^3.1.2",
|
|
||||||
"minimatch": "^9.0.4",
|
|
||||||
"minipass": "^7.1.2",
|
|
||||||
"package-json-from-dist": "^1.0.0",
|
|
||||||
"path-scurry": "^1.11.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"glob": "dist/esm/bin.mjs"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sucrase/node_modules/minimatch": {
|
|
||||||
"version": "9.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
|
||||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
|
||||||
"dependencies": {
|
|
||||||
"brace-expansion": "^2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16 || 14 >=14.17"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/supports-preserve-symlinks-flag": {
|
"node_modules/supports-preserve-symlinks-flag": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||||
|
|
@ -5774,9 +5668,9 @@
|
||||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
|
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
|
||||||
},
|
},
|
||||||
"node_modules/tsconfck": {
|
"node_modules/tsconfck": {
|
||||||
"version": "3.1.4",
|
"version": "3.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.5.tgz",
|
||||||
"integrity": "sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==",
|
"integrity": "sha512-CLDfGgUp7XPswWnezWwsCRxNmgQjhYq3VXHM0/XIRxhVrKw0M1if9agzryh1QS3nxjCROvV+xWxoJO1YctzzWg==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsconfck": "bin/tsconfck.js"
|
"tsconfck": "bin/tsconfck.js"
|
||||||
},
|
},
|
||||||
|
|
@ -5842,18 +5736,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
||||||
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
|
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
|
||||||
},
|
},
|
||||||
"node_modules/unenv": {
|
|
||||||
"version": "1.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/unenv/-/unenv-1.10.0.tgz",
|
|
||||||
"integrity": "sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"consola": "^3.2.3",
|
|
||||||
"defu": "^6.1.4",
|
|
||||||
"mime": "^3.0.0",
|
|
||||||
"node-fetch-native": "^1.6.4",
|
|
||||||
"pathe": "^1.1.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/unified": {
|
"node_modules/unified": {
|
||||||
"version": "11.0.5",
|
"version": "11.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
|
||||||
|
|
@ -6069,9 +5951,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.1.tgz",
|
||||||
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==",
|
"integrity": "sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
|
|
@ -6139,9 +6021,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vitefu": {
|
"node_modules/vitefu": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.6.tgz",
|
||||||
"integrity": "sha512-h4Vflt9gxODPFNGPwp4zAMZRpZR7eslzwH2c5hn5kNZ5rhnKyRJ50U+yGCdc2IRaBs8O4haIgLNGrV5CrpMsCA==",
|
"integrity": "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"tests/deps/*",
|
"tests/deps/*",
|
||||||
"tests/projects/*"
|
"tests/projects/*"
|
||||||
|
|
@ -6309,11 +6191,6 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/wrappy": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
|
||||||
},
|
|
||||||
"node_modules/xml-js": {
|
"node_modules/xml-js": {
|
||||||
"version": "1.6.11",
|
"version": "1.6.11",
|
||||||
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
|
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
|
||||||
|
|
@ -6369,9 +6246,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yocto-spinner": {
|
"node_modules/yocto-spinner": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-0.2.1.tgz",
|
||||||
"integrity": "sha512-Qu6WAqNLGleB687CCGcmgHIo8l+J19MX/32UrSMfbf/4L8gLoxjpOYoiHT1asiWyqvjRZbgvOhLlvne6E5Tbdw==",
|
"integrity": "sha512-lHHxjh0bXaLgdJy3cNnVb/F9myx3CkhrvSOEVTkaUgNMXnYFa2xYPVhtGnqhh3jErY2gParBOHallCbc7NrlZQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"yoctocolors": "^2.1.1"
|
"yoctocolors": "^2.1.1"
|
||||||
},
|
},
|
||||||
|
|
@ -6394,17 +6271,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/zod": {
|
"node_modules/zod": {
|
||||||
"version": "3.24.1",
|
"version": "3.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
|
||||||
"integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
|
"integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/zod-to-json-schema": {
|
"node_modules/zod-to-json-schema": {
|
||||||
"version": "3.24.1",
|
"version": "3.24.3",
|
||||||
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.1.tgz",
|
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.3.tgz",
|
||||||
"integrity": "sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==",
|
"integrity": "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"zod": "^3.24.1"
|
"zod": "^3.24.1"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/rss": "^4.0.11",
|
"@astrojs/rss": "^4.0.11",
|
||||||
"@astrojs/tailwind": "^6.0.0",
|
"@astrojs/tailwind": "^6.0.0",
|
||||||
"@astrojs/vercel": "^8.1.0",
|
"@astrojs/vercel": "^8.1.1",
|
||||||
"@floating-ui/dom": "^1.6.13",
|
"@floating-ui/dom": "^1.6.13",
|
||||||
"@types/node": "^22.13.9",
|
"@types/node": "^22.13.9",
|
||||||
"@vercel/analytics": "^1.5.0",
|
"@vercel/analytics": "^1.5.0",
|
||||||
"@vercel/kv": "^3.0.0",
|
"@vercel/kv": "^3.0.0",
|
||||||
"astro": "^5.4.1",
|
"astro": "^5.4.2",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"ioredis": "^5.5.0",
|
"ioredis": "^5.6.0",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
238
src/lib/db.ts
238
src/lib/db.ts
|
|
@ -7,16 +7,9 @@ interface RedisNetworkError extends Error {
|
||||||
code?: string;
|
code?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Primary Redis configuration - with more robust fallbacks and logging
|
// Primary Redis configuration
|
||||||
const PRIMARY_REDIS_URL = import.meta.env.PRIMARY_REDIS_URL || process.env.PRIMARY_REDIS_URL || process.env.REDIS_URL;
|
const PRIMARY_REDIS_URL = import.meta.env.PRIMARY_REDIS_URL || process.env.PRIMARY_REDIS_URL || process.env.REDIS_URL;
|
||||||
|
|
||||||
// Log Redis URL status (without exposing sensitive data)
|
|
||||||
console.log(`Redis URLs status: Primary=${Boolean(PRIMARY_REDIS_URL)}`);
|
|
||||||
|
|
||||||
if (!PRIMARY_REDIS_URL) {
|
|
||||||
console.warn('WARNING: No Redis URL configured. Database functionality will not work properly.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiple replicas support
|
// Multiple replicas support
|
||||||
const REPLICA_URLS = [
|
const REPLICA_URLS = [
|
||||||
import.meta.env.REPLICA_REDIS_URL_1 || process.env.REPLICA_REDIS_URL_1 || import.meta.env.REPLICA_REDIS_URL || process.env.REPLICA_REDIS_URL,
|
import.meta.env.REPLICA_REDIS_URL_1 || process.env.REPLICA_REDIS_URL_1 || import.meta.env.REPLICA_REDIS_URL || process.env.REPLICA_REDIS_URL,
|
||||||
|
|
@ -24,8 +17,6 @@ const REPLICA_URLS = [
|
||||||
import.meta.env.REPLICA_REDIS_URL_3 || process.env.REPLICA_REDIS_URL_3,
|
import.meta.env.REPLICA_REDIS_URL_3 || process.env.REPLICA_REDIS_URL_3,
|
||||||
].filter(Boolean) as string[];
|
].filter(Boolean) as string[];
|
||||||
|
|
||||||
console.log(`Found ${REPLICA_URLS.length} Redis replica URLs`);
|
|
||||||
|
|
||||||
// Create a mapping of URLs to friendly names for logging
|
// Create a mapping of URLs to friendly names for logging
|
||||||
const redisInstanceNames = new Map<string, string>();
|
const redisInstanceNames = new Map<string, string>();
|
||||||
|
|
||||||
|
|
@ -53,8 +44,8 @@ let replicaClients: Map<string, Redis> = new Map();
|
||||||
const DEFAULT_CACHE_TTL = 60 * 60 * 24 * 30; // 30 days
|
const DEFAULT_CACHE_TTL = 60 * 60 * 24 * 30; // 30 days
|
||||||
const MAX_RETRIES = 5;
|
const MAX_RETRIES = 5;
|
||||||
const BASE_DELAY_MS = 100;
|
const BASE_DELAY_MS = 100;
|
||||||
const IS_VERCEL = process.env.VERCEL || import.meta.env.VERCEL || false;
|
const IS_VERCEL = process.env.VERCEL || false;
|
||||||
const VERCEL_CONNECTION_TIMEOUT = 25000; // 25 seconds for Vercel
|
const VERCEL_CONNECTION_TIMEOUT = 15000; // 15 seconds for Vercel
|
||||||
const LOCAL_CONNECTION_TIMEOUT = 5000; // 5 seconds for local
|
const LOCAL_CONNECTION_TIMEOUT = 5000; // 5 seconds for local
|
||||||
|
|
||||||
// Improved connection handling with exponential backoff
|
// Improved connection handling with exponential backoff
|
||||||
|
|
@ -62,34 +53,26 @@ async function createRedisClient(url: string): Promise<Redis> {
|
||||||
if (!url) throw new Error('Redis URL is not set');
|
if (!url) throw new Error('Redis URL is not set');
|
||||||
|
|
||||||
const redisName = getRedisName(url);
|
const redisName = getRedisName(url);
|
||||||
console.log(`Connecting to ${redisName} Redis instance in ${IS_VERCEL ? 'Vercel' : 'local'} environment`);
|
|
||||||
|
|
||||||
// Parse URL to extract authentication info
|
// Parse URL to extract authentication info
|
||||||
const options = {
|
const options = {
|
||||||
retryStrategy: (times) => {
|
retryStrategy: (times) => {
|
||||||
if (times >= MAX_RETRIES) {
|
if (times >= MAX_RETRIES) return null;
|
||||||
console.error(`${redisName} max retries (${MAX_RETRIES}) reached, giving up`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const delay = Math.min(BASE_DELAY_MS * Math.pow(2, times), 5000);
|
const delay = Math.min(BASE_DELAY_MS * Math.pow(2, times), 5000);
|
||||||
console.log(`${redisName} retry attempt ${times}, next try in ${delay}ms`);
|
console.log(`${redisName} retry attempt ${times}, next try in ${delay}ms`);
|
||||||
return delay + Math.random() * 200; // Add jitter
|
return delay + Math.random() * 200; // Add jitter
|
||||||
},
|
},
|
||||||
maxRetriesPerRequest: 3, // Limit retries for queued commands
|
maxRetriesPerRequest: null, // Allow retries for queued commands
|
||||||
enableOfflineQueue: true, // Enable command queuing
|
enableOfflineQueue: true, // Enable command queuing
|
||||||
enableReadyCheck: true,
|
enableReadyCheck: true,
|
||||||
connectTimeout: IS_VERCEL ? VERCEL_CONNECTION_TIMEOUT : LOCAL_CONNECTION_TIMEOUT,
|
connectTimeout: 15000, // Increase connection timeout to 15 seconds for Vercel's serverless environment
|
||||||
disconnectTimeout: 10000, // Increase disconnect timeout to 10 seconds
|
disconnectTimeout: 10000, // Increase disconnect timeout to 10 seconds
|
||||||
keepAlive: 10000, // Send keepalive every 10 seconds
|
keepAlive: 10000, // Send keepalive every 10 seconds
|
||||||
commandTimeout: 15000, // Command timeout
|
commandTimeout: 10000, // Command timeout
|
||||||
retryMaxDelay: 5000, // Maximum delay between retries
|
retryMaxDelay: 5000, // Maximum delay between retries
|
||||||
reconnectOnError: (err) => {
|
reconnectOnError: (err) => {
|
||||||
const targetErrors = ['READONLY', 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND'];
|
const targetErrors = ['READONLY', 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND'];
|
||||||
const shouldReconnect = targetErrors.some(e => err.message.includes(e));
|
return targetErrors.some(e => err.message.includes(e));
|
||||||
if (shouldReconnect) {
|
|
||||||
console.log(`Reconnecting due to error: ${err.message}`);
|
|
||||||
}
|
|
||||||
return shouldReconnect;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -103,60 +86,138 @@ export async function getRedisClient(): Promise<Redis> {
|
||||||
console.log('Running in Vercel environment - using optimized Redis connection strategy');
|
console.log('Running in Vercel environment - using optimized Redis connection strategy');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if Redis is configured
|
// Try primary first
|
||||||
if (!PRIMARY_REDIS_URL && REPLICA_URLS.length === 0) {
|
if (primaryClient?.status === 'ready') {
|
||||||
throw new Error('No Redis URLs configured. Please check your environment variables in the Vercel dashboard.');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Try primary first
|
|
||||||
if (!primaryClient) {
|
|
||||||
console.log('Creating new primary Redis client');
|
|
||||||
if (!PRIMARY_REDIS_URL) {
|
|
||||||
throw new Error('Primary Redis URL is not set. Please check your environment variables.');
|
|
||||||
}
|
|
||||||
primaryClient = await createRedisClient(PRIMARY_REDIS_URL);
|
|
||||||
} else if (primaryClient.status !== 'ready') {
|
|
||||||
console.log('Primary Redis client not ready, reconnecting');
|
|
||||||
try {
|
|
||||||
await primaryClient.disconnect();
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error disconnecting primary client:', e);
|
|
||||||
}
|
|
||||||
primaryClient = await createRedisClient(PRIMARY_REDIS_URL);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Add timeout to ping
|
// Add timeout to ping
|
||||||
const pingPromise = primaryClient.ping();
|
const pingPromise = primaryClient.ping();
|
||||||
const timeoutPromise = new Promise((_, reject) =>
|
const timeoutPromise = new Promise((_, reject) =>
|
||||||
setTimeout(() => reject(new Error('Ping timeout')), 5000)
|
setTimeout(() => reject(new Error('Ping timeout')), 3000)
|
||||||
);
|
);
|
||||||
|
|
||||||
await Promise.race([pingPromise, timeoutPromise]);
|
await Promise.race([pingPromise, timeoutPromise]);
|
||||||
return primaryClient;
|
return primaryClient;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Primary Redis client ping failed:', error);
|
console.warn('Primary Redis connection failed, will try replicas:', error);
|
||||||
throw error;
|
// Fall through to try replicas
|
||||||
}
|
}
|
||||||
} catch (primaryError) {
|
}
|
||||||
console.error('Error connecting to primary Redis:', primaryError);
|
|
||||||
|
// Try replicas in sequence
|
||||||
|
for (const [url, client] of replicaClients.entries()) {
|
||||||
|
if (client.status === 'ready') {
|
||||||
|
try {
|
||||||
|
// Add timeout to ping
|
||||||
|
const pingPromise = client.ping();
|
||||||
|
const timeoutPromise = new Promise((_, reject) =>
|
||||||
|
setTimeout(() => reject(new Error('Ping timeout')), 3000)
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.race([pingPromise, timeoutPromise]);
|
||||||
|
console.log(`Using ${getRedisName(url)}`);
|
||||||
|
return client;
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`${getRedisName(url)} connection failed:`, error);
|
||||||
|
// Continue to next replica
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconnect to primary
|
||||||
|
try {
|
||||||
|
console.log('Initializing new primary Redis connection...');
|
||||||
|
primaryClient = await createRedisClient(PRIMARY_REDIS_URL!);
|
||||||
|
|
||||||
|
primaryClient
|
||||||
|
.on('ready', () => console.log('Primary Redis connection ready'))
|
||||||
|
.on('error', (err: RedisNetworkError) => {
|
||||||
|
// Log more details for connection errors
|
||||||
|
if (err.code === 'ETIMEDOUT') {
|
||||||
|
console.error('Primary Redis connection timeout. This is common in serverless environments like Vercel. Check your network connectivity and Redis server availability.');
|
||||||
|
} else if (err.code === 'ECONNREFUSED') {
|
||||||
|
console.error('Primary Redis connection refused. Ensure the Redis server is running and the URL is correct.');
|
||||||
|
} else if (err.code === 'ENOTFOUND') {
|
||||||
|
console.error('Primary Redis host not found. Check your PRIMARY_REDIS_URL environment variable.');
|
||||||
|
} else {
|
||||||
|
console.error('Primary Redis error:', err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on('reconnecting', () => console.log('Primary Redis reconnecting'))
|
||||||
|
.on('end', () => console.log('Primary Redis connection closed'));
|
||||||
|
|
||||||
|
return primaryClient;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to connect to primary Redis:', error);
|
||||||
|
|
||||||
// Special handling for Vercel ETIMEDOUT errors
|
// Special handling for Vercel ETIMEDOUT errors
|
||||||
if (IS_VERCEL && primaryError instanceof Error) {
|
if (IS_VERCEL && error instanceof Error && error.message.includes('ETIMEDOUT')) {
|
||||||
const errorMsg = primaryError.message;
|
console.log('Encountered ETIMEDOUT in Vercel environment. Retrying with longer timeout...');
|
||||||
|
try {
|
||||||
|
// Try one more time with increased timeout
|
||||||
|
const tempClient = new Redis(PRIMARY_REDIS_URL!, {
|
||||||
|
connectTimeout: 20000, // Increased timeout for last-ditch effort
|
||||||
|
retryStrategy: () => null // No retries for this attempt
|
||||||
|
});
|
||||||
|
|
||||||
if (errorMsg.includes('ETIMEDOUT')) {
|
// Wait for ready or error
|
||||||
console.log('Encountered ETIMEDOUT in Vercel environment. This is a common issue with Vercel serverless functions and Redis.');
|
await new Promise((resolve, reject) => {
|
||||||
throw new Error('Redis connection timed out. Please ensure your Redis service allows connections from Vercel IP ranges. See Vercel documentation for IP ranges used by their serverless functions.');
|
const timeout = setTimeout(() => {
|
||||||
} else if (errorMsg.includes('ECONNREFUSED')) {
|
tempClient.disconnect();
|
||||||
throw new Error('Redis connection refused. Please check if your Redis service is running and accessible from Vercel.');
|
reject(new Error('Final connection attempt timed out'));
|
||||||
} else if (errorMsg.includes('ENOTFOUND')) {
|
}, 20000);
|
||||||
throw new Error('Redis host not found. Please check your PRIMARY_REDIS_URL environment variable.');
|
|
||||||
|
tempClient.once('ready', () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
tempClient.once('error', (err) => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// If we get here, connection was successful
|
||||||
|
primaryClient = tempClient;
|
||||||
|
return tempClient;
|
||||||
|
} catch (finalError) {
|
||||||
|
console.error('Final Redis connection attempt failed:', finalError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw primaryError;
|
// Try connecting to any replica that might be available
|
||||||
|
for (const url of REPLICA_URLS) {
|
||||||
|
try {
|
||||||
|
const redisName = getRedisName(url);
|
||||||
|
console.log(`Trying to connect to ${redisName}...`);
|
||||||
|
const client = await createRedisClient(url);
|
||||||
|
|
||||||
|
client
|
||||||
|
.on('ready', () => console.log(`${redisName} connection ready`))
|
||||||
|
.on('error', (err: RedisNetworkError) => {
|
||||||
|
// Log more details for connection errors
|
||||||
|
if (err.code === 'ETIMEDOUT') {
|
||||||
|
console.error(`${redisName} connection timeout. This is common in serverless environments like Vercel. Check your network connectivity and Redis server availability.`);
|
||||||
|
} else if (err.code === 'ECONNREFUSED') {
|
||||||
|
console.error(`${redisName} connection refused. Ensure the Redis server is running and the URL is correct.`);
|
||||||
|
} else if (err.code === 'ENOTFOUND') {
|
||||||
|
console.error(`${redisName} host not found. Check your Redis URL environment variables.`);
|
||||||
|
} else {
|
||||||
|
console.error(`${redisName} error:`, err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on('reconnecting', () => console.log(`${redisName} reconnecting`))
|
||||||
|
.on('end', () => console.log(`${redisName} connection closed`));
|
||||||
|
|
||||||
|
replicaClients.set(url, client);
|
||||||
|
return client;
|
||||||
|
} catch (replicaError) {
|
||||||
|
console.error(`Failed to connect to ${getRedisName(url)}:`, replicaError);
|
||||||
|
// Continue to next replica
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('All Redis connections failed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -277,57 +338,24 @@ export async function warmChapterCache(slugs: string[], lang: string): Promise<v
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function storeFeedMapping(feedId: string, slugs: string[], lang: string): Promise<void> {
|
export async function storeFeedMapping(feedId: string, slugs: string[], lang: string): Promise<void> {
|
||||||
if (!feedId) throw new Error('Feed ID is required');
|
|
||||||
if (!Array.isArray(slugs) || slugs.length === 0) throw new Error('Slugs array is required and cannot be empty');
|
|
||||||
if (!lang) throw new Error('Language is required');
|
|
||||||
|
|
||||||
const mapping = {
|
const mapping = {
|
||||||
slugs,
|
slugs,
|
||||||
lang,
|
lang,
|
||||||
created_at: new Date().toISOString()
|
created_at: new Date().toISOString()
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`Attempting to store feed mapping with ID: ${feedId}, language: ${lang}, and ${slugs.length} slugs`);
|
|
||||||
|
|
||||||
// Check if Redis is configured
|
|
||||||
if (!PRIMARY_REDIS_URL && REPLICA_URLS.length === 0) {
|
|
||||||
console.error('No Redis URLs configured. Cannot store feed mapping.');
|
|
||||||
throw new Error('Database connection not configured. Please check your environment variables.');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await writeToAllRedis(async (redis) => {
|
await writeToAllRedis(async (redis) => {
|
||||||
console.log(`Writing feed mapping to Redis instance...`);
|
await redis.set(
|
||||||
|
feedId,
|
||||||
try {
|
JSON.stringify(mapping),
|
||||||
await redis.set(
|
'EX',
|
||||||
feedId,
|
DEFAULT_CACHE_TTL
|
||||||
JSON.stringify(mapping),
|
);
|
||||||
'EX',
|
|
||||||
DEFAULT_CACHE_TTL
|
|
||||||
);
|
|
||||||
console.log(`Successfully stored feed mapping in Redis instance`);
|
|
||||||
} catch (redisError: any) {
|
|
||||||
console.error(`Redis set operation failed:`, redisError);
|
|
||||||
throw new Error(`Redis operation failed: ${redisError.message || 'Unknown Redis error'}`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
console.log(`Feed mapping successfully stored with ID: ${feedId}`);
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error('Error storing feed mapping:', error);
|
console.error('Error storing feed mapping:', error);
|
||||||
|
throw new Error('Failed to store feed mapping');
|
||||||
// Check for common connection issues
|
|
||||||
const errorMsg = error.message || '';
|
|
||||||
if (errorMsg.includes('ECONNREFUSED')) {
|
|
||||||
throw new Error('Unable to connect to the Redis database. Connection refused.');
|
|
||||||
} else if (errorMsg.includes('ETIMEDOUT')) {
|
|
||||||
throw new Error('Connection to Redis database timed out. This may be due to network issues or firewall settings.');
|
|
||||||
} else if (errorMsg.includes('ENOTFOUND')) {
|
|
||||||
throw new Error('Redis host not found. Please check your database URL configuration.');
|
|
||||||
} else {
|
|
||||||
throw new Error(`Failed to store feed mapping: ${errorMsg}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,52 +7,18 @@ const feedMappings = new Map<string, { slugs: string[], lang: string }>();
|
||||||
|
|
||||||
export const POST: APIRoute = async ({ request }) => {
|
export const POST: APIRoute = async ({ request }) => {
|
||||||
try {
|
try {
|
||||||
console.log("Handling create-feed API request");
|
const { slugs, lang } = await request.json();
|
||||||
|
|
||||||
if (!request.body) {
|
|
||||||
console.error("Request has no body");
|
|
||||||
return new Response("Request body is required", { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
let body;
|
|
||||||
try {
|
|
||||||
body = await request.json();
|
|
||||||
} catch (parseError) {
|
|
||||||
console.error("Failed to parse request JSON:", parseError);
|
|
||||||
return new Response("Invalid JSON in request body", { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const { slugs, lang } = body;
|
|
||||||
|
|
||||||
if (!Array.isArray(slugs) || slugs.length === 0) {
|
if (!Array.isArray(slugs) || slugs.length === 0) {
|
||||||
console.error("Invalid slugs array:", slugs);
|
|
||||||
return new Response("Invalid slugs array", { status: 400 });
|
return new Response("Invalid slugs array", { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lang) {
|
|
||||||
console.error("Language not specified");
|
|
||||||
return new Response("Language is required", { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Creating feed for ${slugs.length} slugs in language: ${lang}`);
|
|
||||||
|
|
||||||
// Create a unique hash based on slugs and language
|
// Create a unique hash based on slugs and language
|
||||||
const dataString = `${slugs.sort().join(',')}:${lang}`;
|
const dataString = `${slugs.sort().join(',')}:${lang}`;
|
||||||
const hash = createHash('md5').update(dataString).digest('hex').slice(0, 8);
|
const hash = createHash('md5').update(dataString).digest('hex').slice(0, 8);
|
||||||
|
|
||||||
try {
|
// Store the mapping in Vercel KV
|
||||||
// Store the mapping in Redis
|
await storeFeedMapping(hash, slugs, lang);
|
||||||
await storeFeedMapping(hash, slugs, lang);
|
|
||||||
console.log(`Successfully created feed with ID: ${hash}`);
|
|
||||||
} catch (dbError: any) {
|
|
||||||
console.error("Database error while storing feed mapping:", dbError);
|
|
||||||
return new Response(`Database error: ${dbError.message || "Unknown error"}`, {
|
|
||||||
status: 500,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response(JSON.stringify({ feedId: hash }), {
|
return new Response(JSON.stringify({ feedId: hash }), {
|
||||||
status: 200,
|
status: 200,
|
||||||
|
|
@ -60,18 +26,9 @@ export const POST: APIRoute = async ({ request }) => {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('Unexpected error creating feed:', error);
|
console.error('Error creating feed:', error);
|
||||||
return new Response(JSON.stringify({
|
return new Response("Internal server error", { status: 500 });
|
||||||
error: "Internal server error",
|
|
||||||
message: error.message || "Unknown error",
|
|
||||||
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
|
|
||||||
}), {
|
|
||||||
status: 500,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue