mirror of
https://github.com/ld3z/new-manga.git
synced 2026-11-11 06:13:44 -07:00
Compare commits
No commits in common. "019f86ad1300bd19e44f28bda8b35581e30130db" and "e1116cd72411fb11613b252fabe71cb729eb13c8" have entirely different histories.
019f86ad13
...
e1116cd724
5 changed files with 268 additions and 443 deletions
|
|
@ -11,10 +11,7 @@ export default defineConfig({
|
||||||
integrations: [tailwind()],
|
integrations: [tailwind()],
|
||||||
vite: {
|
vite: {
|
||||||
define: {
|
define: {
|
||||||
'process.env.PRIMARY_REDIS_URL': JSON.stringify(process.env.PRIMARY_REDIS_URL || process.env.REDIS_URL),
|
'process.env.REDIS_URL': JSON.stringify(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_2': JSON.stringify(process.env.REPLICA_REDIS_URL_2),
|
|
||||||
'process.env.REPLICA_REDIS_URL_3': JSON.stringify(process.env.REPLICA_REDIS_URL_3)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
359
package-lock.json
generated
359
package-lock.json
generated
|
|
@ -10,12 +10,12 @@
|
||||||
"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.0.7",
|
||||||
"@floating-ui/dom": "^1.6.13",
|
"@floating-ui/dom": "^1.6.13",
|
||||||
"@types/node": "^22.13.7",
|
"@types/node": "^22.13.4",
|
||||||
"@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.3.0",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"ioredis": "^5.5.0",
|
"ioredis": "^5.5.0",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
|
|
@ -33,21 +33,20 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@astrojs/compiler": {
|
"node_modules/@astrojs/compiler": {
|
||||||
"version": "2.10.4",
|
"version": "2.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.10.4.tgz",
|
"resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.10.3.tgz",
|
||||||
"integrity": "sha512-86B3QGagP99MvSNwuJGiYSBHnh8nLvm2Q1IFI15wIUJJsPeQTO3eb2uwBmrqRsXykeR/mBzH8XCgz5AAt1BJrQ=="
|
"integrity": "sha512-bL/O7YBxsFt55YHU021oL+xz+B/9HvGNId3F9xURN16aeqDK9juHGktdkCSXz+U4nqFACq6ZFvWomOzhV+zfPw=="
|
||||||
},
|
},
|
||||||
"node_modules/@astrojs/internal-helpers": {
|
"node_modules/@astrojs/internal-helpers": {
|
||||||
"version": "0.6.0",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.5.1.tgz",
|
||||||
"integrity": "sha512-XgHIJDQaGlFnTr0sDp1PiJrtqsWzbHP2qkTU+JpQ8SnBewKP2IKOe/wqCkl0CyfyRXRu3TSWu4t/cpYMVfuBNA=="
|
"integrity": "sha512-M7rAge1n2+aOSxNvKUFa0u/KFn0W+sZy7EW91KOSERotm2Ti8qs+1K0xx3zbOxtAVrmJb5/J98eohVvvEqtNkw=="
|
||||||
},
|
},
|
||||||
"node_modules/@astrojs/markdown-remark": {
|
"node_modules/@astrojs/markdown-remark": {
|
||||||
"version": "6.2.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.1.0.tgz",
|
||||||
"integrity": "sha512-LUDjgd9p1yG0qTFSocaj3GOLmZs8Hsw/pNtvqzvNY58Acebxvb/46vDO/e/wxYgsKgIfWS+p+ZI5SfOjoVrbCg==",
|
"integrity": "sha512-emZNNSTPGgPc3V399Cazpp5+snogjaF04ocOSQn9vy3Kw/eIC4vTQjXOrWDEoSEy+AwPDZX9bQ4wd3bxhpmGgQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/internal-helpers": "0.6.0",
|
|
||||||
"@astrojs/prism": "3.2.0",
|
"@astrojs/prism": "3.2.0",
|
||||||
"github-slugger": "^2.0.0",
|
"github-slugger": "^2.0.0",
|
||||||
"hast-util-from-html": "^2.0.3",
|
"hast-util-from-html": "^2.0.3",
|
||||||
|
|
@ -61,7 +60,7 @@
|
||||||
"remark-parse": "^11.0.0",
|
"remark-parse": "^11.0.0",
|
||||||
"remark-rehype": "^11.1.1",
|
"remark-rehype": "^11.1.1",
|
||||||
"remark-smartypants": "^3.0.2",
|
"remark-smartypants": "^3.0.2",
|
||||||
"shiki": "^1.29.2",
|
"shiki": "^1.29.1",
|
||||||
"smol-toml": "^1.3.1",
|
"smol-toml": "^1.3.1",
|
||||||
"unified": "^11.0.5",
|
"unified": "^11.0.5",
|
||||||
"unist-util-remove-position": "^5.0.0",
|
"unist-util-remove-position": "^5.0.0",
|
||||||
|
|
@ -122,17 +121,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@astrojs/vercel": {
|
"node_modules/@astrojs/vercel": {
|
||||||
"version": "8.1.0",
|
"version": "8.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@astrojs/vercel/-/vercel-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@astrojs/vercel/-/vercel-8.0.7.tgz",
|
||||||
"integrity": "sha512-qaztQ0WCg8epe9+3PS7+eTbukNcwDtfjgN/QeWk0+wmmWHpEBlhzUA17Vmk5OINBX/Tf0bzXgydDWrAVG+/irQ==",
|
"integrity": "sha512-2DPqPGZ/Et4afpJt8CAoIql2S649rzEmLBNJPHUGBysP0JklMaZ05HhQVKr+qEhZSm3NrVccxpkiIG/eLW3nPg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/internal-helpers": "0.6.0",
|
"@astrojs/internal-helpers": "^0.5.1",
|
||||||
"@vercel/analytics": "^1.4.1",
|
"@vercel/analytics": "^1.4.1",
|
||||||
"@vercel/edge": "^1.2.1",
|
"@vercel/edge": "^1.2.1",
|
||||||
"@vercel/nft": "^0.29.0",
|
"@vercel/nft": "^0.29.0",
|
||||||
"@vercel/routing-utils": "^5.0.4",
|
"@vercel/routing-utils": "^5.0.4",
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.24.0",
|
||||||
"tinyglobby": "^0.2.12"
|
"fast-glob": "^3.3.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "^5.0.0"
|
"astro": "^5.0.0"
|
||||||
|
|
@ -190,9 +189,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
|
||||||
"integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
|
"integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
|
|
@ -205,9 +204,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm": {
|
"node_modules/@esbuild/android-arm": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
|
||||||
"integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
|
"integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
|
@ -220,9 +219,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm64": {
|
"node_modules/@esbuild/android-arm64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
|
||||||
"integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
|
"integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -235,9 +234,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-x64": {
|
"node_modules/@esbuild/android-x64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
|
||||||
"integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
|
"integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -250,9 +249,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-arm64": {
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
|
||||||
"integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
|
"integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -265,9 +264,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-x64": {
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
|
||||||
"integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
|
"integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -280,9 +279,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-arm64": {
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
|
||||||
"integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
|
"integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -295,9 +294,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-x64": {
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
|
||||||
"integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
|
"integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -310,9 +309,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm": {
|
"node_modules/@esbuild/linux-arm": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
|
||||||
"integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
|
"integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
|
@ -325,9 +324,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm64": {
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
|
||||||
"integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
|
"integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -340,9 +339,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ia32": {
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
|
||||||
"integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
|
"integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
|
@ -355,9 +354,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-loong64": {
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
|
||||||
"integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
|
"integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
|
|
@ -370,9 +369,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-mips64el": {
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
|
||||||
"integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
|
"integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"mips64el"
|
"mips64el"
|
||||||
],
|
],
|
||||||
|
|
@ -385,9 +384,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ppc64": {
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
|
||||||
"integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
|
"integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
|
|
@ -400,9 +399,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-riscv64": {
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
|
||||||
"integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
|
"integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
|
|
@ -415,9 +414,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-s390x": {
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
|
||||||
"integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
|
"integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
|
|
@ -430,9 +429,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-x64": {
|
"node_modules/@esbuild/linux-x64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
|
||||||
"integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
|
"integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -445,9 +444,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-arm64": {
|
"node_modules/@esbuild/netbsd-arm64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
|
||||||
"integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
|
"integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -460,9 +459,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-x64": {
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
|
||||||
"integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
|
"integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -475,9 +474,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-arm64": {
|
"node_modules/@esbuild/openbsd-arm64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
|
||||||
"integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
|
"integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -490,9 +489,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-x64": {
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
|
||||||
"integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
|
"integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -505,9 +504,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/sunos-x64": {
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
|
||||||
"integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
|
"integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -520,9 +519,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-arm64": {
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
|
||||||
"integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
|
"integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -535,9 +534,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-ia32": {
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
|
||||||
"integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
|
"integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
|
@ -550,9 +549,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-x64": {
|
"node_modules/@esbuild/win32-x64": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
|
||||||
"integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
|
"integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -1413,9 +1412,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@shikijs/vscode-textmate": {
|
"node_modules/@shikijs/vscode-textmate": {
|
||||||
"version": "10.0.2",
|
"version": "10.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.1.tgz",
|
||||||
"integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="
|
"integrity": "sha512-fTIQwLF+Qhuws31iw7Ncl1R3HUDtGwIipiJ9iU+UsDUwMhegFcQKQHd51nZjb7CArq0MvON8rbgCGQYWHUKAdg=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/cookie": {
|
"node_modules/@types/cookie": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
|
|
@ -1465,9 +1464,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.13.7",
|
"version": "22.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz",
|
||||||
"integrity": "sha512-oU2q+BsQldB9lYxHNp/5aZO+/Bs0Usa74Abo9mAKulz4ahQyXRHK6UVKYIN8KSC8HXwhWSi7b49JnX+txuac0w==",
|
"integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~6.20.0"
|
"undici-types": "~6.20.0"
|
||||||
}
|
}
|
||||||
|
|
@ -1754,13 +1753,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/astro": {
|
"node_modules/astro": {
|
||||||
"version": "5.4.1",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/astro/-/astro-5.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/astro/-/astro-5.3.0.tgz",
|
||||||
"integrity": "sha512-z9BiBz8pV7pZVn1evZv/9bJil3A9UZNyEjDFH3IjD87ioz95HHGLgbjRbbqF1EwSy8JOLKlMNyuQPqjrX8xqWw==",
|
"integrity": "sha512-e88l/Yk/6enR/ZDddLbqtM+oblBFk5mneNSmNesyVYGL/6Dj4UA67GPAZOk79VxT5dbLlclZSyyw/wlxN1aj3A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/compiler": "^2.10.4",
|
"@astrojs/compiler": "^2.10.3",
|
||||||
"@astrojs/internal-helpers": "0.6.0",
|
"@astrojs/internal-helpers": "0.5.1",
|
||||||
"@astrojs/markdown-remark": "6.2.0",
|
"@astrojs/markdown-remark": "6.1.0",
|
||||||
"@astrojs/telemetry": "3.2.0",
|
"@astrojs/telemetry": "3.2.0",
|
||||||
"@oslojs/encoding": "^1.1.0",
|
"@oslojs/encoding": "^1.1.0",
|
||||||
"@rollup/pluginutils": "^5.1.4",
|
"@rollup/pluginutils": "^5.1.4",
|
||||||
|
|
@ -1781,8 +1780,9 @@
|
||||||
"dlv": "^1.1.3",
|
"dlv": "^1.1.3",
|
||||||
"dset": "^3.1.4",
|
"dset": "^3.1.4",
|
||||||
"es-module-lexer": "^1.6.0",
|
"es-module-lexer": "^1.6.0",
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.24.2",
|
||||||
"estree-walker": "^3.0.3",
|
"estree-walker": "^3.0.3",
|
||||||
|
"fast-glob": "^3.3.3",
|
||||||
"flattie": "^1.1.1",
|
"flattie": "^1.1.1",
|
||||||
"github-slugger": "^2.0.0",
|
"github-slugger": "^2.0.0",
|
||||||
"html-escaper": "3.0.3",
|
"html-escaper": "3.0.3",
|
||||||
|
|
@ -1791,24 +1791,23 @@
|
||||||
"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",
|
||||||
|
"micromatch": "^4.0.8",
|
||||||
"mrmime": "^2.0.0",
|
"mrmime": "^2.0.0",
|
||||||
"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",
|
||||||
"picomatch": "^4.0.2",
|
|
||||||
"preferred-pm": "^4.1.1",
|
"preferred-pm": "^4.1.1",
|
||||||
"prompts": "^2.4.2",
|
"prompts": "^2.4.2",
|
||||||
"rehype": "^13.0.2",
|
"rehype": "^13.0.2",
|
||||||
"semver": "^7.7.1",
|
"semver": "^7.7.1",
|
||||||
"shiki": "^1.29.2",
|
"shiki": "^1.29.2",
|
||||||
"tinyexec": "^0.3.2",
|
"tinyexec": "^0.3.2",
|
||||||
"tinyglobby": "^0.2.12",
|
|
||||||
"tsconfck": "^3.1.4",
|
"tsconfck": "^3.1.4",
|
||||||
"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.14.4",
|
||||||
"vfile": "^6.0.3",
|
"vfile": "^6.0.3",
|
||||||
"vite": "^6.2.0",
|
"vite": "^6.0.11",
|
||||||
"vitefu": "^1.0.5",
|
"vitefu": "^1.0.5",
|
||||||
"which-pm": "^3.0.1",
|
"which-pm": "^3.0.1",
|
||||||
"xxhash-wasm": "^1.1.0",
|
"xxhash-wasm": "^1.1.0",
|
||||||
|
|
@ -2549,9 +2548,9 @@
|
||||||
"integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ=="
|
"integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ=="
|
||||||
},
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.25.0",
|
"version": "0.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
|
||||||
"integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
|
"integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"esbuild": "bin/esbuild"
|
"esbuild": "bin/esbuild"
|
||||||
|
|
@ -2560,31 +2559,31 @@
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@esbuild/aix-ppc64": "0.25.0",
|
"@esbuild/aix-ppc64": "0.24.2",
|
||||||
"@esbuild/android-arm": "0.25.0",
|
"@esbuild/android-arm": "0.24.2",
|
||||||
"@esbuild/android-arm64": "0.25.0",
|
"@esbuild/android-arm64": "0.24.2",
|
||||||
"@esbuild/android-x64": "0.25.0",
|
"@esbuild/android-x64": "0.24.2",
|
||||||
"@esbuild/darwin-arm64": "0.25.0",
|
"@esbuild/darwin-arm64": "0.24.2",
|
||||||
"@esbuild/darwin-x64": "0.25.0",
|
"@esbuild/darwin-x64": "0.24.2",
|
||||||
"@esbuild/freebsd-arm64": "0.25.0",
|
"@esbuild/freebsd-arm64": "0.24.2",
|
||||||
"@esbuild/freebsd-x64": "0.25.0",
|
"@esbuild/freebsd-x64": "0.24.2",
|
||||||
"@esbuild/linux-arm": "0.25.0",
|
"@esbuild/linux-arm": "0.24.2",
|
||||||
"@esbuild/linux-arm64": "0.25.0",
|
"@esbuild/linux-arm64": "0.24.2",
|
||||||
"@esbuild/linux-ia32": "0.25.0",
|
"@esbuild/linux-ia32": "0.24.2",
|
||||||
"@esbuild/linux-loong64": "0.25.0",
|
"@esbuild/linux-loong64": "0.24.2",
|
||||||
"@esbuild/linux-mips64el": "0.25.0",
|
"@esbuild/linux-mips64el": "0.24.2",
|
||||||
"@esbuild/linux-ppc64": "0.25.0",
|
"@esbuild/linux-ppc64": "0.24.2",
|
||||||
"@esbuild/linux-riscv64": "0.25.0",
|
"@esbuild/linux-riscv64": "0.24.2",
|
||||||
"@esbuild/linux-s390x": "0.25.0",
|
"@esbuild/linux-s390x": "0.24.2",
|
||||||
"@esbuild/linux-x64": "0.25.0",
|
"@esbuild/linux-x64": "0.24.2",
|
||||||
"@esbuild/netbsd-arm64": "0.25.0",
|
"@esbuild/netbsd-arm64": "0.24.2",
|
||||||
"@esbuild/netbsd-x64": "0.25.0",
|
"@esbuild/netbsd-x64": "0.24.2",
|
||||||
"@esbuild/openbsd-arm64": "0.25.0",
|
"@esbuild/openbsd-arm64": "0.24.2",
|
||||||
"@esbuild/openbsd-x64": "0.25.0",
|
"@esbuild/openbsd-x64": "0.24.2",
|
||||||
"@esbuild/sunos-x64": "0.25.0",
|
"@esbuild/sunos-x64": "0.24.2",
|
||||||
"@esbuild/win32-arm64": "0.25.0",
|
"@esbuild/win32-arm64": "0.24.2",
|
||||||
"@esbuild/win32-ia32": "0.25.0",
|
"@esbuild/win32-ia32": "0.24.2",
|
||||||
"@esbuild/win32-x64": "0.25.0"
|
"@esbuild/win32-x64": "0.24.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/escalade": {
|
"node_modules/escalade": {
|
||||||
|
|
@ -2689,19 +2688,6 @@
|
||||||
"reusify": "^1.0.4"
|
"reusify": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fdir": {
|
|
||||||
"version": "6.4.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
|
|
||||||
"integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"picomatch": "^3 || ^4"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"picomatch": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/feed": {
|
"node_modules/feed": {
|
||||||
"version": "4.2.2",
|
"version": "4.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz",
|
||||||
|
|
@ -3502,9 +3488,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mdast-util-gfm": {
|
"node_modules/mdast-util-gfm": {
|
||||||
"version": "3.1.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz",
|
||||||
"integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==",
|
"integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mdast-util-from-markdown": "^2.0.0",
|
"mdast-util-from-markdown": "^2.0.0",
|
||||||
"mdast-util-gfm-autolink-literal": "^2.0.0",
|
"mdast-util-gfm-autolink-literal": "^2.0.0",
|
||||||
|
|
@ -3536,9 +3522,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mdast-util-gfm-footnote": {
|
"node_modules/mdast-util-gfm-footnote": {
|
||||||
"version": "2.1.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz",
|
||||||
"integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==",
|
"integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/mdast": "^4.0.0",
|
"@types/mdast": "^4.0.0",
|
||||||
"devlop": "^1.1.0",
|
"devlop": "^1.1.0",
|
||||||
|
|
@ -3670,9 +3656,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/micromark": {
|
"node_modules/micromark": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.1.tgz",
|
||||||
"integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==",
|
"integrity": "sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "GitHub Sponsors",
|
"type": "GitHub Sponsors",
|
||||||
|
|
@ -3704,9 +3690,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/micromark-core-commonmark": {
|
"node_modules/micromark-core-commonmark": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.2.tgz",
|
||||||
"integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==",
|
"integrity": "sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "GitHub Sponsors",
|
"type": "GitHub Sponsors",
|
||||||
|
|
@ -4154,9 +4140,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/micromark-util-subtokenize": {
|
"node_modules/micromark-util-subtokenize": {
|
||||||
"version": "2.1.0",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.4.tgz",
|
||||||
"integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==",
|
"integrity": "sha512-N6hXjrin2GTJDe3MVjf5FuXpm12PGm80BrUAeub9XFXca8JZbP+oIwY4LJSVwFUCL1IPm/WwSVUN7goFHmSGGQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "GitHub Sponsors",
|
"type": "GitHub Sponsors",
|
||||||
|
|
@ -4671,9 +4657,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.3",
|
"version": "8.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
|
||||||
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
|
@ -5018,9 +5004,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/remark-gfm": {
|
"node_modules/remark-gfm": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz",
|
||||||
"integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==",
|
"integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/mdast": "^4.0.0",
|
"@types/mdast": "^4.0.0",
|
||||||
"mdast-util-gfm": "^3.0.0",
|
"mdast-util-gfm": "^3.0.0",
|
||||||
|
|
@ -5726,21 +5712,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
|
||||||
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="
|
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="
|
||||||
},
|
},
|
||||||
"node_modules/tinyglobby": {
|
|
||||||
"version": "0.2.12",
|
|
||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz",
|
|
||||||
"integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
|
|
||||||
"dependencies": {
|
|
||||||
"fdir": "^6.4.3",
|
|
||||||
"picomatch": "^4.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/to-regex-range": {
|
"node_modules/to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
|
@ -6076,13 +6047,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "6.2.0",
|
"version": "6.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz",
|
||||||
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==",
|
"integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.24.2",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.4.49",
|
||||||
"rollup": "^4.30.1"
|
"rollup": "^4.23.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,12 @@
|
||||||
"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.0.7",
|
||||||
"@floating-ui/dom": "^1.6.13",
|
"@floating-ui/dom": "^1.6.13",
|
||||||
"@types/node": "^22.13.7",
|
"@types/node": "^22.13.4",
|
||||||
"@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.3.0",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"ioredis": "^5.5.0",
|
"ioredis": "^5.5.0",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,12 @@ const isCreditsPage = Astro.url.pathname === '/credits';
|
||||||
|
|
||||||
// Add the announcement configuration
|
// Add the announcement configuration
|
||||||
const announcement = {
|
const announcement = {
|
||||||
message: "Your custom feed may have been affected.",
|
message: "Custom feeds have been fixed.",
|
||||||
type: "info" as const,
|
type: "success" as const,
|
||||||
dismissible: true,
|
dismissible: true,
|
||||||
link: {
|
link: {
|
||||||
text: "Find out what happened here",
|
text: "Find out what happened here",
|
||||||
url: "https://status-6cv.pages.dev/issues/2025_02_28_database-failure-2-20/"
|
url: "https://status-6cv.pages.dev/issues/2025_02_21_database-down-220/"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
---
|
---
|
||||||
|
|
|
||||||
263
src/lib/db.ts
263
src/lib/db.ts
|
|
@ -2,56 +2,21 @@ import Redis from 'ioredis';
|
||||||
import type { FeedMapping } from './types';
|
import type { FeedMapping } from './types';
|
||||||
import { getChaptersForSlugs } from './api';
|
import { getChaptersForSlugs } from './api';
|
||||||
|
|
||||||
// Primary Redis configuration
|
const REDIS_URL = import.meta.env.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;
|
let redisClient: Redis | null = null;
|
||||||
|
|
||||||
// Multiple replicas support
|
|
||||||
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_2 || process.env.REPLICA_REDIS_URL_2,
|
|
||||||
import.meta.env.REPLICA_REDIS_URL_3 || process.env.REPLICA_REDIS_URL_3,
|
|
||||||
].filter(Boolean) as string[];
|
|
||||||
|
|
||||||
// Create a mapping of URLs to friendly names for logging
|
|
||||||
const redisInstanceNames = new Map<string, string>();
|
|
||||||
|
|
||||||
// Initialize friendly names for each Redis instance
|
|
||||||
function initializeRedisNames() {
|
|
||||||
redisInstanceNames.set(PRIMARY_REDIS_URL!, 'Primary');
|
|
||||||
|
|
||||||
REPLICA_URLS.forEach((url, index) => {
|
|
||||||
redisInstanceNames.set(url, `Replica ${index + 1}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call this immediately
|
|
||||||
initializeRedisNames();
|
|
||||||
|
|
||||||
// Helper function to get a safe name for a Redis instance
|
|
||||||
function getRedisName(url: string): string {
|
|
||||||
return redisInstanceNames.get(url) || 'Unknown Redis instance';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client instances
|
|
||||||
let primaryClient: Redis | null = null;
|
|
||||||
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;
|
||||||
|
|
||||||
// Improved connection handling with exponential backoff
|
// Improved connection handling with exponential backoff
|
||||||
async function createRedisClient(url: string): Promise<Redis> {
|
async function createRedisClient(): Promise<Redis> {
|
||||||
if (!url) throw new Error('Redis URL is not set');
|
if (!REDIS_URL) throw new Error('REDIS_URL environment variable is not set');
|
||||||
|
|
||||||
const redisName = getRedisName(url);
|
return new Redis(REDIS_URL, {
|
||||||
|
|
||||||
// Parse URL to extract authentication info
|
|
||||||
const options = {
|
|
||||||
retryStrategy: (times) => {
|
retryStrategy: (times) => {
|
||||||
if (times >= MAX_RETRIES) return null;
|
if (times >= MAX_RETRIES) 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(`Redis retry attempt ${times}, next try in ${delay}ms`);
|
||||||
return delay + Math.random() * 200; // Add jitter
|
return delay + Math.random() * 200; // Add jitter
|
||||||
},
|
},
|
||||||
maxRetriesPerRequest: null, // Allow retries for queued commands
|
maxRetriesPerRequest: null, // Allow retries for queued commands
|
||||||
|
|
@ -60,154 +25,37 @@ async function createRedisClient(url: string): Promise<Redis> {
|
||||||
reconnectOnError: (err) => {
|
reconnectOnError: (err) => {
|
||||||
return err.message.includes('READONLY');
|
return err.message.includes('READONLY');
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
return new Redis(url, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the best available Redis client
|
// Singleton pattern with connection pooling
|
||||||
export async function getRedisClient(): Promise<Redis> {
|
export async function getRedisClient(): Promise<Redis> {
|
||||||
// Try primary first
|
if (redisClient?.status === 'ready') {
|
||||||
if (primaryClient?.status === 'ready') {
|
// Validate connection with a quick ping
|
||||||
try {
|
try {
|
||||||
await primaryClient.ping();
|
await redisClient.ping();
|
||||||
return primaryClient;
|
return redisClient;
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.warn('Primary Redis connection failed, will try replicas:', error);
|
// Fall through to reconnect
|
||||||
// Fall through to try replicas
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try replicas in sequence
|
console.log('Initializing new Redis connection...');
|
||||||
for (const [url, client] of replicaClients.entries()) {
|
redisClient = await createRedisClient();
|
||||||
if (client.status === 'ready') {
|
|
||||||
try {
|
|
||||||
await client.ping();
|
|
||||||
console.log(`Using ${getRedisName(url)}`);
|
|
||||||
return client;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`${getRedisName(url)} connection failed:`, error);
|
|
||||||
// Continue to next replica
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reconnect to primary
|
// Add event listeners for better monitoring
|
||||||
try {
|
redisClient
|
||||||
console.log('Initializing new primary Redis connection...');
|
.on('ready', () => console.log('Redis connection ready'))
|
||||||
primaryClient = await createRedisClient(PRIMARY_REDIS_URL!);
|
.on('error', (err) => console.error('Redis error:', err))
|
||||||
|
.on('reconnecting', () => console.log('Redis reconnecting'))
|
||||||
|
.on('end', () => console.log('Redis connection closed'));
|
||||||
|
|
||||||
primaryClient
|
return redisClient;
|
||||||
.on('ready', () => console.log('Primary Redis connection ready'))
|
|
||||||
.on('error', (err) => 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);
|
|
||||||
|
|
||||||
// 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) => 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');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to primary and all replicas for redundancy
|
// Batch operations for better performance
|
||||||
export async function writeToAllRedis(operation: (redis: Redis) => Promise<any>): Promise<void> {
|
|
||||||
const errors = [];
|
|
||||||
let successCount = 0;
|
|
||||||
|
|
||||||
// Try primary
|
|
||||||
try {
|
|
||||||
if (!primaryClient || primaryClient.status !== 'ready') {
|
|
||||||
primaryClient = await createRedisClient(PRIMARY_REDIS_URL!);
|
|
||||||
}
|
|
||||||
await operation(primaryClient);
|
|
||||||
successCount++;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to write to Primary Redis:', error);
|
|
||||||
errors.push(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try all replicas
|
|
||||||
for (const url of REPLICA_URLS) {
|
|
||||||
try {
|
|
||||||
let client = replicaClients.get(url);
|
|
||||||
if (!client || client.status !== 'ready') {
|
|
||||||
client = await createRedisClient(url);
|
|
||||||
replicaClients.set(url, client);
|
|
||||||
}
|
|
||||||
await operation(client);
|
|
||||||
successCount++;
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Failed to write to ${getRedisName(url)}:`, error);
|
|
||||||
errors.push(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If all writes failed, throw an error
|
|
||||||
if (successCount === 0) {
|
|
||||||
throw new Error('Failed to write to any Redis instance');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log warning if some writes failed
|
|
||||||
if (errors.length > 0) {
|
|
||||||
console.warn(`${errors.length} Redis writes failed out of ${errors.length + successCount} attempts`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize all connections on startup
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
// Initialize primary
|
|
||||||
if (PRIMARY_REDIS_URL) {
|
|
||||||
primaryClient = await createRedisClient(PRIMARY_REDIS_URL);
|
|
||||||
await primaryClient.ping();
|
|
||||||
console.log('Primary Redis pre-connected successfully');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize all replicas
|
|
||||||
for (const url of REPLICA_URLS) {
|
|
||||||
try {
|
|
||||||
const client = await createRedisClient(url);
|
|
||||||
await client.ping();
|
|
||||||
replicaClients.set(url, client);
|
|
||||||
console.log(`${getRedisName(url)} pre-connected successfully`);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Failed to pre-connect to ${getRedisName(url)}:`, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Redis setup complete: 1 primary and ${replicaClients.size} replicas connected`);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Redis pre-connection failed:', error);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Update existing functions to use the new methods
|
|
||||||
|
|
||||||
export async function storeFeedMappings(mappings: Array<{ feedId: string, slugs: string[], lang: string }>): Promise<void> {
|
export async function storeFeedMappings(mappings: Array<{ feedId: string, slugs: string[], lang: string }>): Promise<void> {
|
||||||
await writeToAllRedis(async (redis) => {
|
const redis = await getRedisClient();
|
||||||
const pipeline = redis.pipeline();
|
const pipeline = redis.pipeline();
|
||||||
|
|
||||||
mappings.forEach(({ feedId, slugs, lang }) => {
|
mappings.forEach(({ feedId, slugs, lang }) => {
|
||||||
|
|
@ -220,19 +68,18 @@ export async function storeFeedMappings(mappings: Array<{ feedId: string, slugs:
|
||||||
});
|
});
|
||||||
|
|
||||||
await pipeline.exec();
|
await pipeline.exec();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update warmChapterCache to prevent empty cache entries
|
||||||
export async function warmChapterCache(slugs: string[], lang: string): Promise<void> {
|
export async function warmChapterCache(slugs: string[], lang: string): Promise<void> {
|
||||||
const redis = await getRedisClient();
|
const redis = await getRedisClient();
|
||||||
const needsCache = await checkCacheStatus(slugs, lang);
|
const needsCache = await checkCacheStatus(slugs, lang);
|
||||||
|
|
||||||
if (needsCache.length > 0) {
|
if (needsCache.length > 0) {
|
||||||
console.log(`Pre-warming cache for ${needsCache.length} comics`);
|
console.log(`Pre-warming cache for ${needsCache.length} comics`);
|
||||||
|
|
||||||
await writeToAllRedis(async (redis) => {
|
|
||||||
const pipeline = redis.pipeline();
|
const pipeline = redis.pipeline();
|
||||||
|
|
||||||
|
// Replace empty array with actual chapter fetching
|
||||||
await Promise.all(needsCache.map(async slug => {
|
await Promise.all(needsCache.map(async slug => {
|
||||||
try {
|
try {
|
||||||
const chapters = await getChaptersForSlugs([slug], lang);
|
const chapters = await getChaptersForSlugs([slug], lang);
|
||||||
|
|
@ -244,32 +91,10 @@ export async function warmChapterCache(slugs: string[], lang: string): Promise<v
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await pipeline.exec();
|
await pipeline.exec();
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function storeFeedMapping(feedId: string, slugs: string[], lang: string): Promise<void> {
|
|
||||||
const mapping = {
|
|
||||||
slugs,
|
|
||||||
lang,
|
|
||||||
created_at: new Date().toISOString()
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await writeToAllRedis(async (redis) => {
|
|
||||||
await redis.set(
|
|
||||||
feedId,
|
|
||||||
JSON.stringify(mapping),
|
|
||||||
'EX',
|
|
||||||
DEFAULT_CACHE_TTL
|
|
||||||
);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error storing feed mapping:', error);
|
|
||||||
throw new Error('Failed to store feed mapping');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add batch cache checking
|
||||||
export async function checkCacheStatus(slugs: string[], lang: string): Promise<string[]> {
|
export async function checkCacheStatus(slugs: string[], lang: string): Promise<string[]> {
|
||||||
const redis = await getRedisClient();
|
const redis = await getRedisClient();
|
||||||
const pipeline = redis.pipeline();
|
const pipeline = redis.pipeline();
|
||||||
|
|
@ -283,6 +108,27 @@ export async function checkCacheStatus(slugs: string[], lang: string): Promise<s
|
||||||
return slugs.filter((_, index) => results![index][1] === 0);
|
return slugs.filter((_, index) => results![index][1] === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function storeFeedMapping(feedId: string, slugs: string[], lang: string): Promise<void> {
|
||||||
|
const redis = await getRedisClient();
|
||||||
|
const mapping = {
|
||||||
|
slugs,
|
||||||
|
lang,
|
||||||
|
created_at: new Date().toISOString()
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await redis.set(
|
||||||
|
feedId,
|
||||||
|
JSON.stringify(mapping),
|
||||||
|
'EX',
|
||||||
|
DEFAULT_CACHE_TTL
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error storing feed mapping:', error);
|
||||||
|
throw new Error('Failed to store feed mapping');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function getFeedMapping(feedId: string): Promise<FeedMapping | null> {
|
export async function getFeedMapping(feedId: string): Promise<FeedMapping | null> {
|
||||||
const redis = await getRedisClient();
|
const redis = await getRedisClient();
|
||||||
|
|
||||||
|
|
@ -304,3 +150,14 @@ export async function getFeedMapping(feedId: string): Promise<FeedMapping | null
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need for manual cleanup as we're using TTL (expire)
|
// No need for manual cleanup as we're using TTL (expire)
|
||||||
|
|
||||||
|
// Warm connection on startup
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const client = await getRedisClient();
|
||||||
|
await client.ping();
|
||||||
|
console.log('Redis pre-connected successfully');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Redis pre-connection failed:', error);
|
||||||
|
}
|
||||||
|
})();
|
||||||
Loading…
Add table
Add a link
Reference in a new issue