diff --git a/.gitignore b/.gitignore index 9e0c207..72e7307 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ build/ .env .DS_Store *.log +scripts/ # Local Android SDK path — machine-specific android/local.properties diff --git a/PLAN.md b/PLAN.md index ab6af64..bb888d5 100644 --- a/PLAN.md +++ b/PLAN.md @@ -1,363 +1,276 @@ -# FarmaFinder — Feature Plan +# Monitoring Integration Plan for Pharmacy Integration Platform (PIP) -## Overview +This document outlines how to integrate the PIP application with an existing Prometheus/Grafana/Alertmanager stack running on a remote host. The PIP application already exposes Prometheus metrics at `/metrics` and includes OpenTelemetry instrumentation for tracing. -Three features in recommended implementation order. Each is self-contained and can be shipped independently. +## Prerequisites ---- +1. **Running PIP instance** - The application must be accessible from the monitoring host (via network). +2. **Existing monitoring stack** - Prometheus server, Grafana, and Alertmanager already deployed and reachable. +3. **Network access** - Ensure the monitoring host can scrape the PIP application's metrics endpoint (default port 8000). +4. **Credentials** (if applicable) - Any authentication tokens or basic auth required for scraping. -## Step 1 — "Near Me" Sorting (~2 hrs) +## 1. Metrics Endpoint -### Goal -Sort pharmacy results by distance from user's current location. Works in browser today, same logic reusable in React Native later. +The PIP application exposes Prometheus-formatted metrics at: -### Backend changes -None. `latitude` and `longitude` already returned by `GET /api/medicines/:nregistro/pharmacies`. - -### Frontend changes - -**`frontend/src/utils/geo.js`** (new) -```js -export function haversineKm(lat1, lon1, lat2, lon2) { - const R = 6371; - const dLat = ((lat2 - lat1) * Math.PI) / 180; - const dLon = ((lon2 - lon1) * Math.PI) / 180; - const a = - Math.sin(dLat / 2) ** 2 + - Math.cos((lat1 * Math.PI) / 180) * - Math.cos((lat2 * Math.PI) / 180) * - Math.sin(dLon / 2) ** 2; - return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); -} - -export function getUserPosition() { - return new Promise((resolve, reject) => { - if (!navigator.geolocation) return reject(new Error('Geolocation not supported')); - navigator.geolocation.getCurrentPosition( - pos => resolve({ lat: pos.coords.latitude, lon: pos.coords.longitude }), - reject, - { timeout: 8000 } - ); - }); -} +``` +http://:8000/metrics ``` -**`frontend/src/views/PublicView.jsx`** -- Add state: `userPosition` (null | { lat, lon }), `sortByDistance` (bool) -- Add "Sort by distance" button — on click calls `getUserPosition()`, sets `userPosition`, sets `sortByDistance = true` -- Before rendering pharmacies, if `sortByDistance && userPosition`: - ```js - const sorted = [...pharmacies].sort((a, b) => { - if (!a.latitude) return 1; - if (!b.latitude) return -1; - return haversineKm(userPosition.lat, userPosition.lon, a.latitude, a.longitude) - - haversineKm(userPosition.lat, userPosition.lon, b.latitude, b.longitude); - }); - ``` -- Pass `sorted` (or original `pharmacies`) to `PharmacyList` and `PharmacyMap` +This endpoint is already mounted in the FastAPI application (see `src/main.py` line 64-65). No further changes are required unless you need to change the path or add authentication. -**`frontend/src/components/PharmacyList.jsx`** -- Accept optional `userPosition` prop -- When present and pharmacy has lat/lng, show distance badge: `1.2 km` next to pharmacy name +### Optional: Add Basic Auth to Metrics Endpoint +If your Prometheus server requires authentication, you can wrap the metrics endpoint with middleware. Example: -### Verification +```python +# In src/main.py after creating the app +from starlette.basic_auth import BasicAuthMiddleware +from src.infrastructure.config.settings import settings + +if settings.METRICS_AUTH_USERNAME and settings.METRICS_AUTH_PASSWORD: + app.add_middleware( + BasicAuthMiddleware, + username=settings.METRICS_AUTH_USERNAME, + password=settings.METRICS_AUTH_PASSWORD, + ) +``` + +Add the corresponding environment variables to your deployment. + +## 2. Prometheus Configuration + +Add a scrape job for the PIP service in your Prometheus configuration file (typically `prometheus.yml`). + +```yaml +scrape_configs: + - job_name: 'pip-api' + static_configs: + - targets: [':8000'] # replace with actual host/IP + # Optional: if you enabled basic auth on /metrics + # basic_auth: + # username: + # password: + # Optional: TLS configuration if using HTTPS + # scheme: https + # tls_config: + # ca_file: /path/to/ca.pem + # cert_file: /path/to/client-cert.pem + # key_file: /path/to/client-key.pem + metric_relabel_configs: + # Optional: filter or relabel metrics as needed + - source_labels: [__name__] + regex: 'pip_.*' + action: keep +``` + +After updating the configuration, reload Prometheus: ```bash -# Start app, search a medicine, click "Sort by distance", allow geolocation -# Pharmacies reorder, distance badges appear +curl -X POST http://:9090/-/reload ``` ---- +## 3. Grafana Dashboards -## Step 2 — Pharmacy Hours (~3 hrs) +You can import a pre-built dashboard JSON (provided below) or create your own panels using the exposed metrics. -### Goal -Store structured opening hours per pharmacy. Show "Open now" / "Closed" / "Opens at HH:MM" badge on pharmacy cards. - -### Data model - -Store hours as JSON in a single column — structured enough to parse, simple enough to edit manually in admin: +### Example Dashboard JSON +Save this as `pip-dashboard.json` and import via Grafana UI (`+ Import` → Paste JSON). ```json { - "mon": ["09:00", "21:00"], - "tue": ["09:00", "21:00"], - "wed": ["09:00", "21:00"], - "thu": ["09:00", "21:00"], - "fri": ["09:00", "21:00"], - "sat": ["09:00", "14:00"], - "sun": null -} -``` - -`null` = closed that day. 24h format strings. Only one time range per day (no split shifts) — extend later if needed. - -### Backend changes - -**`backend/server.js`** — `initDatabase()` -```sql -ALTER TABLE pharmacies ADD COLUMN opening_hours TEXT; -``` -Wrap in try/catch — `ALTER TABLE` throws if column already exists. - -**`GET /api/medicines/:nregistro/pharmacies`** — already returns `SELECT *`, no change needed. - -**`POST /api/admin/pharmacies`** and **`PUT /api/admin/pharmacies/:id`** -- Accept `opening_hours` in request body (JSON string or object) -- Serialize to string before INSERT/UPDATE: `JSON.stringify(opening_hours) || null` - -### Frontend changes - -**`frontend/src/utils/hours.js`** (new) -```js -const DAYS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']; - -export function getOpenStatus(openingHoursJson) { - if (!openingHoursJson) return null; - let hours; - try { hours = typeof openingHoursJson === 'string' ? JSON.parse(openingHoursJson) : openingHoursJson; } - catch { return null; } - - const now = new Date(); - const day = DAYS[now.getDay()]; - const range = hours[day]; - - if (!range) return { status: 'closed', label: 'Closed today' }; - - const [openStr, closeStr] = range; - const [oh, om] = openStr.split(':').map(Number); - const [ch, cm] = closeStr.split(':').map(Number); - const nowMins = now.getHours() * 60 + now.getMinutes(); - const openMins = oh * 60 + om; - const closeMins = ch * 60 + cm; - - if (nowMins < openMins) return { status: 'closed', label: `Opens at ${openStr}` }; - if (nowMins >= closeMins) return { status: 'closed', label: `Closed · Opens ${getNextOpen(hours, now)}` }; - return { status: 'open', label: `Open · Closes at ${closeStr}` }; -} -``` - -**`frontend/src/components/PharmacyList.jsx`** -- Import `getOpenStatus`, render status badge per pharmacy card -- CSS: `.badge-open { color: green }` / `.badge-closed { color: #999 }` - -**`frontend/src/components/admin/PharmacyManagement.jsx`** -- Add hours editor: 7 rows (Mon–Sun), each with two time inputs (open/close) + "Closed" checkbox -- Serialize to JSON on save - -### Verification -```bash -# Add pharmacy with hours via admin panel -# Search medicine linked to that pharmacy -# Card shows "Open · Closes at 21:00" or "Closed · Opens at 09:00" -# Change system clock or test at different times -``` - ---- - -## Step 3 — PWA + Push Notifications / Medicine Alerts (~1 day) - -### Goal -User subscribes to a medicine. When any pharmacy links that medicine (via admin panel), the user receives a push notification in the browser. Foundation reusable for React Native (swap `web-push` for FCM). - -### Architecture - -``` -User visits app - → service worker registered (PWA) - → user searches medicine, clicks "Notify me" - → browser prompts for notification permission - → browser generates push subscription (endpoint + keys) - → POST /api/notifications/subscribe { medicine_nregistro, subscription } - → stored in DB - -Admin links medicine to pharmacy (POST /api/admin/pharmacy-medicines) - → backend queries notifications table for medicine_nregistro - → fires web-push to each subscription endpoint - → user receives notification: "Ibuprofeno 400mg now available at Farmacia Sol" -``` - -### Backend changes - -**Dependencies** -```bash -npm install web-push -``` - -Generate VAPID keys (one-time, store in `.env`): -```bash -node -e "const wp = require('web-push'); const k = wp.generateVAPIDKeys(); console.log(k)" -``` -Add to `.env.example`: -``` -VAPID_PUBLIC_KEY= -VAPID_PRIVATE_KEY= -VAPID_EMAIL=mailto:admin@example.com -``` - -**`backend/server.js`** — `initDatabase()` -```sql -CREATE TABLE IF NOT EXISTS push_subscriptions ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - medicine_nregistro TEXT NOT NULL, - endpoint TEXT NOT NULL, - p256dh TEXT NOT NULL, - auth TEXT NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - UNIQUE(medicine_nregistro, endpoint) -); -``` - -**New routes** -``` -POST /api/notifications/subscribe - body: { medicine_nregistro, medicine_name, subscription: { endpoint, keys: { p256dh, auth } } } - → upsert into push_subscriptions - → 201 - -DELETE /api/notifications/unsubscribe - body: { medicine_nregistro, endpoint } - → delete from push_subscriptions - → 204 - -GET /api/notifications/vapid-public-key - → returns { publicKey: process.env.VAPID_PUBLIC_KEY } -``` - -**Hook into `POST /api/admin/pharmacy-medicines`** -After successful insert: -```js -const subs = await dbAll( - 'SELECT * FROM push_subscriptions WHERE medicine_nregistro = ?', - [medicine_nregistro] -); -for (const sub of subs) { - await webpush.sendNotification( - { endpoint: sub.endpoint, keys: { p256dh: sub.p256dh, auth: sub.auth } }, - JSON.stringify({ - title: 'Medicine available', - body: `${medicine_name} now available at ${pharmacyName}`, - url: '/' - }) - ).catch(() => { - // subscription expired — delete it - dbRun('DELETE FROM push_subscriptions WHERE id = ?', [sub.id]); - }); -} -``` - -### Frontend changes - -**Dependencies** -```bash -npm install vite-plugin-pwa -``` - -**`frontend/vite.config.js`** -```js -import { VitePWA } from 'vite-plugin-pwa'; - -// Add to plugins array: -VitePWA({ - registerType: 'autoUpdate', - manifest: { - name: 'FarmaFinder', - short_name: 'FarmaFinder', - theme_color: '#2563eb', - icons: [{ src: '/icon-192.png', sizes: '192x192', type: 'image/png' }], + "dashboard": { + "id": null, + "title": "Pharmacy Integration Platform", + "timezone": "browser", + "schemaVersion": 38, + "version": 1, + "refresh": "10s", + "panels": [ + { + "type": "graph", + "title": "HTTP Requests Rate", + "datasource": "Prometheus", + "targets": [ + { + "expr": "sum by (method, endpoint, http_status) (rate(pip_http_requests_total[5m]))", + "legendFormat": "{{method}} {{endpoint}} {{http_status}}", + "refId": "A" + } + ], + "yAxes": [ + { + "format": "ops", + "label": "req/s" + } + ], + "gridPos": { "x": 0, "y": 0, "w": 12, "h": 8 } + }, + { + "type": "graph", + "title": "Request Duration (seconds)", + "datasource": "Prometheus", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum by (le, method, endpoint) (rate(pip_http_request_duration_seconds_bucket[5m])))", + "legendFormat": "{{method}} {{endpoint}} 95th percentile", + "refId": "A" + } + ], + "yAxes": [ + { + "format": "seconds", + "label": "seconds" + } + ], + "gridPos": { "x": 12, "y": 0, "w": 12, "h": 8 } + }, + { + "type": "graph", + "title": "Database Query Duration", + "datasource": "Prometheus", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum by (le, operation) (rate(pip_db_query_duration_seconds_bucket[5m])))", + "legendFormat": "{{operation}} 95th percentile", + "refId": "A" + } + ], + "yAxes": [ + { + "format": "seconds", + "label": "seconds" + } + ], + "gridPos": { "x": 0, "y": 8, "w": 12, "h": 8 } + }, + { + "type": "graph", + "title": "Redis Operations", + "datasource": "Prometheus", + "targets": [ + { + "expr": "sum by (operation) (rate(pip_redis_operations_total[5m]))", + "legendFormat": "{{operation}}", + "refId": "A" + } + ], + "yAxes": [ + { + "format": "ops", + "label": "ops/s" + } + ], + "gridPos": { "x": 12, "y": 8, "w": 12, "h": 8 } + }, + { + "type": "graph", + "title": "RabbitMQ Messages Published", + "datasource": "Prometheus", + "targets": [ + { + "expr": "sum by (exchange, routing_key) (rate(pip_rabbitmq_messages_published_total[5m]))", + "legendFormat": "{{exchange}} -> {{routing_key}}", + "refId": "A" + } + ], + "yAxes": [ + { + "format": "ops", + "label": "msgs/s" + } + ], + "gridPos": { "x": 0, "y": 16, "w": 24, "h": 8 } + } + ], + "templating": { + "list": [] + }, + "annotations": { + "list": [] + } }, - workbox: { - globPatterns: ['**/*.{js,css,html,ico,png,svg}'], - }, -}) -``` - -**`frontend/src/utils/notifications.js`** (new) -```js -export async function getVapidKey() { - const res = await fetch('/api/notifications/vapid-public-key'); - const { publicKey } = await res.json(); - return publicKey; -} - -export function urlBase64ToUint8Array(base64String) { - const padding = '='.repeat((4 - (base64String.length % 4)) % 4); - const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/'); - return Uint8Array.from(atob(base64), c => c.charCodeAt(0)); -} - -export async function subscribeToPush(medicineNregistro, medicineName) { - const reg = await navigator.serviceWorker.ready; - const publicKey = await getVapidKey(); - const subscription = await reg.pushManager.subscribe({ - userVisibleOnly: true, - applicationServerKey: urlBase64ToUint8Array(publicKey), - }); - await fetch('/api/notifications/subscribe', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - medicine_nregistro: medicineNregistro, - medicine_name: medicineName, - subscription, - }), - }); + "overwrite": true } ``` -**`frontend/src/components/MedicineResults.jsx`** -- Add "Notify me" bell button per medicine result -- On click: call `subscribeToPush(medicine.id, medicine.name)` -- Toggle state: subscribed / not subscribed (persist in `localStorage`) +### Import Steps +1. In Grafana, click the **+** icon → **Import**. +2. Paste the JSON above or upload the file. +3. Select your Prometheus data source. +4. Click **Import**. -**Service worker push handler** — `vite-plugin-pwa` injects the SW; add a custom handler: -```js -// frontend/src/sw.js (custom SW additions via injectManifest mode) -self.addEventListener('push', event => { - const data = event.data.json(); - event.waitUntil( - self.registration.showNotification(data.title, { - body: data.body, - icon: '/icon-192.png', - data: { url: data.url }, - }) - ); -}); +## 4. Alerting Rules (Optional) -self.addEventListener('notificationclick', event => { - event.notification.close(); - event.waitUntil(clients.openWindow(event.notification.data.url)); -}); +Create a rule file for Alertmanager (e.g., `pip_alerts.yml`) and add it to your Prometheus server. + +```yaml +groups: + - name: pip-alerts + rules: + - alert: HighRequestLatency + expr: histogram_quantile(0.95, sum by (le, method, endpoint) (rate(pip_http_request_duration_seconds_bucket[5m]))) > 2 + for: 2m + labels: + severity: warning + annotations: + summary: "High request latency on {{ $labels.endpoint }}" + description: "95th percentile latency is above 2 seconds for {{ $labels.method }} {{ $labels.endpoint }}." + + - alert: APIErrorRateHigh + expr: sum by (http_status) (rate(pip_http_requests_total{http_status=~"5.."}[5m])) / sum by (http_status) (rate(pip_http_requests_total[5m])) > 0.05 + for: 5m + labels: + severity: critical + annotations: + summary: "High error rate ({{ $value | printf \"%.2f\" }})" + description: "More than 5% of requests are returning 5xx errors." + + - alert: RedisDown + expr: up{job="pip-api"} == 0 + for: 1m + labels: + severity: critical + annotations: + summary: "PIP application scrape failed" + description: "Prometheus cannot scrape the PIP application metrics endpoint." + + - alert: DatabaseConnectionFailures + expr: increase(pip_db_connection_errors_total[5m]) > 0 + for: 2m + labels: + severity: warning + annotations: + summary: "Database connection errors detected" + description: "There have been {{ $value }} database connection errors in the last 5 minutes." ``` -### React Native path (future) -- Replace `web-push` with Firebase Admin SDK (`firebase-admin`) -- Replace `push_subscriptions.endpoint/p256dh/auth` with `fcm_token` -- Frontend subscription logic moves to Expo `registerForPushNotificationsAsync()` -- Backend notification dispatch abstracted into `notify(medicineNregistro, message)` function — same interface, different transport +Add the file to your Prometheus server's rule files configuration and reload. -### Verification -```bash -# Start app over HTTPS (required for push — use ngrok or deploy) -# Search medicine, click bell icon -# Browser prompts notification permission — allow -# In admin: link that medicine to a pharmacy -# Browser notification fires: "Ibuprofeno 400mg now available at Farmacia Sol" +## 5. Verification Steps + +1. **Verify Metrics Endpoint** + From the monitoring host, run: + ```bash + curl -s http://:8000/metrics | head -20 + ``` + You should see lines like `# HELP pip_http_requests_total ...` and `# TYPE pip_http_requests_total counter`. + +2. **Check Prometheus Targets** + In Prometheus UI (`http://:9090/targets`), ensure the `pip-api` job shows `UP`. + +3. **View Dashboard** + Open the imported dashboard in Grafana and verify panels populate with data. + +4. **Test Alerts (Optional)** + You can temporarily trigger an alert by modifying the threshold (e.g., set `HighRequestLatency` to `> 0`) and verify Alertmanager fires. + +## 6. Cleanup / Roll‑needed) later you decide howto monitor within the docker compose stack again, just edit `docker-compose.yml` and uncomment the monitoring services (prometheus, grafana, alertmanager) and the related volumes, then run: + +``` +docker compose -f pip-platform/docker-compose.yml up -d ``` ---- +Make sure the healthcheck in the `pip-api` service still points to `/api/v1/system/health` (already updated). -## Recommended Order +--- -| Step | Time | Depends on | -|------|------|-----------| -| 1. Near me sorting | ~2 hrs | Nothing | -| 2. Pharmacy hours | ~3 hrs | Nothing (can run parallel with step 1) | -| 3. PWA + alerts | ~1 day | Steps 1 and 2 done (better UX in notification: "open now, 1.2 km away") | - ---- - -## Notes - -- Push notifications require HTTPS in production. In development use ngrok or set `CHROME_FLAGS=--unsafely-treat-insecure-origin-as-secure=http://localhost:3000` for testing. -- VAPID keys are per-environment — generate once, never rotate unless necessary (rotation invalidates all existing subscriptions). -- The `UNIQUE(medicine_nregistro, endpoint)` constraint on `push_subscriptions` prevents duplicate alerts if user clicks "Notify me" multiple times. +*This plan is intended to be a one‑time setup guide. Adjust hostnames, ports, authentication, and resource limits to match your production environment.* \ No newline at end of file diff --git a/Pre-Conversion_Archive.zip b/Pre-Conversion_Archive.zip new file mode 100644 index 0000000..cab999b Binary files /dev/null and b/Pre-Conversion_Archive.zip differ diff --git a/STATE.md b/STATE.md new file mode 100644 index 0000000..2c930c8 --- /dev/null +++ b/STATE.md @@ -0,0 +1,115 @@ +# Pharmacy Integration Platform (PIP) — State Log + +## Goal +Build a Python/FastAPI backend that abstracts pharmacy ERPs behind a unified REST API. Currently implementing Phase 3 (Inventory & Medication APIs). + +## Constraints & Preferences +- Backend only, no UI/mobile. Python 3.13, FastAPI, SQLAlchemy async, Alembic, PostgreSQL, Redis, RabbitMQ. +- Clean Architecture, SOLID, Repository Pattern, DI, DDD where valuable, Event Driven, CQRS where needed. +- Versioned API at `/api/v1/`. JWT+OAuth2 auth. RBAC with role hierarchy and scopes. API Keys for third parties. +- No code secrets. Structured JSON logs. OpenTelemetry, Prometheus, Grafana. +- Docker Compose with health checks; Kubernetes-migratable. +- Monitoring (Prometheus, Grafana, OTEL Collector) omitted from Docker stack; remote monitoring stack exists. PLAN.md provided for external integration. +- Incremental phases — wait for validation before advancing. + +## Progress + +### Done +- **Phase 1 complete**: full project structure, domain entities, ORM models, repositories, auth, security, API endpoints, middleware, Docker, CLI, Alembic, tests scaffolding +- **Phase 2 complete**: Connector Framework + SDK + Concrete Connectors + API Endpoints + Event Publishers + Tests +- **Phase 3 (medication/inventory)**: Medication & Inventory API endpoints — all E2E validated: + - Medications: CRUD, search by name/ingredient/nregistro/atc, nregistro lookup, duplicate 409 + - Catalog: per-pharmacy upsert, list, get + - Inventory: per-pharmacy upsert with history tracking, list, get, history endpoint + - Reservations: create, idempotency key, list, get, confirm, cancel, insufficient stock 422 + +### In Progress +- Phase 3 remaining items: Sync Job management, Audit logging integration, API Key auth flow, Rate limiting + +### Blocked +- (none) + +## Key Decisions +- Monitoring removed from Docker stack; `PLAN.md` provides instructions for external Prometheus/Grafana integration +- `docker-compose.runtime.yml` is the lean compose file for local dev +- Connector Registry uses singleton pattern with lazy loading via `importlib` for builtin connector types +- SDK architecture: `SDKConnector` base class composes auth handler + retry policy + circuit breaker + httpx client; concrete connectors extend it +- `_BUILTIN_CONNECTORS` registry maps ERPType values to `module.Class` strings for dynamic import +- Circuit breaker: 5 failures → open → 30s recovery → half_open (1 probe call) → close on success / reopen on failure +- OAuth2 handler fetches client_credentials tokens with 30s expiry buffer +- Replaced `passlib` with direct `bcrypt` library due to Python 3.13 incompatibility +- Connector events published to RabbitMQ with `connector.{event}` routing keys via `ConnectorService._publish_event()` +- `test_connection` sets connector status to ACTIVE on success, ERROR on failure; `deploy` refuses if already active +- Catalog entries are per-pharmacy, keyed by `(pharmacy_id, medication_id)` — upsert pattern +- Inventory records use same composite key pattern as catalog — upsert with history tracking +- Reservations support idempotency via `idempotency_key`, auto-expire, stock reservation/release on confirm/cancel +- Event publishing uses `event_type.replace(".", "_")` to map dotted event types to RabbitMQ routing keys +- Auth token endpoint expects JSON body (`LoginRequest`), not OAuth2 form data +- `InventoryHistoryEntity` has `inventory_record_id` field — must be set from service when creating history records +- Reservation `expires_at` uses `timedelta` (not timestamp arithmetic — float type error with Python 3.13 datetime) + +## Critical Bugs Fixed (this session) +1. `inventory_repository.py:add_history()` was using `entity.id` (None) instead of `entity.inventory_record_id` for the FK +2. `inventory_service.py:upsert_inventory_record()` wasn't passing `inventory_record_id=upserted.id` to `InventoryHistoryEntity` +3. `inventory_service.py:_release_reserved_stock()` wasn't passing `inventory_record_id` either +4. `inventory_service.py:create_reservation()` used `now.__class__(now.timestamp() + ttl_minutes * 60, tz=timezone.utc)` which fails with TypeError on float — replaced with `now + timedelta(minutes=ttl_minutes)` + +## Next Steps +- Implement Sync Job management (create, list, get, trigger, cancel sync jobs) +- Add Audit logging integration +- Implement API Key auth flow +- Add Rate limiting +- Replace `Base.metadata.create_all` with Alembic migrations +- Add more connector implementations (NixFara, Unycop, CSV, FTP, SQL) +- Enhance test coverage +- Set up CI/CD pipeline + +## Critical Context +- `bcrypt` library used directly (not via passlib) — must keep `bcrypt>=4.2.0` in dependencies +- OTel collector reference in docker-compose points to `otel-collector:4317` which doesn't exist in runtime stack — harmless warning logs +- System router has `/system` prefix; health at `/api/v1/system/health` +- Auth: register at `/api/v1/auth/register`, token at `/api/v1/auth/token` (JSON body, not form data) +- Generic exception handler in `main.py` swallows all errors as `{"error": {"code": "INTERNAL_ERROR", "message": "Internal server error"}}` — no traceback in response; check container logs or test repo/service directly for debugging +- Inventory endpoint uses `PUT /pharmacies/{pharmacy_id}/inventory` for upsert +- Reservation endpoints: `POST .../reservations` (create), `POST .../reservations/{id}/confirm`, `POST .../reservations/{id}/cancel`## Recent changes (OTel migration in progress) + +- **Observability now lives on srv84-macos.** The in-stack otel-collector / prometheus / grafana services have been stripped from `pip-platform/docker-compose.yml`, the orphaned `pip-platform/monitoring/otel-collector-config.yaml` has been deleted, and `pip-platform/docker-compose.runtime.yml` was previously pointing at a non-existent `otel-collector:4317` — fixed to `host.docker.localhost:4317` to route through Grafana Alloy. See PLAN.md for the external-integration rationale. +- **`pip-platform/monitoring/prometheus/prometheus.yml` is now documentation-only** — kept as a reference; the active scraper is the Prometheus on srv84-macos. +- **Monitoring stack (~/Projects/Monitoring/)**: Telegram bot token was externalized from `alertmanager/config.yml` (was plaintext literal) to `${TG_BOT_TOKEN}` resolved by an `envsubst` entrypoint on the remote. `OTel→Alloy` swap is local-canonical; srv84-macos merge still pending (see PLAN.md). + +## Relevant Files + + +### Domain +- `pip-platform/src/domain/entities/entities.py` — All domain entities (including `inventory_record_id` on `InventoryHistoryEntity`) +- `pip-platform/src/domain/entities/enums.py` — All enums + +### Repositories +- `pip-platform/src/infrastructure/database/repositories/medication_repository.py` — Medication CRUD + search +- `pip-platform/src/infrastructure/database/repositories/medication_catalog_repository.py` — Per-pharmacy catalog upsert +- `pip-platform/src/infrastructure/database/repositories/inventory_repository.py` — Inventory upsert + history +- `pip-platform/src/infrastructure/database/repositories/reservation_repository.py` — Reservation CRUD + idempotency +- `pip-platform/src/infrastructure/database/repositories/__init__.py` — All repo exports + +### Services +- `pip-platform/src/services/medication/medication_service.py` — Medication + catalog business logic + events +- `pip-platform/src/services/inventory/inventory_service.py` — Inventory + reservation business logic (stock reservation/release, confirm, cancel, idempotency) + events +- `pip-platform/src/services/connector_service.py` — Connector lifecycle + event publishing + +### API Endpoints +- `pip-platform/src/api/v1/endpoints/medications.py` — Medication CRUD + search +- `pip-platform/src/api/v1/endpoints/catalog.py` — Per-pharmacy catalog list/get/upsert +- `pip-platform/src/api/v1/endpoints/inventory.py` — Per-pharmacy inventory list/get/upsert + history +- `pip-platform/src/api/v1/endpoints/reservations.py` — Per-pharmacy reservation create/confirm/cancel/list/get +- `pip-platform/src/api/v1/endpoints/connectors.py` — Connector CRUD + test/deploy/deactivate/configs +- `pip-platform/src/api/v1/endpoints/erp_systems.py` — ERP System CRUD +- `pip-platform/src/api/v1/router.py` — All routers wired + +### Infrastructure +- `pip-platform/src/infrastructure/messaging/rabbitmq.py` — RabbitMQ client with routing keys +- `pip-platform/src/connectors/registry.py` — ConnectorRegistry singleton +- `pip-platform/src/connectors/sdk/base_sdk.py` — SDKConnector base class +- `pip-platform/src/services/auth/security.py` — Fixed bcrypt usage (no passlib) + +### Docker +- `pip-platform/docker-compose.runtime.yml` — Lean runtime stack diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 2ab351e..8dac37d 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -354,7 +354,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MARKETING_VERSION = 1.0; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; - PRODUCT_BUNDLE_IDENTIFIER = net.hacecalor.farmafinder; + PRODUCT_BUNDLE_IDENTIFIER = net.hacecalor.farmaclic; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_VERSION = 5.0; @@ -373,7 +373,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 15.5; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = net.hacecalor.farmafinder; + PRODUCT_BUNDLE_IDENTIFIER = net.hacecalor.farmaclic; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; SWIFT_VERSION = 5.0; diff --git a/ios/App/App/Info.plist b/ios/App/App/Info.plist index 0918a92..f959867 100644 --- a/ios/App/App/Info.plist +++ b/ios/App/App/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - FarmaFinder + FarmaClic CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -46,11 +46,11 @@ UIViewControllerBasedStatusBarAppearance NSLocationWhenInUseUsageDescription - FarmaFinder uses your location to sort nearby pharmacies by distance. + FarmaClic uses your location to sort nearby pharmacies by distance. NSLocationAlwaysAndWhenInUseUsageDescription - FarmaFinder uses your location to sort nearby pharmacies by distance. + FarmaClic uses your location to sort nearby pharmacies by distance. NSCameraUsageDescription - FarmaFinder uses the camera to scan your TSI health card barcode and QR code. + FarmaClic uses the camera to scan your TSI health card barcode and QR code. UIBackgroundModes diff --git a/postman/FarmaClic.postman_collection.json b/postman/FarmaClic.postman_collection.json new file mode 100644 index 0000000..38a0375 --- /dev/null +++ b/postman/FarmaClic.postman_collection.json @@ -0,0 +1,639 @@ +{ + "info": { + "_postman_id": "8f8e8a60-a292-4c28-9892-a1f727de5a6b", + "name": "FarmaFinder API Monitoring Collection", + "description": "Comprehensive integration testing and monitoring collection for FarmaFinder's Express API. Includes automated lifecycle tests for pharmacies and medicine links.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Public APIs", + "item": [ + { + "name": "Search Medicines", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/medicines/search?q=Paracetamol", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "medicines", + "search" + ], + "query": [ + { + "key": "q", + "value": "Paracetamol" + } + ] + }, + "description": "Searches medicines via the CIMA API with Redis cache." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response is an array\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.be.an('array');", + "});", + "", + "pm.test(\"Response returns valid medicine objects\", function () {", + " var jsonData = pm.response.json();", + " if (jsonData.length > 0) {", + " pm.expect(jsonData[0]).to.have.property('nregistro');", + " pm.expect(jsonData[0]).to.have.property('name');", + " }", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Get Medicine Details", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/medicines/51346", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "medicines", + "51346" + ] + }, + "description": "Retrieves medicine metadata from CIMA using its registration number (nregistro)." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200 or 404\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 404]);", + "});", + "", + "pm.test(\"Response time is acceptable\", function () {", + " pm.expect(pm.response.responseTime).to.be.below(3000);", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Get Pharmacies Selling Medicine", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/medicines/51346/pharmacies", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "medicines", + "51346", + "pharmacies" + ] + }, + "description": "Retrieves the list of pharmacies offering a specific medicine." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response is an array\", function () {", + " pm.expect(pm.response.json()).to.be.an('array');", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Get All Pharmacies", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/pharmacies", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "pharmacies" + ] + }, + "description": "Retrieves all registered pharmacies." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response is a list of pharmacies\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.be.an('array');", + " if (jsonData.length > 0) {", + " pm.expect(jsonData[0]).to.have.property('name');", + " pm.expect(jsonData[0]).to.have.property('address');", + " }", + "});" + ], + "type": "text/javascript" + } + } + ] + } + ] + }, + { + "name": "Authentication APIs", + "item": [ + { + "name": "Login", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"username\": \"{{username}}\",\n \"password\": \"{{password}}\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/auth/login", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "auth", + "login" + ] + }, + "description": "Authenticates the admin user and receives session cookie." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Verify user is admin\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.message).to.equal(\"Login successful\");", + " pm.expect(jsonData.user.is_admin).to.be.true;", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Check Authentication Status", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/auth/check", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "auth", + "check" + ] + }, + "description": "Checks if the session cookie is valid and active." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Session is authenticated\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.authenticated).to.be.true;", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Get Admin Profile", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/users/me", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "users", + "me" + ] + }, + "description": "Loads profile details for the authenticated user." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Logout", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/auth/logout", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "auth", + "logout" + ] + }, + "description": "Destroys the current authenticated session." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ] + } + ] + }, + { + "name": "Admin APIs (Transactional)", + "item": [ + { + "name": "Create Pharmacy", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Postman Monitor Pharmacy\",\n \"address\": \"Calle del Monitor 99, Madrid\",\n \"phone\": \"+34 900 123 456\",\n \"latitude\": 40.4168,\n \"longitude\": -3.7038,\n \"opening_hours\": \"24h\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/admin/pharmacies", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "admin", + "pharmacies" + ] + }, + "description": "Creates a new pharmacy for testing." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});", + "", + "var jsonData = pm.response.json();", + "pm.test(\"Response contains created pharmacy ID\", function () {", + " pm.expect(jsonData.id).to.exist;", + " pm.collectionVariables.set(\"temp_pharmacy_id\", jsonData.id);", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Update Pharmacy", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Postman Monitor Pharmacy - Updated\",\n \"address\": \"Calle del Monitor 99, Madrid\",\n \"phone\": \"+34 900 123 456\",\n \"latitude\": 40.4170,\n \"longitude\": -3.7040,\n \"opening_hours\": \"9:00 - 22:00\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/admin/pharmacies/{{temp_pharmacy_id}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "admin", + "pharmacies", + "{{temp_pharmacy_id}}" + ] + }, + "description": "Updates the properties of the temporary pharmacy." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Fields were successfully updated\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.name).to.include(\"Updated\");", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Get Pharmacy Medicines", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/admin/pharmacies/{{temp_pharmacy_id}}/medicines", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "admin", + "pharmacies", + "{{temp_pharmacy_id}}", + "medicines" + ] + }, + "description": "Retrieves the list of medicines linked to the temporary pharmacy." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response is an array\", function () {", + " pm.expect(pm.response.json()).to.be.an('array');", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Link Medicine to Pharmacy", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"pharmacy_id\": {{temp_pharmacy_id}},\n \"medicine_nregistro\": \"51346\",\n \"medicine_name\": \"Paracetamol 500mg\",\n \"price\": 4.75,\n \"stock\": 100\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/admin/pharmacy-medicines", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "admin", + "pharmacy-medicines" + ] + }, + "description": "Links a medicine to the temporary pharmacy with stock and price details." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + "});", + "", + "var jsonData = pm.response.json();", + "pm.test(\"Link relationship created\", function () {", + " pm.expect(jsonData.id).to.exist;", + " pm.collectionVariables.set(\"temp_relation_id\", jsonData.id);", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Update Pharmacy Medicine Relation", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"price\": 5.25,\n \"stock\": 95\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/admin/pharmacy-medicines/{{temp_relation_id}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "admin", + "pharmacy-medicines", + "{{temp_relation_id}}" + ] + }, + "description": "Updates price and stock properties on the relation." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Unlink Medicine from Pharmacy", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/admin/pharmacy-medicines/{{temp_relation_id}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "admin", + "pharmacy-medicines", + "{{temp_relation_id}}" + ] + }, + "description": "Removes the relation between the medicine and pharmacy." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Delete Pharmacy", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/admin/pharmacies/{{temp_pharmacy_id}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "admin", + "pharmacies", + "{{temp_pharmacy_id}}" + ] + }, + "description": "Deletes the temporary pharmacy to restore database clean state." + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ] + } + ] + } + ], + "variable": [ + { + "key": "temp_pharmacy_id", + "value": "" + }, + { + "key": "temp_relation_id", + "value": "" + } + ] +} diff --git a/postman/FarmaClic.postman_environment.json b/postman/FarmaClic.postman_environment.json new file mode 100644 index 0000000..75da0b5 --- /dev/null +++ b/postman/FarmaClic.postman_environment.json @@ -0,0 +1,27 @@ +{ + "id": "a988d8db-6be5-4cf5-8025-a131843b0d4d", + "name": "FarmaFinder Local Environment", + "values": [ + { + "key": "baseUrl", + "value": "http://localhost:3001", + "type": "default", + "enabled": true + }, + { + "key": "username", + "value": "admin", + "type": "default", + "enabled": true + }, + { + "key": "password", + "value": "admin123", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2026-06-30T13:00:00.000Z", + "_postman_exported_using": "Postman/10.0.0" +} diff --git a/postman/com.farmaclic.monitoring.plist b/postman/com.farmaclic.monitoring.plist new file mode 100644 index 0000000..fec7127 --- /dev/null +++ b/postman/com.farmaclic.monitoring.plist @@ -0,0 +1,21 @@ + + + + + Label + com.farmafinder.monitoring + ProgramArguments + + + /Users/username/FarmaFinder/scripts/run-newman-monitoring.sh + + StartInterval + 3600 + RunAtLoad + + StandardOutPath + /Users/username/FarmaFinder/logs/launchd-stdout.log + StandardErrorPath + /Users/username/FarmaFinder/logs/launchd-stderr.log + + diff --git a/prompt_plan.md b/prompt_plan.md new file mode 100644 index 0000000..6411f7c --- /dev/null +++ b/prompt_plan.md @@ -0,0 +1,154 @@ +# Plan: Grafana FARO + Alloy for FarmaFinder + +> **Status**: Approved (user answers 2026-06-30). +> **Path note**: User said `/root/Monitoring/` but the stack lives at `/home/f80ans0/Projects/Monitoring/`. + +## User decisions +1. **Network**: FarmaFinder runs on the same host as srv84-macos → use `host.docker.internal:4317/4318`. +2. **Auth**: Open on `back-tier` only, no auth. +3. **Existing otel-collector**: Remove it. Alloy is the only collector. +4. **Faro env**: Build-time via Vite `VITE_FARO_*` build args. + +## Architecture +``` +Browser (FarmaFinder PWA, Faro SDK) + │ OTLP HTTP + ▼ +┌─────────────────────────────────────────────┐ +│ Grafana Alloy :4317 gRPC :4318 HTTP :8889│ +│ otel.receiver → batch → exporters │ +│ prometheus.exporter.self :12345 │ +└──┬─────────────┬──────────────┬─────────────┘ + │ traces │ logs │ metrics (:8889 scraped) + ▼ ▼ ▼ +Tempo:4317 Loki:3100/otlp Prometheus:9090 + +backend (Express) ── OTLP gRPC ─▶ Alloy:4317 (host.docker.internal) +pip-platform (FastAPI) ── OTLP gRPC ─▶ Alloy:4317 (host.docker.internal) +scraper (Puppeteer) ── OTLP gRPC ─▶ Alloy:4317 (host.docker.internal) +API helper (in-process, covered by backend OTel) +``` + +## Files Changed + +### Monitoring (`/home/f80ans0/Projects/Monitoring/`) +- NEW `alloy-config.alloy` — River config (otel receiver, batch, exporters to tempo/loki/prometheus, self-scrape on 12345) +- MOD `docker-compose.yml` — add `alloy` service on `back-tier` (NO front-tier per Q2), bind 4317/4318/8889/12345 to `0.0.0.0` since same host; REMOVE the `otel-collector` service +- MOD `prometheus/prometheus.yml` — add `alloy` scrape job for `alloy:12345` +- MOD `grafana/provisioning/datasources/datasource.yml` — add Tempo + Loki; fix Prometheus URL from `http://localhost:9090` to `http://prometheus:9090` +- NEW `grafana/provisioning/dashboards/faro-web-vitals.json` +- NEW `grafana/provisioning/dashboards/faro-js-errors.json` +- NEW `grafana/provisioning/dashboards/faro-overview.json` +- NEW `README-FARO-ALLOY.md` + +### Frontend (`/home/f80ans0/Projects/Webs/FarmaFinder/frontend/`) +- MOD `package.json` — add `@grafana/faro-react`, `faro-web-sdk`, `faro-web-tracing`, `faro-transport-otlp-http` +- NEW `src/utils/faro.js` +- MOD `src/main.jsx` — call `initFaro()` before render +- MOD `Dockerfile` — accept VITE_FARO_* build args +- MOD `vite.config.js` — no change needed (Vite reads VITE_* automatically) +- NEW `.env.example` + +### Backend Node (`/home/f80ans0/Projects/Webs/FarmaFinder/backend/`) +- MOD `package.json` — add `@opentelemetry/api`, `sdk-node`, `auto-instrumentations-node`, `exporter-trace-otlp-grpc`, `exporter-logs-otlp-grpc`, `instrumentation-pino`, `pino`, `pino-pretty` +- NEW `src/tracing.js` — NodeSDK bootstrap (ESM) +- MOD `server.js` — `import './src/tracing.js';` as line 1; replace some `console.*` with pino +- MOD root `docker-compose.yml`: + - `backend.environment` add OTEL_* env vars + - `frontend.build.args` add `VITE_FARO_ENDPOINT`, `VITE_FARO_APP_NAME`, `VITE_FARO_ENV` + +### pip-platform +- MOD `docker-compose.yml` — change `OTEL_EXPORTER_OTLP_ENDPOINT` from `http://otel-collector:4317` to `http://host.docker.internal:4317`; remove the in-stack `otel-collector`, `prometheus`, `grafana` services (or comment out) since they're replaced by the shared stack +- (For this phase, leave the pip-platform prometheus+grafana running to avoid disrupting the existing setup — change just the OTel endpoint. Document in README.) + +### scraper +- MOD `package.json` — add OTel deps +- NEW `tracing.js` +- MOD `index.js` — wrap `run()` in a span + +### API helper +- No changes (in-process; covered by backend's auto-instrumentation). + +## Phases (8 total) + +### Phase 1: Add Grafana Alloy to monitoring stack +1. Write `/home/f80ans0/Projects/Monitoring/alloy-config.alloy` +2. Modify `/home/f80ans0/Projects/Monitoring/docker-compose.yml`: + - Add `alloy` service (image `grafana/alloy:v1.6.1`) + - Remove the `otel-collector` service +3. Modify `/home/f80ans0/Projects/Monitoring/prometheus/prometheus.yml` — add `alloy` scrape job +4. Verify: `docker compose config -q` + +### Phase 2: Frontend Faro SDK +1. Modify `frontend/package.json` (add deps) +2. Create `frontend/src/utils/faro.js` +3. Modify `frontend/src/main.jsx` (call initFaro) +4. Modify `frontend/Dockerfile` (build args) +5. Create `frontend/.env.example` +6. Verify: `cd frontend && npm ci && npm run build` succeeds + +### Phase 3: Backend Node OTel + pino +1. Modify `backend/package.json` (add OTel + pino deps) +2. Create `backend/src/tracing.js` +3. Modify `backend/server.js` (import tracing first; add pino) +4. Modify root `docker-compose.yml` (backend env + frontend build args) +5. Verify: `cd backend && npm ci` succeeds; container starts; trace appears in Tempo + +### Phase 4: pip-platform OTel re-route +1. Modify `pip-platform/docker-compose.yml` — change `OTEL_EXPORTER_OTLP_ENDPOINT` +2. Verify: pip-api trace appears in Tempo + +### Phase 5: Scraper one-shot OTel +1. Modify `scraper/package.json` (add OTel deps) +2. Create `scraper/tracing.js` +3. Modify `scraper/index.js` (wrap run in span) + +### Phase 6: Grafana provisioning +1. Modify `datasources/datasource.yml` (add Tempo + Loki, fix Prometheus URL) +2. Create 3 dashboard JSONs (web vitals, js errors, overview) +3. Verify: dashboards load in Grafana + +### Phase 7: Documentation +1. Create `Monitoring/README-FARO-ALLOY.md` + +### Phase 8: Verification +1. `docker compose config -q` for both stacks +2. `docker compose up -d alloy` from Monitoring dir +3. `curl -sf http://localhost:12345/-/ready` returns 200 +4. `curl -sf -X POST http://localhost:4318/v1/traces` returns 200 +5. Container logs show OTel init for backend + pip-platform +6. Grafana Explore → Tempo shows traces tagged `service.name=farmafinder-backend` +7. Grafana Explore → Loki shows `{app="farmafinder-frontend"}` logs +8. Grafana Explore → Prometheus shows `farovitals_*` metrics + +## Risks +- **HIGH** — None remaining (Q1 resolved: same host). +- **MEDIUM** — Backend uses ESM; OTel NodeSDK needs ESM-compatible setup via `--import` flag in CMD, not just `import './tracing.js'`. Use the OTel SDK's `register` API in ESM, or use the `--import` Node flag with `instrumentation.mjs` shim. +- **MEDIUM** — Alloy config is River syntax, not YAML. Validate with `alloy fmt` and `alloy validate` if available locally. +- **LOW** — Dashboard JSON validity. +- **INFO (security)** — `alertmanager/config.yml` line 25 has a Telegram bot token in plain text. **Do not fix in this PR**; flag to user. + +## Complexity +8-12 hours end-to-end. + +## Verification commands +```bash +# Syntax +docker compose -f /home/f80ans0/Projects/Monitoring/docker-compose.yml config -q && echo "monitoring OK" +cd /home/f80ans0/Projects/Webs/FarmaFinder && docker compose config -q && echo "farmafinder OK" + +# Start monitoring stack +cd /home/f80ans0/Projects/Monitoring && docker compose up -d alloy +curl -sf http://localhost:12345/-/ready && echo "alloy ready" +curl -sf -X POST http://localhost:4318/v1/traces -H 'Content-Type: application/x-protobuf' --data-binary @/dev/null -o /dev/null -w '%{http_code}\n' + +# Start FarmaFinder +cd /home/f80ans0/Projects/Webs/FarmaFinder && docker compose up -d --build +docker logs farmafinder-frontend 2>&1 | grep -i faro +docker logs farmafinder-backend 2>&1 | grep -i opentelemetry + +# Grafana Explore (manual): +# Tempo → service.name = farmafinder-backend +# Loki → {app="farmafinder-frontend"} | json +# Prometheus → farovitals_largest_contentful_paint +``` diff --git a/scraper/index.js b/scraper/index.js index 2e10fac..d9e9d0b 100644 --- a/scraper/index.js +++ b/scraper/index.js @@ -1,3 +1,7 @@ +// OpenTelemetry SDK — must be required first to instrument http, dns, etc. +require('./tracing'); + +const { trace } = require('@opentelemetry/api'); const puppeteer = require('puppeteer-extra'); const StealthPlugin = require('puppeteer-extra-plugin-stealth'); const fs = require('fs'); @@ -16,43 +20,56 @@ const QUERIES = [ ]; async function run() { - console.log('🚀 Starting Parapharmacy Scraper...'); - // Launching browser - const browser = await puppeteer.launch({ - headless: 'new', - args: ['--no-sandbox', '--disable-setuid-sandbox'] + const tracer = trace.getTracer('farmaclic-scraper'); + return tracer.startActiveSpan('scraper.run', { attributes: { 'scraper.queries': QUERIES.length } }, async (span) => { + try { + console.log('🚀 Starting Parapharmacy Scraper...'); + const browser = await puppeteer.launch({ + headless: 'new', + args: ['--no-sandbox', '--disable-setuid-sandbox'] + }); + + const allResults = {}; + + for (const query of QUERIES) { + const querySpan = tracer.startSpan('scraper.query', { attributes: { 'scraper.query': query } }); + console.log(`\n🔍 Searching for: "${query}"`); + + const promofarmaResults = await scrapePromofarma(query, browser); + console.log(` ✅ Promofarma: found ${promofarmaResults.length} items`); + + const amazonResults = await scrapeAmazon(query, browser); + console.log(` ✅ Amazon: found ${amazonResults.length} items`); + + const googleShoppingResults = await scrapeGoogleShopping(query, browser); + console.log(` ✅ Google Shopping: found ${googleShoppingResults.length} items`); + + const ofFactsResults = await scrapeOpenFoodFacts(query, browser); + console.log(` ✅ OpenFoodFacts: found ${ofFactsResults.length} items`); + + allResults[query] = { + promofarma: promofarmaResults, + amazon: amazonResults, + googleshopping: googleShoppingResults, + openfoodfacts: ofFactsResults + }; + querySpan.setAttribute('scraper.results.total', promofarmaResults.length + amazonResults.length + googleShoppingResults.length + ofFactsResults.length); + querySpan.end(); + } + + await browser.close(); + + fs.writeFileSync('results.json', JSON.stringify(allResults, null, 2)); + console.log('\n💾 Scraping finished. Results saved to results.json'); + span.setStatus({ code: 1 }); // OK + } catch (err) { + span.recordException(err); + span.setStatus({ code: 2, message: err.message }); // ERROR + throw err; + } finally { + span.end(); + } }); - - const allResults = {}; - - for (const query of QUERIES) { - console.log(`\n🔍 Searching for: "${query}"`); - - // We run sequentially to be gentle on CPU and anti-bot systems - const promofarmaResults = await scrapePromofarma(query, browser); - console.log(` ✅ Promofarma: found ${promofarmaResults.length} items`); - - const amazonResults = await scrapeAmazon(query, browser); - console.log(` ✅ Amazon: found ${amazonResults.length} items`); - - const googleShoppingResults = await scrapeGoogleShopping(query, browser); - console.log(` ✅ Google Shopping: found ${googleShoppingResults.length} items`); - - const ofFactsResults = await scrapeOpenFoodFacts(query, browser); - console.log(` ✅ OpenFoodFacts: found ${ofFactsResults.length} items`); - - allResults[query] = { - promofarma: promofarmaResults, - amazon: amazonResults, - googleshopping: googleShoppingResults, - openfoodfacts: ofFactsResults - }; - } - - await browser.close(); - - fs.writeFileSync('results.json', JSON.stringify(allResults, null, 2)); - console.log('\n💾 Scraping finished. Results saved to results.json'); } run().catch(err => { diff --git a/scraper/package-lock.json b/scraper/package-lock.json index af1032e..00ed108 100644 --- a/scraper/package-lock.json +++ b/scraper/package-lock.json @@ -9,6 +9,12 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/auto-instrumentations-node": "^0.52.0", + "@opentelemetry/exporter-trace-otlp-grpc": "^0.55.0", + "@opentelemetry/resources": "^1.28.0", + "@opentelemetry/sdk-node": "^0.55.0", + "@opentelemetry/semantic-conventions": "^1.28.0", "puppeteer": "^24.40.0", "puppeteer-extra": "^3.3.6", "puppeteer-extra-plugin-stealth": "^2.11.2" @@ -37,6 +43,1986 @@ "node": ">=6.9.0" } }, + "node_modules/@grpc/grpc-js": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.4.tgz", + "integrity": "sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ==", + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.1.tgz", + "integrity": "sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg==", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.54.2.tgz", + "integrity": "sha512-4MTVwwmLgUh5QrJnZpYo6YRO5IBLAggf2h8gWDblwRagDStY13aEvt7gGk3jewrMaPlHiF83fENhIx0HO97/cQ==", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.52.1.tgz", + "integrity": "sha512-4QaRTZifSoYnh27B3JA7z7YwE0Nwkd824pDeonAQVijeLLsenhZB1japualZ6mF9lY8VdQId9KkNsgmCGdJVNQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/instrumentation-amqplib": "^0.43.0", + "@opentelemetry/instrumentation-aws-lambda": "^0.47.0", + "@opentelemetry/instrumentation-aws-sdk": "^0.46.0", + "@opentelemetry/instrumentation-bunyan": "^0.42.0", + "@opentelemetry/instrumentation-cassandra-driver": "^0.42.0", + "@opentelemetry/instrumentation-connect": "^0.40.0", + "@opentelemetry/instrumentation-cucumber": "^0.10.0", + "@opentelemetry/instrumentation-dataloader": "^0.13.0", + "@opentelemetry/instrumentation-dns": "^0.40.0", + "@opentelemetry/instrumentation-express": "^0.44.0", + "@opentelemetry/instrumentation-fastify": "^0.41.0", + "@opentelemetry/instrumentation-fs": "^0.16.0", + "@opentelemetry/instrumentation-generic-pool": "^0.40.0", + "@opentelemetry/instrumentation-graphql": "^0.44.0", + "@opentelemetry/instrumentation-grpc": "^0.54.0", + "@opentelemetry/instrumentation-hapi": "^0.42.0", + "@opentelemetry/instrumentation-http": "^0.54.0", + "@opentelemetry/instrumentation-ioredis": "^0.44.0", + "@opentelemetry/instrumentation-kafkajs": "^0.4.0", + "@opentelemetry/instrumentation-knex": "^0.41.0", + "@opentelemetry/instrumentation-koa": "^0.44.0", + "@opentelemetry/instrumentation-lru-memoizer": "^0.41.0", + "@opentelemetry/instrumentation-memcached": "^0.40.0", + "@opentelemetry/instrumentation-mongodb": "^0.48.0", + "@opentelemetry/instrumentation-mongoose": "^0.43.0", + "@opentelemetry/instrumentation-mysql": "^0.42.0", + "@opentelemetry/instrumentation-mysql2": "^0.42.1", + "@opentelemetry/instrumentation-nestjs-core": "^0.41.0", + "@opentelemetry/instrumentation-net": "^0.40.0", + "@opentelemetry/instrumentation-pg": "^0.47.1", + "@opentelemetry/instrumentation-pino": "^0.43.0", + "@opentelemetry/instrumentation-redis": "^0.43.0", + "@opentelemetry/instrumentation-redis-4": "^0.43.0", + "@opentelemetry/instrumentation-restify": "^0.42.0", + "@opentelemetry/instrumentation-router": "^0.41.0", + "@opentelemetry/instrumentation-socket.io": "^0.43.0", + "@opentelemetry/instrumentation-tedious": "^0.15.0", + "@opentelemetry/instrumentation-undici": "^0.7.1", + "@opentelemetry/instrumentation-winston": "^0.41.0", + "@opentelemetry/resource-detector-alibaba-cloud": "^0.29.4", + "@opentelemetry/resource-detector-aws": "^1.7.0", + "@opentelemetry/resource-detector-azure": "^0.2.12", + "@opentelemetry/resource-detector-container": "^0.5.0", + "@opentelemetry/resource-detector-gcp": "^0.29.13", + "@opentelemetry/resources": "^1.24.0", + "@opentelemetry/sdk-node": "^0.54.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.4.1" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/context-async-hooks": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.27.0.tgz", + "integrity": "sha512-CdZ3qmHCwNhFAzjTgHqrDQ44Qxcpz43cVxZRhOs+Ns/79ug+Mr84Bkb626bkJLkA3+BLimA5YAEVRlJC6pFb7g==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/core": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.27.0.tgz", + "integrity": "sha512-yQPKnK5e+76XuiqUH/gKyS8wv/7qITd5ln56QkBTf3uggr0VkXOXfcaAuG330UfdYu83wsyoBwqwxigpIG+Jkg==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/exporter-logs-otlp-grpc": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.54.2.tgz", + "integrity": "sha512-MQNmV5r96+5n3axLFgNYtVy62x8Ru7VERZH3zgC50KDcIKWCiQT3vHOtzakhzd1Wq0HqOgu6bzKdwzneSoDrEQ==", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.27.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.54.2", + "@opentelemetry/otlp-transformer": "0.54.2", + "@opentelemetry/sdk-logs": "0.54.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/exporter-logs-otlp-http": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.54.2.tgz", + "integrity": "sha512-wYeCSbX2XWX2wFslnfQ/YFUolO0fj2nUiGI7oEQWpLKSg40Lc4xOOW14X/EXOkCCijhP7bigo6nvyEQlxEVLjA==", + "dependencies": { + "@opentelemetry/api-logs": "0.54.2", + "@opentelemetry/core": "1.27.0", + "@opentelemetry/otlp-exporter-base": "0.54.2", + "@opentelemetry/otlp-transformer": "0.54.2", + "@opentelemetry/sdk-logs": "0.54.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/exporter-logs-otlp-proto": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.54.2.tgz", + "integrity": "sha512-agrzFbSNmIy6dhkyg41ERlEDUDqkaUJj2n/tVRFp9Tl+6wyNVPsqmwU5RWJOXpyK+lYH/znv6A47VpTeJF0lrw==", + "dependencies": { + "@opentelemetry/api-logs": "0.54.2", + "@opentelemetry/core": "1.27.0", + "@opentelemetry/otlp-exporter-base": "0.54.2", + "@opentelemetry/otlp-transformer": "0.54.2", + "@opentelemetry/resources": "1.27.0", + "@opentelemetry/sdk-logs": "0.54.2", + "@opentelemetry/sdk-trace-base": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.54.2.tgz", + "integrity": "sha512-tmxiCYhQdPrzwlM6O7VQeNP9PBjKhaiOo54wFxQFZQcoVaDiOOES4+6PwHU1eW+43mDsgdQHN5AHSRHVLe9jDA==", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.27.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.54.2", + "@opentelemetry/otlp-transformer": "0.54.2", + "@opentelemetry/resources": "1.27.0", + "@opentelemetry/sdk-trace-base": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.54.2.tgz", + "integrity": "sha512-BgWKKyD/h2zpISdmYHN/sapwTjvt1P4p5yx4xeBV8XAEqh4OQUhOtSGFG80+nPQ1F8of3mKOT1DDoDbJp1u25w==", + "dependencies": { + "@opentelemetry/core": "1.27.0", + "@opentelemetry/otlp-exporter-base": "0.54.2", + "@opentelemetry/otlp-transformer": "0.54.2", + "@opentelemetry/resources": "1.27.0", + "@opentelemetry/sdk-trace-base": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.54.2.tgz", + "integrity": "sha512-XSmm1N2wAhoWDXP1q/N6kpLebWaxl6VIADv4WA5QWKHLRpF3gLz5NAWNJBR8ygsvv8jQcrwnXgwfnJ18H3v1fg==", + "dependencies": { + "@opentelemetry/core": "1.27.0", + "@opentelemetry/otlp-exporter-base": "0.54.2", + "@opentelemetry/otlp-transformer": "0.54.2", + "@opentelemetry/resources": "1.27.0", + "@opentelemetry/sdk-trace-base": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/exporter-zipkin": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.27.0.tgz", + "integrity": "sha512-eGMY3s4QprspFZojqsuQyQpWNFpo+oNVE/aosTbtvAlrJBAlvXcwwsOROOHOd8Y9lkU4i0FpQW482rcXkgwCSw==", + "dependencies": { + "@opentelemetry/core": "1.27.0", + "@opentelemetry/resources": "1.27.0", + "@opentelemetry/sdk-trace-base": "1.27.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.54.2.tgz", + "integrity": "sha512-NrNyxu6R/bGAwanhz1HI0aJWKR6xUED4TjCH4iWMlAfyRukGbI9Kt/Akd2sYLwRKNhfS+sKetKGCUQPMDyYYMA==", + "dependencies": { + "@opentelemetry/core": "1.27.0", + "@opentelemetry/otlp-transformer": "0.54.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.54.2.tgz", + "integrity": "sha512-HZtACQuLhgDcgNa9arGnVVGV28sSGQ+iwRgICWikFKiVxUsoWffqBvTxPa6G3DUTg5R+up97j/zxubEyxSAOHg==", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.27.0", + "@opentelemetry/otlp-exporter-base": "0.54.2", + "@opentelemetry/otlp-transformer": "0.54.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.54.2.tgz", + "integrity": "sha512-2tIjahJlMRRUz0A2SeE+qBkeBXBFkSjR0wqJ08kuOqaL8HNGan5iZf+A8cfrfmZzPUuMKCyY9I+okzFuFs6gKQ==", + "dependencies": { + "@opentelemetry/api-logs": "0.54.2", + "@opentelemetry/core": "1.27.0", + "@opentelemetry/resources": "1.27.0", + "@opentelemetry/sdk-logs": "0.54.2", + "@opentelemetry/sdk-metrics": "1.27.0", + "@opentelemetry/sdk-trace-base": "1.27.0", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/propagator-b3": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.27.0.tgz", + "integrity": "sha512-pTsko3gnMioe3FeWcwTQR3omo5C35tYsKKwjgTCTVCgd3EOWL9BZrMfgLBmszrwXABDfUrlAEFN/0W0FfQGynQ==", + "dependencies": { + "@opentelemetry/core": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/propagator-jaeger": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.27.0.tgz", + "integrity": "sha512-EI1bbK0wn0yIuKlc2Qv2LKBRw6LiUWevrjCF80fn/rlaB+7StAi8Y5s8DBqAYNpY7v1q86+NjU18v7hj2ejU3A==", + "dependencies": { + "@opentelemetry/core": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/resources": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.27.0.tgz", + "integrity": "sha512-jOwt2VJ/lUD5BLc+PMNymDrUCpm5PKi1E9oSVYAvz01U/VdndGmrtV3DU1pG4AwlYhJRHbHfOUIlpBeXCPw6QQ==", + "dependencies": { + "@opentelemetry/core": "1.27.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/sdk-logs": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.54.2.tgz", + "integrity": "sha512-yIbYqDLS/AtBbPjCjh6eSToGNRMqW2VR8RrKEy+G+J7dFG7pKoptTH5T+XlKPleP9NY8JZYIpgJBlI+Osi0rFw==", + "dependencies": { + "@opentelemetry/api-logs": "0.54.2", + "@opentelemetry/core": "1.27.0", + "@opentelemetry/resources": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/sdk-metrics": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.27.0.tgz", + "integrity": "sha512-JzWgzlutoXCydhHWIbLg+r76m+m3ncqvkCcsswXAQ4gqKS+LOHKhq+t6fx1zNytvLuaOUBur7EvWxECc4jPQKg==", + "dependencies": { + "@opentelemetry/core": "1.27.0", + "@opentelemetry/resources": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/sdk-node": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.54.2.tgz", + "integrity": "sha512-afn8GBpA7Gb55aU0LUxIQ+oe6QxLhsf+Te9iw12Non3ZAspzdoCcfz5+hqecwpuVpEDdnj5iSalF7VVaL2pDeg==", + "dependencies": { + "@opentelemetry/api-logs": "0.54.2", + "@opentelemetry/core": "1.27.0", + "@opentelemetry/exporter-logs-otlp-grpc": "0.54.2", + "@opentelemetry/exporter-logs-otlp-http": "0.54.2", + "@opentelemetry/exporter-logs-otlp-proto": "0.54.2", + "@opentelemetry/exporter-trace-otlp-grpc": "0.54.2", + "@opentelemetry/exporter-trace-otlp-http": "0.54.2", + "@opentelemetry/exporter-trace-otlp-proto": "0.54.2", + "@opentelemetry/exporter-zipkin": "1.27.0", + "@opentelemetry/instrumentation": "0.54.2", + "@opentelemetry/resources": "1.27.0", + "@opentelemetry/sdk-logs": "0.54.2", + "@opentelemetry/sdk-metrics": "1.27.0", + "@opentelemetry/sdk-trace-base": "1.27.0", + "@opentelemetry/sdk-trace-node": "1.27.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.27.0.tgz", + "integrity": "sha512-btz6XTQzwsyJjombpeqCX6LhiMQYpzt2pIYNPnw0IPO/3AhT6yjnf8Mnv3ZC2A4eRYOjqrg+bfaXg9XHDRJDWQ==", + "dependencies": { + "@opentelemetry/core": "1.27.0", + "@opentelemetry/resources": "1.27.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/sdk-trace-node": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.27.0.tgz", + "integrity": "sha512-dWZp/dVGdUEfRBjBq2BgNuBlFqHCxyyMc8FsN0NX15X07mxSUO0SZRLyK/fdAVrde8nqFI/FEdMH4rgU9fqJfQ==", + "dependencies": { + "@opentelemetry/context-async-hooks": "1.27.0", + "@opentelemetry/core": "1.27.0", + "@opentelemetry/propagator-b3": "1.27.0", + "@opentelemetry/propagator-jaeger": "1.27.0", + "@opentelemetry/sdk-trace-base": "1.27.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.28.0.tgz", + "integrity": "sha512-igcl4Ve+F1N2063PJUkesk/GkYyuGIWinYkSyAFTnIj3gzrOgvOA4k747XNdL47HRRL1w/qh7UW8NDuxOLvKFA==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.28.0.tgz", + "integrity": "sha512-ZLwRMV+fNDpVmF2WYUdBHlq0eOWtEaUJSusrzjGnBt7iSRvfjFE3RXYUZJrqou/wIDWV0DwQ5KIfYe9WXg9Xqw==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.55.0.tgz", + "integrity": "sha512-ykqawCL0ILJWyCJlxCPSAlqQXZ6x2bQsxAVUu8S3z22XNqY5SMx0rl2d93XnvnrOwtcfm+sM9ZhbGh/i5AZ9xw==", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.28.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.55.0", + "@opentelemetry/otlp-transformer": "0.55.0", + "@opentelemetry/sdk-logs": "0.55.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.55.0.tgz", + "integrity": "sha512-fpFObWWq+DoLVrBU2dyMEaVkibByEkmKQZIUIjW/4j7lwIsTgW7aJCoD9RYFVB/tButcqov5Es2C0J2wTjM2tg==", + "dependencies": { + "@opentelemetry/api-logs": "0.55.0", + "@opentelemetry/core": "1.28.0", + "@opentelemetry/otlp-exporter-base": "0.55.0", + "@opentelemetry/otlp-transformer": "0.55.0", + "@opentelemetry/sdk-logs": "0.55.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/api-logs": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.55.0.tgz", + "integrity": "sha512-3cpa+qI45VHYcA5c0bHM6VHo9gicv3p5mlLHNG3rLyjQU8b7e0st1rWtrUn3JbZ3DwwCfhKop4eQ9UuYlC6Pkg==", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.55.0.tgz", + "integrity": "sha512-vjE+DxUr+cUpxikdKCPiLZM5Wx7g1bywjCG76TQocvsA7Tmbb9p0t1+8gPlu9AGH7VEzPwDxxpN4p1ajpOurzQ==", + "dependencies": { + "@opentelemetry/api-logs": "0.55.0", + "@opentelemetry/core": "1.28.0", + "@opentelemetry/otlp-exporter-base": "0.55.0", + "@opentelemetry/otlp-transformer": "0.55.0", + "@opentelemetry/resources": "1.28.0", + "@opentelemetry/sdk-logs": "0.55.0", + "@opentelemetry/sdk-trace-base": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/api-logs": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.55.0.tgz", + "integrity": "sha512-3cpa+qI45VHYcA5c0bHM6VHo9gicv3p5mlLHNG3rLyjQU8b7e0st1rWtrUn3JbZ3DwwCfhKop4eQ9UuYlC6Pkg==", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/resources": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.28.0.tgz", + "integrity": "sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.55.0.tgz", + "integrity": "sha512-ohIkCLn2Wc3vhhFuf1bH8kOXHMEdcWiD847x7f3Qfygc+CGiatGLzQYscTcEYsWGMV22gVwB/kVcNcx5a3o8gA==", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.28.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.55.0", + "@opentelemetry/otlp-transformer": "0.55.0", + "@opentelemetry/resources": "1.28.0", + "@opentelemetry/sdk-trace-base": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/resources": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.28.0.tgz", + "integrity": "sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.55.0.tgz", + "integrity": "sha512-lMiNic63EVHpW+eChmLD2CieDmwQBFi72+LFbh8+5hY0ShrDGrsGP/zuT5MRh7M/vM/UZYO/2A/FYd7CMQGR7A==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/otlp-exporter-base": "0.55.0", + "@opentelemetry/otlp-transformer": "0.55.0", + "@opentelemetry/resources": "1.28.0", + "@opentelemetry/sdk-trace-base": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/resources": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.28.0.tgz", + "integrity": "sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.55.0.tgz", + "integrity": "sha512-qxiJFP+bBZW3+goHCGkE1ZdW9gJU0fR7eQ6OP+Rz5oGtEBbq4nkGodhb7C9FJlEFlE2siPtCxoeupV0gtYynag==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/otlp-exporter-base": "0.55.0", + "@opentelemetry/otlp-transformer": "0.55.0", + "@opentelemetry/resources": "1.28.0", + "@opentelemetry/sdk-trace-base": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/resources": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.28.0.tgz", + "integrity": "sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/exporter-zipkin": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.28.0.tgz", + "integrity": "sha512-AMwr3eGXaPEH7gk8yhcUcen31VXy1yU5VJETu0pCfGpggGCYmhm0FKgYBpL5/vlIgQJWU/sW2vIjCL7aSilpKg==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/resources": "1.28.0", + "@opentelemetry/sdk-trace-base": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/resources": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.28.0.tgz", + "integrity": "sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.54.2.tgz", + "integrity": "sha512-go6zpOVoZVztT9r1aPd79Fr3OWiD4N24bCPJsIKkBses8oyFo12F/Ew3UBTdIu6hsW4HC4MVEJygG6TEyJI/lg==", + "dependencies": { + "@opentelemetry/api-logs": "0.54.2", + "@types/shimmer": "^1.2.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-amqplib": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.43.0.tgz", + "integrity": "sha512-ALjfQC+0dnIEcvNYsbZl/VLh7D2P1HhFF4vicRKHhHFIUV3Shpg4kXgiek5PLhmeKSIPiUB25IYH5RIneclL4A==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-aws-lambda": { + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.47.0.tgz", + "integrity": "sha512-0BidKDPziHWGl5mnpLuh7ob1X3KpR0UN3QcJkcxIsOMylBbMMp9EoB55dHsTMoNO7bx2uyeY0iirEuTchjF1gQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/aws-lambda": "8.10.143" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-aws-sdk": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.46.0.tgz", + "integrity": "sha512-EyxGQVYhgY8OI4/CKzqamUswiEVlua6DJcsmkeNSykZrDGs78jPfssbqoMQGetywHWPZBRVJN4Ba/7aB5iLHBA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/propagation-utils": "^0.30.12", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-bunyan": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.42.0.tgz", + "integrity": "sha512-GBh6ybwKmFZjc86SyHVx72jHg+4pFPaXT3IZgJ4QtnMsMf0/q5m2aHAjid+yakmEkApsnRWX8pJ8nkl1e+6mag==", + "dependencies": { + "@opentelemetry/api-logs": "^0.54.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@types/bunyan": "1.8.9" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-cassandra-driver": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.42.0.tgz", + "integrity": "sha512-35I9Gw4BeSs9NPe7fugu9e/mWKaapc/N1wounHnGt259/Q3ISGMOQRrOwIBw+x/XJygJvn4Ss1c+r5h89TsVAw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-connect": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.40.0.tgz", + "integrity": "sha512-3aR/3YBQ160siitwwRLjwqrv2KBT16897+bo6yz8wIfel6nWOxTZBJudcbsK3p42pTC7qrbotJ9t/1wRLpv79Q==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/connect": "3.4.36" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-cucumber": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cucumber/-/instrumentation-cucumber-0.10.0.tgz", + "integrity": "sha512-5sT6Ap3W7StEL0Oax/vd1YTEcTPTefx+9myzkKrr72hxzFzSooGRCxlU3sfPwZqWptUV7+QWTMd7SqGEEPnE/w==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dataloader": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.13.0.tgz", + "integrity": "sha512-wbU3WdgUAXljEIY2nfpkqID/VH70ThnES8mZZHKCZlV/Pl5T4+qmrVdT7U9/WUzz8flwsXfER6T6jl48Wbl+LQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dns": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.40.0.tgz", + "integrity": "sha512-tLNR8XLPiYRKKk3/UqifXnPP2TVt1RcwvHU0R1ETL1xkZ1ZHMTmSC4x6TignnHOFtRixtJ05EgMGejnffaBXkQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-express": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.44.0.tgz", + "integrity": "sha512-GWgibp6Q0wxyFaaU8ERIgMMYgzcHmGrw3ILUtGchLtLncHNOKk0SNoWGqiylXWWT4HTn5XdV8MGawUgpZh80cA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fastify": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.41.0.tgz", + "integrity": "sha512-pNRjFvf0mvqfJueaeL/qEkuGJwgtE5pgjIHGYwjc2rMViNCrtY9/Sf+Nu8ww6dDd/Oyk2fwZZP7i0XZfCnETrA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.16.0.tgz", + "integrity": "sha512-hMDRUxV38ln1R3lNz6osj3YjlO32ykbHqVrzG7gEhGXFQfu7LJUx8t9tEwE4r2h3CD4D0Rw4YGDU4yF4mP3ilg==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-generic-pool": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.40.0.tgz", + "integrity": "sha512-k+/JlNDHN3bPi/Cir+Ew6tKHFVCa1ZFeQyGUw5HQkRX/twCRaN3kJFXJW+rDAN90XwK3RtC9AWwBihDGh/oSlQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-graphql": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.44.0.tgz", + "integrity": "sha512-FYXTe3Bv96aNpYktqm86BFUTpjglKD0kWI5T5bxYkLUPEPvFn38vWGMJTGrDMVou/i55E4jlWvcm6hFIqLsMbg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-grpc": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.54.2.tgz", + "integrity": "sha512-KhSzerCaaqVH2zfDro7nTunWUZXt1pQISQpE83LuQTOKGk7mN3G60T1wliQ3Qdg0X3UUuhCXEC7u6IAVfDxkUQ==", + "dependencies": { + "@opentelemetry/instrumentation": "0.54.2", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-grpc/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/instrumentation-hapi": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.42.0.tgz", + "integrity": "sha512-TQC0BtIWLHrp6nKsYdZ5t5B7aiZ16BwbRqZtYYQxeJVsq/HQTANWpknjtA7KMxv5tAUMCrU/eDo8F3qioUOSZg==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http": { + "version": "0.54.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.54.2.tgz", + "integrity": "sha512-mABjJ34UcU32pg8g18L9xBh0U3JON/2F6/57BYYy8AZJp2a71lZjcKr0T00pICoic50TW5HvcTrmyfMil+AiXQ==", + "dependencies": { + "@opentelemetry/core": "1.27.0", + "@opentelemetry/instrumentation": "0.54.2", + "@opentelemetry/semantic-conventions": "1.27.0", + "forwarded-parse": "2.1.2", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/core": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.27.0.tgz", + "integrity": "sha512-yQPKnK5e+76XuiqUH/gKyS8wv/7qITd5ln56QkBTf3uggr0VkXOXfcaAuG330UfdYu83wsyoBwqwxigpIG+Jkg==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/instrumentation-ioredis": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.44.0.tgz", + "integrity": "sha512-312pE2xc0ihX9haTf9WC4OF9in5EfVO1y5I8Ef9aMQKJNhuSe3IgzQAqGoLfaYajC+ig0IZ9SQKU8mRbFwHU+A==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/redis-common": "^0.36.2", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-kafkajs": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.4.0.tgz", + "integrity": "sha512-I9VwDG314g7SDL4t8kD/7+1ytaDBRbZQjhVaQaVIDR8K+mlsoBhLsWH79yHxhHQKvwCSZwqXF+TiTOhoQVUt7A==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-knex": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.41.0.tgz", + "integrity": "sha512-OhI1SlLv5qnsnm2dOVrian/x3431P75GngSpnR7c4fcVFv7prXGYu29Z6ILRWJf/NJt6fkbySmwdfUUnFnHCTg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-koa": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.44.0.tgz", + "integrity": "sha512-ryPqGIQ4hpMGd85bAGjRMDAy/ic+Qdh1GtFGJo9KaXdzbcvZoF1ZgXVsKTYDxbD1n5C0BoQy6rcWg8Lu68iCJA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-lru-memoizer": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.41.0.tgz", + "integrity": "sha512-6OePkk4RYCPVsnS0TroEK6UZzxxxjVWaE6EPdOn2qxGHMtm+Qb80tiBQ6BbmC+f7bjc27O85JY8gxeTybhHZXw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-memcached": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-memcached/-/instrumentation-memcached-0.40.0.tgz", + "integrity": "sha512-VzJUUH6cVz8yrb25RvvjhxCpwu4vUk28I0m5nnnhebULOo8p9lda5PgQeVde2+jQAd977C/vN714fkbYOmwb+A==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/memcached": "^2.2.6" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongodb": { + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.48.0.tgz", + "integrity": "sha512-9YWvaGvrrcrydMsYGLu0w+RgmosLMKe3kv/UNlsPy8RLnCkN2z+bhhbjjjuxtUmvEuKZMCoXFluABVuBr1yhjw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongoose": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.43.0.tgz", + "integrity": "sha512-y1mWuL/zb6IKi199HkROgmStxF/ybEsnKYgx+/lpLATd57oZHOqrXP9tLmp9qRVI5c6P5XEWfe7ZCvrj07iDMQ==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.42.0.tgz", + "integrity": "sha512-1GN2EBGVSZABGQ25MSz3faeBW/DwhzmE10aNW1/A2mvQAxF1CvpMk17YmNUzwapVt29iKsiU3SXQG7vjh/019A==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/mysql": "2.15.26" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql2": { + "version": "0.42.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.42.1.tgz", + "integrity": "sha512-5hOQbFSpqsgDLaqIeWZNbSWB6XdwN+aBjoCIe60lmGG86zeNXu9I6l1kEckRb+Gy0i7zrt0Tk8S62zsOSZ8l7Q==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.40.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-nestjs-core": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.41.0.tgz", + "integrity": "sha512-XCqtghFktpcJ2BOaJtFfqtTMsHffJADxfYhJl28WT6ygCChS2uZVxMKKLsy+i9VtPaw/i1IumPICL6mbhwq+Vw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-net": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-net/-/instrumentation-net-0.40.0.tgz", + "integrity": "sha512-abErnVRxTmtiF7EvBISW81Se2nj/j3Xtpfy//9++dgvDOXwbcD1Xz1via6ZHOm/VamboGhqPlYiO7ABzluPLwg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.47.1.tgz", + "integrity": "sha512-qIcydMBVlKtAyFQWYunjqvFMVqIGvxGMXISrdLuSbcCqico9QKhK7bF5wzsotjGwHcGnc7q5kRqSL7j+LnY1Cw==", + "dependencies": { + "@opentelemetry/core": "^1.26.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "1.27.0", + "@opentelemetry/sql-common": "^0.40.1", + "@types/pg": "8.6.1", + "@types/pg-pool": "2.0.6" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/instrumentation-pino": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.43.0.tgz", + "integrity": "sha512-jlOOgbODWRRNknWXY1VLgmqgG0SO4kLgU3XnejjO/3De4OisroAsMGk+1cRB5AQ6WZ8WLAMkMyTShaOe6j2Asw==", + "dependencies": { + "@opentelemetry/api-logs": "^0.54.0", + "@opentelemetry/core": "^1.25.0", + "@opentelemetry/instrumentation": "^0.54.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.43.0.tgz", + "integrity": "sha512-dufe08W3sCOjutbTJmV6tg2Y3+7IBe59oQrnIW2RCgjRhsW0Jjaenezt490eawO0MdXjUfFyrIUg8WetKhE4xA==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/redis-common": "^0.36.2", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis-4": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.43.0.tgz", + "integrity": "sha512-6B2+CFRY9xRnkeZrSvlTyY2yB/zAgxjbXS5EwXhE3ZAKR1hWWoUzaTADIKT5xe9/VbDW42U3UoOPCcaCmeAXww==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/redis-common": "^0.36.2", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-restify": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.42.0.tgz", + "integrity": "sha512-ApDD9HNy6de6xrHmISEfkQHwwX1f1JrBj0ADnlk6tVdJ0j/vNmsZNLwaU2IA2K3mHqbp2YLarLgxAZp6rjcfWg==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-router": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-router/-/instrumentation-router-0.41.0.tgz", + "integrity": "sha512-IbvzgaoylMqStOOtwucEvSu5CDbfQN+H1ZZ2p6c9Kmvzptqh6G441GFy0FFVVqxOAHNhQm2w6n0Ag8trdBjCfw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-socket.io": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.43.0.tgz", + "integrity": "sha512-HAQoIZ6N/ey1L4jF69gmqo7RyeSv5rc4sZZAd1v6SVaB8ZolTEyWEzGlu1NRZZTnqfWNxDkX6J1/omWpDd9k0w==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-tedious": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.15.0.tgz", + "integrity": "sha512-Kb7yo8Zsq2TUwBbmwYgTAMPK0VbhoS8ikJ6Bup9KrDtCx2JC01nCb+M0VJWXt7tl0+5jARUbKWh5jRSoImxdCw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.54.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/tedious": "^4.0.14" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-undici": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.7.1.tgz", + "integrity": "sha512-sIl4zrRDP7pR+2Pmdm9XJQULMKiUmvZze2cEW6gUz7TXCEaYmJ+vNMdd7qgeRo8C7AMm+T08mptobFVKPzdz+A==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.54.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.7.0" + } + }, + "node_modules/@opentelemetry/instrumentation-winston": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-winston/-/instrumentation-winston-0.41.0.tgz", + "integrity": "sha512-qtqGDx2Plu71s9xaeXut0YgZFG/y68ENG9vvo/SODeEC+4/APiS/htQ5YNJIxxjOuxYowdFYRqV9Kmef2EUzmw==", + "dependencies": { + "@opentelemetry/api-logs": "^0.54.0", + "@opentelemetry/instrumentation": "^0.54.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.55.0.tgz", + "integrity": "sha512-iHQI0Zzq3h1T6xUJTVFwmFl5Dt5y1es+fl4kM+k5T/3YvmVyeYkSiF+wHCg6oKrlUAJfk+t55kaAu3sYmt7ZYA==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/otlp-transformer": "0.55.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.55.0.tgz", + "integrity": "sha512-gebbjl9FiSp52igWXuGjcWQKfB6IBwFGt5z1VFwTcVZVeEZevB6bJIqoFrhH4A02m7OUlpJ7l4EfRi3UtkNANQ==", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.28.0", + "@opentelemetry/otlp-exporter-base": "0.55.0", + "@opentelemetry/otlp-transformer": "0.55.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.55.0.tgz", + "integrity": "sha512-kVqEfxtp6mSN2Dhpy0REo1ghP4PYhC1kMHQJ2qVlO99Pc+aigELjZDfg7/YKmL71gR6wVGIeJfiql/eXL7sQPA==", + "dependencies": { + "@opentelemetry/api-logs": "0.55.0", + "@opentelemetry/core": "1.28.0", + "@opentelemetry/resources": "1.28.0", + "@opentelemetry/sdk-logs": "0.55.0", + "@opentelemetry/sdk-metrics": "1.28.0", + "@opentelemetry/sdk-trace-base": "1.28.0", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/api-logs": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.55.0.tgz", + "integrity": "sha512-3cpa+qI45VHYcA5c0bHM6VHo9gicv3p5mlLHNG3rLyjQU8b7e0st1rWtrUn3JbZ3DwwCfhKop4eQ9UuYlC6Pkg==", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.28.0.tgz", + "integrity": "sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/propagation-utils": { + "version": "0.30.16", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagation-utils/-/propagation-utils-0.30.16.tgz", + "integrity": "sha512-ZVQ3Z/PQ+2GQlrBfbMMMT0U7MzvYZLCPP800+ooyaBqm4hMvuQHfP028gB9/db0mwkmyEAMad9houukUVxhwcw==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/propagator-b3": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.28.0.tgz", + "integrity": "sha512-Q7HVDIMwhN5RxL4bECMT4BdbyYSAKkC6U/RGn4NpO/cbqP6ZRg+BS7fPo/pGZi2w8AHfpIGQFXQmE8d2PC5xxQ==", + "dependencies": { + "@opentelemetry/core": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.28.0.tgz", + "integrity": "sha512-wKJ94+s8467CnIRgoSRh0yXm/te0QMOwTq9J01PfG/RzYZvlvN8aRisN2oZ9SznB45dDGnMj3BhUlchSA9cEKA==", + "dependencies": { + "@opentelemetry/core": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/redis-common": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz", + "integrity": "sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/resource-detector-alibaba-cloud": { + "version": "0.29.7", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-alibaba-cloud/-/resource-detector-alibaba-cloud-0.29.7.tgz", + "integrity": "sha512-PExUl/R+reSQI6Y/eNtgAsk6RHk1ElYSzOa8/FHfdc/nLmx9sqMasBEpLMkETkzDP7t27ORuXe4F9vwkV2uwwg==", + "dependencies": { + "@opentelemetry/core": "^1.26.0", + "@opentelemetry/resources": "^1.10.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-aws": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.12.0.tgz", + "integrity": "sha512-Cvi7ckOqiiuWlHBdA1IjS0ufr3sltex2Uws2RK6loVp4gzIJyOijsddAI6IZ5kiO8h/LgCWe8gxPmwkTKImd+Q==", + "dependencies": { + "@opentelemetry/core": "^1.0.0", + "@opentelemetry/resources": "^1.10.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-azure": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-azure/-/resource-detector-azure-0.2.12.tgz", + "integrity": "sha512-iIarQu6MiCjEEp8dOzmBvCSlRITPFTinFB2oNKAjU6xhx8d7eUcjNOKhBGQTvuCriZrxrEvDaEEY9NfrPQ6uYQ==", + "dependencies": { + "@opentelemetry/core": "^1.25.1", + "@opentelemetry/resources": "^1.10.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-container": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-container/-/resource-detector-container-0.5.3.tgz", + "integrity": "sha512-x5DxWu+ZALBuFpxwO2viv9ktH4Y3Gk9LaYKn2U8J+aeD412iy/OcGLPbQ76Px7pQ8qaJ5rnjcevBOHYT4aA+zQ==", + "dependencies": { + "@opentelemetry/core": "^1.26.0", + "@opentelemetry/resources": "^1.10.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-gcp": { + "version": "0.29.13", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.29.13.tgz", + "integrity": "sha512-vdotx+l3Q+89PeyXMgKEGnZ/CwzwMtuMi/ddgD9/5tKZ08DfDGB2Npz9m2oXPHRCjc4Ro6ifMqFlRyzIvgOjhg==", + "dependencies": { + "@opentelemetry/core": "^1.0.0", + "@opentelemetry/resources": "^1.10.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "gcp-metadata": "^6.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.30.1.tgz", + "integrity": "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==", + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", + "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.55.0.tgz", + "integrity": "sha512-TSx+Yg/d48uWW6HtjS1AD5x6WPfLhDWLl/WxC7I2fMevaiBuKCuraxTB8MDXieCNnBI24bw9ytyXrDCswFfWgA==", + "dependencies": { + "@opentelemetry/api-logs": "0.55.0", + "@opentelemetry/core": "1.28.0", + "@opentelemetry/resources": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/api-logs": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.55.0.tgz", + "integrity": "sha512-3cpa+qI45VHYcA5c0bHM6VHo9gicv3p5mlLHNG3rLyjQU8b7e0st1rWtrUn3JbZ3DwwCfhKop4eQ9UuYlC6Pkg==", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.28.0.tgz", + "integrity": "sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.28.0.tgz", + "integrity": "sha512-43tqMK/0BcKTyOvm15/WQ3HLr0Vu/ucAl/D84NO7iSlv6O4eOprxSHa3sUtmYkaZWHqdDJV0AHVz/R6u4JALVQ==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/resources": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.28.0.tgz", + "integrity": "sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-node": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.55.0.tgz", + "integrity": "sha512-gSXQWV23+9vhbjsvAIeM0LxY3W8DTKI3MZlzFp61noIb1jSr46ET+qoUjHlfZ1Yymebv9KXWeZsqhft81HBXuQ==", + "dependencies": { + "@opentelemetry/api-logs": "0.55.0", + "@opentelemetry/core": "1.28.0", + "@opentelemetry/exporter-logs-otlp-grpc": "0.55.0", + "@opentelemetry/exporter-logs-otlp-http": "0.55.0", + "@opentelemetry/exporter-logs-otlp-proto": "0.55.0", + "@opentelemetry/exporter-trace-otlp-grpc": "0.55.0", + "@opentelemetry/exporter-trace-otlp-http": "0.55.0", + "@opentelemetry/exporter-trace-otlp-proto": "0.55.0", + "@opentelemetry/exporter-zipkin": "1.28.0", + "@opentelemetry/instrumentation": "0.55.0", + "@opentelemetry/resources": "1.28.0", + "@opentelemetry/sdk-logs": "0.55.0", + "@opentelemetry/sdk-metrics": "1.28.0", + "@opentelemetry/sdk-trace-base": "1.28.0", + "@opentelemetry/sdk-trace-node": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/api-logs": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.55.0.tgz", + "integrity": "sha512-3cpa+qI45VHYcA5c0bHM6VHo9gicv3p5mlLHNG3rLyjQU8b7e0st1rWtrUn3JbZ3DwwCfhKop4eQ9UuYlC6Pkg==", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/instrumentation": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.55.0.tgz", + "integrity": "sha512-YDCMlaQRZkziLL3t6TONRgmmGxDx6MyQDXRD0dknkkgUZtOK5+8MWft1OXzmNu6XfBOdT12MKN5rz+jHUkafKQ==", + "dependencies": { + "@opentelemetry/api-logs": "0.55.0", + "@types/shimmer": "^1.2.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/resources": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.28.0.tgz", + "integrity": "sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.28.0.tgz", + "integrity": "sha512-ceUVWuCpIao7Y5xE02Xs3nQi0tOGmMea17ecBdwtCvdo9ekmO+ijc9RFDgfifMl7XCBf41zne/1POM3LqSTZDA==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/resources": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/resources": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.28.0.tgz", + "integrity": "sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw==", + "dependencies": { + "@opentelemetry/core": "1.28.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.28.0.tgz", + "integrity": "sha512-N0sYfYXvHpP0FNIyc+UfhLnLSTOuZLytV0qQVrDWIlABeD/DWJIGttS7nYeR14gQLXch0M1DW8zm3VeN6Opwtg==", + "dependencies": { + "@opentelemetry/context-async-hooks": "1.28.0", + "@opentelemetry/core": "1.28.0", + "@opentelemetry/propagator-b3": "1.28.0", + "@opentelemetry/propagator-jaeger": "1.28.0", + "@opentelemetry/sdk-trace-base": "1.28.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", + "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sql-common": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz", + "integrity": "sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==", + "dependencies": { + "@opentelemetry/core": "^1.1.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==" + }, "node_modules/@puppeteer/browsers": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.0.tgz", @@ -64,6 +2050,27 @@ "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", "license": "MIT" }, + "node_modules/@types/aws-lambda": { + "version": "8.10.143", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.143.tgz", + "integrity": "sha512-u5vzlcR14ge/4pMTTMDQr3MF0wEe38B2F9o84uC4F43vN5DGTy63npRrB6jQhyt+C0lGv4ZfiRcRkqJoZuPnmg==" + }, + "node_modules/@types/bunyan": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.9.tgz", + "integrity": "sha512-ZqS9JGpBxVOvsawzmVt30sP++gSQMTejCkIAQ3VdadOcRE8izTyW66hufvwLeH+YEGP6Js2AW7Gz+RMyvrEbmw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.36", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", + "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", @@ -73,22 +2080,68 @@ "@types/ms": "*" } }, + "node_modules/@types/memcached": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/@types/memcached/-/memcached-2.2.10.tgz", + "integrity": "sha512-AM9smvZN55Gzs2wRrqeMHVP7KE8KWgCJO/XL5yCly2xF6EKa4YlbpK+cLSAH4NG/Ah64HrlegmGqW8kYws7Vxg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, + "node_modules/@types/mysql": { + "version": "2.15.26", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz", + "integrity": "sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "25.5.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", "license": "MIT", - "optional": true, "dependencies": { "undici-types": "~7.18.0" } }, + "node_modules/@types/pg": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", + "integrity": "sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/pg-pool": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.6.tgz", + "integrity": "sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==", + "dependencies": { + "@types/pg": "*" + } + }, + "node_modules/@types/shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==" + }, + "node_modules/@types/tedious": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", + "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -99,6 +2152,25 @@ "@types/node": "*" } }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -279,6 +2351,14 @@ "node": ">=10.0.0" } }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "engines": { + "node": "*" + } + }, "node_modules/brace-expansion": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", @@ -320,6 +2400,11 @@ "devtools-protocol": "*" } }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==" + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -488,6 +2573,14 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -558,6 +2651,11 @@ "bare-events": "^2.7.0" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -614,6 +2712,11 @@ "node": ">=0.10.0" } }, + "node_modules/forwarded-parse": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", + "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==" + }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -634,6 +2737,42 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC" }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -693,12 +2832,31 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "engines": { + "node": ">=14" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -741,6 +2899,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-in-the-middle": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.15.0.tgz", + "integrity": "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==", + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -779,6 +2948,20 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "license": "MIT" }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -809,6 +2992,17 @@ "node": ">=0.10.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", @@ -836,6 +3030,14 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -881,6 +3083,16 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" + }, "node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -944,6 +3156,11 @@ "node": ">=0.10.0" } }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -959,6 +3176,25 @@ "node": ">= 0.4.0" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1039,18 +3275,86 @@ "node": ">=0.10.0" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "license": "MIT" }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.15.0.tgz", + "integrity": "sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -1060,6 +3364,28 @@ "node": ">=0.4.0" } }, + "node_modules/protobufjs": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.4.tgz", + "integrity": "sha512-RJJPTTpvFfHcWLkIa2JFWK4XvtSzS0yEWDmunqHXli1h3JlkbcQZXDZdcWxv+JK3Xsl5/UFDPZ0iGm7DAengYw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-agent": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", @@ -1279,6 +3605,39 @@ "node": ">=0.10.0" } }, + "node_modules/require-in-the-middle": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", + "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1352,6 +3711,11 @@ "node": ">=0.10.0" } }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -1437,6 +3801,17 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tar-fs": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", @@ -1481,6 +3856,11 @@ "b4a": "^1.6.4" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -1497,8 +3877,7 @@ "version": "7.18.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/universalify": { "version": "2.0.1", @@ -1509,12 +3888,39 @@ "node": ">= 10.0.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/webdriver-bidi-protocol": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz", "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==", "license": "Apache-2.0" }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -1559,6 +3965,14 @@ } } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/scraper/package.json b/scraper/package.json index 0a4fa8f..2889acc 100644 --- a/scraper/package.json +++ b/scraper/package.json @@ -11,6 +11,12 @@ "license": "ISC", "type": "commonjs", "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/auto-instrumentations-node": "^0.52.0", + "@opentelemetry/exporter-trace-otlp-grpc": "^0.55.0", + "@opentelemetry/resources": "^1.28.0", + "@opentelemetry/sdk-node": "^0.55.0", + "@opentelemetry/semantic-conventions": "^1.28.0", "puppeteer": "^24.40.0", "puppeteer-extra": "^3.3.6", "puppeteer-extra-plugin-stealth": "^2.11.2" diff --git a/scraper/tracing.js b/scraper/tracing.js new file mode 100644 index 0000000..f1fd224 --- /dev/null +++ b/scraper/tracing.js @@ -0,0 +1,46 @@ +// OpenTelemetry Node SDK bootstrap for the FarmaClic scraper. +// Started as a side-effect require from index.js (CommonJS). +// +// Env vars: +// OTEL_SERVICE_NAME — default: farmaclic-scraper +// OTEL_EXPORTER_OTLP_ENDPOINT — OTLP gRPC endpoint (e.g. http://alloy:4317) + +const { NodeSDK } = require('@opentelemetry/sdk-node'); +const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); +const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc'); +const { resourceFromAttributes } = require('@opentelemetry/resources'); +const { + ATTR_SERVICE_NAME, + ATTR_SERVICE_NAMESPACE, +} = require('@opentelemetry/semantic-conventions'); + +const serviceName = process.env.OTEL_SERVICE_NAME || 'farmaclic-scraper'; +const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4317'; + +const sdk = new NodeSDK({ + resource: resourceFromAttributes({ + [ATTR_SERVICE_NAME]: serviceName, + [ATTR_SERVICE_NAMESPACE]: 'farmaclic', + }), + traceExporter: new OTLPTraceExporter({ url: otlpEndpoint }), + instrumentations: [ + getNodeAutoInstrumentations({ + '@opentelemetry/instrumentation-fs': { enabled: false }, + '@opentelemetry/instrumentation-dns': { enabled: false }, + }), + ], +}); + +sdk.start(); + +const shutdown = async () => { + try { + await sdk.shutdown(); + } catch (err) { + // eslint-disable-next-line no-console + console.error('OpenTelemetry shutdown failed', err); + } +}; + +process.on('SIGTERM', shutdown); +process.on('SIGINT', shutdown); diff --git a/scripts/build-ios.sh b/scripts/build-ios.sh index 651125e..af8a761 100755 --- a/scripts/build-ios.sh +++ b/scripts/build-ios.sh @@ -8,7 +8,7 @@ ARCHIVE_PATH="build/App.xcarchive" IPA_DIR="build" EXPORT_OPTIONS="${EXPORT_OPTIONS:-scripts/export-options.plist}" -echo "=== FarmaFinder iOS Build Script ===" +echo "=== FarmaClic iOS Build Script ===" echo "[1/6] Installing frontend dependencies..." (cd frontend && npm ci) diff --git a/scripts/export-options.plist b/scripts/export-options.plist index 08fdeaf..827269f 100644 --- a/scripts/export-options.plist +++ b/scripts/export-options.plist @@ -12,7 +12,7 @@ manual provisioningProfiles - net.hacecalor.farmafinder + net.hacecalor.farmaclic YOUR_PROVISIONING_PROFILE_NAME