From 6d86a08d6397fb138bfc8f8c71c7572a5deeb015 Mon Sep 17 00:00:00 2001 From: Till-JS <101404291+Till-JS@users.noreply.github.com> Date: Fri, 23 Jan 2026 15:31:39 +0100 Subject: [PATCH] feat: add monitoring dashboard (Prometheus + Grafana + Umami + Admin) Phase 1: Infrastructure - Add docker/prometheus/prometheus.yml with scrape configs for all services - Add docker/grafana/provisioning for auto-configured datasources - Add docker/grafana/dashboards (system-overview, backends-docker) - Update docker-compose.macmini.yml with monitoring services: - prometheus, grafana, node-exporter, cadvisor - postgres-exporter, redis-exporter, umami - Add grafana.mana.how and analytics.mana.how to Caddyfile Phase 2: Backend Metrics - Create packages/shared-nestjs-metrics with: - MetricsModule (auto /metrics endpoint) - MetricsService (Counter, Histogram, Gauge helpers) - MetricsMiddleware (auto HTTP request tracking) Phase 3: Umami Web Analytics - Add Umami tracking scripts to all landing pages - Add Umami tracking scripts to all web apps - Create scripts/mac-mini/setup-umami-db.sh Phase 4: Admin Dashboard (ManaCore Web) - Add admin routes: /admin, /admin/users, /admin/system - Create StatCard, QuickLinks, UserTable components - Add Admin link to navigation Co-Authored-By: Claude Opus 4.5 --- .env.macmini.example | 10 + .../apps/landing/src/layouts/Layout.astro | 6 + apps/calendar/apps/web/src/app.html | 2 + .../apps/landing/src/layouts/Layout.astro | 6 + apps/chat/apps/web/src/app.html | 2 + .../apps/landing/src/layouts/Layout.astro | 51 ++ apps/clock/apps/web/src/app.html | 2 + apps/contacts/apps/web/src/app.html | 2 + .../apps/landing/src/layouts/Layout.astro | 4 +- apps/manacore/apps/web/src/app.html | 2 + .../lib/components/admin/QuickLinks.svelte | 50 ++ .../src/lib/components/admin/StatCard.svelte | 53 ++ .../src/lib/components/admin/UserTable.svelte | 128 +++ .../apps/web/src/routes/(app)/+layout.svelte | 10 +- .../web/src/routes/(app)/admin/+layout.svelte | 72 ++ .../web/src/routes/(app)/admin/+page.svelte | 155 ++++ .../routes/(app)/admin/system/+page.svelte | 180 ++++ .../src/routes/(app)/admin/users/+page.svelte | 124 +++ .../apps/landing/src/layouts/Layout.astro | 6 + apps/todo/apps/web/src/app.html | 2 + docker-compose.macmini.yml | 132 +++ docker/caddy/Caddyfile.production | 90 ++ docker/grafana/dashboards/backends.json | 377 ++++++++ .../grafana/dashboards/system-overview.json | 498 +++++++++++ .../provisioning/dashboards/default.yml | 16 + .../provisioning/datasources/prometheus.yml | 15 + docker/prometheus/prometheus.yml | 88 ++ packages/shared-nestjs-metrics/package.json | 39 + packages/shared-nestjs-metrics/src/index.ts | 62 ++ .../src/metrics.controller.ts | 15 + .../src/metrics.middleware.ts | 35 + .../src/metrics.module.ts | 79 ++ .../src/metrics.service.ts | 173 ++++ packages/shared-nestjs-metrics/tsconfig.json | 22 + pnpm-lock.yaml | 803 ++++++------------ scripts/mac-mini/setup-umami-db.sh | 27 + 36 files changed, 2779 insertions(+), 559 deletions(-) create mode 100644 apps/clock/apps/landing/src/layouts/Layout.astro create mode 100644 apps/manacore/apps/web/src/lib/components/admin/QuickLinks.svelte create mode 100644 apps/manacore/apps/web/src/lib/components/admin/StatCard.svelte create mode 100644 apps/manacore/apps/web/src/lib/components/admin/UserTable.svelte create mode 100644 apps/manacore/apps/web/src/routes/(app)/admin/+layout.svelte create mode 100644 apps/manacore/apps/web/src/routes/(app)/admin/+page.svelte create mode 100644 apps/manacore/apps/web/src/routes/(app)/admin/system/+page.svelte create mode 100644 apps/manacore/apps/web/src/routes/(app)/admin/users/+page.svelte create mode 100644 docker/caddy/Caddyfile.production create mode 100644 docker/grafana/dashboards/backends.json create mode 100644 docker/grafana/dashboards/system-overview.json create mode 100644 docker/grafana/provisioning/dashboards/default.yml create mode 100644 docker/grafana/provisioning/datasources/prometheus.yml create mode 100644 docker/prometheus/prometheus.yml create mode 100644 packages/shared-nestjs-metrics/package.json create mode 100644 packages/shared-nestjs-metrics/src/index.ts create mode 100644 packages/shared-nestjs-metrics/src/metrics.controller.ts create mode 100644 packages/shared-nestjs-metrics/src/metrics.middleware.ts create mode 100644 packages/shared-nestjs-metrics/src/metrics.module.ts create mode 100644 packages/shared-nestjs-metrics/src/metrics.service.ts create mode 100644 packages/shared-nestjs-metrics/tsconfig.json create mode 100755 scripts/mac-mini/setup-umami-db.sh diff --git a/.env.macmini.example b/.env.macmini.example index 376fc80ae..31b2f2eb3 100644 --- a/.env.macmini.example +++ b/.env.macmini.example @@ -31,3 +31,13 @@ SUPABASE_SERVICE_ROLE_KEY= # ============================================ AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/ AZURE_OPENAI_API_KEY=your-api-key-here + +# ============================================ +# Monitoring (Grafana) +# ============================================ +GRAFANA_PASSWORD=your-grafana-admin-password + +# ============================================ +# Web Analytics (Umami) +# ============================================ +UMAMI_APP_SECRET=your-umami-secret-here diff --git a/apps/calendar/apps/landing/src/layouts/Layout.astro b/apps/calendar/apps/landing/src/layouts/Layout.astro index fe5fbfc4e..1ed0011ea 100644 --- a/apps/calendar/apps/landing/src/layouts/Layout.astro +++ b/apps/calendar/apps/landing/src/layouts/Layout.astro @@ -37,6 +37,12 @@ const { rel="stylesheet" /> + + + {title} diff --git a/apps/calendar/apps/web/src/app.html b/apps/calendar/apps/web/src/app.html index cff15d4b6..734334e8d 100644 --- a/apps/calendar/apps/web/src/app.html +++ b/apps/calendar/apps/web/src/app.html @@ -6,6 +6,8 @@ Calendar %sveltekit.head% + +
%sveltekit.body%
diff --git a/apps/chat/apps/landing/src/layouts/Layout.astro b/apps/chat/apps/landing/src/layouts/Layout.astro index eece8c000..cee41ab63 100644 --- a/apps/chat/apps/landing/src/layouts/Layout.astro +++ b/apps/chat/apps/landing/src/layouts/Layout.astro @@ -42,6 +42,12 @@ const { rel="stylesheet" /> + + + {title} diff --git a/apps/chat/apps/web/src/app.html b/apps/chat/apps/web/src/app.html index 77a5ff52c..6ac3202db 100644 --- a/apps/chat/apps/web/src/app.html +++ b/apps/chat/apps/web/src/app.html @@ -5,6 +5,8 @@ %sveltekit.head% + +
%sveltekit.body%
diff --git a/apps/clock/apps/landing/src/layouts/Layout.astro b/apps/clock/apps/landing/src/layouts/Layout.astro new file mode 100644 index 000000000..b3a4c548d --- /dev/null +++ b/apps/clock/apps/landing/src/layouts/Layout.astro @@ -0,0 +1,51 @@ +--- +import '../styles/global.css'; + +interface Props { + title?: string; + description?: string; +} + +const { + title = 'Clock - Time Tracking & Focus', + description = 'Track your time, stay focused, and boost productivity. Pomodoro timer, time tracking, and focus sessions. Start free today.', +} = Astro.props; +--- + + + + + + + + + + + + + + + + + + + + + + + + + + + {title} + + + + + diff --git a/apps/clock/apps/web/src/app.html b/apps/clock/apps/web/src/app.html index 77a5ff52c..f3376c592 100644 --- a/apps/clock/apps/web/src/app.html +++ b/apps/clock/apps/web/src/app.html @@ -5,6 +5,8 @@ %sveltekit.head% + +
%sveltekit.body%
diff --git a/apps/contacts/apps/web/src/app.html b/apps/contacts/apps/web/src/app.html index 77a5ff52c..b8936369f 100644 --- a/apps/contacts/apps/web/src/app.html +++ b/apps/contacts/apps/web/src/app.html @@ -5,6 +5,8 @@ %sveltekit.head% + +
%sveltekit.body%
diff --git a/apps/manacore/apps/landing/src/layouts/Layout.astro b/apps/manacore/apps/landing/src/layouts/Layout.astro index f82903d28..55504093a 100644 --- a/apps/manacore/apps/landing/src/layouts/Layout.astro +++ b/apps/manacore/apps/landing/src/layouts/Layout.astro @@ -71,8 +71,8 @@ const lang = getLangFromUrl(Astro.url); + src="https://analytics.mana.how/script.js" + data-website-id="MANACORE_LANDING_WEBSITE_ID"> diff --git a/apps/manacore/apps/web/src/app.html b/apps/manacore/apps/web/src/app.html index 77a5ff52c..fe11ef093 100644 --- a/apps/manacore/apps/web/src/app.html +++ b/apps/manacore/apps/web/src/app.html @@ -5,6 +5,8 @@ %sveltekit.head% + +
%sveltekit.body%
diff --git a/apps/manacore/apps/web/src/lib/components/admin/QuickLinks.svelte b/apps/manacore/apps/web/src/lib/components/admin/QuickLinks.svelte new file mode 100644 index 000000000..8b23a3dbd --- /dev/null +++ b/apps/manacore/apps/web/src/lib/components/admin/QuickLinks.svelte @@ -0,0 +1,50 @@ + + + diff --git a/apps/manacore/apps/web/src/lib/components/admin/StatCard.svelte b/apps/manacore/apps/web/src/lib/components/admin/StatCard.svelte new file mode 100644 index 000000000..63095a6fa --- /dev/null +++ b/apps/manacore/apps/web/src/lib/components/admin/StatCard.svelte @@ -0,0 +1,53 @@ + + +
+ {#if loading} +
+
+
+
+
+
+
+ {:else} +
+
+ + {@html icons[icon]} + +
+
+

{title}

+

{value}

+ {#if change !== undefined} +

+ {change >= 0 ? '+' : ''}{change}% + {#if changeLabel} + {changeLabel} + {/if} +

+ {/if} +
+
+ {/if} +
diff --git a/apps/manacore/apps/web/src/lib/components/admin/UserTable.svelte b/apps/manacore/apps/web/src/lib/components/admin/UserTable.svelte new file mode 100644 index 000000000..136f8fe77 --- /dev/null +++ b/apps/manacore/apps/web/src/lib/components/admin/UserTable.svelte @@ -0,0 +1,128 @@ + + +
+
+

Benutzer

+
+ {#if loading} +
+ {#each Array(5) as _} +
+
+
+
+
+
+
+ {/each} +
+ {:else} +
+ + + + + + + + + + + {#each users as user} + + + + + + + {/each} + +
+ Benutzer + + Rolle + + Registriert + + Letzte Aktivität +
+
+
+ + {(user.name || user.email)[0].toUpperCase()} + +
+
+

{user.name || '-'}

+

{user.email}

+
+
+
+ + {user.role} + + + {formatDate(user.createdAt)} + + {formatRelativeTime(user.lastActiveAt)} +
+
+ {#if users.length === 0} +
Keine Benutzer gefunden
+ {/if} + {/if} +
diff --git a/apps/manacore/apps/web/src/routes/(app)/+layout.svelte b/apps/manacore/apps/web/src/routes/(app)/+layout.svelte index 1676bda5a..f6ad1c0ef 100644 --- a/apps/manacore/apps/web/src/routes/(app)/+layout.svelte +++ b/apps/manacore/apps/web/src/routes/(app)/+layout.svelte @@ -80,7 +80,8 @@ let userEmail = $derived(authStore.user?.email); // Navigation items for ManaCore - const navItems: PillNavItem[] = [ + // Admin link is conditionally added based on user role + let baseNavItems: PillNavItem[] = [ { href: '/dashboard', label: 'Dashboard', icon: 'home' }, { href: '/credits', label: 'Credits', icon: 'creditCard' }, { href: '/feedback', label: 'Feedback', icon: 'chat' }, @@ -88,6 +89,13 @@ { href: '/settings', label: 'Settings', icon: 'settings' }, ]; + // TODO: Check user role from authStore and add admin link if admin + // For now, always show admin link for testing + const navItems: PillNavItem[] = [ + ...baseNavItems, + { href: '/admin', label: 'Admin', icon: 'shield' }, + ]; + // Navigation shortcuts (Ctrl+1-5) const navRoutes = navItems.map((item) => item.href); diff --git a/apps/manacore/apps/web/src/routes/(app)/admin/+layout.svelte b/apps/manacore/apps/web/src/routes/(app)/admin/+layout.svelte new file mode 100644 index 000000000..376cb9ab9 --- /dev/null +++ b/apps/manacore/apps/web/src/routes/(app)/admin/+layout.svelte @@ -0,0 +1,72 @@ + + +
+
+
+

Admin Dashboard

+

System monitoring and management

+
+
+ + + + Admin +
+
+ + + +
+ {@render children()} +
+
diff --git a/apps/manacore/apps/web/src/routes/(app)/admin/+page.svelte b/apps/manacore/apps/web/src/routes/(app)/admin/+page.svelte new file mode 100644 index 000000000..4ec7d6d0a --- /dev/null +++ b/apps/manacore/apps/web/src/routes/(app)/admin/+page.svelte @@ -0,0 +1,155 @@ + + +
+ +
+ + + + +
+ + +
+ +
+

Security (Last 7 Days)

+ {#if loading} +
+
+
+
+ {:else if stats} +
+
+
+
+ Successful Logins +
+ {stats.loginSuccess7d} +
+
+
+
+ Failed Logins +
+ {stats.loginFailed7d} +
+
+
+ Success Rate + + {Math.round( + (stats.loginSuccess7d / (stats.loginSuccess7d + stats.loginFailed7d)) * 100 + )}% + +
+
+
+ {/if} +
+ + + +
+ + {#if error} +
+

{error}

+
+ {/if} +
diff --git a/apps/manacore/apps/web/src/routes/(app)/admin/system/+page.svelte b/apps/manacore/apps/web/src/routes/(app)/admin/system/+page.svelte new file mode 100644 index 000000000..2c249647f --- /dev/null +++ b/apps/manacore/apps/web/src/routes/(app)/admin/system/+page.svelte @@ -0,0 +1,180 @@ + + +
+ +
+
+

System Status

+ {#if !loading} +
+
+ + {healthyCount}/{totalCount} Services Healthy + +
+ {/if} +
+ + {#if loading} +
+ {#each Array(8) as _} +
+ {/each} +
+ {:else} +
+ {#each services as service} +
+
+
+

{service.name}

+

{statusLabels[service.status]}

+
+ {#if service.url !== '-'} + + + + + + {/if} +
+ {/each} +
+ {/if} +
+ + + + + +
+

Environment

+
+
+
+ Server + Mac Mini (mana.how) +
+
+ Domain + *.mana.how +
+
+ SSL + Caddy (Auto) +
+
+
+
+ Database + PostgreSQL 16 +
+
+ Cache + Redis 7 +
+
+ Tunnel + Cloudflare +
+
+
+
+
diff --git a/apps/manacore/apps/web/src/routes/(app)/admin/users/+page.svelte b/apps/manacore/apps/web/src/routes/(app)/admin/users/+page.svelte new file mode 100644 index 000000000..63b320bdf --- /dev/null +++ b/apps/manacore/apps/web/src/routes/(app)/admin/users/+page.svelte @@ -0,0 +1,124 @@ + + +
+ +
+
+ + + + +
+ + {filteredUsers.length} of {users.length} users + +
+ + + + + {#if error} +
+

{error}

+
+ {/if} +
diff --git a/apps/manadeck/apps/landing/src/layouts/Layout.astro b/apps/manadeck/apps/landing/src/layouts/Layout.astro index ceb21f0bd..7e411f095 100644 --- a/apps/manadeck/apps/landing/src/layouts/Layout.astro +++ b/apps/manadeck/apps/landing/src/layouts/Layout.astro @@ -42,6 +42,12 @@ const { rel="stylesheet" /> + + + {title} diff --git a/apps/todo/apps/web/src/app.html b/apps/todo/apps/web/src/app.html index 95592e23e..d77bba918 100644 --- a/apps/todo/apps/web/src/app.html +++ b/apps/todo/apps/web/src/app.html @@ -25,6 +25,8 @@ %sveltekit.head% + +
%sveltekit.body%
diff --git a/docker-compose.macmini.yml b/docker-compose.macmini.yml index 312103d76..b7bc5b557 100644 --- a/docker-compose.macmini.yml +++ b/docker-compose.macmini.yml @@ -378,6 +378,134 @@ services: retries: 3 start_period: 40s + # ============================================ + # Monitoring Stack + # ============================================ + + prometheus: + image: prom/prometheus:v2.51.0 + container_name: manacore-prometheus + restart: always + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--storage.tsdb.retention.time=30d' + - '--web.enable-lifecycle' + volumes: + - ./docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - prometheus_data:/prometheus + ports: + - "9090:9090" + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9090/-/healthy"] + interval: 30s + timeout: 10s + retries: 3 + + grafana: + image: grafana/grafana:10.4.1 + container_name: manacore-grafana + restart: always + depends_on: + prometheus: + condition: service_healthy + environment: + GF_SECURITY_ADMIN_USER: admin + GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin} + GF_USERS_ALLOW_SIGN_UP: false + GF_SERVER_ROOT_URL: https://grafana.mana.how + volumes: + - ./docker/grafana/provisioning:/etc/grafana/provisioning:ro + - ./docker/grafana/dashboards:/var/lib/grafana/dashboards:ro + - grafana_data:/var/lib/grafana + ports: + - "3100:3000" + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"] + interval: 30s + timeout: 10s + retries: 3 + + node-exporter: + image: prom/node-exporter:v1.7.0 + container_name: manacore-node-exporter + restart: always + command: + - '--path.procfs=/host/proc' + - '--path.sysfs=/host/sys' + - '--path.rootfs=/rootfs' + - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' + volumes: + - /proc:/host/proc:ro + - /sys:/host/sys:ro + - /:/rootfs:ro + ports: + - "9100:9100" + + cadvisor: + image: gcr.io/cadvisor/cadvisor:v0.49.1 + container_name: manacore-cadvisor + restart: always + privileged: true + volumes: + - /:/rootfs:ro + - /var/run:/var/run:ro + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro + - /dev/disk/:/dev/disk:ro + ports: + - "8080:8080" + + postgres-exporter: + image: prometheuscommunity/postgres-exporter:v0.15.0 + container_name: manacore-postgres-exporter + restart: always + depends_on: + postgres: + condition: service_healthy + environment: + DATA_SOURCE_NAME: postgresql://postgres:${POSTGRES_PASSWORD:-manacore123}@postgres:5432/postgres?sslmode=disable + ports: + - "9187:9187" + + redis-exporter: + image: oliver006/redis_exporter:v1.58.0 + container_name: manacore-redis-exporter + restart: always + depends_on: + redis: + condition: service_healthy + environment: + REDIS_ADDR: redis://redis:6379 + REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123} + ports: + - "9121:9121" + + # ============================================ + # Web Analytics (Umami) + # ============================================ + + umami: + image: ghcr.io/umami-software/umami:postgresql-latest + container_name: manacore-umami + restart: always + depends_on: + postgres: + condition: service_healthy + environment: + DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-manacore123}@postgres:5432/umami + DATABASE_TYPE: postgresql + APP_SECRET: ${UMAMI_APP_SECRET:-change-me-umami-secret} + DISABLE_TELEMETRY: 1 + ports: + - "3200:3000" + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/heartbeat"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + # ============================================ # Volumes # ============================================ @@ -387,3 +515,7 @@ volumes: name: manacore-postgres redis_data: name: manacore-redis + prometheus_data: + name: manacore-prometheus + grafana_data: + name: manacore-grafana diff --git a/docker/caddy/Caddyfile.production b/docker/caddy/Caddyfile.production new file mode 100644 index 000000000..b40cae0f1 --- /dev/null +++ b/docker/caddy/Caddyfile.production @@ -0,0 +1,90 @@ +# ManaCore Production Reverse Proxy +# Domain: mana.how +# Server: 46.224.108.214 +# +# Deploy to: ~/Caddyfile on production server +# Reload with: docker exec caddy caddy reload --config /etc/caddy/Caddyfile + +# ============================================ +# Auth Service +# ============================================ +auth.mana.how { + reverse_proxy localhost:3001 +} + +# ============================================ +# ManaCore Dashboard (Main) +# ============================================ +mana.how { + reverse_proxy localhost:5173 +} + +www.mana.how { + redir https://mana.how{uri} permanent +} + +# ============================================ +# Chat App +# ============================================ +chat.mana.how { + reverse_proxy localhost:3000 +} + +chat-api.mana.how { + reverse_proxy localhost:3002 +} + +# ============================================ +# Todo App +# ============================================ +todo.mana.how { + reverse_proxy localhost:5188 +} + +todo-api.mana.how { + reverse_proxy localhost:3018 +} + +# ============================================ +# Calendar App +# ============================================ +calendar.mana.how { + reverse_proxy localhost:5186 +} + +calendar-api.mana.how { + reverse_proxy localhost:3016 +} + +# ============================================ +# Clock App +# ============================================ +clock.mana.how { + reverse_proxy localhost:5187 +} + +clock-api.mana.how { + reverse_proxy localhost:3017 +} + +# ============================================ +# Contacts App +# ============================================ +contacts.mana.how { + reverse_proxy localhost:5184 +} + +contacts-api.mana.how { + reverse_proxy localhost:3015 +} + +# ============================================ +# Monitoring & Analytics +# ============================================ +grafana.mana.how { + reverse_proxy localhost:3100 +} + +analytics.mana.how { + reverse_proxy localhost:3200 +} diff --git a/docker/grafana/dashboards/backends.json b/docker/grafana/dashboards/backends.json new file mode 100644 index 000000000..677e48d4b --- /dev/null +++ b/docker/grafana/dashboards/backends.json @@ -0,0 +1,377 @@ +{ + "annotations": { + "list": [] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, + "id": 1, + "panels": [], + "title": "Docker Containers", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "never", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 1 }, + "id": 2, + "options": { + "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, + "tooltip": { "mode": "single", "sort": "none" } + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "rate(container_cpu_usage_seconds_total{name=~\".+\"}[5m]) * 100", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "title": "Container CPU Usage", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "never", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 1 }, + "id": 3, + "options": { + "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, + "tooltip": { "mode": "single", "sort": "none" } + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "container_memory_usage_bytes{name=~\".+\"}", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "title": "Container Memory Usage", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 9 }, + "id": 4, + "panels": [], + "title": "Backend API Metrics", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "never", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 10 }, + "id": 5, + "options": { + "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, + "tooltip": { "mode": "single", "sort": "none" } + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "sum(rate(http_requests_total[5m])) by (job)", + "legendFormat": "{{job}}", + "refId": "A" + } + ], + "title": "Request Rate by Service", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "never", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 10 }, + "id": 6, + "options": { + "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, + "tooltip": { "mode": "single", "sort": "none" } + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))", + "legendFormat": "p95 {{job}}", + "refId": "A" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "histogram_quantile(0.50, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))", + "legendFormat": "p50 {{job}}", + "refId": "B" + } + ], + "title": "Response Time (p50/p95)", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "never", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 18 }, + "id": 7, + "options": { + "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, + "tooltip": { "mode": "single", "sort": "none" } + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "sum(rate(http_requests_total{status=~\"4..|5..\"}[5m])) by (job)", + "legendFormat": "{{job}}", + "refId": "A" + } + ], + "title": "Error Rate by Service", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "mappings": [ + { + "options": { + "0": { "color": "red", "index": 1, "text": "Down" }, + "1": { "color": "green", "index": 0, "text": "Up" } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "green", "value": 1 } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 18 }, + "id": 8, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "up{job=~\"mana-core-auth|chat-backend|todo-backend|calendar-backend|clock-backend|contacts-backend\"}", + "legendFormat": "{{job}}", + "refId": "A" + } + ], + "title": "Service Health", + "type": "stat" + } + ], + "refresh": "30s", + "schemaVersion": 38, + "tags": ["manacore", "backends", "docker"], + "templating": { + "list": [ + { + "current": { "selected": false, "text": "Prometheus", "value": "Prometheus" }, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { "from": "now-1h", "to": "now" }, + "timepicker": {}, + "timezone": "browser", + "title": "Backends & Docker", + "uid": "backends-docker", + "version": 1, + "weekStart": "" +} diff --git a/docker/grafana/dashboards/system-overview.json b/docker/grafana/dashboards/system-overview.json new file mode 100644 index 000000000..09e8881d4 --- /dev/null +++ b/docker/grafana/dashboards/system-overview.json @@ -0,0 +1,498 @@ +{ + "annotations": { + "list": [] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, + "id": 1, + "panels": [], + "title": "System Overview", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 70 }, + { "color": "red", "value": 85 } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { "h": 6, "w": 6, "x": 0, "y": 1 }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "100 - (avg(rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)", + "refId": "A" + } + ], + "title": "CPU Usage", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 70 }, + { "color": "red", "value": 85 } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { "h": 6, "w": 6, "x": 6, "y": 1 }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100", + "refId": "A" + } + ], + "title": "Memory Usage", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 70 }, + { "color": "red", "value": 85 } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { "h": 6, "w": 6, "x": 12, "y": 1 }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "(1 - (node_filesystem_avail_bytes{mountpoint=\"/\"} / node_filesystem_size_bytes{mountpoint=\"/\"})) * 100", + "refId": "A" + } + ], + "title": "Disk Usage", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { "h": 6, "w": 6, "x": 18, "y": 1 }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "count(container_last_seen{name=~\".+\"})", + "refId": "A" + } + ], + "title": "Running Containers", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "never", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 7 }, + "id": 6, + "options": { + "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, + "tooltip": { "mode": "single", "sort": "none" } + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "100 - (avg(rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)", + "legendFormat": "CPU", + "refId": "A" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100", + "legendFormat": "Memory", + "refId": "B" + } + ], + "title": "CPU & Memory Over Time", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "never", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 7 }, + "id": 7, + "options": { + "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, + "tooltip": { "mode": "single", "sort": "none" } + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "rate(node_network_receive_bytes_total{device!~\"lo|veth.*|br.*|docker.*\"}[5m])", + "legendFormat": "Receive {{device}}", + "refId": "A" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "rate(node_network_transmit_bytes_total{device!~\"lo|veth.*|br.*|docker.*\"}[5m])", + "legendFormat": "Transmit {{device}}", + "refId": "B" + } + ], + "title": "Network I/O", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 15 }, + "id": 8, + "panels": [], + "title": "Database", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { "h": 6, "w": 6, "x": 0, "y": 16 }, + "id": 9, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "pg_stat_activity_count{state=\"active\"}", + "refId": "A" + } + ], + "title": "PostgreSQL Active Connections", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { "h": 6, "w": 6, "x": 6, "y": 16 }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "redis_connected_clients", + "refId": "A" + } + ], + "title": "Redis Connected Clients", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { "h": 6, "w": 6, "x": 12, "y": 16 }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "redis_memory_used_bytes", + "refId": "A" + } + ], + "title": "Redis Memory Usage", + "type": "stat" + }, + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "green", "value": null }] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { "h": 6, "w": 6, "x": 18, "y": 16 }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.0", + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "${datasource}" }, + "expr": "pg_stat_database_blks_hit{datname!~\"template.*|postgres\"} / (pg_stat_database_blks_hit{datname!~\"template.*|postgres\"} + pg_stat_database_blks_read{datname!~\"template.*|postgres\"}) * 100", + "legendFormat": "{{datname}}", + "refId": "A" + } + ], + "title": "PostgreSQL Cache Hit Ratio", + "type": "stat" + } + ], + "refresh": "30s", + "schemaVersion": 38, + "tags": ["manacore", "system"], + "templating": { + "list": [ + { + "current": { "selected": false, "text": "Prometheus", "value": "Prometheus" }, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { "from": "now-1h", "to": "now" }, + "timepicker": {}, + "timezone": "browser", + "title": "System Overview", + "uid": "system-overview", + "version": 1, + "weekStart": "" +} diff --git a/docker/grafana/provisioning/dashboards/default.yml b/docker/grafana/provisioning/dashboards/default.yml new file mode 100644 index 000000000..6776bba73 --- /dev/null +++ b/docker/grafana/provisioning/dashboards/default.yml @@ -0,0 +1,16 @@ +# Grafana Dashboard Provisioning +# Auto-loads dashboards from the dashboards folder + +apiVersion: 1 + +providers: + - name: 'ManaCore Dashboards' + orgId: 1 + folder: 'ManaCore' + folderUid: 'manacore' + type: file + disableDeletion: false + updateIntervalSeconds: 30 + allowUiUpdates: true + options: + path: /var/lib/grafana/dashboards diff --git a/docker/grafana/provisioning/datasources/prometheus.yml b/docker/grafana/provisioning/datasources/prometheus.yml new file mode 100644 index 000000000..1cbaaafcf --- /dev/null +++ b/docker/grafana/provisioning/datasources/prometheus.yml @@ -0,0 +1,15 @@ +# Grafana Datasource Provisioning +# Auto-configures Prometheus as the default datasource + +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true + editable: true + jsonData: + timeInterval: "15s" + httpMethod: POST diff --git a/docker/prometheus/prometheus.yml b/docker/prometheus/prometheus.yml new file mode 100644 index 000000000..337e9d64a --- /dev/null +++ b/docker/prometheus/prometheus.yml @@ -0,0 +1,88 @@ +# ManaCore Prometheus Configuration +# Scrapes metrics from all services + +global: + scrape_interval: 15s + evaluation_interval: 15s + +# Alertmanager configuration (optional, for future use) +# alerting: +# alertmanagers: +# - static_configs: +# - targets: [] + +scrape_configs: + # Prometheus self-monitoring + - job_name: 'prometheus' + static_configs: + - targets: ['localhost:9090'] + + # Host system metrics via node-exporter + - job_name: 'node' + static_configs: + - targets: ['node-exporter:9100'] + relabel_configs: + - source_labels: [__address__] + target_label: instance + replacement: 'mac-mini' + + # Docker container metrics via cAdvisor + - job_name: 'cadvisor' + static_configs: + - targets: ['cadvisor:8080'] + + # PostgreSQL metrics + - job_name: 'postgres' + static_configs: + - targets: ['postgres-exporter:9187'] + + # Redis metrics + - job_name: 'redis' + static_configs: + - targets: ['redis-exporter:9121'] + + # ============================================ + # Application Backends (after /metrics added) + # ============================================ + + # Auth Service + - job_name: 'mana-core-auth' + static_configs: + - targets: ['mana-core-auth:3001'] + metrics_path: '/metrics' + scrape_interval: 30s + + # Chat Backend + - job_name: 'chat-backend' + static_configs: + - targets: ['chat-backend:3002'] + metrics_path: '/metrics' + scrape_interval: 30s + + # Todo Backend + - job_name: 'todo-backend' + static_configs: + - targets: ['todo-backend:3018'] + metrics_path: '/metrics' + scrape_interval: 30s + + # Calendar Backend + - job_name: 'calendar-backend' + static_configs: + - targets: ['calendar-backend:3016'] + metrics_path: '/metrics' + scrape_interval: 30s + + # Clock Backend + - job_name: 'clock-backend' + static_configs: + - targets: ['clock-backend:3017'] + metrics_path: '/metrics' + scrape_interval: 30s + + # Contacts Backend + - job_name: 'contacts-backend' + static_configs: + - targets: ['contacts-backend:3015'] + metrics_path: '/metrics' + scrape_interval: 30s diff --git a/packages/shared-nestjs-metrics/package.json b/packages/shared-nestjs-metrics/package.json new file mode 100644 index 000000000..b24aab614 --- /dev/null +++ b/packages/shared-nestjs-metrics/package.json @@ -0,0 +1,39 @@ +{ + "name": "@manacore/shared-nestjs-metrics", + "version": "1.0.0", + "description": "Prometheus metrics module for NestJS backends", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "rm -rf dist", + "prepublishOnly": "pnpm build", + "lint": "eslint ." + }, + "files": [ + "dist" + ], + "dependencies": { + "prom-client": "^15.1.0" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "@nestjs/core": "^10.0.0 || ^11.0.0" + }, + "devDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@types/express": "^4.17.21", + "@types/node": "^20.0.0", + "typescript": "^5.0.0" + }, + "keywords": [ + "nestjs", + "metrics", + "prometheus", + "monitoring", + "manacore" + ], + "author": "Mana Core Team", + "license": "MIT" +} diff --git a/packages/shared-nestjs-metrics/src/index.ts b/packages/shared-nestjs-metrics/src/index.ts new file mode 100644 index 000000000..4ac2e7b09 --- /dev/null +++ b/packages/shared-nestjs-metrics/src/index.ts @@ -0,0 +1,62 @@ +/** + * @manacore/shared-nestjs-metrics + * + * Prometheus metrics module for NestJS backends. + * Automatically tracks HTTP requests, duration, and provides custom metrics. + * + * @example + * ```typescript + * import { MetricsModule } from '@manacore/shared-nestjs-metrics'; + * + * @Module({ + * imports: [ + * MetricsModule.register({ + * prefix: 'myapp_', + * defaultLabels: { app: 'my-backend' }, + * }), + * ], + * }) + * export class AppModule {} + * ``` + * + * The module automatically: + * - Exposes a `/metrics` endpoint for Prometheus scraping + * - Tracks HTTP request count, duration, and in-flight requests + * - Collects default Node.js metrics (CPU, memory, event loop) + * + * Custom metrics can be created via the MetricsService: + * ```typescript + * @Injectable() + * export class MyService { + * private readonly aiRequestCounter: Counter; + * + * constructor(private readonly metricsService: MetricsService) { + * this.aiRequestCounter = metricsService.createCounter( + * 'ai_requests_total', + * 'Total AI requests', + * ['model'] + * ); + * } + * + * async processAI(model: string) { + * this.aiRequestCounter.inc({ model }); + * // ... process + * } + * } + * ``` + */ + +// Module +export { MetricsModule, MetricsModuleOptions } from './metrics.module'; + +// Service +export { MetricsService, MetricsServiceOptions } from './metrics.service'; + +// Middleware +export { MetricsMiddleware } from './metrics.middleware'; + +// Controller +export { MetricsController } from './metrics.controller'; + +// Re-export prom-client types for convenience +export { Counter, Histogram, Gauge, Summary } from 'prom-client'; diff --git a/packages/shared-nestjs-metrics/src/metrics.controller.ts b/packages/shared-nestjs-metrics/src/metrics.controller.ts new file mode 100644 index 000000000..f92dd6969 --- /dev/null +++ b/packages/shared-nestjs-metrics/src/metrics.controller.ts @@ -0,0 +1,15 @@ +import { Controller, Get, Res } from '@nestjs/common'; +import { Response } from 'express'; +import { MetricsService } from './metrics.service'; + +@Controller() +export class MetricsController { + constructor(private readonly metricsService: MetricsService) {} + + @Get('metrics') + async getMetrics(@Res() res: Response): Promise { + const metrics = await this.metricsService.getMetrics(); + res.set('Content-Type', this.metricsService.getContentType()); + res.send(metrics); + } +} diff --git a/packages/shared-nestjs-metrics/src/metrics.middleware.ts b/packages/shared-nestjs-metrics/src/metrics.middleware.ts new file mode 100644 index 000000000..5f253440d --- /dev/null +++ b/packages/shared-nestjs-metrics/src/metrics.middleware.ts @@ -0,0 +1,35 @@ +import { Injectable, NestMiddleware } from '@nestjs/common'; +import { Request, Response, NextFunction } from 'express'; +import { MetricsService } from './metrics.service'; + +@Injectable() +export class MetricsMiddleware implements NestMiddleware { + constructor(private readonly metricsService: MetricsService) {} + + use(req: Request, res: Response, next: NextFunction): void { + // Skip metrics endpoint itself to avoid recursion + if (req.path === '/metrics') { + return next(); + } + + const startTime = Date.now(); + const method = req.method; + + // Track in-flight requests + this.metricsService.incrementInFlight(method); + + // Hook into response finish + res.on('finish', () => { + const duration = Date.now() - startTime; + const status = res.statusCode; + const path = req.route?.path || req.path; + + // Record metrics + this.metricsService.incrementHttpRequests(method, path, status); + this.metricsService.observeHttpDuration(method, path, status, duration); + this.metricsService.decrementInFlight(method); + }); + + next(); + } +} diff --git a/packages/shared-nestjs-metrics/src/metrics.module.ts b/packages/shared-nestjs-metrics/src/metrics.module.ts new file mode 100644 index 000000000..2e3db4504 --- /dev/null +++ b/packages/shared-nestjs-metrics/src/metrics.module.ts @@ -0,0 +1,79 @@ +import { Module, DynamicModule, MiddlewareConsumer, NestModule } from '@nestjs/common'; +import { MetricsService, MetricsServiceOptions } from './metrics.service'; +import { MetricsMiddleware } from './metrics.middleware'; +import { MetricsController } from './metrics.controller'; + +export interface MetricsModuleOptions extends MetricsServiceOptions { + /** + * Path for metrics endpoint (default: '/metrics') + */ + path?: string; + + /** + * Paths to exclude from metrics collection + */ + excludePaths?: string[]; + + /** + * Whether to register the metrics endpoint controller (default: true) + */ + registerController?: boolean; +} + +@Module({}) +export class MetricsModule implements NestModule { + private static options: MetricsModuleOptions = {}; + + /** + * Register the metrics module with options + * + * @example + * ```typescript + * import { MetricsModule } from '@manacore/shared-nestjs-metrics'; + * + * @Module({ + * imports: [ + * MetricsModule.register({ + * prefix: 'myapp_', + * defaultLabels: { app: 'my-backend' }, + * }), + * ], + * }) + * export class AppModule {} + * ``` + */ + static register(options: MetricsModuleOptions = {}): DynamicModule { + MetricsModule.options = options; + + const providers = [ + { + provide: MetricsService, + useFactory: () => new MetricsService(options), + }, + MetricsMiddleware, + ]; + + const controllers = options.registerController !== false ? [MetricsController] : []; + + return { + module: MetricsModule, + controllers, + providers, + exports: [MetricsService], + global: true, + }; + } + + configure(consumer: MiddlewareConsumer) { + const excludePaths = MetricsModule.options.excludePaths || []; + const metricsPath = MetricsModule.options.path || '/metrics'; + + // Always exclude the metrics endpoint itself + const allExcludePaths = [...excludePaths, metricsPath]; + + consumer + .apply(MetricsMiddleware) + .exclude(...allExcludePaths) + .forRoutes('*'); + } +} diff --git a/packages/shared-nestjs-metrics/src/metrics.service.ts b/packages/shared-nestjs-metrics/src/metrics.service.ts new file mode 100644 index 000000000..6201cdba0 --- /dev/null +++ b/packages/shared-nestjs-metrics/src/metrics.service.ts @@ -0,0 +1,173 @@ +import { Injectable, OnModuleInit } from '@nestjs/common'; +import { Registry, Counter, Histogram, Gauge, collectDefaultMetrics, register } from 'prom-client'; + +export interface MetricsServiceOptions { + prefix?: string; + defaultLabels?: Record; + collectDefaultMetrics?: boolean; +} + +@Injectable() +export class MetricsService implements OnModuleInit { + private readonly registry: Registry; + private readonly httpRequestsTotal: Counter; + private readonly httpRequestDuration: Histogram; + private readonly httpRequestsInFlight: Gauge; + + constructor(private readonly options: MetricsServiceOptions = {}) { + this.registry = register; + + const prefix = options.prefix || ''; + + // Set default labels if provided + if (options.defaultLabels) { + this.registry.setDefaultLabels(options.defaultLabels); + } + + // HTTP Request Counter + this.httpRequestsTotal = new Counter({ + name: `${prefix}http_requests_total`, + help: 'Total number of HTTP requests', + labelNames: ['method', 'path', 'status'], + registers: [this.registry], + }); + + // HTTP Request Duration Histogram + this.httpRequestDuration = new Histogram({ + name: `${prefix}http_request_duration_seconds`, + help: 'HTTP request duration in seconds', + labelNames: ['method', 'path', 'status'], + buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10], + registers: [this.registry], + }); + + // HTTP Requests In Flight + this.httpRequestsInFlight = new Gauge({ + name: `${prefix}http_requests_in_flight`, + help: 'Number of HTTP requests currently being processed', + labelNames: ['method'], + registers: [this.registry], + }); + } + + onModuleInit() { + // Collect default Node.js metrics (CPU, memory, event loop, etc.) + if (this.options.collectDefaultMetrics !== false) { + collectDefaultMetrics({ + register: this.registry, + prefix: this.options.prefix || '', + }); + } + } + + /** + * Increment HTTP request counter + */ + incrementHttpRequests(method: string, path: string, status: number): void { + this.httpRequestsTotal.inc({ + method, + path: this.normalizePath(path), + status: String(status), + }); + } + + /** + * Observe HTTP request duration + */ + observeHttpDuration(method: string, path: string, status: number, durationMs: number): void { + this.httpRequestDuration.observe( + { + method, + path: this.normalizePath(path), + status: String(status), + }, + durationMs / 1000 // Convert to seconds + ); + } + + /** + * Increment in-flight requests + */ + incrementInFlight(method: string): void { + this.httpRequestsInFlight.inc({ method }); + } + + /** + * Decrement in-flight requests + */ + decrementInFlight(method: string): void { + this.httpRequestsInFlight.dec({ method }); + } + + /** + * Get all metrics as Prometheus text format + */ + async getMetrics(): Promise { + return this.registry.metrics(); + } + + /** + * Get content type for metrics endpoint + */ + getContentType(): string { + return this.registry.contentType; + } + + /** + * Create a custom counter + */ + createCounter(name: string, help: string, labelNames: string[] = []): Counter { + return new Counter({ + name: this.options.prefix ? `${this.options.prefix}${name}` : name, + help, + labelNames, + registers: [this.registry], + }); + } + + /** + * Create a custom histogram + */ + createHistogram( + name: string, + help: string, + labelNames: string[] = [], + buckets?: number[] + ): Histogram { + return new Histogram({ + name: this.options.prefix ? `${this.options.prefix}${name}` : name, + help, + labelNames, + buckets, + registers: [this.registry], + }); + } + + /** + * Create a custom gauge + */ + createGauge(name: string, help: string, labelNames: string[] = []): Gauge { + return new Gauge({ + name: this.options.prefix ? `${this.options.prefix}${name}` : name, + help, + labelNames, + registers: [this.registry], + }); + } + + /** + * Normalize path to prevent high cardinality + * Replaces UUIDs and numeric IDs with placeholders + */ + private normalizePath(path: string): string { + return ( + path + // Replace UUIDs + .replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, ':id') + // Replace numeric IDs + .replace(/\/\d+/g, '/:id') + // Remove query strings + .split('?')[0] + ); + } +} diff --git a/packages/shared-nestjs-metrics/tsconfig.json b/packages/shared-nestjs-metrics/tsconfig.json new file mode 100644 index 000000000..9b4b43f08 --- /dev/null +++ b/packages/shared-nestjs-metrics/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2021", + "module": "CommonJS", + "lib": ["ES2021"], + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 31c8c4534..38bbff977 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -116,7 +116,7 @@ importers: devDependencies: '@nestjs/cli': specifier: ^10.4.9 - version: 10.4.9(esbuild@0.19.12) + version: 10.4.9(esbuild@0.27.0) '@nestjs/schematics': specifier: ^10.2.3 version: 10.2.3(chokidar@3.6.0)(typescript@5.9.3) @@ -149,7 +149,7 @@ importers: version: 0.5.21 ts-loader: specifier: ^9.5.1 - version: 9.5.4(typescript@5.9.3)(webpack@5.97.1(esbuild@0.19.12)) + version: 9.5.4(typescript@5.9.3)(webpack@5.97.1(esbuild@0.27.0)) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@22.19.1)(typescript@5.9.3) @@ -173,14 +173,14 @@ importers: version: link:../../../../packages/shared-landing-ui astro: specifier: ^5.16.0 - version: 5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + version: 5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) typescript: specifier: ^5.9.2 version: 5.9.3 devDependencies: '@astrojs/tailwind': specifier: ^6.0.2 - version: 6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + version: 6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) '@tailwindcss/typography': specifier: ^0.5.18 version: 0.5.19(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1)) @@ -189,13 +189,13 @@ importers: version: 20.19.25 eslint: specifier: ^9.0.0 - version: 9.39.1(jiti@1.21.7) + version: 9.39.1(jiti@2.6.1) eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.2(eslint@9.39.1(jiti@1.21.7)) + version: 9.1.2(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-astro: specifier: ^1.0.0 - version: 1.5.0(eslint@9.39.1(jiti@1.21.7)) + version: 1.5.0(eslint@9.39.1(jiti@2.6.1)) prettier: specifier: ^3.6.2 version: 3.6.2 @@ -552,19 +552,19 @@ importers: version: 18.3.27 '@typescript-eslint/eslint-plugin': specifier: ^7.7.0 - version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) + version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) '@typescript-eslint/parser': specifier: ^7.7.0 - version: 7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) + version: 7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) dotenv: specifier: ^16.4.7 version: 16.6.1 eslint: specifier: ^9.39.1 - version: 9.39.1(jiti@2.6.1) + version: 9.39.1(jiti@1.21.7) eslint-config-universe: specifier: ^12.0.1 - version: 12.1.0(@types/eslint@9.6.1)(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2)(typescript@5.3.3) + version: 12.1.0(@types/eslint@9.6.1)(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2)(typescript@5.3.3) prettier: specifier: ^3.2.5 version: 3.6.2 @@ -3430,6 +3430,28 @@ importers: specifier: ^5.0.0 version: 5.9.3 + packages/shared-nestjs-metrics: + dependencies: + prom-client: + specifier: ^15.1.0 + version: 15.1.3 + devDependencies: + '@nestjs/common': + specifier: ^10.0.0 + version: 10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^10.0.0 + version: 10.4.20(@nestjs/common@10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@10.4.20)(@nestjs/websockets@10.4.20)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@types/express': + specifier: ^4.17.21 + version: 4.17.25 + '@types/node': + specifier: ^20.0.0 + version: 20.19.25 + typescript: + specifier: ^5.0.0 + version: 5.9.3 + packages/shared-profile-ui: devDependencies: svelte: @@ -3738,7 +3760,7 @@ importers: devDependencies: '@nestjs/cli': specifier: ^11.0.0 - version: 11.0.12(@types/node@22.19.1) + version: 11.0.12(@types/node@22.19.1)(esbuild@0.19.12) '@nestjs/schematics': specifier: ^11.0.0 version: 11.0.9(chokidar@4.0.3)(typescript@5.9.3) @@ -3792,10 +3814,10 @@ importers: version: 7.1.4 ts-jest: specifier: ^29.2.5 - version: 29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest-util@30.2.0)(jest@29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(esbuild@0.19.12)(jest-util@30.2.0)(jest@29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(typescript@5.9.3) ts-loader: specifier: ^9.5.1 - version: 9.5.4(typescript@5.9.3)(webpack@5.100.2) + version: 9.5.4(typescript@5.9.3)(webpack@5.100.2(esbuild@0.19.12)) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@22.19.1)(typescript@5.9.3) @@ -5992,7 +6014,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {'0': node >=0.10.0} + engines: {node: '>=0.10.0'} '@expo/cli@0.22.26': resolution: {integrity: sha512-I689wc8Fn/AX7aUGiwrh3HnssiORMJtR2fpksX+JIe8Cj/EDleblYMSwRPd0025wrwOV9UN1KM/RuEt/QjCS3Q==} @@ -8838,9 +8860,15 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/express-serve-static-core@4.19.8': + resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} + '@types/express-serve-static-core@5.1.0': resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==} + '@types/express@4.17.25': + resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} + '@types/express@5.0.5': resolution: {integrity: sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==} @@ -10097,6 +10125,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + bintrees@1.0.2: + resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -15823,6 +15854,10 @@ packages: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} + prom-client@15.1.3: + resolution: {integrity: sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==} + engines: {node: ^16 || ^18 || >=20} + promise@7.3.1: resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} @@ -17152,6 +17187,9 @@ packages: resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} engines: {node: '>=18'} + tdigest@0.1.2: + resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==} + temp-dir@2.0.0: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} engines: {node: '>=8'} @@ -18246,6 +18284,7 @@ packages: whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} @@ -18840,16 +18879,6 @@ snapshots: transitivePeerDependencies: - ts-node - '@astrojs/tailwind@6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))': - dependencies: - astro: 5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) - autoprefixer: 10.4.22(postcss@8.5.6) - postcss: 8.5.6 - postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) - tailwindcss: 3.4.18(tsx@4.20.6)(yaml@2.8.1) - transitivePeerDependencies: - - ts-node - '@astrojs/tailwind@6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))': dependencies: astro: 5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) @@ -21498,7 +21527,7 @@ snapshots: wrap-ansi: 7.0.0 ws: 8.18.3 optionalDependencies: - expo-router: 6.0.15(nttrd3tw67nnyhowcwgdzipb5e) + expo-router: 6.0.15(dux2nvtiztnejw7mxzfaajqvh4) react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0) transitivePeerDependencies: - '@modelcontextprotocol/sdk' @@ -22797,43 +22826,6 @@ snapshots: - supports-color - ts-node - '@jest/core@30.2.0(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3))': - dependencies: - '@jest/console': 30.2.0 - '@jest/pattern': 30.0.1 - '@jest/reporters': 30.2.0 - '@jest/test-result': 30.2.0 - '@jest/transform': 30.2.0 - '@jest/types': 30.2.0 - '@types/node': 22.19.1 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 4.3.1 - exit-x: 0.2.2 - graceful-fs: 4.2.11 - jest-changed-files: 30.2.0 - jest-config: 30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) - jest-haste-map: 30.2.0 - jest-message-util: 30.2.0 - jest-regex-util: 30.0.1 - jest-resolve: 30.2.0 - jest-resolve-dependencies: 30.2.0 - jest-runner: 30.2.0 - jest-runtime: 30.2.0 - jest-snapshot: 30.2.0 - jest-util: 30.2.0 - jest-validate: 30.2.0 - jest-watcher: 30.2.0 - micromatch: 4.0.8 - pretty-format: 30.2.0 - slash: 3.0.0 - transitivePeerDependencies: - - babel-plugin-macros - - esbuild-register - - supports-color - - ts-node - optional: true - '@jest/core@30.2.0(esbuild-register@3.6.0(esbuild@0.27.0))': dependencies: '@jest/console': 30.2.0 @@ -23232,32 +23224,6 @@ snapshots: axios: 1.13.2 rxjs: 7.8.2 - '@nestjs/cli@10.4.9(esbuild@0.19.12)': - dependencies: - '@angular-devkit/core': 17.3.11(chokidar@3.6.0) - '@angular-devkit/schematics': 17.3.11(chokidar@3.6.0) - '@angular-devkit/schematics-cli': 17.3.11(chokidar@3.6.0) - '@nestjs/schematics': 10.2.3(chokidar@3.6.0)(typescript@5.7.2) - chalk: 4.1.2 - chokidar: 3.6.0 - cli-table3: 0.6.5 - commander: 4.1.1 - fork-ts-checker-webpack-plugin: 9.0.2(typescript@5.7.2)(webpack@5.97.1(esbuild@0.19.12)) - glob: 10.4.5 - inquirer: 8.2.6 - node-emoji: 1.11.0 - ora: 5.4.1 - tree-kill: 1.2.2 - tsconfig-paths: 4.2.0 - tsconfig-paths-webpack-plugin: 4.2.0 - typescript: 5.7.2 - webpack: 5.97.1(esbuild@0.19.12) - webpack-node-externals: 3.0.0 - transitivePeerDependencies: - - esbuild - - uglify-js - - webpack-cli - '@nestjs/cli@10.4.9(esbuild@0.27.0)': dependencies: '@angular-devkit/core': 17.3.11(chokidar@3.6.0) @@ -23284,7 +23250,7 @@ snapshots: - uglify-js - webpack-cli - '@nestjs/cli@11.0.12(@types/node@22.19.1)': + '@nestjs/cli@11.0.12(@types/node@22.19.1)(esbuild@0.19.12)': dependencies: '@angular-devkit/core': 19.2.19(chokidar@4.0.3) '@angular-devkit/schematics': 19.2.19(chokidar@4.0.3) @@ -23295,14 +23261,14 @@ snapshots: chokidar: 4.0.3 cli-table3: 0.6.5 commander: 4.1.1 - fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.100.2) + fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.100.2(esbuild@0.19.12)) glob: 12.0.0 node-emoji: 1.11.0 ora: 5.4.1 tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.2.0 typescript: 5.9.3 - webpack: 5.100.2 + webpack: 5.100.2(esbuild@0.19.12) webpack-node-externals: 3.0.0 transitivePeerDependencies: - '@types/node' @@ -23636,8 +23602,7 @@ snapshots: '@opentelemetry/api': 1.9.0 optional: true - '@opentelemetry/api@1.9.0': - optional: true + '@opentelemetry/api@1.9.0': {} '@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0)': dependencies: @@ -26071,19 +26036,6 @@ snapshots: jest: 30.2.0(@types/node@20.19.25)(esbuild-register@3.6.0(esbuild@0.27.0)) optional: true - '@testing-library/react-native@13.3.3(jest@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - jest-matcher-utils: 30.2.0 - picocolors: 1.1.1 - pretty-format: 30.2.0 - react: 19.1.0 - react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0) - react-test-renderer: 19.1.0(react@19.1.0) - redent: 3.0.0 - optionalDependencies: - jest: 30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) - optional: true - '@testing-library/react-native@13.3.3(jest@30.2.0(esbuild-register@3.6.0(esbuild@0.27.0)))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: jest-matcher-utils: 30.2.0 @@ -26351,6 +26303,13 @@ snapshots: '@types/estree@1.0.8': {} + '@types/express-serve-static-core@4.19.8': + dependencies: + '@types/node': 22.19.1 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + '@types/send': 1.2.1 + '@types/express-serve-static-core@5.1.0': dependencies: '@types/node': 22.19.1 @@ -26358,6 +26317,13 @@ snapshots: '@types/range-parser': 1.2.7 '@types/send': 1.2.1 + '@types/express@4.17.25': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 4.19.8 + '@types/qs': 6.14.0 + '@types/serve-static': 1.15.10 + '@types/express@5.0.5': dependencies: '@types/body-parser': 1.19.6 @@ -26579,16 +26545,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)': + '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) + '@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) - '@typescript-eslint/utils': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) + '@typescript-eslint/type-utils': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) + '@typescript-eslint/utils': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.1(jiti@1.21.7) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -26637,15 +26603,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)': + '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) + '@typescript-eslint/parser': 7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/type-utils': 7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) - '@typescript-eslint/utils': 7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) + '@typescript-eslint/type-utils': 7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) + '@typescript-eslint/utils': 7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) '@typescript-eslint/visitor-keys': 7.18.0 - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.1(jiti@1.21.7) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -26737,14 +26703,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)': + '@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)': dependencies: '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.1(jiti@1.21.7) optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: @@ -26776,14 +26742,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)': + '@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)': dependencies: '@typescript-eslint/scope-manager': 7.18.0 '@typescript-eslint/types': 7.18.0 '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.3.3) '@typescript-eslint/visitor-keys': 7.18.0 debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.1(jiti@1.21.7) optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: @@ -26909,12 +26875,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)': + '@typescript-eslint/type-utils@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)': dependencies: '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) - '@typescript-eslint/utils': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) + '@typescript-eslint/utils': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.1(jiti@1.21.7) ts-api-utils: 1.4.3(typescript@5.3.3) optionalDependencies: typescript: 5.3.3 @@ -26945,12 +26911,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)': + '@typescript-eslint/type-utils@7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)': dependencies: '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.3.3) - '@typescript-eslint/utils': 7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) + '@typescript-eslint/utils': 7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.1(jiti@1.21.7) ts-api-utils: 1.4.3(typescript@5.3.3) optionalDependencies: typescript: 5.3.3 @@ -27132,15 +27098,15 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)': + '@typescript-eslint/utils@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7)) '@types/json-schema': 7.0.15 '@types/semver': 7.7.1 '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.1(jiti@1.21.7) semver: 7.7.3 transitivePeerDependencies: - supports-color @@ -27171,13 +27137,13 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)': + '@typescript-eslint/utils@7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7)) '@typescript-eslint/scope-manager': 7.18.0 '@typescript-eslint/types': 7.18.0 '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.3.3) - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.1(jiti@1.21.7) transitivePeerDependencies: - supports-color - typescript @@ -27968,108 +27934,6 @@ snapshots: transitivePeerDependencies: - supports-color - astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1): - dependencies: - '@astrojs/compiler': 2.13.0 - '@astrojs/internal-helpers': 0.7.5 - '@astrojs/markdown-remark': 6.3.9 - '@astrojs/telemetry': 3.3.0 - '@capsizecss/unpack': 3.0.1 - '@oslojs/encoding': 1.1.0 - '@rollup/pluginutils': 5.3.0(rollup@4.53.3) - acorn: 8.15.0 - aria-query: 5.3.2 - axobject-query: 4.1.0 - boxen: 8.0.1 - ci-info: 4.3.1 - clsx: 2.1.1 - common-ancestor-path: 1.0.1 - cookie: 1.1.0 - cssesc: 3.0.0 - debug: 4.4.3 - deterministic-object-hash: 2.0.2 - devalue: 5.5.0 - diff: 5.2.0 - dlv: 1.1.3 - dset: 3.1.4 - es-module-lexer: 1.7.0 - esbuild: 0.25.12 - estree-walker: 3.0.3 - flattie: 1.1.1 - fontace: 0.3.1 - github-slugger: 2.0.0 - html-escaper: 3.0.3 - http-cache-semantics: 4.2.0 - import-meta-resolve: 4.2.0 - js-yaml: 4.1.1 - magic-string: 0.30.21 - magicast: 0.5.1 - mrmime: 2.0.1 - neotraverse: 0.6.18 - p-limit: 6.2.0 - p-queue: 8.1.1 - package-manager-detector: 1.5.0 - piccolore: 0.1.3 - picomatch: 4.0.3 - prompts: 2.4.2 - rehype: 13.0.2 - semver: 7.7.3 - shiki: 3.15.0 - smol-toml: 1.5.2 - svgo: 4.0.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tsconfck: 3.1.6(typescript@5.9.3) - ultrahtml: 1.6.0 - unifont: 0.6.0 - unist-util-visit: 5.0.0 - unstorage: 1.17.3(@netlify/blobs@10.4.1)(ioredis@5.8.2) - vfile: 6.0.3 - vite: 6.4.1(@types/node@20.19.25)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) - vitefu: 1.1.1(vite@6.4.1(@types/node@20.19.25)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) - xxhash-wasm: 1.1.0 - yargs-parser: 21.1.1 - yocto-spinner: 0.2.3 - zod: 3.25.76 - zod-to-json-schema: 3.25.0(zod@3.25.76) - zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76) - optionalDependencies: - sharp: 0.34.5 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@types/node' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - db0 - - idb-keyval - - ioredis - - jiti - - less - - lightningcss - - rollup - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - typescript - - uploadthing - - yaml - astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1): dependencies: '@astrojs/compiler': 2.13.0 @@ -28646,6 +28510,8 @@ snapshots: binary-extensions@2.3.0: {} + bintrees@1.0.2: {} + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -30320,11 +30186,6 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-compat-utils@0.6.5(eslint@9.39.1(jiti@1.21.7)): - dependencies: - eslint: 9.39.1(jiti@1.21.7) - semver: 7.7.3 - eslint-compat-utils@0.6.5(eslint@9.39.1(jiti@2.6.1)): dependencies: eslint: 9.39.1(jiti@2.6.1) @@ -30335,9 +30196,9 @@ snapshots: '@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.1(jiti@2.6.1) - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-expo: 1.0.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@2.6.1)) globals: 16.5.0 @@ -30352,9 +30213,9 @@ snapshots: '@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3) '@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3) eslint: 9.39.1(jiti@2.6.1) - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-expo: 0.1.4(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@2.6.1)) globals: 16.5.0 @@ -30372,14 +30233,14 @@ snapshots: dependencies: eslint: 8.57.1 + eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@1.21.7)): + dependencies: + eslint: 9.39.1(jiti@1.21.7) + eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@2.6.1)): dependencies: eslint: 9.39.1(jiti@2.6.1) - eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@1.21.7)): - dependencies: - eslint: 9.39.1(jiti@1.21.7) - eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@2.6.1)): dependencies: eslint: 9.39.1(jiti@2.6.1) @@ -30404,17 +30265,17 @@ snapshots: - supports-color - typescript - eslint-config-universe@12.1.0(@types/eslint@9.6.1)(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2)(typescript@5.3.3): + eslint-config-universe@12.1.0(@types/eslint@9.6.1)(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2)(typescript@5.3.3): dependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) - '@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) - eslint: 9.39.1(jiti@2.6.1) - eslint-config-prettier: 8.10.2(eslint@9.39.1(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1)) - eslint-plugin-node: 11.1.0(eslint@9.39.1(jiti@2.6.1)) - eslint-plugin-prettier: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2) - eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1)) - eslint-plugin-react-hooks: 4.6.2(eslint@9.39.1(jiti@2.6.1)) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) + '@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) + eslint: 9.39.1(jiti@1.21.7) + eslint-config-prettier: 8.10.2(eslint@9.39.1(jiti@1.21.7)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7)) + eslint-plugin-node: 11.1.0(eslint@9.39.1(jiti@1.21.7)) + eslint-plugin-prettier: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2) + eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@1.21.7)) + eslint-plugin-react-hooks: 4.6.2(eslint@9.39.1(jiti@1.21.7)) optionalDependencies: prettier: 3.6.2 transitivePeerDependencies: @@ -30452,7 +30313,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 @@ -30463,22 +30324,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) - transitivePeerDependencies: - - supports-color - - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)): - dependencies: - '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) - get-tsconfig: 4.13.0 - is-bun-module: 2.0.0 - stable-hash: 0.0.5 - tinyglobby: 0.2.15 - unrs-resolver: 1.11.1 - optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -30492,12 +30338,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@1.21.7)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) - eslint: 9.39.1(jiti@2.6.1) + '@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) + eslint: 9.39.1(jiti@1.21.7) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color @@ -30512,39 +30358,25 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3) eslint: 9.39.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)) - transitivePeerDependencies: - - supports-color - - eslint-plugin-astro@1.5.0(eslint@9.39.1(jiti@1.21.7)): - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7)) - '@jridgewell/sourcemap-codec': 1.5.5 - '@typescript-eslint/types': 8.48.0 - astro-eslint-parser: 1.2.2 - eslint: 9.39.1(jiti@1.21.7) - eslint-compat-utils: 0.6.5(eslint@9.39.1(jiti@1.21.7)) - globals: 16.5.0 - postcss: 8.5.6 - postcss-selector-parser: 7.1.0 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -30568,6 +30400,12 @@ snapshots: eslint-utils: 2.1.0 regexpp: 3.2.0 + eslint-plugin-es@3.0.1(eslint@9.39.1(jiti@1.21.7)): + dependencies: + eslint: 9.39.1(jiti@1.21.7) + eslint-utils: 2.1.0 + regexpp: 3.2.0 + eslint-plugin-es@3.0.1(eslint@9.39.1(jiti@2.6.1)): dependencies: eslint: 9.39.1(jiti@2.6.1) @@ -30621,7 +30459,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -30630,9 +30468,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.1(jiti@1.21.7) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@1.21.7)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -30644,7 +30482,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3) + '@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -30679,7 +30517,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -30690,7 +30528,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -30708,7 +30546,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -30719,7 +30557,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -30747,6 +30585,16 @@ snapshots: resolve: 1.22.11 semver: 6.3.1 + eslint-plugin-node@11.1.0(eslint@9.39.1(jiti@1.21.7)): + dependencies: + eslint: 9.39.1(jiti@1.21.7) + eslint-plugin-es: 3.0.1(eslint@9.39.1(jiti@1.21.7)) + eslint-utils: 2.1.0 + ignore: 5.3.2 + minimatch: 3.1.2 + resolve: 1.22.11 + semver: 6.3.1 + eslint-plugin-node@11.1.0(eslint@9.39.1(jiti@2.6.1)): dependencies: eslint: 9.39.1(jiti@2.6.1) @@ -30777,6 +30625,16 @@ snapshots: '@types/eslint': 9.6.1 eslint-config-prettier: 8.10.2(eslint@8.57.1) + eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2): + dependencies: + eslint: 9.39.1(jiti@1.21.7) + prettier: 3.6.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.11.11 + optionalDependencies: + '@types/eslint': 9.6.1 + eslint-config-prettier: 8.10.2(eslint@9.39.1(jiti@1.21.7)) + eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2): dependencies: eslint: 9.39.1(jiti@2.6.1) @@ -30801,6 +30659,10 @@ snapshots: dependencies: eslint: 8.57.1 + eslint-plugin-react-hooks@4.6.2(eslint@9.39.1(jiti@1.21.7)): + dependencies: + eslint: 9.39.1(jiti@1.21.7) + eslint-plugin-react-hooks@4.6.2(eslint@9.39.1(jiti@2.6.1)): dependencies: eslint: 9.39.1(jiti@2.6.1) @@ -30831,6 +30693,28 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 + eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@1.21.7)): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.39.1(jiti@1.21.7) + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@2.6.1)): dependencies: array-includes: 3.1.9 @@ -31998,53 +31882,6 @@ snapshots: - supports-color optional: true - expo-router@6.0.15(nttrd3tw67nnyhowcwgdzipb5e): - dependencies: - '@expo/metro-runtime': 6.1.2(expo@54.0.25)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - '@expo/schema-utils': 0.1.7 - '@radix-ui/react-slot': 1.2.0(@types/react@19.2.7)(react@19.1.0) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-navigation/bottom-tabs': 7.8.6(@react-navigation/native@7.1.21(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - '@react-navigation/native': 7.1.21(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - '@react-navigation/native-stack': 7.8.0(@react-navigation/native@7.1.21(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - client-only: 0.0.1 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native-webview@13.12.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - expo-constants: 18.0.10(expo@54.0.25)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0)) - expo-linking: 8.0.9(expo@54.0.25)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - expo-server: 1.0.4 - fast-deep-equal: 3.1.3 - invariant: 2.2.4 - nanoid: 3.3.11 - query-string: 7.1.3 - react: 19.1.0 - react-fast-compare: 3.2.2 - react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0) - react-native-is-edge-to-edge: 1.2.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - react-native-safe-area-context: 5.6.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - react-native-screens: 4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - semver: 7.6.3 - server-only: 0.0.1 - sf-symbols-typescript: 2.1.0 - shallowequal: 1.1.0 - use-latest-callback: 0.2.6(react@19.1.0) - vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - optionalDependencies: - '@react-navigation/drawer': 7.7.4(@react-navigation/native@7.1.21(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@0.6.1(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - '@testing-library/react-native': 13.3.3(jest@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0) - react-dom: 19.1.0(react@19.1.0) - react-native-gesture-handler: 2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - react-native-reanimated: 4.1.5(@babel/core@7.28.5)(react-native-worklets@0.6.1(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) - react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - react-server-dom-webpack: 19.0.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(webpack@5.97.1(esbuild@0.19.12)) - transitivePeerDependencies: - - '@react-native-masked-view/masked-view' - - '@types/react' - - '@types/react-dom' - - supports-color - optional: true - expo-router@6.0.15(qjp3usx4acoq47dkosl6pmu254): dependencies: '@expo/metro-runtime': 6.1.2(expo@54.0.13)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0) @@ -32895,23 +32732,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@9.0.2(typescript@5.7.2)(webpack@5.97.1(esbuild@0.19.12)): - dependencies: - '@babel/code-frame': 7.27.1 - chalk: 4.1.2 - chokidar: 3.6.0 - cosmiconfig: 8.3.6(typescript@5.7.2) - deepmerge: 4.3.1 - fs-extra: 10.1.0 - memfs: 3.5.3 - minimatch: 3.1.2 - node-abort-controller: 3.1.1 - schema-utils: 3.3.0 - semver: 7.7.3 - tapable: 2.3.0 - typescript: 5.7.2 - webpack: 5.97.1(esbuild@0.19.12) - fork-ts-checker-webpack-plugin@9.0.2(typescript@5.7.2)(webpack@5.97.1(esbuild@0.27.0)): dependencies: '@babel/code-frame': 7.27.1 @@ -32929,6 +32749,23 @@ snapshots: typescript: 5.7.2 webpack: 5.97.1(esbuild@0.27.0) + fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.100.2(esbuild@0.19.12)): + dependencies: + '@babel/code-frame': 7.27.1 + chalk: 4.1.2 + chokidar: 4.0.3 + cosmiconfig: 8.3.6(typescript@5.9.3) + deepmerge: 4.3.1 + fs-extra: 10.1.0 + memfs: 3.5.3 + minimatch: 3.1.2 + node-abort-controller: 3.1.1 + schema-utils: 3.3.0 + semver: 7.7.3 + tapable: 2.3.0 + typescript: 5.9.3 + webpack: 5.100.2(esbuild@0.19.12) + fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.100.2(esbuild@0.27.0)): dependencies: '@babel/code-frame': 7.27.1 @@ -32946,23 +32783,6 @@ snapshots: typescript: 5.9.3 webpack: 5.100.2(esbuild@0.27.0) - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.100.2): - dependencies: - '@babel/code-frame': 7.27.1 - chalk: 4.1.2 - chokidar: 4.0.3 - cosmiconfig: 8.3.6(typescript@5.9.3) - deepmerge: 4.3.1 - fs-extra: 10.1.0 - memfs: 3.5.3 - minimatch: 3.1.2 - node-abort-controller: 3.1.1 - schema-utils: 3.3.0 - semver: 7.7.3 - tapable: 2.3.0 - typescript: 5.9.3 - webpack: 5.100.2 - form-data-encoder@1.7.2: {} form-data@3.0.4: @@ -34159,26 +33979,6 @@ snapshots: - ts-node optional: true - jest-cli@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)): - dependencies: - '@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) - '@jest/test-result': 30.2.0 - '@jest/types': 30.2.0 - chalk: 4.1.2 - exit-x: 0.2.2 - import-local: 3.2.0 - jest-config: 30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) - jest-util: 30.2.0 - jest-validate: 30.2.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - esbuild-register - - supports-color - - ts-node - optional: true - jest-cli@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.27.0)): dependencies: '@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.27.0)) @@ -34364,41 +34164,6 @@ snapshots: - supports-color optional: true - jest-config@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)): - dependencies: - '@babel/core': 7.28.5 - '@jest/get-type': 30.1.0 - '@jest/pattern': 30.0.1 - '@jest/test-sequencer': 30.2.0 - '@jest/types': 30.2.0 - babel-jest: 30.2.0(@babel/core@7.28.5) - chalk: 4.1.2 - ci-info: 4.3.1 - deepmerge: 4.3.1 - glob: 10.5.0 - graceful-fs: 4.2.11 - jest-circus: 30.2.0 - jest-docblock: 30.2.0 - jest-environment-node: 30.2.0 - jest-regex-util: 30.0.1 - jest-resolve: 30.2.0 - jest-runner: 30.2.0 - jest-util: 30.2.0 - jest-validate: 30.2.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 30.2.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 22.19.1 - esbuild-register: 3.6.0(esbuild@0.19.12) - ts-node: 10.9.2(@types/node@22.19.1)(typescript@5.9.3) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - optional: true - jest-config@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.27.0)): dependencies: '@babel/core': 7.28.5 @@ -34973,20 +34738,6 @@ snapshots: - ts-node optional: true - jest@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)): - dependencies: - '@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) - '@jest/types': 30.2.0 - import-local: 3.2.0 - jest-cli: 30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - esbuild-register - - supports-color - - ts-node - optional: true - jest@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.27.0)): dependencies: '@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.27.0)) @@ -37574,6 +37325,11 @@ snapshots: progress@2.0.3: {} + prom-client@15.1.3: + dependencies: + '@opentelemetry/api': 1.9.0 + tdigest: 0.1.2 + promise@7.3.1: dependencies: asap: 2.0.6 @@ -38787,16 +38543,6 @@ snapshots: webpack-sources: 3.3.3 optional: true - react-server-dom-webpack@19.0.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(webpack@5.97.1(esbuild@0.19.12)): - dependencies: - acorn-loose: 8.5.2 - neo-async: 2.6.2 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - webpack: 5.97.1(esbuild@0.19.12) - webpack-sources: 3.3.3 - optional: true - react-style-singleton@2.2.3(@types/react@18.3.27)(react@18.3.1): dependencies: get-nonce: 1.0.1 @@ -40027,6 +39773,10 @@ snapshots: minizlib: 3.1.0 yallist: 5.0.0 + tdigest@0.1.2: + dependencies: + bintrees: 1.0.2 + temp-dir@2.0.0: {} temp@0.8.4: @@ -40046,14 +39796,14 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser-webpack-plugin@5.3.14(esbuild@0.19.12)(webpack@5.97.1(esbuild@0.19.12)): + terser-webpack-plugin@5.3.14(esbuild@0.19.12)(webpack@5.100.2(esbuild@0.19.12)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.44.1 - webpack: 5.97.1(esbuild@0.19.12) + webpack: 5.100.2(esbuild@0.19.12) optionalDependencies: esbuild: 0.19.12 @@ -40079,15 +39829,6 @@ snapshots: optionalDependencies: esbuild: 0.27.0 - terser-webpack-plugin@5.3.14(webpack@5.100.2): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - terser: 5.44.1 - webpack: 5.100.2 - terser@5.44.1: dependencies: '@jridgewell/source-map': 0.3.11 @@ -40225,6 +39966,27 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-jest@29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(esbuild@0.19.12)(jest-util@30.2.0)(jest@29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(typescript@5.9.3): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + handlebars: 4.7.8 + jest: 29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.3 + type-fest: 4.41.0 + typescript: 5.9.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.28.5 + '@jest/transform': 30.2.0 + '@jest/types': 30.2.0 + babel-jest: 30.2.0(@babel/core@7.28.5) + esbuild: 0.19.12 + jest-util: 30.2.0 + ts-jest@29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(esbuild@0.27.0)(jest-util@30.2.0)(jest@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.27.0))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 @@ -40267,25 +40029,15 @@ snapshots: esbuild: 0.27.0 jest-util: 30.2.0 - ts-jest@29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest-util@30.2.0)(jest@29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(typescript@5.9.3): + ts-loader@9.5.4(typescript@5.9.3)(webpack@5.100.2(esbuild@0.19.12)): dependencies: - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - handlebars: 4.7.8 - jest: 29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 + chalk: 4.1.2 + enhanced-resolve: 5.18.3 + micromatch: 4.0.8 semver: 7.7.3 - type-fest: 4.41.0 + source-map: 0.7.6 typescript: 5.9.3 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.28.5 - '@jest/transform': 30.2.0 - '@jest/types': 30.2.0 - babel-jest: 30.2.0(@babel/core@7.28.5) - jest-util: 30.2.0 + webpack: 5.100.2(esbuild@0.19.12) ts-loader@9.5.4(typescript@5.9.3)(webpack@5.100.2(esbuild@0.27.0)): dependencies: @@ -40297,7 +40049,7 @@ snapshots: typescript: 5.9.3 webpack: 5.100.2(esbuild@0.27.0) - ts-loader@9.5.4(typescript@5.9.3)(webpack@5.100.2): + ts-loader@9.5.4(typescript@5.9.3)(webpack@5.97.1(esbuild@0.27.0)): dependencies: chalk: 4.1.2 enhanced-resolve: 5.18.3 @@ -40305,17 +40057,7 @@ snapshots: semver: 7.7.3 source-map: 0.7.6 typescript: 5.9.3 - webpack: 5.100.2 - - ts-loader@9.5.4(typescript@5.9.3)(webpack@5.97.1(esbuild@0.19.12)): - dependencies: - chalk: 4.1.2 - enhanced-resolve: 5.18.3 - micromatch: 4.0.8 - semver: 7.7.3 - source-map: 0.7.6 - typescript: 5.9.3 - webpack: 5.97.1(esbuild@0.19.12) + webpack: 5.97.1(esbuild@0.27.0) ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3): dependencies: @@ -40916,23 +40658,6 @@ snapshots: lightningcss: 1.30.2 terser: 5.44.1 - vite@6.4.1(@types/node@20.19.25)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): - dependencies: - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.53.3 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 20.19.25 - fsevents: 2.3.3 - jiti: 1.21.7 - lightningcss: 1.30.2 - terser: 5.44.1 - tsx: 4.20.6 - yaml: 2.8.1 - vite@6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.25.12 @@ -41035,10 +40760,6 @@ snapshots: tsx: 4.20.6 yaml: 2.8.1 - vitefu@1.1.1(vite@6.4.1(@types/node@20.19.25)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)): - optionalDependencies: - vite: 6.4.1(@types/node@20.19.25)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) - vitefu@1.1.1(vite@6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)): optionalDependencies: vite: 6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) @@ -41289,7 +41010,7 @@ snapshots: webpack-sources@3.3.3: {} - webpack@5.100.2: + webpack@5.100.2(esbuild@0.19.12): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -41313,7 +41034,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(webpack@5.100.2) + terser-webpack-plugin: 5.3.14(esbuild@0.19.12)(webpack@5.100.2(esbuild@0.19.12)) watchpack: 2.4.4 webpack-sources: 3.3.3 transitivePeerDependencies: @@ -41353,36 +41074,6 @@ snapshots: - esbuild - uglify-js - webpack@5.97.1(esbuild@0.19.12): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - browserslist: 4.28.0 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.3 - es-module-lexer: 1.7.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 3.3.0 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(esbuild@0.19.12)(webpack@5.97.1(esbuild@0.19.12)) - watchpack: 2.4.4 - webpack-sources: 3.3.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - webpack@5.97.1(esbuild@0.27.0): dependencies: '@types/eslint-scope': 3.7.7 diff --git a/scripts/mac-mini/setup-umami-db.sh b/scripts/mac-mini/setup-umami-db.sh new file mode 100755 index 000000000..5e4cb7203 --- /dev/null +++ b/scripts/mac-mini/setup-umami-db.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Setup Umami database on Mac Mini +# Run this script after starting PostgreSQL container + +set -e + +echo "Creating Umami database..." + +# Check if running inside docker network or from host +if docker ps | grep -q manacore-postgres; then + docker exec -i manacore-postgres psql -U postgres <