Fix pre-commit script to properly handle multiple files and resolve ESLint warnings
This commit is contained in:
+13
-12
@@ -159,23 +159,24 @@ Configure `DEPLOYMENT_WEBHOOK_URL` to receive notifications:
|
|||||||
|
|
||||||
1. **Build Fails - Buildx Not Available**
|
1. **Build Fails - Buildx Not Available**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Ensure Docker Buildx is installed on runner
|
# Ensure Docker Buildx is installed on runner
|
||||||
docker buildx version
|
docker buildx version
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Registry Push Fails**
|
2. **Registry Push Fails**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check GITEA_TOKEN has package write permissions
|
# Check GITEA_TOKEN has package write permissions
|
||||||
# Verify registry URL is correct
|
# Verify registry URL is correct
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Deployment Fails**
|
3. **Deployment Fails**
|
||||||
```bash
|
|
||||||
# Check environment variables are set
|
```bash
|
||||||
# Verify server has Docker/Kubernetes access
|
# Check environment variables are set
|
||||||
```
|
# Verify server has Docker/Kubernetes access
|
||||||
|
```
|
||||||
|
|
||||||
### Debug Commands
|
### Debug Commands
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -56,12 +56,12 @@ target "app" {
|
|||||||
"linux/amd64",
|
"linux/amd64",
|
||||||
"linux/arm64"
|
"linux/arm64"
|
||||||
]
|
]
|
||||||
|
|
||||||
tags = [
|
tags = [
|
||||||
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:${TAG}",
|
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:${TAG}",
|
||||||
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:latest"
|
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:latest"
|
||||||
]
|
]
|
||||||
|
|
||||||
args = {
|
args = {
|
||||||
VITE_COUCHDB_URL = "${VITE_COUCHDB_URL}"
|
VITE_COUCHDB_URL = "${VITE_COUCHDB_URL}"
|
||||||
VITE_COUCHDB_USER = "${VITE_COUCHDB_USER}"
|
VITE_COUCHDB_USER = "${VITE_COUCHDB_USER}"
|
||||||
@@ -71,12 +71,12 @@ target "app" {
|
|||||||
VITE_GITHUB_CLIENT_ID = "${VITE_GITHUB_CLIENT_ID}"
|
VITE_GITHUB_CLIENT_ID = "${VITE_GITHUB_CLIENT_ID}"
|
||||||
NODE_ENV = "production"
|
NODE_ENV = "production"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Gitea registry caching
|
# Gitea registry caching
|
||||||
cache-from = [
|
cache-from = [
|
||||||
"type=registry,ref=${GITEA_REGISTRY}/${GITEA_REPOSITORY}:buildcache"
|
"type=registry,ref=${GITEA_REGISTRY}/${GITEA_REPOSITORY}:buildcache"
|
||||||
]
|
]
|
||||||
|
|
||||||
cache-to = [
|
cache-to = [
|
||||||
"type=registry,ref=${GITEA_REGISTRY}/${GITEA_REPOSITORY}:buildcache,mode=max"
|
"type=registry,ref=${GITEA_REGISTRY}/${GITEA_REPOSITORY}:buildcache,mode=max"
|
||||||
]
|
]
|
||||||
@@ -89,13 +89,13 @@ target "app-ci" {
|
|||||||
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:${GITEA_SHA}",
|
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:${GITEA_SHA}",
|
||||||
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:latest"
|
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:latest"
|
||||||
]
|
]
|
||||||
|
|
||||||
# Enhanced CI-specific features
|
# Enhanced CI-specific features
|
||||||
attest = [
|
attest = [
|
||||||
"type=provenance,mode=max",
|
"type=provenance,mode=max",
|
||||||
"type=sbom"
|
"type=sbom"
|
||||||
]
|
]
|
||||||
|
|
||||||
# CI registry push
|
# CI registry push
|
||||||
output = ["type=registry"]
|
output = ["type=registry"]
|
||||||
}
|
}
|
||||||
@@ -105,11 +105,11 @@ target "dev" {
|
|||||||
inherits = ["app"]
|
inherits = ["app"]
|
||||||
platforms = ["linux/amd64"]
|
platforms = ["linux/amd64"]
|
||||||
tags = ["rxminder:dev"]
|
tags = ["rxminder:dev"]
|
||||||
|
|
||||||
# Local caching only
|
# Local caching only
|
||||||
cache-from = ["type=registry,ref=${GITEA_REGISTRY}/${GITEA_REPOSITORY}:buildcache"]
|
cache-from = ["type=registry,ref=${GITEA_REGISTRY}/${GITEA_REPOSITORY}:buildcache"]
|
||||||
cache-to = ["type=registry,ref=${GITEA_REGISTRY}/${GITEA_REPOSITORY}:buildcache"]
|
cache-to = ["type=registry,ref=${GITEA_REGISTRY}/${GITEA_REPOSITORY}:buildcache"]
|
||||||
|
|
||||||
# Load locally instead of push
|
# Load locally instead of push
|
||||||
output = ["type=docker"]
|
output = ["type=docker"]
|
||||||
}
|
}
|
||||||
@@ -117,13 +117,13 @@ target "dev" {
|
|||||||
# Production target with full attestations
|
# Production target with full attestations
|
||||||
target "prod" {
|
target "prod" {
|
||||||
inherits = ["app-ci"]
|
inherits = ["app-ci"]
|
||||||
|
|
||||||
# Production-specific tags
|
# Production-specific tags
|
||||||
tags = [
|
tags = [
|
||||||
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:prod-${TAG}",
|
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:prod-${TAG}",
|
||||||
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:production"
|
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:production"
|
||||||
]
|
]
|
||||||
|
|
||||||
# Full security attestations for production
|
# Full security attestations for production
|
||||||
attest = [
|
attest = [
|
||||||
"type=provenance,mode=max",
|
"type=provenance,mode=max",
|
||||||
@@ -135,12 +135,12 @@ target "prod" {
|
|||||||
target "staging" {
|
target "staging" {
|
||||||
inherits = ["app"]
|
inherits = ["app"]
|
||||||
platforms = ["linux/amd64"] # Single platform for staging
|
platforms = ["linux/amd64"] # Single platform for staging
|
||||||
|
|
||||||
tags = [
|
tags = [
|
||||||
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:staging-${TAG}",
|
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:staging-${TAG}",
|
||||||
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:staging"
|
"${GITEA_REGISTRY}/${GITEA_REPOSITORY}:staging"
|
||||||
]
|
]
|
||||||
|
|
||||||
# Staging-specific build args
|
# Staging-specific build args
|
||||||
args = {
|
args = {
|
||||||
VITE_COUCHDB_URL = "${VITE_COUCHDB_URL}"
|
VITE_COUCHDB_URL = "${VITE_COUCHDB_URL}"
|
||||||
@@ -151,6 +151,6 @@ target "staging" {
|
|||||||
VITE_GITHUB_CLIENT_ID = "${VITE_GITHUB_CLIENT_ID}"
|
VITE_GITHUB_CLIENT_ID = "${VITE_GITHUB_CLIENT_ID}"
|
||||||
NODE_ENV = "staging"
|
NODE_ENV = "staging"
|
||||||
}
|
}
|
||||||
|
|
||||||
output = ["type=registry"]
|
output = ["type=registry"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import {
|
|||||||
ScheduleItem,
|
ScheduleItem,
|
||||||
DailyStat,
|
DailyStat,
|
||||||
MedicationStat,
|
MedicationStat,
|
||||||
UserRole,
|
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
// Component imports - organized by feature
|
// Component imports - organized by feature
|
||||||
@@ -43,7 +42,7 @@ import {
|
|||||||
OnboardingModal,
|
OnboardingModal,
|
||||||
StatsModal,
|
StatsModal,
|
||||||
} from './components/modals';
|
} from './components/modals';
|
||||||
import { BarChart, ReminderCard, ThemeSwitcher } from './components/ui';
|
import { ReminderCard, ThemeSwitcher } from './components/ui';
|
||||||
|
|
||||||
// Icon and utility imports
|
// Icon and utility imports
|
||||||
import {
|
import {
|
||||||
@@ -239,7 +238,7 @@ const MedicationScheduleApp: React.FC<{ user: User }> = ({ user }) => {
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
console.log('Fetching data for user:', user._id);
|
console.warn('Fetching data for user:', user._id);
|
||||||
|
|
||||||
const [medsData, remindersData, takenDosesData, settingsData] =
|
const [medsData, remindersData, takenDosesData, settingsData] =
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
@@ -249,7 +248,7 @@ const MedicationScheduleApp: React.FC<{ user: User }> = ({ user }) => {
|
|||||||
dbService.getSettings(user._id),
|
dbService.getSettings(user._id),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log('Data fetched successfully:', {
|
console.warn('Data fetched successfully:', {
|
||||||
medications: medsData.length,
|
medications: medsData.length,
|
||||||
reminders: remindersData.length,
|
reminders: remindersData.length,
|
||||||
hasTakenDoses: !!takenDosesData,
|
hasTakenDoses: !!takenDosesData,
|
||||||
@@ -279,7 +278,7 @@ const MedicationScheduleApp: React.FC<{ user: User }> = ({ user }) => {
|
|||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
return () => clearTimeout(timeoutId);
|
return () => clearTimeout(timeoutId);
|
||||||
}, [user._id]);
|
}, [user._id, user]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
@@ -911,7 +910,7 @@ const App: React.FC = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const runSeeding = async () => {
|
const runSeeding = async () => {
|
||||||
try {
|
try {
|
||||||
console.log('🌱 Initializing database seeding...');
|
console.warn('🌱 Initializing database seeding...');
|
||||||
await databaseSeeder.seedDatabase();
|
await databaseSeeder.seedDatabase();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Database seeding failed:', error);
|
console.error('❌ Database seeding failed:', error);
|
||||||
|
|||||||
+11
-10
@@ -62,21 +62,22 @@ INGRESS_HOST=rxminder.yourdomain.com
|
|||||||
|
|
||||||
1. **Copy environment template:**
|
1. **Copy environment template:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Update .env with your secure credentials:**
|
2. **Update .env with your secure credentials:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Edit .env with your secure passwords and configuration
|
# Edit .env with your secure passwords and configuration
|
||||||
nano .env
|
nano .env
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Deploy with templates:**
|
3. **Deploy with templates:**
|
||||||
```bash
|
|
||||||
./scripts/k8s-deploy-template.sh deploy
|
```bash
|
||||||
```
|
./scripts/k8s-deploy-template.sh deploy
|
||||||
|
```
|
||||||
|
|
||||||
The deployment script automatically:
|
The deployment script automatically:
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
|
"express": "^5.1.0",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.1.1",
|
"react-dom": "^19.1.1",
|
||||||
"uuid": "^12.0.0",
|
"uuid": "^12.0.0",
|
||||||
@@ -472,6 +474,8 @@
|
|||||||
|
|
||||||
"@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="],
|
"@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="],
|
||||||
|
|
||||||
|
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
||||||
|
|
||||||
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||||
|
|
||||||
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
|
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
|
||||||
@@ -548,6 +552,8 @@
|
|||||||
|
|
||||||
"binaryextensions": ["binaryextensions@6.11.0", "", { "dependencies": { "editions": "^6.21.0" } }, "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw=="],
|
"binaryextensions": ["binaryextensions@6.11.0", "", { "dependencies": { "editions": "^6.21.0" } }, "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw=="],
|
||||||
|
|
||||||
|
"body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
|
||||||
|
|
||||||
"boundary": ["boundary@2.0.0", "", {}, "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA=="],
|
"boundary": ["boundary@2.0.0", "", {}, "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA=="],
|
||||||
|
|
||||||
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
||||||
@@ -562,6 +568,8 @@
|
|||||||
|
|
||||||
"buffer-equal": ["buffer-equal@1.0.1", "", {}, "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg=="],
|
"buffer-equal": ["buffer-equal@1.0.1", "", {}, "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg=="],
|
||||||
|
|
||||||
|
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
||||||
|
|
||||||
"buffer-equals": ["buffer-equals@1.0.4", "", {}, "sha512-99MsCq0j5+RhubVEtKQgKaD6EM+UP3xJgIvQqwJ3SOLDUekzxMX1ylXBng+Wa2sh7mGT0W6RUly8ojjr1Tt6nA=="],
|
"buffer-equals": ["buffer-equals@1.0.4", "", {}, "sha512-99MsCq0j5+RhubVEtKQgKaD6EM+UP3xJgIvQqwJ3SOLDUekzxMX1ylXBng+Wa2sh7mGT0W6RUly8ojjr1Tt6nA=="],
|
||||||
|
|
||||||
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
||||||
@@ -570,6 +578,8 @@
|
|||||||
|
|
||||||
"bufferstreams": ["bufferstreams@2.0.1", "", { "dependencies": { "readable-stream": "^2.3.6" } }, "sha512-ZswyIoBfFb3cVDsnZLLj2IDJ/0ppYdil/v2EGlZXvoefO689FokEmFEldhN5dV7R2QBxFneqTJOMIpfqhj+n0g=="],
|
"bufferstreams": ["bufferstreams@2.0.1", "", { "dependencies": { "readable-stream": "^2.3.6" } }, "sha512-ZswyIoBfFb3cVDsnZLLj2IDJ/0ppYdil/v2EGlZXvoefO689FokEmFEldhN5dV7R2QBxFneqTJOMIpfqhj+n0g=="],
|
||||||
|
|
||||||
|
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
||||||
|
|
||||||
"call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="],
|
"call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="],
|
||||||
|
|
||||||
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
||||||
@@ -630,8 +640,16 @@
|
|||||||
|
|
||||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||||
|
|
||||||
|
"content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
|
||||||
|
|
||||||
|
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
||||||
|
|
||||||
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||||
|
|
||||||
|
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
||||||
|
|
||||||
|
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
||||||
|
|
||||||
"core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
|
"core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
|
||||||
|
|
||||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||||
@@ -664,6 +682,8 @@
|
|||||||
|
|
||||||
"define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
|
"define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
|
||||||
|
|
||||||
|
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
||||||
|
|
||||||
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
|
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
|
||||||
|
|
||||||
"detect-newline": ["detect-newline@3.1.0", "", {}, "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="],
|
"detect-newline": ["detect-newline@3.1.0", "", {}, "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="],
|
||||||
@@ -680,12 +700,16 @@
|
|||||||
|
|
||||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||||
|
|
||||||
|
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
|
||||||
|
|
||||||
"eclint": ["eclint@2.8.1", "", { "dependencies": { "editorconfig": "^0.15.2", "file-type": "^10.1.0", "gulp-exclude-gitignore": "^1.2.0", "gulp-filter": "^5.1.0", "gulp-reporter": "^2.9.0", "gulp-tap": "^1.0.1", "linez": "^4.1.4", "lodash": "^4.17.11", "minimatch": "^3.0.4", "os-locale": "^3.0.1", "plugin-error": "^1.0.1", "through2": "^2.0.3", "vinyl": "^2.2.0", "vinyl-fs": "^3.0.3", "yargs": "^12.0.2" }, "bin": { "eclint": "bin/eclint.js" } }, "sha512-0u1UubFXSOgZgXNhuPeliYyTFmjWStVph8JR6uD6NDuxl3xI5VSCsA1KX6/BSYtM9v4wQMifGoNFfN5VlRn4LQ=="],
|
"eclint": ["eclint@2.8.1", "", { "dependencies": { "editorconfig": "^0.15.2", "file-type": "^10.1.0", "gulp-exclude-gitignore": "^1.2.0", "gulp-filter": "^5.1.0", "gulp-reporter": "^2.9.0", "gulp-tap": "^1.0.1", "linez": "^4.1.4", "lodash": "^4.17.11", "minimatch": "^3.0.4", "os-locale": "^3.0.1", "plugin-error": "^1.0.1", "through2": "^2.0.3", "vinyl": "^2.2.0", "vinyl-fs": "^3.0.3", "yargs": "^12.0.2" }, "bin": { "eclint": "bin/eclint.js" } }, "sha512-0u1UubFXSOgZgXNhuPeliYyTFmjWStVph8JR6uD6NDuxl3xI5VSCsA1KX6/BSYtM9v4wQMifGoNFfN5VlRn4LQ=="],
|
||||||
|
|
||||||
"editions": ["editions@6.22.0", "", { "dependencies": { "version-range": "^4.15.0" } }, "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ=="],
|
"editions": ["editions@6.22.0", "", { "dependencies": { "version-range": "^4.15.0" } }, "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ=="],
|
||||||
|
|
||||||
"editorconfig": ["editorconfig@0.15.3", "", { "dependencies": { "commander": "^2.19.0", "lru-cache": "^4.1.5", "semver": "^5.6.0", "sigmund": "^1.0.1" }, "bin": { "editorconfig": "bin/editorconfig" } }, "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g=="],
|
"editorconfig": ["editorconfig@0.15.3", "", { "dependencies": { "commander": "^2.19.0", "lru-cache": "^4.1.5", "semver": "^5.6.0", "sigmund": "^1.0.1" }, "bin": { "editorconfig": "bin/editorconfig" } }, "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g=="],
|
||||||
|
|
||||||
|
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||||
|
|
||||||
"electron-to-chromium": ["electron-to-chromium@1.5.214", "", {}, "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q=="],
|
"electron-to-chromium": ["electron-to-chromium@1.5.214", "", {}, "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q=="],
|
||||||
|
|
||||||
"emittery": ["emittery@0.13.1", "", {}, "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ=="],
|
"emittery": ["emittery@0.13.1", "", {}, "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ=="],
|
||||||
@@ -694,6 +718,8 @@
|
|||||||
|
|
||||||
"emphasize": ["emphasize@2.1.0", "", { "dependencies": { "chalk": "^2.4.0", "highlight.js": "~9.12.0", "lowlight": "~1.9.0" } }, "sha512-wRlO0Qulw2jieQynsS3STzTabIhHCyjTjZraSkchOiT8rdvWZlahJAJ69HRxwGkv2NThmci2MSnDfJ60jB39tw=="],
|
"emphasize": ["emphasize@2.1.0", "", { "dependencies": { "chalk": "^2.4.0", "highlight.js": "~9.12.0", "lowlight": "~1.9.0" } }, "sha512-wRlO0Qulw2jieQynsS3STzTabIhHCyjTjZraSkchOiT8rdvWZlahJAJ69HRxwGkv2NThmci2MSnDfJ60jB39tw=="],
|
||||||
|
|
||||||
|
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
||||||
|
|
||||||
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
|
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
|
||||||
|
|
||||||
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
||||||
@@ -714,6 +740,8 @@
|
|||||||
|
|
||||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||||
|
|
||||||
|
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
|
||||||
|
|
||||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||||
|
|
||||||
"eslint": ["eslint@9.35.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.35.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg=="],
|
"eslint": ["eslint@9.35.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.35.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg=="],
|
||||||
@@ -738,6 +766,8 @@
|
|||||||
|
|
||||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||||
|
|
||||||
|
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
||||||
|
|
||||||
"eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
|
"eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
|
||||||
|
|
||||||
"execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
|
"execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
|
||||||
@@ -746,6 +776,8 @@
|
|||||||
|
|
||||||
"expect": ["expect@30.1.2", "", { "dependencies": { "@jest/expect-utils": "30.1.2", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.1.2", "jest-message-util": "30.1.0", "jest-mock": "30.0.5", "jest-util": "30.0.5" } }, "sha512-xvHszRavo28ejws8FpemjhwswGj4w/BetHIL8cU49u4sGyXDw2+p3YbeDbj6xzlxi6kWTjIRSTJ+9sNXPnF0Zg=="],
|
"expect": ["expect@30.1.2", "", { "dependencies": { "@jest/expect-utils": "30.1.2", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.1.2", "jest-message-util": "30.1.0", "jest-mock": "30.0.5", "jest-util": "30.0.5" } }, "sha512-xvHszRavo28ejws8FpemjhwswGj4w/BetHIL8cU49u4sGyXDw2+p3YbeDbj6xzlxi6kWTjIRSTJ+9sNXPnF0Zg=="],
|
||||||
|
|
||||||
|
"express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
|
||||||
|
|
||||||
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
||||||
|
|
||||||
"extend-shallow": ["extend-shallow@3.0.2", "", { "dependencies": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" } }, "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q=="],
|
"extend-shallow": ["extend-shallow@3.0.2", "", { "dependencies": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" } }, "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q=="],
|
||||||
@@ -776,6 +808,8 @@
|
|||||||
|
|
||||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||||
|
|
||||||
|
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
|
||||||
|
|
||||||
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
||||||
|
|
||||||
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
|
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
|
||||||
@@ -792,6 +826,10 @@
|
|||||||
|
|
||||||
"format": ["format@0.2.2", "", {}, "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww=="],
|
"format": ["format@0.2.2", "", {}, "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww=="],
|
||||||
|
|
||||||
|
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
||||||
|
|
||||||
|
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
||||||
|
|
||||||
"fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="],
|
"fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="],
|
||||||
|
|
||||||
"fs-mkdirp-stream": ["fs-mkdirp-stream@1.0.0", "", { "dependencies": { "graceful-fs": "^4.1.11", "through2": "^2.0.3" } }, "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ=="],
|
"fs-mkdirp-stream": ["fs-mkdirp-stream@1.0.0", "", { "dependencies": { "graceful-fs": "^4.1.11", "through2": "^2.0.3" } }, "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ=="],
|
||||||
@@ -866,6 +904,8 @@
|
|||||||
|
|
||||||
"html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="],
|
"html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="],
|
||||||
|
|
||||||
|
"http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
|
||||||
|
|
||||||
"http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
|
"http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
|
||||||
|
|
||||||
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
|
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
|
||||||
@@ -896,6 +936,8 @@
|
|||||||
|
|
||||||
"invert-kv": ["invert-kv@2.0.0", "", {}, "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA=="],
|
"invert-kv": ["invert-kv@2.0.0", "", {}, "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA=="],
|
||||||
|
|
||||||
|
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
||||||
|
|
||||||
"is-absolute": ["is-absolute@1.0.0", "", { "dependencies": { "is-relative": "^1.0.0", "is-windows": "^1.0.1" } }, "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA=="],
|
"is-absolute": ["is-absolute@1.0.0", "", { "dependencies": { "is-relative": "^1.0.0", "is-windows": "^1.0.1" } }, "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA=="],
|
||||||
|
|
||||||
"is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
|
"is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
|
||||||
@@ -944,6 +986,8 @@
|
|||||||
|
|
||||||
"is-potential-custom-element-name": ["is-potential-custom-element-name@1.0.1", "", {}, "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="],
|
"is-potential-custom-element-name": ["is-potential-custom-element-name@1.0.1", "", {}, "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="],
|
||||||
|
|
||||||
|
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
|
||||||
|
|
||||||
"is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="],
|
"is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="],
|
||||||
|
|
||||||
"is-relative": ["is-relative@1.0.0", "", { "dependencies": { "is-unc-path": "^1.0.0" } }, "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA=="],
|
"is-relative": ["is-relative@1.0.0", "", { "dependencies": { "is-unc-path": "^1.0.0" } }, "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA=="],
|
||||||
@@ -1066,8 +1110,14 @@
|
|||||||
|
|
||||||
"jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
|
"jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
|
||||||
|
|
||||||
|
"jsonwebtoken": ["jsonwebtoken@9.0.2", "", { "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ=="],
|
||||||
|
|
||||||
"junit-report-builder": ["junit-report-builder@1.3.3", "", { "dependencies": { "date-format": "0.0.2", "lodash": "^4.17.15", "mkdirp": "^0.5.0", "xmlbuilder": "^10.0.0" } }, "sha512-75bwaXjP/3ogyzOSkkcshXGG7z74edkJjgTZlJGAyzxlOHaguexM3VLG6JyD9ZBF8mlpgsUPB1sIWU4LISgeJw=="],
|
"junit-report-builder": ["junit-report-builder@1.3.3", "", { "dependencies": { "date-format": "0.0.2", "lodash": "^4.17.15", "mkdirp": "^0.5.0", "xmlbuilder": "^10.0.0" } }, "sha512-75bwaXjP/3ogyzOSkkcshXGG7z74edkJjgTZlJGAyzxlOHaguexM3VLG6JyD9ZBF8mlpgsUPB1sIWU4LISgeJw=="],
|
||||||
|
|
||||||
|
"jwa": ["jwa@1.4.2", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw=="],
|
||||||
|
|
||||||
|
"jws": ["jws@3.2.2", "", { "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA=="],
|
||||||
|
|
||||||
"katex": ["katex@0.16.22", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg=="],
|
"katex": ["katex@0.16.22", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg=="],
|
||||||
|
|
||||||
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
||||||
@@ -1102,10 +1152,24 @@
|
|||||||
|
|
||||||
"lodash.get": ["lodash.get@4.4.2", "", {}, "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="],
|
"lodash.get": ["lodash.get@4.4.2", "", {}, "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="],
|
||||||
|
|
||||||
|
"lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="],
|
||||||
|
|
||||||
|
"lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="],
|
||||||
|
|
||||||
|
"lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="],
|
||||||
|
|
||||||
|
"lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="],
|
||||||
|
|
||||||
|
"lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="],
|
||||||
|
|
||||||
|
"lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="],
|
||||||
|
|
||||||
"lodash.memoize": ["lodash.memoize@4.1.2", "", {}, "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag=="],
|
"lodash.memoize": ["lodash.memoize@4.1.2", "", {}, "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag=="],
|
||||||
|
|
||||||
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
|
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
|
||||||
|
|
||||||
|
"lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="],
|
||||||
|
|
||||||
"lodash.truncate": ["lodash.truncate@4.4.2", "", {}, "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw=="],
|
"lodash.truncate": ["lodash.truncate@4.4.2", "", {}, "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw=="],
|
||||||
|
|
||||||
"log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="],
|
"log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="],
|
||||||
@@ -1136,8 +1200,12 @@
|
|||||||
|
|
||||||
"mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="],
|
"mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="],
|
||||||
|
|
||||||
|
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
||||||
|
|
||||||
"mem": ["mem@4.3.0", "", { "dependencies": { "map-age-cleaner": "^0.1.1", "mimic-fn": "^2.0.0", "p-is-promise": "^2.0.0" } }, "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w=="],
|
"mem": ["mem@4.3.0", "", { "dependencies": { "map-age-cleaner": "^0.1.1", "mimic-fn": "^2.0.0", "p-is-promise": "^2.0.0" } }, "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w=="],
|
||||||
|
|
||||||
|
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
|
||||||
|
|
||||||
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
|
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
|
||||||
|
|
||||||
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
||||||
@@ -1194,6 +1262,10 @@
|
|||||||
|
|
||||||
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
||||||
|
|
||||||
|
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
|
"mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||||
|
|
||||||
"mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
"mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||||
|
|
||||||
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
|
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
|
||||||
@@ -1220,6 +1292,8 @@
|
|||||||
|
|
||||||
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
|
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
|
||||||
|
|
||||||
|
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
||||||
|
|
||||||
"neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="],
|
"neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="],
|
||||||
|
|
||||||
"nice-try": ["nice-try@1.0.5", "", {}, "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="],
|
"nice-try": ["nice-try@1.0.5", "", {}, "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="],
|
||||||
@@ -1246,6 +1320,8 @@
|
|||||||
|
|
||||||
"object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="],
|
"object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="],
|
||||||
|
|
||||||
|
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
||||||
|
|
||||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||||
|
|
||||||
"onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
"onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||||
@@ -1282,6 +1358,8 @@
|
|||||||
|
|
||||||
"parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
|
"parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
|
||||||
|
|
||||||
|
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
||||||
|
|
||||||
"path-dirname": ["path-dirname@1.0.2", "", {}, "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q=="],
|
"path-dirname": ["path-dirname@1.0.2", "", {}, "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q=="],
|
||||||
|
|
||||||
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
|
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
|
||||||
@@ -1292,6 +1370,8 @@
|
|||||||
|
|
||||||
"path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
"path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
||||||
|
|
||||||
|
"path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="],
|
||||||
|
|
||||||
"path-type": ["path-type@6.0.0", "", {}, "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ=="],
|
"path-type": ["path-type@6.0.0", "", {}, "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ=="],
|
||||||
|
|
||||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||||
@@ -1324,6 +1404,8 @@
|
|||||||
|
|
||||||
"process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
|
"process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
|
||||||
|
|
||||||
|
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
||||||
|
|
||||||
"pseudomap": ["pseudomap@1.0.2", "", {}, "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ=="],
|
"pseudomap": ["pseudomap@1.0.2", "", {}, "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ=="],
|
||||||
|
|
||||||
"pump": ["pump@2.0.1", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA=="],
|
"pump": ["pump@2.0.1", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA=="],
|
||||||
@@ -1336,8 +1418,14 @@
|
|||||||
|
|
||||||
"pure-rand": ["pure-rand@7.0.1", "", {}, "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ=="],
|
"pure-rand": ["pure-rand@7.0.1", "", {}, "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ=="],
|
||||||
|
|
||||||
|
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
|
||||||
|
|
||||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||||
|
|
||||||
|
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
|
||||||
|
|
||||||
|
"raw-body": ["raw-body@3.0.1", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.7.0", "unpipe": "1.0.0" } }, "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA=="],
|
||||||
|
|
||||||
"rc-config-loader": ["rc-config-loader@4.1.3", "", { "dependencies": { "debug": "^4.3.4", "js-yaml": "^4.1.0", "json5": "^2.2.2", "require-from-string": "^2.0.2" } }, "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w=="],
|
"rc-config-loader": ["rc-config-loader@4.1.3", "", { "dependencies": { "debug": "^4.3.4", "js-yaml": "^4.1.0", "json5": "^2.2.2", "require-from-string": "^2.0.2" } }, "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w=="],
|
||||||
|
|
||||||
"react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="],
|
"react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="],
|
||||||
@@ -1380,11 +1468,13 @@
|
|||||||
|
|
||||||
"rollup": ["rollup@4.50.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.50.0", "@rollup/rollup-android-arm64": "4.50.0", "@rollup/rollup-darwin-arm64": "4.50.0", "@rollup/rollup-darwin-x64": "4.50.0", "@rollup/rollup-freebsd-arm64": "4.50.0", "@rollup/rollup-freebsd-x64": "4.50.0", "@rollup/rollup-linux-arm-gnueabihf": "4.50.0", "@rollup/rollup-linux-arm-musleabihf": "4.50.0", "@rollup/rollup-linux-arm64-gnu": "4.50.0", "@rollup/rollup-linux-arm64-musl": "4.50.0", "@rollup/rollup-linux-loongarch64-gnu": "4.50.0", "@rollup/rollup-linux-ppc64-gnu": "4.50.0", "@rollup/rollup-linux-riscv64-gnu": "4.50.0", "@rollup/rollup-linux-riscv64-musl": "4.50.0", "@rollup/rollup-linux-s390x-gnu": "4.50.0", "@rollup/rollup-linux-x64-gnu": "4.50.0", "@rollup/rollup-linux-x64-musl": "4.50.0", "@rollup/rollup-openharmony-arm64": "4.50.0", "@rollup/rollup-win32-arm64-msvc": "4.50.0", "@rollup/rollup-win32-ia32-msvc": "4.50.0", "@rollup/rollup-win32-x64-msvc": "4.50.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw=="],
|
"rollup": ["rollup@4.50.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.50.0", "@rollup/rollup-android-arm64": "4.50.0", "@rollup/rollup-darwin-arm64": "4.50.0", "@rollup/rollup-darwin-x64": "4.50.0", "@rollup/rollup-freebsd-arm64": "4.50.0", "@rollup/rollup-freebsd-x64": "4.50.0", "@rollup/rollup-linux-arm-gnueabihf": "4.50.0", "@rollup/rollup-linux-arm-musleabihf": "4.50.0", "@rollup/rollup-linux-arm64-gnu": "4.50.0", "@rollup/rollup-linux-arm64-musl": "4.50.0", "@rollup/rollup-linux-loongarch64-gnu": "4.50.0", "@rollup/rollup-linux-ppc64-gnu": "4.50.0", "@rollup/rollup-linux-riscv64-gnu": "4.50.0", "@rollup/rollup-linux-riscv64-musl": "4.50.0", "@rollup/rollup-linux-s390x-gnu": "4.50.0", "@rollup/rollup-linux-x64-gnu": "4.50.0", "@rollup/rollup-linux-x64-musl": "4.50.0", "@rollup/rollup-openharmony-arm64": "4.50.0", "@rollup/rollup-win32-arm64-msvc": "4.50.0", "@rollup/rollup-win32-ia32-msvc": "4.50.0", "@rollup/rollup-win32-x64-msvc": "4.50.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw=="],
|
||||||
|
|
||||||
|
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
||||||
|
|
||||||
"rrweb-cssom": ["rrweb-cssom@0.8.0", "", {}, "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw=="],
|
"rrweb-cssom": ["rrweb-cssom@0.8.0", "", {}, "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw=="],
|
||||||
|
|
||||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||||
|
|
||||||
"safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
|
|
||||||
"safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="],
|
"safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="],
|
||||||
|
|
||||||
@@ -1396,12 +1486,18 @@
|
|||||||
|
|
||||||
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||||
|
|
||||||
|
"send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
|
||||||
|
|
||||||
|
"serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
|
||||||
|
|
||||||
"set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="],
|
"set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="],
|
||||||
|
|
||||||
"set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="],
|
"set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="],
|
||||||
|
|
||||||
"set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="],
|
"set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="],
|
||||||
|
|
||||||
|
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
|
||||||
|
|
||||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||||
|
|
||||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||||
@@ -1434,6 +1530,8 @@
|
|||||||
|
|
||||||
"stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="],
|
"stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="],
|
||||||
|
|
||||||
|
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
||||||
|
|
||||||
"stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="],
|
"stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="],
|
||||||
|
|
||||||
"stream-shift": ["stream-shift@1.0.3", "", {}, "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="],
|
"stream-shift": ["stream-shift@1.0.3", "", {}, "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="],
|
||||||
@@ -1508,6 +1606,8 @@
|
|||||||
|
|
||||||
"to-time": ["to-time@1.0.2", "", { "dependencies": { "bignumber.js": "^2.4.0" } }, "sha512-+wqaiQvnido2DI1bpiQ/Zv1LiOE9Fd0v35ySnNeqFmKNYJTJY/+ENI+3sHXCMzbAAOR/43aNyLM0XTpi0/zSQg=="],
|
"to-time": ["to-time@1.0.2", "", { "dependencies": { "bignumber.js": "^2.4.0" } }, "sha512-+wqaiQvnido2DI1bpiQ/Zv1LiOE9Fd0v35ySnNeqFmKNYJTJY/+ENI+3sHXCMzbAAOR/43aNyLM0XTpi0/zSQg=="],
|
||||||
|
|
||||||
|
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||||
|
|
||||||
"tough-cookie": ["tough-cookie@5.1.2", "", { "dependencies": { "tldts": "^6.1.32" } }, "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A=="],
|
"tough-cookie": ["tough-cookie@5.1.2", "", { "dependencies": { "tldts": "^6.1.32" } }, "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A=="],
|
||||||
|
|
||||||
"tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="],
|
"tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="],
|
||||||
@@ -1524,6 +1624,8 @@
|
|||||||
|
|
||||||
"type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
|
"type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
|
||||||
|
|
||||||
|
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
||||||
|
|
||||||
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
||||||
|
|
||||||
"uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="],
|
"uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="],
|
||||||
@@ -1540,6 +1642,8 @@
|
|||||||
|
|
||||||
"universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="],
|
"universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="],
|
||||||
|
|
||||||
|
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
||||||
|
|
||||||
"unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="],
|
"unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="],
|
||||||
|
|
||||||
"update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
|
"update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
|
||||||
@@ -1554,6 +1658,8 @@
|
|||||||
|
|
||||||
"value-or-function": ["value-or-function@3.0.0", "", {}, "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg=="],
|
"value-or-function": ["value-or-function@3.0.0", "", {}, "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg=="],
|
||||||
|
|
||||||
|
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
||||||
|
|
||||||
"version-range": ["version-range@4.15.0", "", {}, "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg=="],
|
"version-range": ["version-range@4.15.0", "", {}, "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg=="],
|
||||||
|
|
||||||
"vinyl": ["vinyl@2.2.1", "", { "dependencies": { "clone": "^2.1.1", "clone-buffer": "^1.0.0", "clone-stats": "^1.0.0", "cloneable-readable": "^1.0.0", "remove-trailing-separator": "^1.0.1", "replace-ext": "^1.0.0" } }, "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw=="],
|
"vinyl": ["vinyl@2.2.1", "", { "dependencies": { "clone": "^2.1.1", "clone-buffer": "^1.0.0", "clone-stats": "^1.0.0", "cloneable-readable": "^1.0.0", "remove-trailing-separator": "^1.0.1", "replace-ext": "^1.0.0" } }, "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw=="],
|
||||||
@@ -1712,6 +1818,8 @@
|
|||||||
|
|
||||||
"babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@5.2.1", "", { "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg=="],
|
"babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@5.2.1", "", { "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg=="],
|
||||||
|
|
||||||
|
"body-parser/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||||
|
|
||||||
"buffered-spawn/cross-spawn": ["cross-spawn@4.0.2", "", { "dependencies": { "lru-cache": "^4.0.1", "which": "^1.2.9" } }, "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA=="],
|
"buffered-spawn/cross-spawn": ["cross-spawn@4.0.2", "", { "dependencies": { "lru-cache": "^4.0.1", "which": "^1.2.9" } }, "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA=="],
|
||||||
|
|
||||||
"chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
|
"chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
|
||||||
@@ -1754,6 +1862,8 @@
|
|||||||
|
|
||||||
"gulp-reporter/through2": ["through2@3.0.2", "", { "dependencies": { "inherits": "^2.0.4", "readable-stream": "2 || 3" } }, "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ=="],
|
"gulp-reporter/through2": ["through2@3.0.2", "", { "dependencies": { "inherits": "^2.0.4", "readable-stream": "2 || 3" } }, "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ=="],
|
||||||
|
|
||||||
|
"http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
|
||||||
|
|
||||||
"in-gfw/mem": ["mem@3.0.1", "", { "dependencies": { "mimic-fn": "^1.0.0", "p-is-promise": "^1.1.0" } }, "sha512-QKs47bslvOE0NbXOqG6lMxn6Bk0Iuw0vfrIeLykmQle2LkCw1p48dZDdzE+D88b/xqRJcZGcMNeDvSVma+NuIQ=="],
|
"in-gfw/mem": ["mem@3.0.1", "", { "dependencies": { "mimic-fn": "^1.0.0", "p-is-promise": "^1.1.0" } }, "sha512-QKs47bslvOE0NbXOqG6lMxn6Bk0Iuw0vfrIeLykmQle2LkCw1p48dZDdzE+D88b/xqRJcZGcMNeDvSVma+NuIQ=="],
|
||||||
|
|
||||||
"istanbul-lib-report/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
"istanbul-lib-report/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||||
@@ -1872,10 +1982,16 @@
|
|||||||
|
|
||||||
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
||||||
|
|
||||||
|
"raw-body/iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="],
|
||||||
|
|
||||||
"rc-config-loader/js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
|
"rc-config-loader/js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
|
||||||
|
|
||||||
|
"readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||||
|
|
||||||
"remove-bom-buffer/is-buffer": ["is-buffer@1.1.6", "", {}, "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="],
|
"remove-bom-buffer/is-buffer": ["is-buffer@1.1.6", "", {}, "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="],
|
||||||
|
|
||||||
|
"remove-bom-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||||
|
|
||||||
"resolve-cwd/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
|
"resolve-cwd/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
|
||||||
|
|
||||||
"restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
|
"restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
|
||||||
@@ -1898,6 +2014,8 @@
|
|||||||
|
|
||||||
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||||
|
|
||||||
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
"supports-hyperlinks/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
"supports-hyperlinks/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ const AuthPage: React.FC = () => {
|
|||||||
if (!success) {
|
if (!success) {
|
||||||
setError(`${provider} authentication failed. Please try again.`);
|
setError(`${provider} authentication failed. Please try again.`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
setError(`${provider} authentication failed. Please try again.`);
|
setError(`${provider} authentication failed. Please try again.`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -52,8 +52,10 @@ const ChangePasswordModal: React.FC<ChangePasswordModalProps> = ({
|
|||||||
await authService.changePassword(user!._id, currentPassword, newPassword);
|
await authService.changePassword(user!._id, currentPassword, newPassword);
|
||||||
onSuccess();
|
onSuccess();
|
||||||
onClose();
|
onClose();
|
||||||
} catch (error: any) {
|
} catch (error: unknown) {
|
||||||
setError(error.message || 'Failed to change password');
|
setError(
|
||||||
|
error instanceof Error ? error.message : 'Failed to change password'
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const AccountModal: React.FC<AccountModalProps> = ({
|
|||||||
await onUpdateUser({ ...user, username: username.trim() });
|
await onUpdateUser({ ...user, username: username.trim() });
|
||||||
setSuccessMessage('Username updated successfully!');
|
setSuccessMessage('Username updated successfully!');
|
||||||
setTimeout(() => setSuccessMessage(''), 3000);
|
setTimeout(() => setSuccessMessage(''), 3000);
|
||||||
} catch (error) {
|
} catch {
|
||||||
alert('Failed to update username.');
|
alert('Failed to update username.');
|
||||||
} finally {
|
} finally {
|
||||||
setIsSaving(false);
|
setIsSaving(false);
|
||||||
@@ -77,6 +77,7 @@ const AccountModal: React.FC<AccountModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveAvatar = async () => {
|
const handleRemoveAvatar = async () => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { avatar, ...userWithoutAvatar } = user;
|
const { avatar, ...userWithoutAvatar } = user;
|
||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
try {
|
try {
|
||||||
@@ -90,7 +91,7 @@ const AccountModal: React.FC<AccountModalProps> = ({
|
|||||||
setIsDeleting(true);
|
setIsDeleting(true);
|
||||||
try {
|
try {
|
||||||
await onDeleteAllData();
|
await onDeleteAllData();
|
||||||
} catch (error) {
|
} catch {
|
||||||
alert('Failed to delete data.');
|
alert('Failed to delete data.');
|
||||||
} finally {
|
} finally {
|
||||||
setIsDeleting(false);
|
setIsDeleting(false);
|
||||||
|
|||||||
+13
-13
@@ -22,7 +22,7 @@ interface UserContextType {
|
|||||||
) => Promise<boolean>;
|
) => Promise<boolean>;
|
||||||
loginWithOAuth: (
|
loginWithOAuth: (
|
||||||
provider: 'google' | 'github',
|
provider: 'google' | 'github',
|
||||||
userData: any
|
userData: { email: string; username: string; avatar?: string }
|
||||||
) => Promise<boolean>;
|
) => Promise<boolean>;
|
||||||
changePassword: (
|
changePassword: (
|
||||||
currentPassword: string,
|
currentPassword: string,
|
||||||
@@ -68,22 +68,22 @@ export const UserProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
// Use auth service for password-based login
|
// Use auth service for password-based login
|
||||||
const result = await authService.login({ email, password });
|
const result = await authService.login({ email, password });
|
||||||
|
|
||||||
console.log('Login result received:', result);
|
console.warn('Login result received:', result);
|
||||||
console.log('User from login:', result.user);
|
console.warn('User from login:', result.user);
|
||||||
console.log('User _id:', result.user._id);
|
console.warn('User _id:', result.user._id);
|
||||||
|
|
||||||
// Update last login time
|
// Update last login time
|
||||||
const updatedUser = { ...result.user, lastLoginAt: new Date() };
|
const updatedUser = { ...result.user, lastLoginAt: new Date() };
|
||||||
await dbService.updateUser(updatedUser);
|
await dbService.updateUser(updatedUser);
|
||||||
|
|
||||||
console.log('Updated user with last login:', updatedUser);
|
console.warn('Updated user with last login:', updatedUser);
|
||||||
|
|
||||||
// Store access token for subsequent API calls.
|
// Store access token for subsequent API calls.
|
||||||
localStorage.setItem('access_token', result.accessToken);
|
localStorage.setItem('access_token', result.accessToken);
|
||||||
// Set the user from the login result
|
// Set the user from the login result
|
||||||
setUser(updatedUser);
|
setUser(updatedUser);
|
||||||
|
|
||||||
console.log('User set in context');
|
console.warn('User set in context');
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Login error:', error);
|
console.error('Login error:', error);
|
||||||
@@ -97,7 +97,7 @@ export const UserProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
username?: string
|
username?: string
|
||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
try {
|
try {
|
||||||
const result = await authService.register(email, password, username);
|
await authService.register(email, password, username);
|
||||||
// Don't auto-login after registration, require email verification
|
// Don't auto-login after registration, require email verification
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -108,25 +108,25 @@ export const UserProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
|
|
||||||
const loginWithOAuth = async (
|
const loginWithOAuth = async (
|
||||||
provider: 'google' | 'github',
|
provider: 'google' | 'github',
|
||||||
userData: any
|
userData: { email: string; username: string; avatar?: string }
|
||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
try {
|
try {
|
||||||
const result = await authService.loginWithOAuth(provider, userData);
|
const result = await authService.loginWithOAuth(provider, userData);
|
||||||
|
|
||||||
console.log('OAuth login result received:', result);
|
console.warn('OAuth login result received:', result);
|
||||||
console.log('OAuth user:', result.user);
|
console.warn('OAuth user:', result.user);
|
||||||
console.log('OAuth user _id:', result.user._id);
|
console.warn('OAuth user _id:', result.user._id);
|
||||||
|
|
||||||
// Update last login time
|
// Update last login time
|
||||||
const updatedUser = { ...result.user, lastLoginAt: new Date() };
|
const updatedUser = { ...result.user, lastLoginAt: new Date() };
|
||||||
await dbService.updateUser(updatedUser);
|
await dbService.updateUser(updatedUser);
|
||||||
|
|
||||||
console.log('Updated OAuth user with last login:', updatedUser);
|
console.warn('Updated OAuth user with last login:', updatedUser);
|
||||||
|
|
||||||
localStorage.setItem('access_token', result.accessToken);
|
localStorage.setItem('access_token', result.accessToken);
|
||||||
setUser(updatedUser);
|
setUser(updatedUser);
|
||||||
|
|
||||||
console.log('OAuth user set in context');
|
console.warn('OAuth user set in context');
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('OAuth login error:', error);
|
console.error('OAuth login error:', error);
|
||||||
|
|||||||
+3
-4
@@ -62,8 +62,8 @@ RUN bun run build
|
|||||||
# Production stage - serve with nginx
|
# Production stage - serve with nginx
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|
||||||
# Install curl for health checks
|
# Install wget for health checks
|
||||||
RUN apk add --no-cache curl
|
RUN apk add --no-cache wget
|
||||||
|
|
||||||
# Copy built files from builder stage
|
# Copy built files from builder stage
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
@@ -78,8 +78,7 @@ RUN chown -R nginx:nginx /usr/share/nginx/html && \
|
|||||||
chown -R nginx:nginx /etc/nginx/conf.d
|
chown -R nginx:nginx /etc/nginx/conf.d
|
||||||
|
|
||||||
# Add health check
|
# Add health check
|
||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
||||||
CMD curl -f http://localhost/ || exit 1
|
|
||||||
|
|
||||||
# Expose port 80
|
# Expose port 80
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|||||||
@@ -44,40 +44,40 @@ target "app" {
|
|||||||
"linux/amd64",
|
"linux/amd64",
|
||||||
"linux/arm64"
|
"linux/arm64"
|
||||||
]
|
]
|
||||||
|
|
||||||
tags = [
|
tags = [
|
||||||
"${REGISTRY}rxminder:${TAG}",
|
"${REGISTRY}rxminder:${TAG}",
|
||||||
"${REGISTRY}rxminder:latest"
|
"${REGISTRY}rxminder:latest"
|
||||||
]
|
]
|
||||||
|
|
||||||
args = {
|
args = {
|
||||||
# CouchDB Configuration
|
# CouchDB Configuration
|
||||||
VITE_COUCHDB_URL = "${VITE_COUCHDB_URL}"
|
VITE_COUCHDB_URL = "${VITE_COUCHDB_URL}"
|
||||||
VITE_COUCHDB_USER = "${VITE_COUCHDB_USER}"
|
VITE_COUCHDB_USER = "${VITE_COUCHDB_USER}"
|
||||||
VITE_COUCHDB_PASSWORD = "${VITE_COUCHDB_PASSWORD}"
|
VITE_COUCHDB_PASSWORD = "${VITE_COUCHDB_PASSWORD}"
|
||||||
|
|
||||||
# Application Configuration
|
# Application Configuration
|
||||||
APP_BASE_URL = "${APP_BASE_URL}"
|
APP_BASE_URL = "${APP_BASE_URL}"
|
||||||
|
|
||||||
# OAuth Configuration (Optional)
|
# OAuth Configuration (Optional)
|
||||||
VITE_GOOGLE_CLIENT_ID = "${VITE_GOOGLE_CLIENT_ID}"
|
VITE_GOOGLE_CLIENT_ID = "${VITE_GOOGLE_CLIENT_ID}"
|
||||||
VITE_GITHUB_CLIENT_ID = "${VITE_GITHUB_CLIENT_ID}"
|
VITE_GITHUB_CLIENT_ID = "${VITE_GITHUB_CLIENT_ID}"
|
||||||
|
|
||||||
# Build environment
|
# Build environment
|
||||||
NODE_ENV = "production"
|
NODE_ENV = "production"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Advanced buildx features
|
# Advanced buildx features
|
||||||
cache-from = [
|
cache-from = [
|
||||||
"type=gha",
|
"type=gha",
|
||||||
"type=registry,ref=${REGISTRY}rxminder:buildcache"
|
"type=registry,ref=${REGISTRY}rxminder:buildcache"
|
||||||
]
|
]
|
||||||
|
|
||||||
cache-to = [
|
cache-to = [
|
||||||
"type=gha,mode=max",
|
"type=gha,mode=max",
|
||||||
"type=registry,ref=${REGISTRY}rxminder:buildcache,mode=max"
|
"type=registry,ref=${REGISTRY}rxminder:buildcache,mode=max"
|
||||||
]
|
]
|
||||||
|
|
||||||
# Attestations for supply chain security
|
# Attestations for supply chain security
|
||||||
attest = [
|
attest = [
|
||||||
"type=provenance,mode=max",
|
"type=provenance,mode=max",
|
||||||
|
|||||||
@@ -72,24 +72,28 @@ APP_NAME=StagingApp
|
|||||||
### Files That Use APP_NAME
|
### Files That Use APP_NAME
|
||||||
|
|
||||||
1. **Frontend Files**:
|
1. **Frontend Files**:
|
||||||
- `index.html.template` - Page title
|
|
||||||
- `App.tsx` - UI header text
|
- `index.html.template` - Page title
|
||||||
- `vite.config.ts` - Environment variable mapping
|
- `App.tsx` - UI header text
|
||||||
|
- `vite.config.ts` - Environment variable mapping
|
||||||
|
|
||||||
2. **Docker Files**:
|
2. **Docker Files**:
|
||||||
- `docker/Dockerfile` - Build argument and environment variable
|
|
||||||
- `docker/docker-compose.yaml` - Build args and labels
|
- `docker/Dockerfile` - Build argument and environment variable
|
||||||
|
- `docker/docker-compose.yaml` - Build args and labels
|
||||||
|
|
||||||
3. **Kubernetes Templates**:
|
3. **Kubernetes Templates**:
|
||||||
- `k8s/frontend-deployment.yaml.template` - Resource names and labels
|
|
||||||
- `k8s/configmap.yaml.template` - Resource names and labels
|
- `k8s/frontend-deployment.yaml.template` - Resource names and labels
|
||||||
- All other `k8s/*.yaml.template` files
|
- `k8s/configmap.yaml.template` - Resource names and labels
|
||||||
|
- All other `k8s/*.yaml.template` files
|
||||||
|
|
||||||
4. **Scripts**:
|
4. **Scripts**:
|
||||||
- `scripts/deploy.sh` - Container and image naming
|
|
||||||
- `scripts/buildx-helper.sh` - Container and image naming
|
- `scripts/deploy.sh` - Container and image naming
|
||||||
- `scripts/validate-deployment.sh` - Container and image naming
|
- `scripts/buildx-helper.sh` - Container and image naming
|
||||||
- `scripts/process-html.sh` - HTML template processing
|
- `scripts/validate-deployment.sh` - Container and image naming
|
||||||
|
- `scripts/process-html.sh` - HTML template processing
|
||||||
|
|
||||||
## Build Process
|
## Build Process
|
||||||
|
|
||||||
|
|||||||
+10
-1
@@ -3,6 +3,9 @@ const tsPlugin = require('@typescript-eslint/eslint-plugin');
|
|||||||
const reactHooksPlugin = require('eslint-plugin-react-hooks');
|
const reactHooksPlugin = require('eslint-plugin-react-hooks');
|
||||||
|
|
||||||
module.exports = [
|
module.exports = [
|
||||||
|
{
|
||||||
|
ignores: ['dist/**', 'node_modules/**', '**/*.min.js'],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
files: ['**/*.{js,jsx,ts,tsx}'],
|
files: ['**/*.{js,jsx,ts,tsx}'],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
@@ -29,7 +32,7 @@ module.exports = [
|
|||||||
// TypeScript ESLint rules
|
// TypeScript ESLint rules
|
||||||
'@typescript-eslint/no-unused-vars': [
|
'@typescript-eslint/no-unused-vars': [
|
||||||
'error',
|
'error',
|
||||||
{ argsIgnorePattern: '^_' },
|
{ argsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' },
|
||||||
],
|
],
|
||||||
'@typescript-eslint/no-explicit-any': 'warn',
|
'@typescript-eslint/no-explicit-any': 'warn',
|
||||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
@@ -60,4 +63,10 @@ module.exports = [
|
|||||||
'no-console': 'off',
|
'no-console': 'off',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
files: ['**/tests/e2e/fixtures.ts'],
|
||||||
|
rules: {
|
||||||
|
'react-hooks/rules-of-hooks': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ function getStoredValue<T>(key: string, defaultValue: T): T {
|
|||||||
const saved = localStorage.getItem(key);
|
const saved = localStorage.getItem(key);
|
||||||
try {
|
try {
|
||||||
return saved ? JSON.parse(saved) : defaultValue;
|
return saved ? JSON.parse(saved) : defaultValue;
|
||||||
} catch (e) {
|
} catch {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>MyCustomMeds</title>
|
<title></title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
|||||||
+3
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "${APP_NAME:-rxminder}",
|
"name": "rxminder",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -56,6 +56,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
|
"express": "^5.1.0",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.1.1",
|
"react-dom": "^19.1.1",
|
||||||
"uuid": "^12.0.0"
|
"uuid": "^12.0.0"
|
||||||
|
|||||||
+39
-39
@@ -10,31 +10,31 @@ echo "🚀 Starting deploymif docker compose -f docker/docker-compose.yaml -p rx
|
|||||||
else
|
else
|
||||||
print_error "Docker Compose services failed to start"
|
print_error "Docker Compose services failed to start"
|
||||||
docker compose -f docker/docker-compose.yaml -p rxminder-validation logsalidation..."
|
docker compose -f docker/docker-compose.yaml -p rxminder-validation logsalidation..."
|
||||||
|
|
||||||
# Colors for output
|
# Colors for output
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
BLUE='\033[0;34m'
|
BLUE='\033[0;34m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
# Function to print colored output
|
# Function to print colored output
|
||||||
print_status() {
|
print_status() {
|
||||||
echo -e "${BLUE}[INFO]${NC} $1"
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_success() {
|
print_success() {
|
||||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_warning() {
|
print_warning() {
|
||||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_error() {
|
print_error() {
|
||||||
echo -e "${RED}[ERROR]${NC} $1"
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Cleanup function
|
# Cleanup function
|
||||||
cleanup() {
|
cleanup() {
|
||||||
print_status "Cleaning up test containers..."
|
print_status "Cleaning up test containers..."
|
||||||
@@ -42,48 +42,48 @@ else
|
|||||||
docker rm rxminder-validation-test 2>/dev/null || true
|
docker rm rxminder-validation-test 2>/dev/null || true
|
||||||
docker compose -f docker/docker-compose.yaml -p rxminder-validation down 2>/dev/null || true
|
docker compose -f docker/docker-compose.yaml -p rxminder-validation down 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set trap for cleanup
|
# Set trap for cleanup
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
print_status "1. Validating environment files..."
|
print_status "1. Validating environment files..."
|
||||||
|
|
||||||
# Check if required environment files exist
|
# Check if required environment files exist
|
||||||
if [[ ! -f .env ]]; then
|
if [[ ! -f .env ]]; then
|
||||||
print_error ".env file not found. Run 'cp .env.example .env' and configure it."
|
print_error ".env file not found. Run 'cp .env.example .env' and configure it."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -f .env.example ]]; then
|
if [[ ! -f .env.example ]]; then
|
||||||
print_error ".env.example file not found."
|
print_error ".env.example file not found."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_success "Environment files exist"
|
print_success "Environment files exist"
|
||||||
|
|
||||||
# Validate environment consistency
|
# Validate environment consistency
|
||||||
print_status "2. Checking environment variable consistency..."
|
print_status "2. Checking environment variable consistency..."
|
||||||
./validate-env.sh
|
./validate-env.sh
|
||||||
|
|
||||||
print_status "3. Setting up Docker Buildx..."
|
print_status "3. Setting up Docker Buildx..."
|
||||||
|
|
||||||
# Ensure buildx is available
|
# Ensure buildx is available
|
||||||
if ! docker buildx version >/dev/null 2>&1; then
|
if ! docker buildx version >/dev/null 2>&1; then
|
||||||
print_error "Docker Buildx is not available. Please update Docker to a version that supports Buildx."
|
print_error "Docker Buildx is not available. Please update Docker to a version that supports Buildx."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create a new builder instance if it doesn't exist
|
# Create a new builder instance if it doesn't exist
|
||||||
if ! docker buildx ls | grep -q "rxminder-builder"; then
|
if ! docker buildx ls | grep -q "rxminder-builder"; then
|
||||||
print_status "Creating new buildx builder instance..."
|
print_status "Creating new buildx builder instance..."
|
||||||
docker buildx create --name rxminder-builder --driver docker-container --bootstrap
|
docker buildx create --name rxminder-builder --driver docker-container --bootstrap
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use the builder
|
# Use the builder
|
||||||
docker buildx use rxminder-builder
|
docker buildx use rxminder-builder
|
||||||
|
|
||||||
print_status "4. Building multi-platform Docker image with buildx..."
|
print_status "4. Building multi-platform Docker image with buildx..."
|
||||||
|
|
||||||
# Build the image with buildx for multiple platforms
|
# Build the image with buildx for multiple platforms
|
||||||
docker buildx build --no-cache \
|
docker buildx build --no-cache \
|
||||||
--platform linux/amd64,linux/arm64 \
|
--platform linux/amd64,linux/arm64 \
|
||||||
@@ -102,29 +102,29 @@ else
|
|||||||
-t rxminder-validation \
|
-t rxminder-validation \
|
||||||
--load \
|
--load \
|
||||||
.
|
.
|
||||||
|
|
||||||
print_success "Docker image built successfully"
|
print_success "Docker image built successfully"
|
||||||
|
|
||||||
print_status "5. Testing container startup and health..."
|
print_status "5. Testing container startup and health..."
|
||||||
|
|
||||||
# Run container in background
|
# Run container in background
|
||||||
docker run --rm -d \
|
docker run --rm -d \
|
||||||
-p 8083:80 \
|
-p 8083:80 \
|
||||||
--name rxminder-validation-test \
|
--name rxminder-validation-test \
|
||||||
rxminder-validation
|
rxminder-validation
|
||||||
|
|
||||||
# Wait for container to start
|
# Wait for container to start
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
# Check if container is running
|
# Check if container is running
|
||||||
if ! docker ps | grep -q rxminder-validation-test; then
|
if ! docker ps | grep -q rxminder-validation-test; then
|
||||||
print_error "Container failed to start"
|
print_error "Container failed to start"
|
||||||
docker logs rxminder-validation-test
|
docker logs rxminder-validation-test
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_success "Container started successfully"
|
print_success "Container started successfully"
|
||||||
|
|
||||||
# Test health endpoint
|
# Test health endpoint
|
||||||
print_status "5. Testing health endpoint..."
|
print_status "5. Testing health endpoint..."
|
||||||
for i in {1..10}; do
|
for i in {1..10}; do
|
||||||
@@ -139,7 +139,7 @@ else
|
|||||||
sleep 2
|
sleep 2
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Test main application
|
# Test main application
|
||||||
print_status "6. Testing main application..."
|
print_status "6. Testing main application..."
|
||||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8083)
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8083)
|
||||||
@@ -149,20 +149,20 @@ else
|
|||||||
print_error "Main application not responding properly (HTTP $HTTP_CODE)"
|
print_error "Main application not responding properly (HTTP $HTTP_CODE)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Test docker-compose build
|
# Test docker-compose build
|
||||||
print_status "7. Testing Docker Compose build..."
|
print_status "7. Testing Docker Compose build..."
|
||||||
docker compose -f docker/docker-compose.yaml build frontend --no-cache
|
docker compose -f docker/docker-compose.yaml build frontend --no-cache
|
||||||
|
|
||||||
print_success "Docker Compose build successful"
|
print_success "Docker Compose build successful"
|
||||||
|
|
||||||
# Test docker-compose with validation project name
|
# Test docker-compose with validation project name
|
||||||
print_status "8. Testing Docker Compose deployment..."
|
print_status "8. Testing Docker Compose deployment..."
|
||||||
docker compose -f docker/docker-compose.yaml -p rxminder-validation up -d --build
|
docker compose -f docker/docker-compose.yaml -p rxminder-validation up -d --build
|
||||||
|
|
||||||
# Wait for services to start
|
# Wait for services to start
|
||||||
sleep 10
|
sleep 10
|
||||||
|
|
||||||
# Check service health
|
# Check service health
|
||||||
if docker compose -f docker/docker-compose.yaml -p meds-validation ps | grep -q "Up"; then
|
if docker compose -f docker/docker-compose.yaml -p meds-validation ps | grep -q "Up"; then
|
||||||
print_success "Docker Compose services started successfully"
|
print_success "Docker Compose services started successfully"
|
||||||
@@ -171,20 +171,20 @@ else
|
|||||||
docker compose -f docker/docker-compose.yaml -p meds-validation logs
|
docker compose -f docker/docker-compose.yaml -p meds-validation logs
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Test health of compose deployment
|
# Test health of compose deployment
|
||||||
if curl -s -f http://localhost:8080/health > /dev/null; then
|
if curl -s -f http://localhost:8080/health > /dev/null; then
|
||||||
print_success "Docker Compose health endpoint responding"
|
print_success "Docker Compose health endpoint responding"
|
||||||
else
|
else
|
||||||
print_warning "Docker Compose health endpoint not responding (may need CouchDB)"
|
print_warning "Docker Compose health endpoint not responding (may need CouchDB)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_status "9. Checking image size..."
|
print_status "9. Checking image size..."
|
||||||
IMAGE_SIZE=$(docker image inspect rxminder-validation --format='{{.Size}}' | numfmt --to=iec)
|
IMAGE_SIZE=$(docker image inspect rxminder-validation --format='{{.Size}}' | numfmt --to=iec)
|
||||||
print_success "Image size: $IMAGE_SIZE"
|
print_success "Image size: $IMAGE_SIZE"
|
||||||
|
|
||||||
print_status "10. Validating security configuration..."
|
print_status "10. Validating security configuration..."
|
||||||
|
|
||||||
# Check if image runs as non-root
|
# Check if image runs as non-root
|
||||||
USER_INFO=$(docker run --rm rxminder-validation whoami)
|
USER_INFO=$(docker run --rm rxminder-validation whoami)
|
||||||
if [[ "$USER_INFO" != "root" ]]; then
|
if [[ "$USER_INFO" != "root" ]]; then
|
||||||
@@ -192,7 +192,7 @@ else
|
|||||||
else
|
else
|
||||||
print_warning "Container runs as root user (security consideration)"
|
print_warning "Container runs as root user (security consideration)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check nginx configuration
|
# Check nginx configuration
|
||||||
if docker run --rm rxminder-validation nginx -t 2>/dev/null; then
|
if docker run --rm rxminder-validation nginx -t 2>/dev/null; then
|
||||||
print_success "Nginx configuration is valid"
|
print_success "Nginx configuration is valid"
|
||||||
@@ -200,9 +200,9 @@ else
|
|||||||
print_error "Nginx configuration has issues"
|
print_error "Nginx configuration has issues"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_status "11. Final validation complete!"
|
print_status "11. Final validation complete!"
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "🎉 Deployment validation successful!"
|
echo "🎉 Deployment validation successful!"
|
||||||
echo
|
echo
|
||||||
@@ -223,4 +223,4 @@ else
|
|||||||
echo "3. Set up monitoring and backups"
|
echo "3. Set up monitoring and backups"
|
||||||
echo "4. Configure SSL/TLS certificates"
|
echo "4. Configure SSL/TLS certificates"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|||||||
+54
-54
@@ -10,31 +10,31 @@ echo "🚀 Starting deploymif docker compose -f docker/docker-compose.yaml -p rx
|
|||||||
else
|
else
|
||||||
print_error "Docker Compose services failed to start"
|
print_error "Docker Compose services failed to start"
|
||||||
docker compose -f docker/docker-compose.yaml -p rxminder-validation logsalidation..."
|
docker compose -f docker/docker-compose.yaml -p rxminder-validation logsalidation..."
|
||||||
|
|
||||||
# Colors for output
|
# Colors for output
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
BLUE='\033[0;34m'
|
BLUE='\033[0;34m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
# Function to print colored output
|
# Function to print colored output
|
||||||
print_status() {
|
print_status() {
|
||||||
echo -e "${BLUE}[INFO]${NC} $1"
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_success() {
|
print_success() {
|
||||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_warning() {
|
print_warning() {
|
||||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_error() {
|
print_error() {
|
||||||
echo -e "${RED}[ERROR]${NC} $1"
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Cleanup function
|
# Cleanup function
|
||||||
cleanup() {
|
cleanup() {
|
||||||
print_status "Cleaning up test containers..."
|
print_status "Cleaning up test containers..."
|
||||||
@@ -42,48 +42,48 @@ else
|
|||||||
docker rm rxminder-validation-test 2>/dev/null || true
|
docker rm rxminder-validation-test 2>/dev/null || true
|
||||||
docker compose -f docker/docker-compose.yaml -p rxminder-validation down 2>/dev/null || true
|
docker compose -f docker/docker-compose.yaml -p rxminder-validation down 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set trap for cleanup
|
# Set trap for cleanup
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
print_status "1. Validating environment files..."
|
print_status "1. Validating environment files..."
|
||||||
|
|
||||||
# Check if required environment files exist
|
# Check if required environment files exist
|
||||||
if [[ ! -f .env ]]; then
|
if [[ ! -f .env ]]; then
|
||||||
print_error ".env file not found. Run 'cp .env.example .env' and configure it."
|
print_error ".env file not found. Run 'cp .env.example .env' and configure it."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -f .env.example ]]; then
|
if [[ ! -f .env.example ]]; then
|
||||||
print_error ".env.example file not found."
|
print_error ".env.example file not found."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_success "Environment files exist"
|
print_success "Environment files exist"
|
||||||
|
|
||||||
# Validate environment consistency
|
# Validate environment consistency
|
||||||
print_status "2. Checking environment variable consistency..."
|
print_status "2. Checking environment variable consistency..."
|
||||||
./validate-env.sh
|
./validate-env.sh
|
||||||
|
|
||||||
print_status "3. Setting up Docker Buildx..."
|
print_status "3. Setting up Docker Buildx..."
|
||||||
|
|
||||||
# Ensure buildx is available
|
# Ensure buildx is available
|
||||||
if ! docker buildx version >/dev/null 2>&1; then
|
if ! docker buildx version >/dev/null 2>&1; then
|
||||||
print_error "Docker Buildx is not available. Please update Docker to a version that supports Buildx."
|
print_error "Docker Buildx is not available. Please update Docker to a version that supports Buildx."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create a new builder instance if it doesn't exist
|
# Create a new builder instance if it doesn't exist
|
||||||
if ! docker buildx ls | grep -q "rxminder-builder"; then
|
if ! docker buildx ls | grep -q "rxminder-builder"; then
|
||||||
print_status "Creating new buildx builder instance..."
|
print_status "Creating new buildx builder instance..."
|
||||||
docker buildx create --name rxminder-builder --driver docker-container --bootstrap
|
docker buildx create --name rxminder-builder --driver docker-container --bootstrap
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use the builder
|
# Use the builder
|
||||||
docker buildx use rxminder-builder
|
docker buildx use rxminder-builder
|
||||||
|
|
||||||
print_status "4. Building multi-platform Docker image with buildx..."
|
print_status "4. Building multi-platform Docker image with buildx..."
|
||||||
|
|
||||||
# Build the image with buildx for multiple platforms
|
# Build the image with buildx for multiple platforms
|
||||||
docker buildx build --no-cache \
|
docker buildx build --no-cache \
|
||||||
--platform linux/amd64,linux/arm64 \
|
--platform linux/amd64,linux/arm64 \
|
||||||
@@ -102,29 +102,29 @@ else
|
|||||||
-t rxminder-validation \
|
-t rxminder-validation \
|
||||||
--load \
|
--load \
|
||||||
.
|
.
|
||||||
|
|
||||||
print_success "Docker image built successfully"
|
print_success "Docker image built successfully"
|
||||||
|
|
||||||
print_status "5. Testing container startup and health..."
|
print_status "5. Testing container startup and health..."
|
||||||
|
|
||||||
# Run container in background
|
# Run container in background
|
||||||
docker run --rm -d \
|
docker run --rm -d \
|
||||||
-p 8083:80 \
|
-p 8083:80 \
|
||||||
--name rxminder-validation-test \
|
--name rxminder-validation-test \
|
||||||
rxminder-validation
|
rxminder-validation
|
||||||
|
|
||||||
# Wait for container to start
|
# Wait for container to start
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
# Check if container is running
|
# Check if container is running
|
||||||
if ! docker ps | grep -q rxminder-validation-test; then
|
if ! docker ps | grep -q rxminder-validation-test; then
|
||||||
print_error "Container failed to start"
|
print_error "Container failed to start"
|
||||||
docker logs rxminder-validation-test
|
docker logs rxminder-validation-test
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_success "Container started successfully"
|
print_success "Container started successfully"
|
||||||
|
|
||||||
# Test health endpoint
|
# Test health endpoint
|
||||||
print_status "5. Testing health endpoint..."
|
print_status "5. Testing health endpoint..."
|
||||||
for i in {1..10}; do
|
for i in {1..10}; do
|
||||||
@@ -139,7 +139,7 @@ else
|
|||||||
sleep 2
|
sleep 2
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Test main application
|
# Test main application
|
||||||
print_status "6. Testing main application..."
|
print_status "6. Testing main application..."
|
||||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8083)
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8083)
|
||||||
@@ -149,20 +149,20 @@ else
|
|||||||
print_error "Main application not responding properly (HTTP $HTTP_CODE)"
|
print_error "Main application not responding properly (HTTP $HTTP_CODE)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Test docker-compose build
|
# Test docker-compose build
|
||||||
print_status "7. Testing Docker Compose build..."
|
print_status "7. Testing Docker Compose build..."
|
||||||
docker compose -f docker/docker-compose.yaml build frontend --no-cache
|
docker compose -f docker/docker-compose.yaml build frontend --no-cache
|
||||||
|
|
||||||
print_success "Docker Compose build successful"
|
print_success "Docker Compose build successful"
|
||||||
|
|
||||||
# Test docker-compose with validation project name
|
# Test docker-compose with validation project name
|
||||||
print_status "8. Testing Docker Compose deployment..."
|
print_status "8. Testing Docker Compose deployment..."
|
||||||
docker compose -f docker/docker-compose.yaml -p rxminder-validation up -d --build
|
docker compose -f docker/docker-compose.yaml -p rxminder-validation up -d --build
|
||||||
|
|
||||||
# Wait for services to start
|
# Wait for services to start
|
||||||
sleep 10
|
sleep 10
|
||||||
|
|
||||||
# Check service health
|
# Check service health
|
||||||
if docker compose -f docker/docker-compose.yaml -p meds-validation ps | grep -q "Up"; then
|
if docker compose -f docker/docker-compose.yaml -p meds-validation ps | grep -q "Up"; then
|
||||||
print_success "Docker Compose services started successfully"
|
print_success "Docker Compose services started successfully"
|
||||||
@@ -171,20 +171,20 @@ else
|
|||||||
docker compose -f docker/docker-compose.yaml -p meds-validation logs
|
docker compose -f docker/docker-compose.yaml -p meds-validation logs
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Test health of compose deployment
|
# Test health of compose deployment
|
||||||
if curl -s -f http://localhost:8080/health > /dev/null; then
|
if curl -s -f http://localhost:8080/health > /dev/null; then
|
||||||
print_success "Docker Compose health endpoint responding"
|
print_success "Docker Compose health endpoint responding"
|
||||||
else
|
else
|
||||||
print_warning "Docker Compose health endpoint not responding (may need CouchDB)"
|
print_warning "Docker Compose health endpoint not responding (may need CouchDB)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_status "9. Checking image size..."
|
print_status "9. Checking image size..."
|
||||||
IMAGE_SIZE=$(docker image inspect rxminder-validation --format='{{.Size}}' | numfmt --to=iec)
|
IMAGE_SIZE=$(docker image inspect rxminder-validation --format='{{.Size}}' | numfmt --to=iec)
|
||||||
print_success "Image size: $IMAGE_SIZE"
|
print_success "Image size: $IMAGE_SIZE"
|
||||||
|
|
||||||
print_status "10. Validating security configuration..."
|
print_status "10. Validating security configuration..."
|
||||||
|
|
||||||
# Check if image runs as non-root
|
# Check if image runs as non-root
|
||||||
USER_INFO=$(docker run --rm rxminder-validation whoami)
|
USER_INFO=$(docker run --rm rxminder-validation whoami)
|
||||||
if [[ "$USER_INFO" != "root" ]]; then
|
if [[ "$USER_INFO" != "root" ]]; then
|
||||||
@@ -192,7 +192,7 @@ else
|
|||||||
else
|
else
|
||||||
print_warning "Container runs as root user (security consideration)"
|
print_warning "Container runs as root user (security consideration)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check nginx configuration
|
# Check nginx configuration
|
||||||
if docker run --rm rxminder-validation nginx -t 2>/dev/null; then
|
if docker run --rm rxminder-validation nginx -t 2>/dev/null; then
|
||||||
print_success "Nginx configuration is valid"
|
print_success "Nginx configuration is valid"
|
||||||
@@ -200,9 +200,9 @@ else
|
|||||||
print_error "Nginx configuration has issues"
|
print_error "Nginx configuration has issues"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_status "11. Final validation complete!"
|
print_status "11. Final validation complete!"
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "🎉 Deployment validation successful!"
|
echo "🎉 Deployment validation successful!"
|
||||||
echo
|
echo
|
||||||
@@ -223,12 +223,12 @@ else
|
|||||||
echo "3. Set up monitoring and backups"
|
echo "3. Set up monitoring and backups"
|
||||||
echo "4. Configure SSL/TLS certificates"
|
echo "4. Configure SSL/TLS certificates"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Load Gitea-specific environment variables
|
# Load Gitea-specific environment variables
|
||||||
REGISTRY=${GITEA_SERVER_URL#https://}
|
REGISTRY=${GITEA_SERVER_URL#https://}
|
||||||
IMAGE_NAME=${GITEA_REPOSITORY}
|
IMAGE_NAME=${GITEA_REPOSITORY}
|
||||||
IMAGE_TAG=${GITEA_SHA:0:8}
|
IMAGE_TAG=${GITEA_SHA:0:8}
|
||||||
|
|
||||||
print_status "Registry: $REGISTRY"
|
print_status "Registry: $REGISTRY"
|
||||||
print_status "Image: $IMAGE_NAME:$IMAGE_TAG"
|
print_status "Image: $IMAGE_NAME:$IMAGE_TAG"
|
||||||
fi
|
fi
|
||||||
@@ -236,7 +236,7 @@ fi
|
|||||||
# Check if .env file exists
|
# Check if .env file exists
|
||||||
if [ ! -f ".env" ]; then
|
if [ ! -f ".env" ]; then
|
||||||
print_warning ".env file not found, using defaults"
|
print_warning ".env file not found, using defaults"
|
||||||
|
|
||||||
# Create minimal .env for Gitea deployment
|
# Create minimal .env for Gitea deployment
|
||||||
cat > .env << EOF
|
cat > .env << EOF
|
||||||
COUCHDB_USER=admin
|
COUCHDB_USER=admin
|
||||||
@@ -247,7 +247,7 @@ VITE_COUCHDB_PASSWORD=change-this-secure-password
|
|||||||
APP_BASE_URL=http://localhost:8080
|
APP_BASE_URL=http://localhost:8080
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
print_warning "Created default .env file - please update with your credentials"
|
print_warning "Created default .env file - please update with your credentials"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -269,31 +269,31 @@ print_success "Environment variables validated"
|
|||||||
# Function to deploy via Docker Compose
|
# Function to deploy via Docker Compose
|
||||||
deploy_compose() {
|
deploy_compose() {
|
||||||
print_status "Deploying with Docker Compose..."
|
print_status "Deploying with Docker Compose..."
|
||||||
|
|
||||||
# Export image variables for compose
|
# Export image variables for compose
|
||||||
export IMAGE_TAG
|
export IMAGE_TAG
|
||||||
export REGISTRY
|
export REGISTRY
|
||||||
export IMAGE_NAME
|
export IMAGE_NAME
|
||||||
|
|
||||||
# Use the built image from registry if available
|
# Use the built image from registry if available
|
||||||
if [ "$GITEA_ACTIONS" = "true" ]; then
|
if [ "$GITEA_ACTIONS" = "true" ]; then
|
||||||
# Override the image in docker-compose
|
# Override the image in docker-compose
|
||||||
export FRONTEND_IMAGE="$REGISTRY/$IMAGE_NAME:$IMAGE_TAG"
|
export FRONTEND_IMAGE="$REGISTRY/$IMAGE_NAME:$IMAGE_TAG"
|
||||||
print_status "Using Gitea Actions built image: $FRONTEND_IMAGE"
|
print_status "Using Gitea Actions built image: $FRONTEND_IMAGE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Pull the latest images
|
# Pull the latest images
|
||||||
print_status "Pulling latest images..."
|
print_status "Pulling latest images..."
|
||||||
docker-compose -f docker/docker-compose.yaml pull || print_warning "Failed to pull some images"
|
docker-compose -f docker/docker-compose.yaml pull || print_warning "Failed to pull some images"
|
||||||
|
|
||||||
# Start services
|
# Start services
|
||||||
print_status "Starting services..."
|
print_status "Starting services..."
|
||||||
docker-compose -f docker/docker-compose.yaml up -d
|
docker-compose -f docker/docker-compose.yaml up -d
|
||||||
|
|
||||||
# Wait for services
|
# Wait for services
|
||||||
print_status "Waiting for services to be ready..."
|
print_status "Waiting for services to be ready..."
|
||||||
sleep 10
|
sleep 10
|
||||||
|
|
||||||
# Health check
|
# Health check
|
||||||
print_status "Checking service health..."
|
print_status "Checking service health..."
|
||||||
if curl -f http://localhost:8080/health > /dev/null 2>&1; then
|
if curl -f http://localhost:8080/health > /dev/null 2>&1; then
|
||||||
@@ -302,7 +302,7 @@ deploy_compose() {
|
|||||||
print_warning "Frontend health check failed, checking logs..."
|
print_warning "Frontend health check failed, checking logs..."
|
||||||
docker-compose -f docker/docker-compose.yaml logs frontend
|
docker-compose -f docker/docker-compose.yaml logs frontend
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if curl -f http://localhost:5984/_up > /dev/null 2>&1; then
|
if curl -f http://localhost:5984/_up > /dev/null 2>&1; then
|
||||||
print_success "CouchDB service is healthy"
|
print_success "CouchDB service is healthy"
|
||||||
else
|
else
|
||||||
@@ -313,26 +313,26 @@ deploy_compose() {
|
|||||||
# Function to deploy via Kubernetes
|
# Function to deploy via Kubernetes
|
||||||
deploy_k8s() {
|
deploy_k8s() {
|
||||||
print_status "Deploying to Kubernetes..."
|
print_status "Deploying to Kubernetes..."
|
||||||
|
|
||||||
if ! command -v kubectl &> /dev/null; then
|
if ! command -v kubectl &> /dev/null; then
|
||||||
print_error "kubectl is not installed"
|
print_error "kubectl is not installed"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Update image in k8s manifests
|
# Update image in k8s manifests
|
||||||
if [ "$GITEA_ACTIONS" = "true" ]; then
|
if [ "$GITEA_ACTIONS" = "true" ]; then
|
||||||
print_status "Updating Kubernetes manifests with new image..."
|
print_status "Updating Kubernetes manifests with new image..."
|
||||||
sed -i "s|image:.*rxminder.*|image: $REGISTRY/$IMAGE_NAME:$IMAGE_TAG|g" k8s/frontend-deployment.yaml
|
sed -i "s|image:.*rxminder.*|image: $REGISTRY/$IMAGE_NAME:$IMAGE_TAG|g" k8s/frontend-deployment.yaml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Apply manifests
|
# Apply manifests
|
||||||
print_status "Applying Kubernetes manifests..."
|
print_status "Applying Kubernetes manifests..."
|
||||||
kubectl apply -f k8s/
|
kubectl apply -f k8s/
|
||||||
|
|
||||||
# Wait for rollout
|
# Wait for rollout
|
||||||
print_status "Waiting for deployment rollout..."
|
print_status "Waiting for deployment rollout..."
|
||||||
kubectl rollout status deployment/frontend-deployment
|
kubectl rollout status deployment/frontend-deployment
|
||||||
|
|
||||||
print_success "Kubernetes deployment completed"
|
print_success "Kubernetes deployment completed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+56
-56
@@ -46,12 +46,12 @@ echo "🚀 Deploying RxMinder from Gitea to $ENVIRONMENT environment..."
|
|||||||
# Check if running in Gitea Actions
|
# Check if running in Gitea Actions
|
||||||
if [ "$GITEA_ACTIONS" = "true" ]; then
|
if [ "$GITEA_ACTIONS" = "true" ]; then
|
||||||
print_status "Running in Gitea Actions environment"
|
print_status "Running in Gitea Actions environment"
|
||||||
|
|
||||||
# Load Gitea-specific environment variables
|
# Load Gitea-specific environment variables
|
||||||
REGISTRY=${GITEA_SERVER_URL#https://}
|
REGISTRY=${GITEA_SERVER_URL#https://}
|
||||||
IMAGE_NAME=${GITEA_REPOSITORY}
|
IMAGE_NAME=${GITEA_REPOSITORY}
|
||||||
IMAGE_TAG=${GITEA_SHA:0:8}
|
IMAGE_TAG=${GITEA_SHA:0:8}
|
||||||
|
|
||||||
print_status "Registry: $REGISTRY"
|
print_status "Registry: $REGISTRY"
|
||||||
print_status "Image: $IMAGE_NAME:$IMAGE_TAG"
|
print_status "Image: $IMAGE_NAME:$IMAGE_TAG"
|
||||||
fi
|
fi
|
||||||
@@ -59,7 +59,7 @@ fi
|
|||||||
# Check if .env file exists
|
# Check if .env file exists
|
||||||
if [ ! -f ".env" ]; then
|
if [ ! -f ".env" ]; then
|
||||||
print_warning ".env file not found, using defaults"
|
print_warning ".env file not found, using defaults"
|
||||||
|
|
||||||
# Create minimal .env for Gitea deployment
|
# Create minimal .env for Gitea deployment
|
||||||
cat > .env << EOF
|
cat > .env << EOF
|
||||||
COUCHDB_USER=admin
|
COUCHDB_USER=admin
|
||||||
@@ -70,7 +70,7 @@ VITE_COUCHDB_PASSWORD=change-this-secure-password
|
|||||||
APP_BASE_URL=http://localhost:8080
|
APP_BASE_URL=http://localhost:8080
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
print_warning "Created default .env file - please update with your credentials"
|
print_warning "Created default .env file - please update with your credentials"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -92,31 +92,31 @@ print_success "Environment variables validated"
|
|||||||
# Function to deploy via Docker Compose
|
# Function to deploy via Docker Compose
|
||||||
deploy_compose() {
|
deploy_compose() {
|
||||||
print_status "Deploying with Docker Compose..."
|
print_status "Deploying with Docker Compose..."
|
||||||
|
|
||||||
# Export image variables for compose
|
# Export image variables for compose
|
||||||
export IMAGE_TAG
|
export IMAGE_TAG
|
||||||
export REGISTRY
|
export REGISTRY
|
||||||
export IMAGE_NAME
|
export IMAGE_NAME
|
||||||
|
|
||||||
# Use the built image from registry if available
|
# Use the built image from registry if available
|
||||||
if [ "$GITEA_ACTIONS" = "true" ]; then
|
if [ "$GITEA_ACTIONS" = "true" ]; then
|
||||||
# Override the image in docker-compose
|
# Override the image in docker-compose
|
||||||
export FRONTEND_IMAGE="$REGISTRY/$IMAGE_NAME:$IMAGE_TAG"
|
export FRONTEND_IMAGE="$REGISTRY/$IMAGE_NAME:$IMAGE_TAG"
|
||||||
print_status "Using Gitea Actions built image: $FRONTEND_IMAGE"
|
print_status "Using Gitea Actions built image: $FRONTEND_IMAGE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Pull the latest images
|
# Pull the latest images
|
||||||
print_status "Pulling latest images..."
|
print_status "Pulling latest images..."
|
||||||
docker-compose -f docker/docker-compose.yaml pull || print_warning "Failed to pull some images"
|
docker-compose -f docker/docker-compose.yaml pull || print_warning "Failed to pull some images"
|
||||||
|
|
||||||
# Start services
|
# Start services
|
||||||
print_status "Starting services..."
|
print_status "Starting services..."
|
||||||
docker-compose -f docker/docker-compose.yaml up -d
|
docker-compose -f docker/docker-compose.yaml up -d
|
||||||
|
|
||||||
# Wait for services
|
# Wait for services
|
||||||
print_status "Waiting for services to be ready..."
|
print_status "Waiting for services to be ready..."
|
||||||
sleep 10
|
sleep 10
|
||||||
|
|
||||||
# Health check
|
# Health check
|
||||||
print_status "Checking service health..."
|
print_status "Checking service health..."
|
||||||
if curl -f http://localhost:8080/health > /dev/null 2>&1; then
|
if curl -f http://localhost:8080/health > /dev/null 2>&1; then
|
||||||
@@ -125,7 +125,7 @@ deploy_compose() {
|
|||||||
print_warning "Frontend health check failed, checking logs..."
|
print_warning "Frontend health check failed, checking logs..."
|
||||||
docker-compose -f docker/docker-compose.yaml logs frontend
|
docker-compose -f docker/docker-compose.yaml logs frontend
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if curl -f http://localhost:5984/_up > /dev/null 2>&1; then
|
if curl -f http://localhost:5984/_up > /dev/null 2>&1; then
|
||||||
print_success "CouchDB service is healthy"
|
print_success "CouchDB service is healthy"
|
||||||
else
|
else
|
||||||
@@ -136,26 +136,26 @@ deploy_compose() {
|
|||||||
# Function to deploy via Kubernetes
|
# Function to deploy via Kubernetes
|
||||||
deploy_k8s() {
|
deploy_k8s() {
|
||||||
print_status "Deploying to Kubernetes..."
|
print_status "Deploying to Kubernetes..."
|
||||||
|
|
||||||
if ! command -v kubectl &> /dev/null; then
|
if ! command -v kubectl &> /dev/null; then
|
||||||
print_error "kubectl is not installed"
|
print_error "kubectl is not installed"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Update image in k8s manifests
|
# Update image in k8s manifests
|
||||||
if [ "$GITEA_ACTIONS" = "true" ]; then
|
if [ "$GITEA_ACTIONS" = "true" ]; then
|
||||||
print_status "Updating Kubernetes manifests with new image..."
|
print_status "Updating Kubernetes manifests with new image..."
|
||||||
sed -i "s|image:.*rxminder.*|image: $REGISTRY/$IMAGE_NAME:$IMAGE_TAG|g" k8s/frontend-deployment.yaml
|
sed -i "s|image:.*rxminder.*|image: $REGISTRY/$IMAGE_NAME:$IMAGE_TAG|g" k8s/frontend-deployment.yaml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Apply manifests
|
# Apply manifests
|
||||||
print_status "Applying Kubernetes manifests..."
|
print_status "Applying Kubernetes manifests..."
|
||||||
kubectl apply -f k8s/
|
kubectl apply -f k8s/
|
||||||
|
|
||||||
# Wait for rollout
|
# Wait for rollout
|
||||||
print_status "Waiting for deployment rollout..."
|
print_status "Waiting for deployment rollout..."
|
||||||
kubectl rollout status deployment/frontend-deployment
|
kubectl rollout status deployment/frontend-deployment
|
||||||
|
|
||||||
print_success "Kubernetes deployment completed"
|
print_success "Kubernetes deployment completed"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,26 +206,26 @@ print_success "All tasks completed! 🚀"
|
|||||||
print_error "Docker is not installed"
|
print_error "Docker is not installed"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check Docker Buildx
|
# Check Docker Buildx
|
||||||
if ! docker buildx version >/dev/null 2>&1; then
|
if ! docker buildx version >/dev/null 2>&1; then
|
||||||
print_error "Docker Buildx is not available"
|
print_error "Docker Buildx is not available"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if in Gitea Actions environment
|
# Check if in Gitea Actions environment
|
||||||
if [ "$GITEA_ACTIONS" = "true" ]; then
|
if [ "$GITEA_ACTIONS" = "true" ]; then
|
||||||
print_status "Running in Gitea Actions environment"
|
print_status "Running in Gitea Actions environment"
|
||||||
GITEA_REGISTRY=${GITEA_SERVER_URL#https://}
|
GITEA_REGISTRY=${GITEA_SERVER_URL#https://}
|
||||||
GITEA_REPOSITORY=${GITEA_REPOSITORY}
|
GITEA_REPOSITORY=${GITEA_REPOSITORY}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_success "All requirements met"
|
print_success "All requirements met"
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_buildx() {
|
setup_buildx() {
|
||||||
print_status "Setting up Docker Buildx for Gitea..."
|
print_status "Setting up Docker Buildx for Gitea..."
|
||||||
|
|
||||||
# Create builder if it doesn't exist
|
# Create builder if it doesn't exist
|
||||||
if ! docker buildx ls | grep -q "gitea-builder"; then
|
if ! docker buildx ls | grep -q "gitea-builder"; then
|
||||||
print_status "Creating Gitea buildx builder..."
|
print_status "Creating Gitea buildx builder..."
|
||||||
@@ -243,13 +243,13 @@ setup_buildx() {
|
|||||||
|
|
||||||
login_registry() {
|
login_registry() {
|
||||||
print_status "Logging into Gitea registry..."
|
print_status "Logging into Gitea registry..."
|
||||||
|
|
||||||
if [ -z "$GITEA_TOKEN" ]; then
|
if [ -z "$GITEA_TOKEN" ]; then
|
||||||
print_error "GITEA_TOKEN environment variable is required"
|
print_error "GITEA_TOKEN environment variable is required"
|
||||||
print_status "Set it with: export GITEA_TOKEN=your_token"
|
print_status "Set it with: export GITEA_TOKEN=your_token"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Login to Gitea registry
|
# Login to Gitea registry
|
||||||
echo "$GITEA_TOKEN" | docker login "$GITEA_REGISTRY" -u "$GITEA_ACTOR" --password-stdin
|
echo "$GITEA_TOKEN" | docker login "$GITEA_REGISTRY" -u "$GITEA_ACTOR" --password-stdin
|
||||||
print_success "Logged into Gitea registry"
|
print_success "Logged into Gitea registry"
|
||||||
@@ -257,152 +257,152 @@ login_registry() {
|
|||||||
|
|
||||||
build_local() {
|
build_local() {
|
||||||
print_status "Building for local development..."
|
print_status "Building for local development..."
|
||||||
|
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
|
|
||||||
# Load environment variables
|
# Load environment variables
|
||||||
if [ -f ".env" ]; then
|
if [ -f ".env" ]; then
|
||||||
export $(cat .env | grep -v '^#' | xargs)
|
export $(cat .env | grep -v '^#' | xargs)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Build with Gitea bake file
|
# Build with Gitea bake file
|
||||||
docker buildx bake \
|
docker buildx bake \
|
||||||
-f .gitea/gitea-bake.hcl \
|
-f .gitea/gitea-bake.hcl \
|
||||||
--set="*.platform=linux/amd64" \
|
--set="*.platform=linux/amd64" \
|
||||||
--load \
|
--load \
|
||||||
dev
|
dev
|
||||||
|
|
||||||
print_success "Local build completed"
|
print_success "Local build completed"
|
||||||
}
|
}
|
||||||
|
|
||||||
build_multiplatform() {
|
build_multiplatform() {
|
||||||
local tag=${1:-$DEFAULT_TAG}
|
local tag=${1:-$DEFAULT_TAG}
|
||||||
print_status "Building multi-platform image with tag: $tag..."
|
print_status "Building multi-platform image with tag: $tag..."
|
||||||
|
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
|
|
||||||
# Load environment variables
|
# Load environment variables
|
||||||
if [ -f ".env" ]; then
|
if [ -f ".env" ]; then
|
||||||
export $(cat .env | grep -v '^#' | xargs)
|
export $(cat .env | grep -v '^#' | xargs)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Export variables for bake
|
# Export variables for bake
|
||||||
export TAG="$tag"
|
export TAG="$tag"
|
||||||
export GITEA_SHA=${GITEA_SHA:-$(git rev-parse --short HEAD 2>/dev/null || echo "dev")}
|
export GITEA_SHA=${GITEA_SHA:-$(git rev-parse --short HEAD 2>/dev/null || echo "dev")}
|
||||||
|
|
||||||
# Build with Gitea bake file
|
# Build with Gitea bake file
|
||||||
docker buildx bake \
|
docker buildx bake \
|
||||||
-f .gitea/gitea-bake.hcl \
|
-f .gitea/gitea-bake.hcl \
|
||||||
app-ci
|
app-ci
|
||||||
|
|
||||||
print_success "Multi-platform build completed"
|
print_success "Multi-platform build completed"
|
||||||
}
|
}
|
||||||
|
|
||||||
build_staging() {
|
build_staging() {
|
||||||
print_status "Building staging image..."
|
print_status "Building staging image..."
|
||||||
|
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
|
|
||||||
# Load environment variables
|
# Load environment variables
|
||||||
if [ -f ".env.staging" ]; then
|
if [ -f ".env.staging" ]; then
|
||||||
export $(cat .env.staging | grep -v '^#' | xargs)
|
export $(cat .env.staging | grep -v '^#' | xargs)
|
||||||
elif [ -f ".env" ]; then
|
elif [ -f ".env" ]; then
|
||||||
export $(cat .env | grep -v '^#' | xargs)
|
export $(cat .env | grep -v '^#' | xargs)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Export variables for bake
|
# Export variables for bake
|
||||||
export TAG="staging-$(date +%Y%m%d-%H%M%S)"
|
export TAG="staging-$(date +%Y%m%d-%H%M%S)"
|
||||||
export GITEA_SHA=${GITEA_SHA:-$(git rev-parse --short HEAD 2>/dev/null || echo "staging")}
|
export GITEA_SHA=${GITEA_SHA:-$(git rev-parse --short HEAD 2>/dev/null || echo "staging")}
|
||||||
|
|
||||||
# Build staging target
|
# Build staging target
|
||||||
docker buildx bake \
|
docker buildx bake \
|
||||||
-f .gitea/gitea-bake.hcl \
|
-f .gitea/gitea-bake.hcl \
|
||||||
staging
|
staging
|
||||||
|
|
||||||
print_success "Staging build completed"
|
print_success "Staging build completed"
|
||||||
}
|
}
|
||||||
|
|
||||||
build_production() {
|
build_production() {
|
||||||
local tag=${1:-$DEFAULT_TAG}
|
local tag=${1:-$DEFAULT_TAG}
|
||||||
print_status "Building production image with tag: $tag..."
|
print_status "Building production image with tag: $tag..."
|
||||||
|
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
|
|
||||||
# Load production environment variables
|
# Load production environment variables
|
||||||
if [ -f ".env.production" ]; then
|
if [ -f ".env.production" ]; then
|
||||||
export $(cat .env.production | grep -v '^#' | xargs)
|
export $(cat .env.production | grep -v '^#' | xargs)
|
||||||
elif [ -f ".env" ]; then
|
elif [ -f ".env" ]; then
|
||||||
export $(cat .env | grep -v '^#' | xargs)
|
export $(cat .env | grep -v '^#' | xargs)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Export variables for bake
|
# Export variables for bake
|
||||||
export TAG="$tag"
|
export TAG="$tag"
|
||||||
export GITEA_SHA=${GITEA_SHA:-$(git rev-parse --short HEAD 2>/dev/null || echo "prod")}
|
export GITEA_SHA=${GITEA_SHA:-$(git rev-parse --short HEAD 2>/dev/null || echo "prod")}
|
||||||
|
|
||||||
# Build production target with full attestations
|
# Build production target with full attestations
|
||||||
docker buildx bake \
|
docker buildx bake \
|
||||||
-f .gitea/gitea-bake.hcl \
|
-f .gitea/gitea-bake.hcl \
|
||||||
prod
|
prod
|
||||||
|
|
||||||
print_success "Production build completed"
|
print_success "Production build completed"
|
||||||
}
|
}
|
||||||
|
|
||||||
test_local() {
|
test_local() {
|
||||||
print_status "Running tests locally..."
|
print_status "Running tests locally..."
|
||||||
|
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
|
|
||||||
# Install dependencies if needed
|
# Install dependencies if needed
|
||||||
if [ ! -d "node_modules" ]; then
|
if [ ! -d "node_modules" ]; then
|
||||||
print_status "Installing dependencies..."
|
print_status "Installing dependencies..."
|
||||||
bun install --frozen-lockfile
|
bun install --frozen-lockfile
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run linting
|
# Run linting
|
||||||
print_status "Running linter..."
|
print_status "Running linter..."
|
||||||
bun run lint
|
bun run lint
|
||||||
|
|
||||||
# Run type checking
|
# Run type checking
|
||||||
print_status "Running type checker..."
|
print_status "Running type checker..."
|
||||||
bun run type-check
|
bun run type-check
|
||||||
|
|
||||||
# Run tests
|
# Run tests
|
||||||
print_status "Running tests..."
|
print_status "Running tests..."
|
||||||
bun run test
|
bun run test
|
||||||
|
|
||||||
print_success "All tests passed"
|
print_success "All tests passed"
|
||||||
}
|
}
|
||||||
|
|
||||||
deploy() {
|
deploy() {
|
||||||
local environment=${1:-production}
|
local environment=${1:-production}
|
||||||
local tag=${2:-latest}
|
local tag=${2:-latest}
|
||||||
|
|
||||||
print_status "Deploying to $environment with tag $tag..."
|
print_status "Deploying to $environment with tag $tag..."
|
||||||
|
|
||||||
# Use the gitea-deploy script
|
# Use the gitea-deploy script
|
||||||
"$SCRIPT_DIR/gitea-deploy.sh" "$environment" "$tag"
|
"$SCRIPT_DIR/gitea-deploy.sh" "$environment" "$tag"
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
print_status "Cleaning up Gitea builder and images..."
|
print_status "Cleaning up Gitea builder and images..."
|
||||||
|
|
||||||
# Remove builder
|
# Remove builder
|
||||||
if docker buildx ls | grep -q "gitea-builder"; then
|
if docker buildx ls | grep -q "gitea-builder"; then
|
||||||
docker buildx rm gitea-builder
|
docker buildx rm gitea-builder
|
||||||
print_success "Gitea builder removed"
|
print_success "Gitea builder removed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Clean up old images (keep last 3 tags)
|
# Clean up old images (keep last 3 tags)
|
||||||
print_status "Cleaning up old images..."
|
print_status "Cleaning up old images..."
|
||||||
docker image prune -f --filter "until=72h" || print_warning "Image cleanup failed"
|
docker image prune -f --filter "until=72h" || print_warning "Image cleanup failed"
|
||||||
|
|
||||||
print_success "Cleanup completed"
|
print_success "Cleanup completed"
|
||||||
}
|
}
|
||||||
|
|
||||||
show_status() {
|
show_status() {
|
||||||
print_status "Gitea CI/CD Status"
|
print_status "Gitea CI/CD Status"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Check environment
|
# Check environment
|
||||||
if [ "$GITEA_ACTIONS" = "true" ]; then
|
if [ "$GITEA_ACTIONS" = "true" ]; then
|
||||||
echo "🏃 Running in Gitea Actions"
|
echo "🏃 Running in Gitea Actions"
|
||||||
@@ -415,13 +415,13 @@ show_status() {
|
|||||||
echo "📦 Registry: $GITEA_REGISTRY"
|
echo "📦 Registry: $GITEA_REGISTRY"
|
||||||
echo "📋 Repository: $GITEA_REPOSITORY"
|
echo "📋 Repository: $GITEA_REPOSITORY"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Check Docker and buildx
|
# Check Docker and buildx
|
||||||
echo "🐳 Docker version: $(docker --version)"
|
echo "🐳 Docker version: $(docker --version)"
|
||||||
echo "🔧 Buildx version: $(docker buildx version)"
|
echo "🔧 Buildx version: $(docker buildx version)"
|
||||||
|
|
||||||
# Check builders
|
# Check builders
|
||||||
echo
|
echo
|
||||||
echo "🏗️ Available builders:"
|
echo "🏗️ Available builders:"
|
||||||
|
|||||||
@@ -52,9 +52,9 @@ load_env() {
|
|||||||
substitute_template() {
|
substitute_template() {
|
||||||
local template_file="$1"
|
local template_file="$1"
|
||||||
local output_file="$2"
|
local output_file="$2"
|
||||||
|
|
||||||
print_status "Processing template: $template_file"
|
print_status "Processing template: $template_file"
|
||||||
|
|
||||||
# Use envsubst to substitute environment variables
|
# Use envsubst to substitute environment variables
|
||||||
if command -v envsubst >/dev/null 2>&1; then
|
if command -v envsubst >/dev/null 2>&1; then
|
||||||
envsubst < "$template_file" > "$output_file"
|
envsubst < "$template_file" > "$output_file"
|
||||||
@@ -62,14 +62,14 @@ substitute_template() {
|
|||||||
print_error "envsubst not found. Please install gettext package."
|
print_error "envsubst not found. Please install gettext package."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_success "Generated: $output_file"
|
print_success "Generated: $output_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to apply Kubernetes resources
|
# Function to apply Kubernetes resources
|
||||||
apply_k8s_resource() {
|
apply_k8s_resource() {
|
||||||
local resource_file="$1"
|
local resource_file="$1"
|
||||||
|
|
||||||
if [[ -f "$resource_file" ]]; then
|
if [[ -f "$resource_file" ]]; then
|
||||||
print_status "Applying Kubernetes resource: $resource_file"
|
print_status "Applying Kubernetes resource: $resource_file"
|
||||||
if kubectl apply -f "$resource_file"; then
|
if kubectl apply -f "$resource_file"; then
|
||||||
@@ -94,15 +94,15 @@ validate_env() {
|
|||||||
"STORAGE_CLASS"
|
"STORAGE_CLASS"
|
||||||
"STORAGE_SIZE"
|
"STORAGE_SIZE"
|
||||||
)
|
)
|
||||||
|
|
||||||
local missing_vars=()
|
local missing_vars=()
|
||||||
|
|
||||||
for var in "${required_vars[@]}"; do
|
for var in "${required_vars[@]}"; do
|
||||||
if [[ -z "${!var:-}" ]]; then
|
if [[ -z "${!var:-}" ]]; then
|
||||||
missing_vars+=("$var")
|
missing_vars+=("$var")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ${#missing_vars[@]} -gt 0 ]]; then
|
if [[ ${#missing_vars[@]} -gt 0 ]]; then
|
||||||
print_error "Missing required environment variables:"
|
print_error "Missing required environment variables:"
|
||||||
for var in "${missing_vars[@]}"; do
|
for var in "${missing_vars[@]}"; do
|
||||||
@@ -111,7 +111,7 @@ validate_env() {
|
|||||||
print_warning "Please update your .env file with these variables."
|
print_warning "Please update your .env file with these variables."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_success "All required environment variables are set"
|
print_success "All required environment variables are set"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,22 +119,22 @@ validate_env() {
|
|||||||
process_templates() {
|
process_templates() {
|
||||||
local temp_dir="/tmp/rxminder-k8s-$$"
|
local temp_dir="/tmp/rxminder-k8s-$$"
|
||||||
mkdir -p "$temp_dir"
|
mkdir -p "$temp_dir"
|
||||||
|
|
||||||
print_status "Processing Kubernetes templates..."
|
print_status "Processing Kubernetes templates..."
|
||||||
|
|
||||||
# Find all template files
|
# Find all template files
|
||||||
local template_files=(
|
local template_files=(
|
||||||
"$K8S_DIR/couchdb-secret.yaml.template"
|
"$K8S_DIR/couchdb-secret.yaml.template"
|
||||||
"$K8S_DIR/ingress.yaml.template"
|
"$K8S_DIR/ingress.yaml.template"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add any additional template files
|
# Add any additional template files
|
||||||
for template_file in "$K8S_DIR"/*.template; do
|
for template_file in "$K8S_DIR"/*.template; do
|
||||||
if [[ -f "$template_file" ]]; then
|
if [[ -f "$template_file" ]]; then
|
||||||
template_files+=("$template_file")
|
template_files+=("$template_file")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Process each template
|
# Process each template
|
||||||
for template_file in "${template_files[@]}"; do
|
for template_file in "${template_files[@]}"; do
|
||||||
if [[ -f "$template_file" ]]; then
|
if [[ -f "$template_file" ]]; then
|
||||||
@@ -144,16 +144,16 @@ process_templates() {
|
|||||||
substitute_template "$template_file" "$output_file"
|
substitute_template "$template_file" "$output_file"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "$temp_dir"
|
echo "$temp_dir"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to deploy resources in correct order
|
# Function to deploy resources in correct order
|
||||||
deploy_resources() {
|
deploy_resources() {
|
||||||
local resource_dir="$1"
|
local resource_dir="$1"
|
||||||
|
|
||||||
print_status "Deploying Kubernetes resources..."
|
print_status "Deploying Kubernetes resources..."
|
||||||
|
|
||||||
# Deploy in specific order for dependencies
|
# Deploy in specific order for dependencies
|
||||||
local deployment_order=(
|
local deployment_order=(
|
||||||
"couchdb-secret.yaml"
|
"couchdb-secret.yaml"
|
||||||
@@ -167,7 +167,7 @@ deploy_resources() {
|
|||||||
"$K8S_DIR/network-policy.yaml"
|
"$K8S_DIR/network-policy.yaml"
|
||||||
"$K8S_DIR/hpa.yaml"
|
"$K8S_DIR/hpa.yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
for resource in "${deployment_order[@]}"; do
|
for resource in "${deployment_order[@]}"; do
|
||||||
if [[ "$resource" == *.yaml ]]; then
|
if [[ "$resource" == *.yaml ]]; then
|
||||||
# Check if it's a template-generated file
|
# Check if it's a template-generated file
|
||||||
@@ -184,11 +184,11 @@ deploy_resources() {
|
|||||||
# Function to run database seeding job
|
# Function to run database seeding job
|
||||||
run_db_seed() {
|
run_db_seed() {
|
||||||
print_status "Running database seed job..."
|
print_status "Running database seed job..."
|
||||||
|
|
||||||
# Apply the db-seed-job (which uses environment variables from secret)
|
# Apply the db-seed-job (which uses environment variables from secret)
|
||||||
if kubectl apply -f "$K8S_DIR/db-seed-job.yaml"; then
|
if kubectl apply -f "$K8S_DIR/db-seed-job.yaml"; then
|
||||||
print_success "Database seed job submitted"
|
print_success "Database seed job submitted"
|
||||||
|
|
||||||
# Wait for job completion
|
# Wait for job completion
|
||||||
print_status "Waiting for database seed job to complete..."
|
print_status "Waiting for database seed job to complete..."
|
||||||
if kubectl wait --for=condition=complete --timeout=300s job/db-seed-job; then
|
if kubectl wait --for=condition=complete --timeout=300s job/db-seed-job; then
|
||||||
@@ -207,19 +207,19 @@ run_db_seed() {
|
|||||||
show_status() {
|
show_status() {
|
||||||
print_status "Deployment Status:"
|
print_status "Deployment Status:"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
print_status "Pods:"
|
print_status "Pods:"
|
||||||
kubectl get pods -l app="${APP_NAME:-rxminder}"
|
kubectl get pods -l app="${APP_NAME:-rxminder}"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
print_status "Services:"
|
print_status "Services:"
|
||||||
kubectl get services -l app="${APP_NAME:-rxminder}"
|
kubectl get services -l app="${APP_NAME:-rxminder}"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
print_status "Ingress:"
|
print_status "Ingress:"
|
||||||
kubectl get ingress
|
kubectl get ingress
|
||||||
echo
|
echo
|
||||||
|
|
||||||
if [[ -n "${INGRESS_HOST:-}" ]]; then
|
if [[ -n "${INGRESS_HOST:-}" ]]; then
|
||||||
print_success "Application should be available at: http://${INGRESS_HOST}"
|
print_success "Application should be available at: http://${INGRESS_HOST}"
|
||||||
fi
|
fi
|
||||||
@@ -235,12 +235,12 @@ cleanup() {
|
|||||||
# Main deployment function
|
# Main deployment function
|
||||||
main() {
|
main() {
|
||||||
local command="${1:-deploy}"
|
local command="${1:-deploy}"
|
||||||
|
|
||||||
case "$command" in
|
case "$command" in
|
||||||
"deploy"|"apply")
|
"deploy"|"apply")
|
||||||
print_status "🚀 Starting RxMinder Kubernetes deployment..."
|
print_status "🚀 Starting RxMinder Kubernetes deployment..."
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Set default values for required variables
|
# Set default values for required variables
|
||||||
export APP_NAME="${APP_NAME:-rxminder}"
|
export APP_NAME="${APP_NAME:-rxminder}"
|
||||||
export DOCKER_IMAGE="${DOCKER_IMAGE:-gitea-http.taildb3494.ts.net/will/meds:latest}"
|
export DOCKER_IMAGE="${DOCKER_IMAGE:-gitea-http.taildb3494.ts.net/will/meds:latest}"
|
||||||
@@ -249,39 +249,39 @@ main() {
|
|||||||
export INGRESS_HOST="${INGRESS_HOST:-rxminder.local}"
|
export INGRESS_HOST="${INGRESS_HOST:-rxminder.local}"
|
||||||
export STORAGE_CLASS="${STORAGE_CLASS:-longhorn}"
|
export STORAGE_CLASS="${STORAGE_CLASS:-longhorn}"
|
||||||
export STORAGE_SIZE="${STORAGE_SIZE:-5Gi}"
|
export STORAGE_SIZE="${STORAGE_SIZE:-5Gi}"
|
||||||
|
|
||||||
load_env
|
load_env
|
||||||
validate_env
|
validate_env
|
||||||
|
|
||||||
# Process templates
|
# Process templates
|
||||||
temp_dir=$(process_templates)
|
temp_dir=$(process_templates)
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
# Deploy resources
|
# Deploy resources
|
||||||
deploy_resources "$temp_dir"
|
deploy_resources "$temp_dir"
|
||||||
|
|
||||||
# Run database seeding
|
# Run database seeding
|
||||||
run_db_seed
|
run_db_seed
|
||||||
|
|
||||||
# Show status
|
# Show status
|
||||||
echo
|
echo
|
||||||
show_status
|
show_status
|
||||||
|
|
||||||
print_success "🎉 RxMinder deployment completed!"
|
print_success "🎉 RxMinder deployment completed!"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
"status")
|
"status")
|
||||||
load_env
|
load_env
|
||||||
show_status
|
show_status
|
||||||
;;
|
;;
|
||||||
|
|
||||||
"delete"|"cleanup")
|
"delete"|"cleanup")
|
||||||
print_status "🗑️ Cleaning up RxMinder deployment..."
|
print_status "🗑️ Cleaning up RxMinder deployment..."
|
||||||
kubectl delete all,pvc,secret,configmap,ingress -l app="${APP_NAME:-rxminder}" || true
|
kubectl delete all,pvc,secret,configmap,ingress -l app="${APP_NAME:-rxminder}" || true
|
||||||
kubectl delete job db-seed-job || true
|
kubectl delete job db-seed-job || true
|
||||||
print_success "Cleanup completed"
|
print_success "Cleanup completed"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
"help"|"-h"|"--help")
|
"help"|"-h"|"--help")
|
||||||
echo "RxMinder Kubernetes Deployment Script"
|
echo "RxMinder Kubernetes Deployment Script"
|
||||||
echo
|
echo
|
||||||
@@ -302,7 +302,7 @@ main() {
|
|||||||
echo " STORAGE_CLASS Storage class for PVCs (default: longhorn)"
|
echo " STORAGE_CLASS Storage class for PVCs (default: longhorn)"
|
||||||
echo " STORAGE_SIZE Storage size for database (default: 5Gi)"
|
echo " STORAGE_SIZE Storage size for database (default: 5Gi)"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
print_error "Unknown command: $command"
|
print_error "Unknown command: $command"
|
||||||
echo "Use '$0 help' for usage information"
|
echo "Use '$0 help' for usage information"
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ run_check "prettier" "bun run pre-commit"
|
|||||||
# 2. ESLint on staged JS/TS files only
|
# 2. ESLint on staged JS/TS files only
|
||||||
STAGED_JS_TS_FILES=$(echo "$STAGED_FILES" | grep -E '\.(js|jsx|ts|tsx)$' || true)
|
STAGED_JS_TS_FILES=$(echo "$STAGED_FILES" | grep -E '\.(js|jsx|ts|tsx)$' || true)
|
||||||
if [ -n "$STAGED_JS_TS_FILES" ]; then
|
if [ -n "$STAGED_JS_TS_FILES" ]; then
|
||||||
run_check "eslint" "bunx eslint --fix --max-warnings 0 $STAGED_JS_TS_FILES"
|
# Convert newlines to spaces for proper argument passing
|
||||||
|
ESLINT_FILES=$(echo "$STAGED_JS_TS_FILES" | tr '\n' ' ')
|
||||||
|
run_check "eslint" "bunx eslint --fix --max-warnings 0 $ESLINT_FILES"
|
||||||
else
|
else
|
||||||
echo "0" > "$TEMP_DIR/eslint.exit"
|
echo "0" > "$TEMP_DIR/eslint.exit"
|
||||||
echo "No JS/TS files to lint" > "$TEMP_DIR/eslint.out"
|
echo "No JS/TS files to lint" > "$TEMP_DIR/eslint.out"
|
||||||
@@ -87,7 +89,9 @@ fi
|
|||||||
# 4. Markdown linting on staged markdown files
|
# 4. Markdown linting on staged markdown files
|
||||||
STAGED_MD_FILES=$(echo "$STAGED_FILES" | grep -E '\.md$' || true)
|
STAGED_MD_FILES=$(echo "$STAGED_FILES" | grep -E '\.md$' || true)
|
||||||
if [ -n "$STAGED_MD_FILES" ]; then
|
if [ -n "$STAGED_MD_FILES" ]; then
|
||||||
run_check "markdown" "bunx markdownlint-cli2 --fix $STAGED_MD_FILES || echo 'Markdown linting failed but continuing...'"
|
# Convert newlines to spaces for proper argument passing
|
||||||
|
MARKDOWN_FILES=$(echo "$STAGED_MD_FILES" | tr '\n' ' ')
|
||||||
|
run_check "markdown" "bunx markdownlint-cli2 --fix $MARKDOWN_FILES || echo 'Markdown linting failed but continuing...'"
|
||||||
else
|
else
|
||||||
echo "0" > "$TEMP_DIR/markdown.exit"
|
echo "0" > "$TEMP_DIR/markdown.exit"
|
||||||
echo "No markdown files to lint" > "$TEMP_DIR/markdown.out"
|
echo "No markdown files to lint" > "$TEMP_DIR/markdown.out"
|
||||||
@@ -95,7 +99,9 @@ fi
|
|||||||
|
|
||||||
# 5. Secret scanning on staged files (optional check)
|
# 5. Secret scanning on staged files (optional check)
|
||||||
if command -v secretlint > /dev/null; then
|
if command -v secretlint > /dev/null; then
|
||||||
run_check "secrets" "bunx secretlint $STAGED_FILES || echo 'Secret scanning failed but continuing...'"
|
# Convert newlines to spaces for proper argument passing
|
||||||
|
SECRET_FILES=$(echo "$STAGED_FILES" | tr '\n' ' ')
|
||||||
|
run_check "secrets" "bunx secretlint $SECRET_FILES || echo 'Secret scanning failed but continuing...'"
|
||||||
else
|
else
|
||||||
echo "0" > "$TEMP_DIR/secrets.exit"
|
echo "0" > "$TEMP_DIR/secrets.exit"
|
||||||
echo "secretlint not available, skipping secret scanning" > "$TEMP_DIR/secrets.out"
|
echo "secretlint not available, skipping secret scanning" > "$TEMP_DIR/secrets.out"
|
||||||
|
|||||||
+14
-14
@@ -11,14 +11,14 @@ const __filename = fileURLToPath(import.meta.url);
|
|||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
const projectDir = resolve(__dirname, '..');
|
const projectDir = resolve(__dirname, '..');
|
||||||
|
|
||||||
console.log('🌱 Starting production database seeding...');
|
console.warn('🌱 Starting production database seeding...');
|
||||||
|
|
||||||
// Load environment variables from .env file if it exists
|
// Load environment variables from .env file if it exists
|
||||||
try {
|
try {
|
||||||
const envFile = resolve(projectDir, '.env');
|
const envFile = resolve(projectDir, '.env');
|
||||||
const envContent = readFileSync(envFile, 'utf8');
|
const envContent = readFileSync(envFile, 'utf8');
|
||||||
|
|
||||||
console.log('📄 Loading environment variables from .env file...');
|
console.warn('📄 Loading environment variables from .env file...');
|
||||||
|
|
||||||
envContent.split('\n').forEach(line => {
|
envContent.split('\n').forEach(line => {
|
||||||
const trimmed = line.trim();
|
const trimmed = line.trim();
|
||||||
@@ -30,8 +30,8 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
console.log(
|
console.warn(
|
||||||
'ℹ️ No .env file found, using environment variables or defaults'
|
'ℹ️ No .env file found, using environment variables or defaults'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -53,10 +53,10 @@ process.env.VITE_COUCHDB_URL = COUCHDB_URL;
|
|||||||
process.env.VITE_COUCHDB_USER = COUCHDB_USER;
|
process.env.VITE_COUCHDB_USER = COUCHDB_USER;
|
||||||
process.env.VITE_COUCHDB_PASSWORD = COUCHDB_PASSWORD;
|
process.env.VITE_COUCHDB_PASSWORD = COUCHDB_PASSWORD;
|
||||||
|
|
||||||
console.log('🔗 CouchDB Configuration:');
|
console.warn('🔗 CouchDB Configuration:');
|
||||||
console.log(` URL: ${COUCHDB_URL}`);
|
console.warn(` URL: ${COUCHDB_URL}`);
|
||||||
console.log(` User: ${COUCHDB_USER}`);
|
console.warn(` User: ${COUCHDB_USER}`);
|
||||||
console.log(` Password: ${'*'.repeat(COUCHDB_PASSWORD.length)}`);
|
console.warn(` Password: ${'*'.repeat(COUCHDB_PASSWORD.length)}`);
|
||||||
|
|
||||||
// Validate required environment variables
|
// Validate required environment variables
|
||||||
if (!COUCHDB_URL || !COUCHDB_USER || !COUCHDB_PASSWORD) {
|
if (!COUCHDB_URL || !COUCHDB_USER || !COUCHDB_PASSWORD) {
|
||||||
@@ -75,18 +75,18 @@ async function seedDatabase() {
|
|||||||
const { DatabaseSeeder } = await import('../services/database.seeder.ts');
|
const { DatabaseSeeder } = await import('../services/database.seeder.ts');
|
||||||
|
|
||||||
// Wait a bit for databases to be initialized
|
// Wait a bit for databases to be initialized
|
||||||
console.log('⏳ Waiting for databases to initialize...');
|
console.warn('⏳ Waiting for databases to initialize...');
|
||||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||||
|
|
||||||
const seeder = new DatabaseSeeder();
|
const seeder = new DatabaseSeeder();
|
||||||
|
|
||||||
console.log('📊 Seeding admin user...');
|
console.warn('📊 Seeding admin user...');
|
||||||
await seeder.seedDefaultAdmin();
|
await seeder.seedDefaultAdmin();
|
||||||
|
|
||||||
console.log('🎉 Production database seeding completed successfully!');
|
console.warn('🎉 Production database seeding completed successfully!');
|
||||||
console.log('🔐 You can now login with:');
|
console.warn('🔐 You can now login with:');
|
||||||
console.log(' Email: admin@localhost');
|
console.warn(' Email: admin@localhost');
|
||||||
console.log(' Password: change-this-secure-password');
|
console.warn(' Password: change-this-secure-password');
|
||||||
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
+31
-31
@@ -52,21 +52,21 @@ load_env() {
|
|||||||
# Function to substitute environment variables in template files
|
# Function to substitute environment variables in template files
|
||||||
substitute_templates() {
|
substitute_templates() {
|
||||||
print_info "Processing template files..."
|
print_info "Processing template files..."
|
||||||
|
|
||||||
# Create temporary directory
|
# Create temporary directory
|
||||||
mkdir -p "$TEMP_DIR"
|
mkdir -p "$TEMP_DIR"
|
||||||
|
|
||||||
# Process each template file
|
# Process each template file
|
||||||
for template_file in "$K8S_DIR"/*.template; do
|
for template_file in "$K8S_DIR"/*.template; do
|
||||||
if [[ -f "$template_file" ]]; then
|
if [[ -f "$template_file" ]]; then
|
||||||
local filename=$(basename "$template_file" .template)
|
local filename=$(basename "$template_file" .template)
|
||||||
local output_file="$TEMP_DIR/$filename"
|
local output_file="$TEMP_DIR/$filename"
|
||||||
|
|
||||||
print_info "Processing template: $filename"
|
print_info "Processing template: $filename"
|
||||||
|
|
||||||
# Substitute environment variables
|
# Substitute environment variables
|
||||||
envsubst < "$template_file" > "$output_file"
|
envsubst < "$template_file" > "$output_file"
|
||||||
|
|
||||||
print_success "Generated: $output_file"
|
print_success "Generated: $output_file"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -76,13 +76,13 @@ substitute_templates() {
|
|||||||
validate_env() {
|
validate_env() {
|
||||||
local required_vars=("INGRESS_HOST")
|
local required_vars=("INGRESS_HOST")
|
||||||
local missing_vars=()
|
local missing_vars=()
|
||||||
|
|
||||||
for var in "${required_vars[@]}"; do
|
for var in "${required_vars[@]}"; do
|
||||||
if [[ -z "${!var:-}" ]]; then
|
if [[ -z "${!var:-}" ]]; then
|
||||||
missing_vars+=("$var")
|
missing_vars+=("$var")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ${#missing_vars[@]} -gt 0 ]]; then
|
if [[ ${#missing_vars[@]} -gt 0 ]]; then
|
||||||
print_error "Missing required environment variables:"
|
print_error "Missing required environment variables:"
|
||||||
for var in "${missing_vars[@]}"; do
|
for var in "${missing_vars[@]}"; do
|
||||||
@@ -108,15 +108,15 @@ ensure_namespace() {
|
|||||||
# Function to apply Kubernetes manifests
|
# Function to apply Kubernetes manifests
|
||||||
apply_manifests() {
|
apply_manifests() {
|
||||||
local manifest_dir="$1"
|
local manifest_dir="$1"
|
||||||
|
|
||||||
print_info "Applying Kubernetes manifests from $manifest_dir"
|
print_info "Applying Kubernetes manifests from $manifest_dir"
|
||||||
|
|
||||||
# Apply static files that don't have template counterparts
|
# Apply static files that don't have template counterparts
|
||||||
for manifest_file in "$K8S_DIR"/*.yaml; do
|
for manifest_file in "$K8S_DIR"/*.yaml; do
|
||||||
if [[ -f "$manifest_file" && ! "$manifest_file" =~ \.template$ ]]; then
|
if [[ -f "$manifest_file" && ! "$manifest_file" =~ \.template$ ]]; then
|
||||||
local basename_file=$(basename "$manifest_file")
|
local basename_file=$(basename "$manifest_file")
|
||||||
local template_file="$K8S_DIR/${basename_file}.template"
|
local template_file="$K8S_DIR/${basename_file}.template"
|
||||||
|
|
||||||
# Only apply if there's no corresponding template file
|
# Only apply if there's no corresponding template file
|
||||||
if [[ ! -f "$template_file" ]]; then
|
if [[ ! -f "$template_file" ]]; then
|
||||||
print_info "Applying static file: $basename_file"
|
print_info "Applying static file: $basename_file"
|
||||||
@@ -124,7 +124,7 @@ apply_manifests() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Apply processed template files
|
# Apply processed template files
|
||||||
if [[ -d "$TEMP_DIR" ]]; then
|
if [[ -d "$TEMP_DIR" ]]; then
|
||||||
for manifest_file in "$TEMP_DIR"/*.yaml; do
|
for manifest_file in "$TEMP_DIR"/*.yaml; do
|
||||||
@@ -148,19 +148,19 @@ cleanup() {
|
|||||||
show_status() {
|
show_status() {
|
||||||
print_info "Deployment Status:"
|
print_info "Deployment Status:"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
print_info "Pods:"
|
print_info "Pods:"
|
||||||
kubectl get pods -l app=rxminder -n "$NAMESPACE"
|
kubectl get pods -l app=rxminder -n "$NAMESPACE"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
print_info "Services:"
|
print_info "Services:"
|
||||||
kubectl get services -l app=rxminder -n "$NAMESPACE"
|
kubectl get services -l app=rxminder -n "$NAMESPACE"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
print_info "Ingress:"
|
print_info "Ingress:"
|
||||||
kubectl get ingress -l app=rxminder -n "$NAMESPACE"
|
kubectl get ingress -l app=rxminder -n "$NAMESPACE"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
if [[ -n "${INGRESS_HOST:-}" ]]; then
|
if [[ -n "${INGRESS_HOST:-}" ]]; then
|
||||||
print_success "Application should be available at: http://$INGRESS_HOST"
|
print_success "Application should be available at: http://$INGRESS_HOST"
|
||||||
fi
|
fi
|
||||||
@@ -190,7 +190,7 @@ main() {
|
|||||||
local dry_run=false
|
local dry_run=false
|
||||||
local status_only=false
|
local status_only=false
|
||||||
local cleanup_only=false
|
local cleanup_only=false
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse command line arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
@@ -221,54 +221,54 @@ main() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# Handle cleanup only
|
# Handle cleanup only
|
||||||
if [[ "$cleanup_only" == true ]]; then
|
if [[ "$cleanup_only" == true ]]; then
|
||||||
cleanup
|
cleanup
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Handle status only
|
# Handle status only
|
||||||
if [[ "$status_only" == true ]]; then
|
if [[ "$status_only" == true ]]; then
|
||||||
show_status
|
show_status
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if kubectl is available
|
# Check if kubectl is available
|
||||||
if ! command -v kubectl &> /dev/null; then
|
if ! command -v kubectl &> /dev/null; then
|
||||||
print_error "kubectl is not installed or not in PATH"
|
print_error "kubectl is not installed or not in PATH"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if we can connect to Kubernetes cluster
|
# Check if we can connect to Kubernetes cluster
|
||||||
if ! kubectl cluster-info &> /dev/null; then
|
if ! kubectl cluster-info &> /dev/null; then
|
||||||
print_error "Cannot connect to Kubernetes cluster"
|
print_error "Cannot connect to Kubernetes cluster"
|
||||||
print_info "Make sure your kubectl is configured correctly"
|
print_info "Make sure your kubectl is configured correctly"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_info "🚀 Deploying Medication Reminder App to Kubernetes"
|
print_info "🚀 Deploying Medication Reminder App to Kubernetes"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Load environment variables
|
# Load environment variables
|
||||||
load_env "$env_file"
|
load_env "$env_file"
|
||||||
|
|
||||||
# Set default namespace if not provided in environment
|
# Set default namespace if not provided in environment
|
||||||
NAMESPACE="${NAMESPACE:-rxminder}"
|
NAMESPACE="${NAMESPACE:-rxminder}"
|
||||||
|
|
||||||
# Validate required environment variables
|
# Validate required environment variables
|
||||||
validate_env
|
validate_env
|
||||||
|
|
||||||
# Ensure namespace exists
|
# Ensure namespace exists
|
||||||
ensure_namespace
|
ensure_namespace
|
||||||
|
|
||||||
# Process templates
|
# Process templates
|
||||||
substitute_templates
|
substitute_templates
|
||||||
|
|
||||||
if [[ "$dry_run" == true ]]; then
|
if [[ "$dry_run" == true ]]; then
|
||||||
print_info "Dry run mode - showing generated manifests:"
|
print_info "Dry run mode - showing generated manifests:"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
for manifest_file in "$TEMP_DIR"/*.yaml; do
|
for manifest_file in "$TEMP_DIR"/*.yaml; do
|
||||||
if [[ -f "$manifest_file" ]]; then
|
if [[ -f "$manifest_file" ]]; then
|
||||||
echo "=== $(basename "$manifest_file") ==="
|
echo "=== $(basename "$manifest_file") ==="
|
||||||
@@ -279,14 +279,14 @@ main() {
|
|||||||
else
|
else
|
||||||
# Apply manifests
|
# Apply manifests
|
||||||
apply_manifests "$K8S_DIR"
|
apply_manifests "$K8S_DIR"
|
||||||
|
|
||||||
print_success "Deployment completed!"
|
print_success "Deployment completed!"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Show status
|
# Show status
|
||||||
show_status
|
show_status
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
cleanup
|
cleanup
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-34
@@ -55,17 +55,17 @@ OPTIONAL_VARS=(
|
|||||||
validate_file() {
|
validate_file() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local file_type="$2"
|
local file_type="$2"
|
||||||
|
|
||||||
print_section "Validating $file ($file_type)"
|
print_section "Validating $file ($file_type)"
|
||||||
|
|
||||||
if [[ ! -f "$file" ]]; then
|
if [[ ! -f "$file" ]]; then
|
||||||
print_error "File not found: $file"
|
print_error "File not found: $file"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local missing_vars=()
|
local missing_vars=()
|
||||||
local found_vars=()
|
local found_vars=()
|
||||||
|
|
||||||
# Check core variables
|
# Check core variables
|
||||||
for var in "${CORE_VARS[@]}"; do
|
for var in "${CORE_VARS[@]}"; do
|
||||||
if grep -q "^${var}=" "$file" || grep -q "^#.*${var}=" "$file"; then
|
if grep -q "^${var}=" "$file" || grep -q "^#.*${var}=" "$file"; then
|
||||||
@@ -74,7 +74,7 @@ validate_file() {
|
|||||||
missing_vars+=("$var")
|
missing_vars+=("$var")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Check K8s variables for relevant files
|
# Check K8s variables for relevant files
|
||||||
if [[ "$file_type" != "template" ]]; then
|
if [[ "$file_type" != "template" ]]; then
|
||||||
for var in "${K8S_VARS[@]}"; do
|
for var in "${K8S_VARS[@]}"; do
|
||||||
@@ -85,22 +85,22 @@ validate_file() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Report results
|
# Report results
|
||||||
print_success "Found ${#found_vars[@]} variables"
|
print_success "Found ${#found_vars[@]} variables"
|
||||||
|
|
||||||
if [[ ${#missing_vars[@]} -gt 0 ]]; then
|
if [[ ${#missing_vars[@]} -gt 0 ]]; then
|
||||||
print_warning "Missing variables:"
|
print_warning "Missing variables:"
|
||||||
for var in "${missing_vars[@]}"; do
|
for var in "${missing_vars[@]}"; do
|
||||||
echo " - $var"
|
echo " - $var"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check for old VITE_MAILGUN variables
|
# Check for old VITE_MAILGUN variables
|
||||||
if grep -q "VITE_MAILGUN" "$file"; then
|
if grep -q "VITE_MAILGUN" "$file"; then
|
||||||
print_error "Found deprecated VITE_MAILGUN variables (should be MAILGUN_*)"
|
print_error "Found deprecated VITE_MAILGUN variables (should be MAILGUN_*)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check variable format
|
# Check variable format
|
||||||
local malformed_vars=()
|
local malformed_vars=()
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
@@ -111,25 +111,25 @@ validate_file() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done < "$file"
|
done < "$file"
|
||||||
|
|
||||||
if [[ ${#malformed_vars[@]} -gt 0 ]]; then
|
if [[ ${#malformed_vars[@]} -gt 0 ]]; then
|
||||||
print_warning "Malformed variable names:"
|
print_warning "Malformed variable names:"
|
||||||
for var in "${malformed_vars[@]}"; do
|
for var in "${malformed_vars[@]}"; do
|
||||||
echo " - $var"
|
echo " - $var"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_consistency() {
|
validate_consistency() {
|
||||||
print_section "Cross-file Consistency Check"
|
print_section "Cross-file Consistency Check"
|
||||||
|
|
||||||
# Extract variable names from each file
|
# Extract variable names from each file
|
||||||
local example_vars=()
|
local example_vars=()
|
||||||
local env_vars=()
|
local env_vars=()
|
||||||
local prod_vars=()
|
local prod_vars=()
|
||||||
|
|
||||||
if [[ -f ".env.example" ]]; then
|
if [[ -f ".env.example" ]]; then
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
if [[ "$line" =~ ^[A-Z_]+=.* ]]; then
|
if [[ "$line" =~ ^[A-Z_]+=.* ]]; then
|
||||||
@@ -137,7 +137,7 @@ validate_consistency() {
|
|||||||
fi
|
fi
|
||||||
done < ".env.example"
|
done < ".env.example"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f ".env" ]]; then
|
if [[ -f ".env" ]]; then
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
if [[ "$line" =~ ^[A-Z_]+=.* ]]; then
|
if [[ "$line" =~ ^[A-Z_]+=.* ]]; then
|
||||||
@@ -145,7 +145,7 @@ validate_consistency() {
|
|||||||
fi
|
fi
|
||||||
done < ".env"
|
done < ".env"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f ".env.production" ]]; then
|
if [[ -f ".env.production" ]]; then
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
if [[ "$line" =~ ^[A-Z_]+=.* ]]; then
|
if [[ "$line" =~ ^[A-Z_]+=.* ]]; then
|
||||||
@@ -153,11 +153,11 @@ validate_consistency() {
|
|||||||
fi
|
fi
|
||||||
done < ".env.production"
|
done < ".env.production"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if .env and .env.production have all variables from .env.example
|
# Check if .env and .env.production have all variables from .env.example
|
||||||
local missing_in_env=()
|
local missing_in_env=()
|
||||||
local missing_in_prod=()
|
local missing_in_prod=()
|
||||||
|
|
||||||
for var in "${example_vars[@]}"; do
|
for var in "${example_vars[@]}"; do
|
||||||
if [[ ! " ${env_vars[@]} " =~ " ${var} " ]]; then
|
if [[ ! " ${env_vars[@]} " =~ " ${var} " ]]; then
|
||||||
missing_in_env+=("$var")
|
missing_in_env+=("$var")
|
||||||
@@ -166,7 +166,7 @@ validate_consistency() {
|
|||||||
missing_in_prod+=("$var")
|
missing_in_prod+=("$var")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ${#missing_in_env[@]} -eq 0 ]]; then
|
if [[ ${#missing_in_env[@]} -eq 0 ]]; then
|
||||||
print_success ".env has all variables from .env.example"
|
print_success ".env has all variables from .env.example"
|
||||||
else
|
else
|
||||||
@@ -175,7 +175,7 @@ validate_consistency() {
|
|||||||
echo " - $var"
|
echo " - $var"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${#missing_in_prod[@]} -eq 0 ]]; then
|
if [[ ${#missing_in_prod[@]} -eq 0 ]]; then
|
||||||
print_success ".env.production has all variables from .env.example"
|
print_success ".env.production has all variables from .env.example"
|
||||||
else
|
else
|
||||||
@@ -184,20 +184,20 @@ validate_consistency() {
|
|||||||
echo " - $var"
|
echo " - $var"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_k8s_template() {
|
validate_k8s_template() {
|
||||||
print_section "Kubernetes Template Validation"
|
print_section "Kubernetes Template Validation"
|
||||||
|
|
||||||
local template_file="k8s/ingress.yaml.template"
|
local template_file="k8s/ingress.yaml.template"
|
||||||
|
|
||||||
if [[ ! -f "$template_file" ]]; then
|
if [[ ! -f "$template_file" ]]; then
|
||||||
print_error "Template file not found: $template_file"
|
print_error "Template file not found: $template_file"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check for template variables
|
# Check for template variables
|
||||||
local template_vars=()
|
local template_vars=()
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
@@ -208,16 +208,16 @@ validate_k8s_template() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done < "$template_file"
|
done < "$template_file"
|
||||||
|
|
||||||
print_success "Found ${#template_vars[@]} template variables:"
|
print_success "Found ${#template_vars[@]} template variables:"
|
||||||
for var in "${template_vars[@]}"; do
|
for var in "${template_vars[@]}"; do
|
||||||
echo " - \${$var}"
|
echo " - \${$var}"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Check if template variables are defined in env files
|
# Check if template variables are defined in env files
|
||||||
for var in "${template_vars[@]}"; do
|
for var in "${template_vars[@]}"; do
|
||||||
local found_in_files=()
|
local found_in_files=()
|
||||||
|
|
||||||
if grep -q "^${var}=" ".env.example" 2>/dev/null; then
|
if grep -q "^${var}=" ".env.example" 2>/dev/null; then
|
||||||
found_in_files+=(".env.example")
|
found_in_files+=(".env.example")
|
||||||
fi
|
fi
|
||||||
@@ -227,39 +227,39 @@ validate_k8s_template() {
|
|||||||
if grep -q "^${var}=" ".env.production" 2>/dev/null; then
|
if grep -q "^${var}=" ".env.production" 2>/dev/null; then
|
||||||
found_in_files+=(".env.production")
|
found_in_files+=(".env.production")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${#found_in_files[@]} -gt 0 ]]; then
|
if [[ ${#found_in_files[@]} -gt 0 ]]; then
|
||||||
print_success "$var defined in: ${found_in_files[*]}"
|
print_success "$var defined in: ${found_in_files[*]}"
|
||||||
else
|
else
|
||||||
print_error "$var not defined in any environment file"
|
print_error "$var not defined in any environment file"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
print_header
|
print_header
|
||||||
|
|
||||||
# Validate individual files
|
# Validate individual files
|
||||||
if [[ -f ".env.example" ]]; then
|
if [[ -f ".env.example" ]]; then
|
||||||
validate_file ".env.example" "template"
|
validate_file ".env.example" "template"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f ".env" ]]; then
|
if [[ -f ".env" ]]; then
|
||||||
validate_file ".env" "development"
|
validate_file ".env" "development"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f ".env.production" ]]; then
|
if [[ -f ".env.production" ]]; then
|
||||||
validate_file ".env.production" "production"
|
validate_file ".env.production" "production"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Cross-file validation
|
# Cross-file validation
|
||||||
validate_consistency
|
validate_consistency
|
||||||
|
|
||||||
# Kubernetes template validation
|
# Kubernetes template validation
|
||||||
validate_k8s_template
|
validate_k8s_template
|
||||||
|
|
||||||
print_section "Summary"
|
print_section "Summary"
|
||||||
print_success "Environment validation complete!"
|
print_success "Environment validation complete!"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { authService } from '../auth.service';
|
import { authService } from '../auth.service';
|
||||||
import { AccountStatus } from '../auth.constants';
|
import { AccountStatus } from '../auth.constants';
|
||||||
import { User } from '../../../types';
|
|
||||||
|
|
||||||
// Helper to clear localStorage and reset the mock DB before each test
|
// Helper to clear localStorage and reset the mock DB before each test
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { EmailVerificationService } from '../emailVerification.service';
|
import { EmailVerificationService } from '../emailVerification.service';
|
||||||
import { dbService } from '../../couchdb.factory';
|
|
||||||
|
|
||||||
jest.mock('../../couchdb.factory');
|
jest.mock('../../couchdb.factory');
|
||||||
jest.mock('../../email');
|
jest.mock('../../email');
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export const authenticate = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Security: Role-based authorization middleware
|
// Security: Role-based authorization middleware
|
||||||
export const authorize = (...allowedRoles: string[]) => {
|
export const authorize = (..._allowedRoles: string[]) => {
|
||||||
return (req: Request, res: Response, next: NextFunction) => {
|
return (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
// Security: Check if user exists in request
|
// Security: Check if user exists in request
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { dbService } from '../../services/couchdb.factory';
|
import { dbService } from '../../services/couchdb.factory';
|
||||||
import { AccountStatus } from './auth.constants';
|
|
||||||
import { User } from '../../types';
|
|
||||||
import { AuthenticatedUser } from './auth.types';
|
import { AuthenticatedUser } from './auth.types';
|
||||||
import { EmailVerificationService } from './emailVerification.service';
|
import { EmailVerificationService } from './emailVerification.service';
|
||||||
|
|
||||||
@@ -33,17 +31,17 @@ const authService = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async login(input: { email: string; password: string }) {
|
async login(input: { email: string; password: string }) {
|
||||||
console.log('🔐 Login attempt for:', input.email);
|
console.warn('🔐 Login attempt for:', input.email);
|
||||||
|
|
||||||
// Find user by email
|
// Find user by email
|
||||||
const user = await dbService.findUserByEmail(input.email);
|
const user = await dbService.findUserByEmail(input.email);
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
console.log('❌ User not found for email:', input.email);
|
console.warn('❌ User not found for email:', input.email);
|
||||||
throw new Error('User not found');
|
throw new Error('User not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('👤 User found:', {
|
console.warn('👤 User found:', {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
hasPassword: !!user.password,
|
hasPassword: !!user.password,
|
||||||
role: user.role,
|
role: user.role,
|
||||||
@@ -53,25 +51,25 @@ const authService = {
|
|||||||
|
|
||||||
// Check if user has a password (email-based account)
|
// Check if user has a password (email-based account)
|
||||||
if (!user.password) {
|
if (!user.password) {
|
||||||
console.log('❌ No password found - OAuth account');
|
console.warn('❌ No password found - OAuth account');
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'This account was created with OAuth. Please use Google or GitHub to sign in.'
|
'This account was created with OAuth. Please use Google or GitHub to sign in.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple password verification (in production, use bcrypt)
|
// Simple password verification (in production, use bcrypt)
|
||||||
console.log('🔍 Comparing passwords:', {
|
console.warn('🔍 Comparing passwords:', {
|
||||||
inputPassword: input.password,
|
inputPassword: input.password,
|
||||||
storedPassword: user.password,
|
storedPassword: user.password,
|
||||||
match: user.password === input.password,
|
match: user.password === input.password,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (user.password !== input.password) {
|
if (user.password !== input.password) {
|
||||||
console.log('❌ Password mismatch');
|
console.warn('❌ Password mismatch');
|
||||||
throw new Error('Invalid password');
|
throw new Error('Invalid password');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('✅ Login successful for:', user.email);
|
console.warn('✅ Login successful for:', user.email);
|
||||||
|
|
||||||
// Return mock tokens for frontend compatibility
|
// Return mock tokens for frontend compatibility
|
||||||
return {
|
return {
|
||||||
@@ -204,7 +202,10 @@ const authService = {
|
|||||||
const resetTokens = JSON.parse(
|
const resetTokens = JSON.parse(
|
||||||
localStorage.getItem('password_reset_tokens') || '[]'
|
localStorage.getItem('password_reset_tokens') || '[]'
|
||||||
);
|
);
|
||||||
const resetToken = resetTokens.find((t: any) => t.token === token);
|
const resetToken = resetTokens.find(
|
||||||
|
(t: { token: string; userId: string; email: string; expiresAt: Date }) =>
|
||||||
|
t.token === token
|
||||||
|
);
|
||||||
|
|
||||||
if (!resetToken) {
|
if (!resetToken) {
|
||||||
throw new Error('Invalid or expired reset token');
|
throw new Error('Invalid or expired reset token');
|
||||||
@@ -227,7 +228,10 @@ const authService = {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Remove used token
|
// Remove used token
|
||||||
const filteredTokens = resetTokens.filter((t: any) => t.token !== token);
|
const filteredTokens = resetTokens.filter(
|
||||||
|
(t: { token: string; userId: string; email: string; expiresAt: Date }) =>
|
||||||
|
t.token !== token
|
||||||
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'password_reset_tokens',
|
'password_reset_tokens',
|
||||||
JSON.stringify(filteredTokens)
|
JSON.stringify(filteredTokens)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { CouchDBService as MockCouchDBService } from './couchdb';
|
|||||||
// Environment detection
|
// Environment detection
|
||||||
const isProduction = () => {
|
const isProduction = () => {
|
||||||
// Check if we're in a Docker environment or if CouchDB URL is configured
|
// Check if we're in a Docker environment or if CouchDB URL is configured
|
||||||
const env = (import.meta as any).env || {};
|
const env = (import.meta as { env?: Record<string, string> }).env || {};
|
||||||
const couchdbUrl =
|
const couchdbUrl =
|
||||||
env.VITE_COUCHDB_URL ||
|
env.VITE_COUCHDB_URL ||
|
||||||
(typeof process !== 'undefined' ? process.env.VITE_COUCHDB_URL : null) ||
|
(typeof process !== 'undefined' ? process.env.VITE_COUCHDB_URL : null) ||
|
||||||
@@ -20,7 +20,7 @@ const createDbService = () => {
|
|||||||
if (isProduction()) {
|
if (isProduction()) {
|
||||||
try {
|
try {
|
||||||
// Use dynamic require to avoid TypeScript resolution issues
|
// Use dynamic require to avoid TypeScript resolution issues
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
||||||
const {
|
const {
|
||||||
CouchDBService: RealCouchDBService,
|
CouchDBService: RealCouchDBService,
|
||||||
} = require('./couchdb.production');
|
} = require('./couchdb.production');
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ export class CouchDBService {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Get CouchDB configuration from environment
|
// Get CouchDB configuration from environment
|
||||||
const couchdbUrl =
|
const couchdbUrl = process.env.VITE_COUCHDB_URL || 'http://localhost:5984';
|
||||||
(import.meta as any).env?.VITE_COUCHDB_URL || 'http://localhost:5984';
|
const couchdbUser = process.env.VITE_COUCHDB_USER || 'admin';
|
||||||
const couchdbUser = (import.meta as any).env?.VITE_COUCHDB_USER || 'admin';
|
const couchdbPassword = process.env.VITE_COUCHDB_PASSWORD || 'password';
|
||||||
const couchdbPassword =
|
|
||||||
(import.meta as any).env?.VITE_COUCHDB_PASSWORD || 'password';
|
|
||||||
|
|
||||||
this.baseUrl = couchdbUrl;
|
this.baseUrl = couchdbUrl;
|
||||||
this.auth = btoa(`${couchdbUser}:${couchdbPassword}`);
|
this.auth = btoa(`${couchdbUser}:${couchdbPassword}`);
|
||||||
@@ -72,7 +70,7 @@ export class CouchDBService {
|
|||||||
throw new Error(`Failed to create database ${dbName}`);
|
throw new Error(`Failed to create database ${dbName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`✅ Created CouchDB database: ${dbName}`);
|
console.warn(`✅ Created CouchDB database: ${dbName}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error checking/creating database ${dbName}:`, error);
|
console.error(`Error checking/creating database ${dbName}:`, error);
|
||||||
@@ -83,8 +81,8 @@ export class CouchDBService {
|
|||||||
private async makeRequest(
|
private async makeRequest(
|
||||||
method: string,
|
method: string,
|
||||||
path: string,
|
path: string,
|
||||||
body?: any
|
body?: Record<string, unknown>
|
||||||
): Promise<any> {
|
): Promise<Record<string, unknown>> {
|
||||||
const url = `${this.baseUrl}${path}`;
|
const url = `${this.baseUrl}${path}`;
|
||||||
const options: RequestInit = {
|
const options: RequestInit = {
|
||||||
method,
|
method,
|
||||||
@@ -114,7 +112,7 @@ export class CouchDBService {
|
|||||||
): Promise<T | null> {
|
): Promise<T | null> {
|
||||||
try {
|
try {
|
||||||
const doc = await this.makeRequest('GET', `/${dbName}/${id}`);
|
const doc = await this.makeRequest('GET', `/${dbName}/${id}`);
|
||||||
return doc;
|
return doc as T;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof CouchDBError && error.status === 404) {
|
if (error instanceof CouchDBError && error.status === 404) {
|
||||||
return null;
|
return null;
|
||||||
@@ -135,12 +133,15 @@ export class CouchDBService {
|
|||||||
return { ...doc, _rev: response.rev } as T;
|
return { ...doc, _rev: response.rev } as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async query<T>(dbName: string, selector: any): Promise<T[]> {
|
private async query<T>(
|
||||||
|
dbName: string,
|
||||||
|
selector: Record<string, unknown>
|
||||||
|
): Promise<T[]> {
|
||||||
const response = await this.makeRequest('POST', `/${dbName}/_find`, {
|
const response = await this.makeRequest('POST', `/${dbName}/_find`, {
|
||||||
selector,
|
selector,
|
||||||
limit: 1000,
|
limit: 1000,
|
||||||
});
|
});
|
||||||
return response.docs;
|
return response.docs as T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// User Management Methods
|
// User Management Methods
|
||||||
@@ -363,10 +364,13 @@ export class CouchDBService {
|
|||||||
const settings = await this.getDoc('settings', userId);
|
const settings = await this.getDoc('settings', userId);
|
||||||
if (settings) {
|
if (settings) {
|
||||||
deletePromises.push(
|
deletePromises.push(
|
||||||
this.makeRequest('DELETE', `/settings/${userId}?rev=${settings._rev}`)
|
this.makeRequest(
|
||||||
|
'DELETE',
|
||||||
|
`/settings/${userId}?rev=${settings._rev}`
|
||||||
|
).then(() => undefined)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
// Settings might not exist
|
// Settings might not exist
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,10 +381,10 @@ export class CouchDBService {
|
|||||||
this.makeRequest(
|
this.makeRequest(
|
||||||
'DELETE',
|
'DELETE',
|
||||||
`/taken_doses/${userId}?rev=${takenDoses._rev}`
|
`/taken_doses/${userId}?rev=${takenDoses._rev}`
|
||||||
)
|
).then(() => undefined)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
// Taken doses might not exist
|
// Taken doses might not exist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -23,14 +23,14 @@ export class MailgunService {
|
|||||||
// Log configuration status on startup
|
// Log configuration status on startup
|
||||||
const status = this.getConfigurationStatus();
|
const status = this.getConfigurationStatus();
|
||||||
if (status.mode === 'development') {
|
if (status.mode === 'development') {
|
||||||
console.log(
|
console.warn(
|
||||||
'📧 Mailgun Service: Running in development mode (emails will be logged only)'
|
'📧 Mailgun Service: Running in development mode (emails will be logged only)'
|
||||||
);
|
);
|
||||||
console.log(
|
console.warn(
|
||||||
'💡 To enable real emails, configure Mailgun credentials in .env.local'
|
'💡 To enable real emails, configure Mailgun credentials in .env.local'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.warn(
|
||||||
'📧 Mailgun Service: Configured for production with domain:',
|
'📧 Mailgun Service: Configured for production with domain:',
|
||||||
status.domain
|
status.domain
|
||||||
);
|
);
|
||||||
@@ -45,8 +45,8 @@ export class MailgunService {
|
|||||||
<h2 style="color: #4f46e5;">Verify Your Email Address</h2>
|
<h2 style="color: #4f46e5;">Verify Your Email Address</h2>
|
||||||
<p>Thank you for signing up for Medication Reminder! Please click the button below to verify your email address:</p>
|
<p>Thank you for signing up for Medication Reminder! Please click the button below to verify your email address:</p>
|
||||||
<div style="text-align: center; margin: 30px 0;">
|
<div style="text-align: center; margin: 30px 0;">
|
||||||
<a href="${verificationUrl}"
|
<a href="${verificationUrl}"
|
||||||
style="background-color: #4f46e5; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; display: inline-block;">
|
style="background-color: #4f46e5; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; display: inline-block;">
|
||||||
Verify Email Address
|
Verify Email Address
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -57,10 +57,10 @@ export class MailgunService {
|
|||||||
`,
|
`,
|
||||||
text: `
|
text: `
|
||||||
Verify Your Email - Medication Reminder
|
Verify Your Email - Medication Reminder
|
||||||
|
|
||||||
Thank you for signing up! Please verify your email by visiting:
|
Thank you for signing up! Please verify your email by visiting:
|
||||||
${verificationUrl}
|
${verificationUrl}
|
||||||
|
|
||||||
This link will expire in 24 hours.
|
This link will expire in 24 hours.
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
@@ -74,8 +74,8 @@ export class MailgunService {
|
|||||||
<h2 style="color: #4f46e5;">Reset Your Password</h2>
|
<h2 style="color: #4f46e5;">Reset Your Password</h2>
|
||||||
<p>You requested to reset your password. Click the button below to set a new password:</p>
|
<p>You requested to reset your password. Click the button below to set a new password:</p>
|
||||||
<div style="text-align: center; margin: 30px 0;">
|
<div style="text-align: center; margin: 30px 0;">
|
||||||
<a href="${resetUrl}"
|
<a href="${resetUrl}"
|
||||||
style="background-color: #4f46e5; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; display: inline-block;">
|
style="background-color: #4f46e5; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; display: inline-block;">
|
||||||
Reset Password
|
Reset Password
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,10 +86,10 @@ export class MailgunService {
|
|||||||
`,
|
`,
|
||||||
text: `
|
text: `
|
||||||
Reset Your Password - Medication Reminder
|
Reset Your Password - Medication Reminder
|
||||||
|
|
||||||
You requested to reset your password. Visit this link to set a new password:
|
You requested to reset your password. Visit this link to set a new password:
|
||||||
${resetUrl}
|
${resetUrl}
|
||||||
|
|
||||||
This link will expire in 1 hour. If you didn't request this, please ignore this email.
|
This link will expire in 1 hour. If you didn't request this, please ignore this email.
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
@@ -99,7 +99,7 @@ export class MailgunService {
|
|||||||
try {
|
try {
|
||||||
// In development mode or when Mailgun is not configured, just log the email
|
// In development mode or when Mailgun is not configured, just log the email
|
||||||
if (isDevelopmentMode()) {
|
if (isDevelopmentMode()) {
|
||||||
console.log('📧 Mock Email Sent (Development Mode):', {
|
console.warn('📧 Mock Email Sent (Development Mode):', {
|
||||||
to,
|
to,
|
||||||
subject: template.subject,
|
subject: template.subject,
|
||||||
from: `${this.config.fromName} <${this.config.fromEmail}>`,
|
from: `${this.config.fromName} <${this.config.fromEmail}>`,
|
||||||
@@ -140,7 +140,7 @@ export class MailgunService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
console.log('📧 Email sent successfully via Mailgun:', {
|
console.warn('📧 Email sent successfully via Mailgun:', {
|
||||||
to,
|
to,
|
||||||
subject: template.subject,
|
subject: template.subject,
|
||||||
messageId: result.id,
|
messageId: result.id,
|
||||||
|
|||||||
+2
-7
@@ -1,7 +1,4 @@
|
|||||||
import { authService } from './auth/auth.service';
|
import { authService } from './auth/auth.service';
|
||||||
import { OAuthProvider, OAuthState, User } from '../types';
|
|
||||||
import { dbService } from './couchdb.factory';
|
|
||||||
import { AccountStatus } from './auth/auth.constants';
|
|
||||||
|
|
||||||
// Mock OAuth configuration
|
// Mock OAuth configuration
|
||||||
const GOOGLE_CLIENT_ID = 'mock_google_client_id';
|
const GOOGLE_CLIENT_ID = 'mock_google_client_id';
|
||||||
@@ -12,8 +9,6 @@ const GOOGLE_AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
|
|||||||
const GITHUB_AUTH_URL = 'https://github.com/login/oauth/authorize';
|
const GITHUB_AUTH_URL = 'https://github.com/login/oauth/authorize';
|
||||||
|
|
||||||
// Mock token exchange endpoints
|
// Mock token exchange endpoints
|
||||||
const GOOGLE_TOKEN_URL = 'https://oauth2.googleapis.com/token';
|
|
||||||
const GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token';
|
|
||||||
|
|
||||||
// Mock OAuth scopes
|
// Mock OAuth scopes
|
||||||
const GOOGLE_SCOPES = 'openid email profile';
|
const GOOGLE_SCOPES = 'openid email profile';
|
||||||
@@ -60,7 +55,7 @@ export const githubAuth = () => {
|
|||||||
// Mock token exchange
|
// Mock token exchange
|
||||||
const mockExchangeCodeForToken = async (
|
const mockExchangeCodeForToken = async (
|
||||||
provider: 'google' | 'github',
|
provider: 'google' | 'github',
|
||||||
code: string
|
_code: string
|
||||||
): Promise<string> => {
|
): Promise<string> => {
|
||||||
// In a real implementation, we would make a POST request to the token endpoint
|
// In a real implementation, we would make a POST request to the token endpoint
|
||||||
// with the code, client_id, client_secret, and redirect_uri
|
// with the code, client_id, client_secret, and redirect_uri
|
||||||
@@ -72,7 +67,7 @@ const mockExchangeCodeForToken = async (
|
|||||||
// Mock user info retrieval
|
// Mock user info retrieval
|
||||||
const mockGetUserInfo = async (
|
const mockGetUserInfo = async (
|
||||||
provider: 'google' | 'github',
|
provider: 'google' | 'github',
|
||||||
accessToken: string
|
_accessToken: string
|
||||||
): Promise<{ email: string; name: string }> => {
|
): Promise<{ email: string; name: string }> => {
|
||||||
// In a real implementation, we would make a GET request to the user info endpoint
|
// In a real implementation, we would make a GET request to the user info endpoint
|
||||||
// with the access token
|
// with the access token
|
||||||
|
|||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly VITE_APP_NAME: string;
|
||||||
|
readonly VITE_COUCHDB_URL: string;
|
||||||
|
readonly VITE_COUCHDB_USER: string;
|
||||||
|
readonly VITE_COUCHDB_PASSWORD: string;
|
||||||
|
readonly VITE_GOOGLE_CLIENT_ID: string;
|
||||||
|
readonly VITE_GITHUB_CLIENT_ID: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user