diff --git a/.env.development b/.env.development
index 34b9183..ac7c399 100644
--- a/.env.development
+++ b/.env.development
@@ -4,21 +4,37 @@ COMPOSE_PROJECT_NAME=suitecoffee_dev
# Entorno de desarrollo
NODE_ENV=development
-# app - app
-APP_PORT=3030
-# auth - app
-AUTH_PORT=4040
+MANSO_PORT=1010 # MVP Manso Microservicio -> services/manso/src/index.mjs
+APP_PORT=3030 # Microservicio APP-> services/app/src/index.mjs
+AUTH_PORT=4040 # Microservicio AUTH -> services/auth/src/index.mjs
+PLUGINS_PORT=5050 # Microservicio PLUGINS-> services/plugins/src/index.mjs
-# tenants - postgres
-TENANTS_DB_NAME=dev-postgres
-TENANTS_DB_USER=dev-user-postgres
-TENANTS_DB_PASS=dev-pass-postgres
-
-# db primaria - postgres
-DB_NAME=dev-suitecoffee
+# ===== DB principal (metadatos de SuiteCoffee) =====
+# Usa el alias de red del servicio 'db' (compose: aliases [dev-db])
+DB_HOST=dev-db
+DB_NAME=dev_suitecoffee_core
+DB_PORT=5432
DB_USER=dev-user-suitecoffee
DB_PASS=dev-pass-suitecoffee
+CORE_DB_HOST=dev-db
+CORE_DB_NAME=dev_suitecoffee_core
+CORE_DB_PORT=5432
+CORE_DB_USER=dev-user-suitecoffee
+CORE_DB_PASS=dev-pass-suitecoffee
+
+# ===== DB tenants (Tenants de SuiteCoffee) =====
+TENANTS_HOST=dev-tenants
+TENANTS_DB=dev_suitecoffee_tenants
+TENANTS_PORT=5432
+TENANTS_USER=suitecoffee
+TENANTS_PASS=suitecoffee
+
+TENANTS_DB_HOST=dev-tenants
+TENANTS_DB_NAME=dev_suitecoffee_tenants
+TENANTS_DB_PORT=5432
+TENANTS_DB_USER=suitecoffee
+TENANTS_DB_PASS=suitecoffee
# Authentik PostgreSQL Setup
AK_HOST_DB=ak-db
AK_PG_DB=authentik
@@ -26,12 +42,20 @@ AK_PG_USER=authentik
AK_PG_PASS=gOWjL8V564vyh1aXUcqh4o/xo7eObraaCVZezPi3iw2LzPlU
# Authentik Cookies
-AUTHENTIK_COOKIE__DOMAIN=sso.suitecoffee.uy
-AUTHENTIK_SECURITY__CSRF_TRUSTED_ORIGINS=https://sso.suitecoffee.uy,https://suitecoffee.uy
+AUTHENTIK_COOKIE__DOMAIN=dev.sso.suitecoffee.uy
+AUTHENTIK_SECURITY__CSRF_TRUSTED_ORIGINS=https://dev.sso.suitecoffee.uy,https://dev.suitecoffee.uy
# Authentik Security
AUTHENTIK_SECRET_KEY=11zMsUL57beO+okjeGh7OB3lQdGUWII+VaATHs/zsw1+6KMSTyGfAY0yHpq3C442+3CwrZ/KtjgHBfbv
# Authentik Bootstrap
AUTHENTIK_BOOTSTRAP_PASSWORD=info.suitecoffee@gmail.com
-AUTHENTIK_BOOTSTRAP_EMAIL=info.suitecoffee@gmail.com
\ No newline at end of file
+AUTHENTIK_BOOTSTRAP_EMAIL=info.suitecoffee@gmail.com
+
+AUTHENTIK_EMAIL__HOST=smtp.gmail.com
+AUTHENTIK_EMAIL__PORT=25
+AUTHENTIK_EMAIL__USERNAME=info.suitecoffee@gmail.com
+AUTHENTIK_EMAIL__PASSWORD=Succulent-Sanded7
+AUTHENTIK_EMAIL__USE_TLS=true # Or false if not using TLS
+AUTHENTIK_EMAIL__USE_SSL=false # Or true if using SSL directly
+AUTHENTIK_EMAIL__FROM=info.suitecoffee@gmail.com
\ No newline at end of file
diff --git a/.env.production b/.env.production
index 4834ca8..e9c13a3 100644
--- a/.env.production
+++ b/.env.production
@@ -1,26 +1,23 @@
# Archivo de variables de entorno para docker-compose.yml
-COMPOSE_PROJECT_NAME=suitecoffee_prod
+COMPOSE_PROJECT_NAME=suitecoffee_
# Entorno de desarrollo
NODE_ENV=production
-# app - app
-APP_PORT=3000
-
-# auth - app
-AUTH_PORT=4000
+APP_PORT=3000 # Microservicio APP-> services/app/src/index.mjs
+AUTH_PORT=4000 # Microservicio AUTH -> services/auth/src/index.mjs
+PLUGIN_PORT=5000 # Microservicio PLUGINS-> services/plugins/src/index.mjs
# tenants - postgres
-TENANTS_DB_NAME=postgres
-TENANTS_DB_USER=postgres
-TENANTS_DB_PASS=postgres
+TENANTS_DB_NAME=suitecoffee_tenants
+TENANTS_DB_USER=suitecoffee
+TENANTS_DB_PASS=suitecoffee
# db primaria - postgres
-DB_NAME=suitecoffee
+DB_NAME=suitecoffee_core
DB_USER=suitecoffee
DB_PASS=suitecoffee
-
# Authentik PostgreSQL Setup
AK_HOST_DB=ak-db
AK_PG_DB=authentik
diff --git a/compose.dev.yaml b/compose.dev.yaml
index f19944b..322f6d8 100644
--- a/compose.dev.yaml
+++ b/compose.dev.yaml
@@ -4,13 +4,12 @@
services:
app:
- image: node:20-bookworm
+ image: node:20.19.5-bookworm
working_dir: /app
user: "${UID:-1000}:${GID:-1000}"
volumes:
- ./services/app:/app:rw
- ./services/app/node_modules:/app/node_modules
- # - ./services/shared:/app/shared
env_file:
- ./services/app/.env.development
environment:
@@ -22,26 +21,43 @@ services:
aliases: [dev-app]
command: npm run dev
- # auth:
- # image: node:20-bookworm
- # working_dir: /app
- # user: "${UID:-1000}:${GID:-1000}"
- # volumes:
- # - ./services/auth:/app:rw
- # - ./services/auth/node_modules:/app/node_modules
- # - ./services/shared:/app/shared
- # env_file:
- # - ./services/auth/.env.development
- # environment:
- # NODE_ENV: development # <- fuerza el entorno para que el loader tome .env.development
- # expose:
- # - ${AUTH_PORT}
- # networks:
- # net:
- # aliases: [dev-auth]
- # command: npm run dev
+ plugins:
+ image: node:20.19.5-bookworm
+ working_dir: /app
+ user: "${UID:-1000}:${GID:-1000}"
+ volumes:
+ - ./services/plugins:/app:rw
+ - ./services/plugins/node_modules:/app/node_modules
+ env_file:
+ - ./services/plugins/.env.development
+ environment:
+ NODE_ENV: development # <- fuerza el entorno para que el loader tome .env.development
+ expose:
+ - ${PLUGINS_PORT}
+ networks:
+ net:
+ aliases: [dev-plugins]
+ command: npm run dev
- db:
+ auth:
+ image: node:20.19.5-bookworm
+ working_dir: /app
+ user: "${UID:-1000}:${GID:-1000}"
+ volumes:
+ - ./services/auth:/app:rw
+ - ./services/auth/node_modules:/app/node_modules
+ env_file:
+ - ./services/auth/.env.development
+ environment:
+ NODE_ENV: development # <- fuerza el entorno para que el loader tome .env.development
+ expose:
+ - ${AUTH_PORT}
+ networks:
+ net:
+ aliases: [dev-auth]
+ command: npm run dev
+
+ dbCore:
image: postgres:16
environment:
POSTGRES_DB: ${DB_NAME}
@@ -53,7 +69,7 @@ services:
net:
aliases: [dev-db]
- tenants:
+ dbTenants:
image: postgres:16
environment:
POSTGRES_DB: ${TENANTS_DB_NAME}
@@ -108,7 +124,6 @@ services:
AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD}
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}
-
AUTHENTIK_HTTP__TRUSTED_PROXY__CIDRS: "0.0.0.0/0,::/0"
AUTHENTIK_SECURITY__CSRF_TRUSTED_ORIGINS: ${AUTHENTIK_SECURITY__CSRF_TRUSTED_ORIGINS}
AUTHENTIK_COOKIE__DOMAIN: ${AUTHENTIK_COOKIE__DOMAIN}
@@ -117,7 +132,7 @@ services:
aliases: [dev-authentik]
volumes:
- ./authentik-media:/media
- - ./authentik-custom-templates:/templates
+ - ./authentik-custom-templates:/templates
ak-worker:
image: ghcr.io/goauthentik/server:latest
diff --git a/compose.manso.yaml b/compose.manso.yaml
index 33f5a33..b05e098 100644
--- a/compose.manso.yaml
+++ b/compose.manso.yaml
@@ -1,4 +1,4 @@
-# docker-compose.overrride.yml
+# compose.manso.yml
# Docker Comose para entorno de desarrollo o development.
@@ -11,8 +11,8 @@ services:
# condition: service_healthy
# tenants:
# condition: service_healthy
- # expose:
- # - ${APP_LOCAL_PORT}
+ expose:
+ - ${MANSO_PORT}
working_dir: /app
user: "${UID:-1000}:${GID:-1000}"
volumes:
@@ -21,16 +21,16 @@ services:
env_file:
- ./services/manso/.env.development
environment:
- - NODE_ENV=${NODE_ENV}
+ NODE_ENV: development
networks:
net:
aliases: [manso]
- healthcheck:
- test: ["CMD-SHELL", "curl -fsS http://localhost:${APP_PORT}/health || exit 1"]
- interval: 10s
- timeout: 3s
- retries: 10
- start_period: 20s
+ #healthcheck:
+ # test: ["CMD-SHELL", "curl -fsS http://localhost:${MANSO_PORT}/health || exit 1"]
+ # interval: 10s
+ # timeout: 3s
+ # retries: 10
+ # start_period: 20s
command: npm run dev
profiles: [manso]
restart: unless-stopped
diff --git a/compose.prod.yaml b/compose.prod.yaml
index 4c990a2..dcae4e8 100644
--- a/compose.prod.yaml
+++ b/compose.prod.yaml
@@ -15,10 +15,27 @@ services:
env_file:
- ./services/app/.env.production
environment:
- - NODE_ENV=${NODE_ENV}
+ - NODE_ENV: production
networks:
net:
- aliases: [prod-app]
+ aliases: [app]
+ command: npm run start
+
+ plugins:
+ build:
+ context: ./services/plugins
+ dockerfile: Dockerfile.production
+ expose:
+ - ${PLUGIN_PORT}
+ volumes:
+ - ./services/plugins:/app
+ env_file:
+ - ./services/plugins/.env.production
+ environment:
+ - NODE_ENV: production
+ networks:
+ net:
+ aliases: [plugins]
command: npm run start
auth:
@@ -32,40 +49,41 @@ services:
env_file:
- ./services/auth/.env.production
environment:
- - NODE_ENV=${NODE_ENV}
- command: npm run start
+ - NODE_ENV: production
networks:
net:
- aliases: [prod-auth]
+ aliases: [auth]
+ command: npm run start
- db:
+ dbCore:
image: postgres:16
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASS}
volumes:
- - suitecoffee-db:/var/lib/postgresql/data
+ - dbCore_data:/var/lib/postgresql/data
networks:
net:
- aliases: [prod-db]
+ aliases: [dbCore]
- tenants:
+ dbTenants:
image: postgres:16
environment:
POSTGRES_DB: ${TENANTS_DB_NAME}
POSTGRES_USER: ${TENANTS_DB_USER}
POSTGRES_PASSWORD: ${TENANTS_DB_PASS}
volumes:
- - tenants-db:/var/lib/postgresql/data
+ - dbTenants_data:/var/lib/postgresql/data
networks:
net:
- aliases: [prod-tenants]
+ aliases: [dbTenants]
+
+falta implementar authentik en compose.prod.yaml
volumes:
- tenants-db:
- suitecoffee-db:
-
+ dbCore_data:
+ dbTenants_data:
networks:
net:
driver: bridge
\ No newline at end of file
diff --git a/compose.yaml b/compose.yaml
index 20429b8..c9063ab 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -5,33 +5,47 @@ name: ${COMPOSE_PROJECT_NAME:-suitecoffee}
services:
app:
depends_on:
- db:
+ dbCore:
condition: service_healthy
- tenants:
+ dbTenants:
condition: service_healthy
healthcheck:
- test: ["CMD-SHELL", "curl -fsS http://localhost:${APP_PORT}/health || exit 1"]
+ test: ["CMD-SHELL", "curl -fsS http://localhost:${APP_PORT}/health || exit 1"]
+ interval: 10s
+ timeout: 3s
+ retries: 10
+ start_period: 20s
+ restart: unless-stopped
+
+ plugins:
+ depends_on:
+ app:
+ condition: service_healthy
+ auth:
+ condition: service_healthy
+ healthcheck:
+ test: ["CMD-SHELL", "curl -fsS http://localhost:${PLUGINS_PORT}/health || exit 1"]
interval: 10s
timeout: 3s
retries: 10
start_period: 20s
restart: unless-stopped
- # auth:
- # depends_on:
- # db:
- # condition: service_healthy
- # ak:
- # condition: service_started
- # healthcheck:
- # test: ["CMD-SHELL", "curl -fsS http://localhost:${AUTH_PORT}/health || exit 1"]
- # interval: 10s
- # timeout: 3s
- # retries: 10
- # start_period: 15s
- # restart: unless-stopped
+ auth:
+ depends_on:
+ dbCore:
+ condition: service_healthy
+ ak:
+ condition: service_started
+ healthcheck:
+ test: ["CMD-SHELL", "curl -fsS http://localhost:${AUTH_PORT}/health || exit 1"]
+ interval: 10s
+ timeout: 3s
+ retries: 10
+ start_period: 20s
+ restart: unless-stopped
- db:
+ dbCore:
image: postgres:16
environment:
TZ: America/Montevideo
@@ -43,7 +57,7 @@ services:
start_period: 10s
restart: unless-stopped
- tenants:
+ dbTenants:
image: postgres:16
environment:
TZ: America/Montevideo
@@ -92,4 +106,4 @@ services:
ak-redis:
condition: service_healthy
restart: unless-stopped
-
\ No newline at end of file
+
diff --git a/package.json b/package.json
index 3094296..1979a65 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,8 @@
"name": "suitecoffee",
"version": "1.0.0",
"description": "Software para gestión de cafeterías",
+ "private": true,
+ "workspaces": [],
"keywords": [
"coffee",
"suite",
diff --git a/packages/db/package.json b/packages/db/package.json
new file mode 100644
index 0000000..31c995d
--- /dev/null
+++ b/packages/db/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "@suitecoffee/db",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "description": "Utilidades de acceso a Postgres para SuiteCoffee (pool por proceso + helpers multi-tenant).",
+ "exports": {
+ ".": "./src/index.mjs"
+ },
+ "main": "./src/index.mjs",
+ "files": ["src"],
+ "sideEffects": false,
+ "peerDependencies": {
+ "pg": "^8.12.0"
+ }
+}
diff --git a/packages/db/src/index.mjs b/packages/db/src/index.mjs
new file mode 100644
index 0000000..0364e56
--- /dev/null
+++ b/packages/db/src/index.mjs
@@ -0,0 +1,2 @@
+export * from './pool-registry.mjs';
+export * from './poolSingleton.mjs';
diff --git a/packages/db/src/pool-registry.mjs b/packages/db/src/pool-registry.mjs
new file mode 100644
index 0000000..8251002
--- /dev/null
+++ b/packages/db/src/pool-registry.mjs
@@ -0,0 +1,54 @@
+import { Pool } from 'pg';
+
+const REGISTRY = new Map();
+
+export function getPool(name = 'core', cfg = {}) {
+ if (REGISTRY.has(name)) return REGISTRY.get(name);
+
+ const pool = new Pool({
+ connectionString: process.env.PG_URL,
+ max: Number(process.env.PG_POOL_MAX ?? 10),
+ idleTimeoutMillis: Number(process.env.PG_IDLE_MS ?? 30000),
+ connectionTimeoutMillis: Number(process.env.PG_CONN_MS ?? 5000),
+ statement_timeout: Number(process.env.PG_STMT_MS ?? 15000),
+ ssl: process.env.PGSSL === 'true' ? { rejectUnauthorized: false } : undefined,
+ ...cfg
+ });
+
+ pool.on('error', (err) => {
+ // ideal: reemplazar con pino/sentry
+ console.error(`[pg:${name}] pool error`, err);
+ });
+
+ REGISTRY.set(name, pool);
+ return pool;
+}
+
+function assertTenantSchema(schema) {
+ if (!/^tenant_[a-f0-9-]{16,36}$/i.test(schema)) {
+ throw new Error('Invalid tenant schema');
+ }
+ return `"${schema.replace(/"/g, '""')}"`;
+}
+
+export async function withTenant(poolName, tenantSchema, fn) {
+ const pool = getPool(poolName);
+ const client = await pool.connect();
+ try {
+ await client.query('BEGIN');
+ await client.query(`SET LOCAL search_path TO ${assertTenantSchema(tenantSchema)}`);
+ const res = await fn(client);
+ await client.query('COMMIT');
+ return res;
+ } catch (e) {
+ try { await client.query('ROLLBACK'); } catch {}
+ throw e;
+ } finally {
+ client.release();
+ }
+}
+
+export async function shutdownAll() {
+ await Promise.all([...REGISTRY.values()].map(p => p.end()));
+ REGISTRY.clear();
+}
diff --git a/packages/db/src/poolSingleton.mjs b/packages/db/src/poolSingleton.mjs
new file mode 100644
index 0000000..35d0fae
--- /dev/null
+++ b/packages/db/src/poolSingleton.mjs
@@ -0,0 +1,46 @@
+// Coneción Singleton a base de datos.
+
+import { Pool } from 'pg';
+
+class Database {
+ constructor() {
+
+ if (Database.instance) {
+ return Database.instance;
+ }
+
+ const config = {
+ host: process.env.DB_HOST,
+ user: process.env.DB_USER,
+ password: process.env.DB_PASS,
+ database: process.env.DB_NAME,
+ port: process.env.DB_LOCAL_PORT ? Number(process.env.DB_LOCAL_PORT) : undefined,
+ ssl: process.env.PGSSL === 'true' ? { rejectUnauthorized: false } : undefined,
+ };
+
+ this.connection = new Pool(config);
+
+ Database.instance = this;
+ }
+ async query(sql, params) {
+ return this.connection.query(sql,params);
+ }
+
+ async connect() { /* Definida solo para evitar errores */
+ return this.connection.connect();
+ }
+ async getClient() {
+ return this.connection.connect();
+ }
+
+ async release() {
+ await this.connection.end();
+ }
+}
+
+// const db = new Database();
+// db.query('SELECT * FROM users');
+
+const pool = new Database();
+export default pool;
+export { Database };
\ No newline at end of file
diff --git a/services/app/.env.development b/services/app/.env.development
index 4e75a73..4ad8890 100644
--- a/services/app/.env.development
+++ b/services/app/.env.development
@@ -2,37 +2,61 @@
NODE_ENV=development
PORT=3030
+
# ===== Session (usa el Redis del stack) =====
# Para DEV podemos reutilizar el Redis de Authentik. En prod conviene uno separado.
SESSION_SECRET=Neon*Mammal*Boaster*Ludicrous*Fender8*Crablike
SESSION_COOKIE_NAME=sc.sid
-REDIS_URL=redis://ak-redis:6379
# ===== DB principal (metadatos de SuiteCoffee) =====
# Usa el alias de red del servicio 'db' (compose: aliases [dev-db])
DB_HOST=dev-db
+DB_NAME=dev_suitecoffee_core
DB_PORT=5432
-DB_NAME=dev-suitecoffee
DB_USER=dev-user-suitecoffee
DB_PASS=dev-pass-suitecoffee
+CORE_DB_HOST=dev-db
+CORE_DB_NAME=dev_suitecoffee_core
+CORE_DB_PORT=5432
+CORE_DB_USER=dev-user-suitecoffee
+CORE_DB_PASS=dev-pass-suitecoffee
+
# ===== DB tenants (Tenants de SuiteCoffee) =====
TENANTS_HOST=dev-tenants
-TENANTS_DB=dev-postgres
-TENANTS_USER=dev-user-postgres
-TENANTS_PASS=dev-pass-postgres
+TENANTS_DB=dev_suitecoffee_tenants
TENANTS_PORT=5432
+TENANTS_USER=suitecoffee
+TENANTS_PASS=suitecoffee
-TENANT_INIT_SQL=/app/src/db/initTenant_v2.sql
+TENANTS_DB_HOST=dev-tenants
+TENANTS_DB_NAME=dev_suitecoffee_tenants
+TENANTS_DB_PORT=5432
+TENANTS_DB_USER=suitecoffee
+TENANTS_DB_PASS=suitecoffee
+
+
+# ===== Authentik — Admin API (server-to-server dentro de la red) =====
+# Usa el alias de red del servicio 'authentik' y su puerto interno 9000
+AK_TOKEN=h2apVHbd3ApMcnnSwfQPXbvximkvP8HnUE25ot3zXWuEEtJFaNCcOzDHB6Xw
+AK_REDIS_URL=redis://ak-redis:6379
+
+# ===== OIDC (DEBE coincidir con el Provider) =====
+# DEV (todo dentro de la red de Docker):
+# - El auth service redirige al navegador a este issuer. Si NO tenés reverse proxy hacia Authentik,
+# esta URL interna NO será accesible desde el navegador del host. En ese caso, ver nota más abajo.
+
+APP_BASE_URL=https://suitecoffee.uy
+
+OIDC_LOGIN_URL=https://sso.suitecoffee.uy
+OIDC_REDIRECT_URI = https://suitecoffee.uy/auth/callback
OIDC_CLIEN_ID=1orMM8vOvf3WkN2FejXYvUFpPtONG0Lx1eMlwIpW
OIDC_CONFIG_URL=https://sso.suitecoffee.uy/application/o/suitecoffee/.well-known/openid-configuration
OIDC_ISSUER=https://sso.suitecoffee.uy/application/o/suitecoffee/
+OIDC_ISSUER_DISCOVERY=https://sso.suitecoffee.uy/application/o/suitecoffee/.well-known/openid-configuration
OIDC_AUTHORIZE_URL=https://sso.suitecoffee.uy/application/o/authorize/
OIDC_TOKEN_URL=https://sso.suitecoffee.uy/application/o/token/
OIDC_USERINFO_URL=https://sso.suitecoffee.uy/application/o/userinfo/
OIDC_LOGOUT_URL=https://sso.suitecoffee.uy/application/o/suitecoffee/end-session/
-OIDC_JWKS_URL=https://sso.suitecoffee.uy/application/o/suitecoffee/jwks/
-
-OIDC_LOGIN_URL=https://sso.suitecoffee.uy
-APP_BASE_URL=https://suitecoffee.uy
+OIDC_JWKS_URL=https://sso.suitecoffee.uy/application/o/suitecoffee/jwks/
\ No newline at end of file
diff --git a/services/app/Dockerfile.production b/services/app/Dockerfile.production
index 2b2dcf3..20e5cfa 100644
--- a/services/app/Dockerfile.production
+++ b/services/app/Dockerfile.production
@@ -1,5 +1,5 @@
# Dockerfile.dev
-FROM node:22.18
+FROM node:20.19.5-bookworm
# Definir variables de entorno con valores predeterminados
# ARG NODE_ENV=production
diff --git a/services/app/package-lock.json b/services/app/package-lock.json
index 6df8869..bedd6b7 100644
--- a/services/app/package-lock.json
+++ b/services/app/package-lock.json
@@ -24,6 +24,7 @@
"jsonwebtoken": "^9.0.2",
"jwks-rsa": "^3.2.0",
"morgan": "^1.10.1",
+ "node-appwrite": "^20.2.1",
"node-fetch": "^3.3.2",
"pg": "^8.16.3",
"pg-format": "^1.0.4",
@@ -42,14 +43,10 @@
},
"node_modules/@ioredis/commands": {
"version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.3.1.tgz",
- "integrity": "sha512-bYtU8avhGIcje3IhvF9aSjsa5URMZBHnwKtOvXsT4sfYy9gppW11gLPT/9oNqlJZD47yPKveQFTAFWpHjKvUoQ==",
"license": "MIT"
},
"node_modules/@redis/bloom": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.8.2.tgz",
- "integrity": "sha512-855DR0ChetZLarblio5eM0yLwxA9Dqq50t8StXKp5bAtLT0G+rZ+eRzzqxl37sPqQKjUudSYypz55o6nNhbz0A==",
"license": "MIT",
"engines": {
"node": ">= 18"
@@ -60,8 +57,6 @@
},
"node_modules/@redis/client": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.8.2.tgz",
- "integrity": "sha512-WtMScno3+eBpTac1Uav2zugXEoXqaU23YznwvFgkPwBQVwEHTDgOG7uEAObtZ/Nyn8SmAMbqkEubJaMOvnqdsQ==",
"license": "MIT",
"dependencies": {
"cluster-key-slot": "1.1.2"
@@ -72,8 +67,6 @@
},
"node_modules/@redis/json": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.8.2.tgz",
- "integrity": "sha512-uxpVfas3I0LccBX9rIfDgJ0dBrUa3+0Gc8sEwmQQH0vHi7C1Rx1Qn8Nv1QWz5bohoeIXMICFZRcyDONvum2l/w==",
"license": "MIT",
"engines": {
"node": ">= 18"
@@ -84,8 +77,6 @@
},
"node_modules/@redis/search": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.8.2.tgz",
- "integrity": "sha512-cNv7HlgayavCBXqPXgaS97DRPVWFznuzsAmmuemi2TMCx5scwLiP50TeZvUS06h/MG96YNPe6A0Zt57yayfxwA==",
"license": "MIT",
"engines": {
"node": ">= 18"
@@ -96,8 +87,6 @@
},
"node_modules/@redis/time-series": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.8.2.tgz",
- "integrity": "sha512-g2NlHM07fK8H4k+613NBsk3y70R2JIM2dPMSkhIjl2Z17SYvaYKdusz85d7VYOrZBWtDrHV/WD2E3vGu+zni8A==",
"license": "MIT",
"engines": {
"node": ">= 18"
@@ -108,8 +97,6 @@
},
"node_modules/@types/body-parser": {
"version": "1.19.6",
- "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
- "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
"license": "MIT",
"dependencies": {
"@types/connect": "*",
@@ -118,8 +105,6 @@
},
"node_modules/@types/connect": {
"version": "3.4.38",
- "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
- "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
@@ -127,8 +112,6 @@
},
"node_modules/@types/express": {
"version": "4.17.23",
- "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz",
- "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==",
"license": "MIT",
"dependencies": {
"@types/body-parser": "*",
@@ -139,8 +122,6 @@
},
"node_modules/@types/express-serve-static-core": {
"version": "4.19.6",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz",
- "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==",
"license": "MIT",
"dependencies": {
"@types/node": "*",
@@ -151,14 +132,10 @@
},
"node_modules/@types/http-errors": {
"version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
- "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
"license": "MIT"
},
"node_modules/@types/jsonwebtoken": {
"version": "9.0.10",
- "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
- "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==",
"license": "MIT",
"dependencies": {
"@types/ms": "*",
@@ -167,20 +144,14 @@
},
"node_modules/@types/mime": {
"version": "1.3.5",
- "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
- "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
"license": "MIT"
},
"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/node": {
"version": "24.3.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz",
- "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==",
"license": "MIT",
"dependencies": {
"undici-types": "~7.10.0"
@@ -188,20 +159,14 @@
},
"node_modules/@types/qs": {
"version": "6.14.0",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
- "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
"license": "MIT"
},
"node_modules/@types/range-parser": {
"version": "1.2.7",
- "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
- "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
"license": "MIT"
},
"node_modules/@types/send": {
"version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz",
- "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==",
"license": "MIT",
"dependencies": {
"@types/mime": "^1",
@@ -210,8 +175,6 @@
},
"node_modules/@types/serve-static": {
"version": "1.15.8",
- "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz",
- "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==",
"license": "MIT",
"dependencies": {
"@types/http-errors": "*",
@@ -252,8 +215,6 @@
},
"node_modules/basic-auth": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
- "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
"license": "MIT",
"dependencies": {
"safe-buffer": "5.1.2"
@@ -264,14 +225,10 @@
},
"node_modules/basic-auth/node_modules/safe-buffer": {
"version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/bcrypt": {
"version": "6.0.0",
- "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
- "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -333,8 +290,6 @@
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
- "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
"license": "BSD-3-Clause"
},
"node_modules/bytes": {
@@ -404,8 +359,6 @@
},
"node_modules/cluster-key-slot": {
"version": "1.1.2",
- "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
- "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10.0"
@@ -418,8 +371,6 @@
},
"node_modules/connect-redis": {
"version": "9.0.0",
- "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-9.0.0.tgz",
- "integrity": "sha512-QwzyvUePTMvEzG1hy45gZYw3X3YHrjmEdSkayURlcZft7hqadQ3X39wYkmCqblK2rGlw+XItELYt6GnyG6DEIQ==",
"license": "MIT",
"engines": {
"node": ">=18"
@@ -448,6 +399,8 @@
},
"node_modules/cookie": {
"version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -521,8 +474,6 @@
},
"node_modules/data-uri-to-buffer": {
"version": "4.0.1",
- "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
- "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
"license": "MIT",
"engines": {
"node": ">= 12"
@@ -545,8 +496,6 @@
},
"node_modules/denque": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
- "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
@@ -583,8 +532,6 @@
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
- "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
- "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
@@ -694,8 +641,6 @@
},
"node_modules/express-session": {
"version": "1.18.2",
- "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz",
- "integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==",
"license": "MIT",
"dependencies": {
"cookie": "0.7.2",
@@ -713,14 +658,10 @@
},
"node_modules/express-session/node_modules/cookie-signature": {
"version": "1.0.7",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
- "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
"license": "MIT"
},
"node_modules/express-session/node_modules/debug": {
"version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
@@ -728,14 +669,10 @@
},
"node_modules/express-session/node_modules/ms": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/fetch-blob": {
"version": "3.2.0",
- "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
- "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
"funding": [
{
"type": "github",
@@ -807,8 +744,6 @@
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
- "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
- "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"license": "MIT",
"dependencies": {
"fetch-blob": "^3.1.2"
@@ -962,8 +897,6 @@
},
"node_modules/ioredis": {
"version": "5.7.0",
- "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.7.0.tgz",
- "integrity": "sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g==",
"license": "MIT",
"dependencies": {
"@ioredis/commands": "^1.3.0",
@@ -1055,8 +988,6 @@
},
"node_modules/jose": {
"version": "6.1.0",
- "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz",
- "integrity": "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
@@ -1064,8 +995,6 @@
},
"node_modules/jsonwebtoken": {
"version": "9.0.2",
- "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
- "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
"license": "MIT",
"dependencies": {
"jws": "^3.2.2",
@@ -1086,8 +1015,6 @@
},
"node_modules/jwa": {
"version": "1.4.2",
- "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
- "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
"license": "MIT",
"dependencies": {
"buffer-equal-constant-time": "^1.0.1",
@@ -1097,8 +1024,6 @@
},
"node_modules/jwks-rsa": {
"version": "3.2.0",
- "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.2.0.tgz",
- "integrity": "sha512-PwchfHcQK/5PSydeKCs1ylNym0w/SSv8a62DgHJ//7x2ZclCoinlsjAfDxAAbpoTPybOum/Jgy+vkvMmKz89Ww==",
"license": "MIT",
"dependencies": {
"@types/express": "^4.17.20",
@@ -1114,8 +1039,6 @@
},
"node_modules/jwks-rsa/node_modules/jose": {
"version": "4.15.9",
- "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
- "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
@@ -1123,8 +1046,6 @@
},
"node_modules/jws": {
"version": "3.2.2",
- "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
- "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"license": "MIT",
"dependencies": {
"jwa": "^1.4.1",
@@ -1132,74 +1053,50 @@
}
},
"node_modules/limiter": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz",
- "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="
+ "version": "1.1.5"
},
"node_modules/lodash.clonedeep": {
"version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
- "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
"license": "MIT"
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
- "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
"license": "MIT"
},
"node_modules/lodash.includes": {
"version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
- "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
"license": "MIT"
},
"node_modules/lodash.isarguments": {
"version": "3.1.0",
- "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
- "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
"license": "MIT"
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
- "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
- "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
"license": "MIT"
},
"node_modules/lodash.isinteger": {
"version": "4.0.4",
- "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
- "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
"license": "MIT"
},
"node_modules/lodash.isnumber": {
"version": "3.0.3",
- "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
- "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
- "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
- "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"license": "MIT"
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
- "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
- "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"license": "MIT"
},
"node_modules/lodash.once": {
"version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
- "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/lru-cache": {
"version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
@@ -1210,8 +1107,6 @@
},
"node_modules/lru-memoizer": {
"version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz",
- "integrity": "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==",
"license": "MIT",
"dependencies": {
"lodash.clonedeep": "^4.5.0",
@@ -1272,8 +1167,6 @@
},
"node_modules/morgan": {
"version": "1.10.1",
- "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz",
- "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==",
"license": "MIT",
"dependencies": {
"basic-auth": "~2.0.1",
@@ -1288,8 +1181,6 @@
},
"node_modules/morgan/node_modules/debug": {
"version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
@@ -1297,14 +1188,10 @@
},
"node_modules/morgan/node_modules/ms": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/morgan/node_modules/on-finished": {
"version": "2.3.0",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
- "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
"license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
@@ -1326,18 +1213,22 @@
},
"node_modules/node-addon-api": {
"version": "8.5.0",
- "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz",
- "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==",
"license": "MIT",
"engines": {
"node": "^18 || ^20 || >= 21"
}
},
+ "node_modules/node-appwrite": {
+ "version": "20.2.1",
+ "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-20.2.1.tgz",
+ "integrity": "sha512-RweIh+3RHjprsxhWaJzcQr/UDMBMsZCma50TIJ9t3onVgs5jAT9aqFnsMlaaC9QZn1sXpPUQV90W6uvtm64DnQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "node-fetch-native-with-agent": "1.7.2"
+ }
+ },
"node_modules/node-domexception": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
- "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
- "deprecated": "Use your platform's native DOMException instead",
"funding": [
{
"type": "github",
@@ -1355,8 +1246,6 @@
},
"node_modules/node-fetch": {
"version": "3.3.2",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
- "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
"license": "MIT",
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
@@ -1371,10 +1260,14 @@
"url": "https://opencollective.com/node-fetch"
}
},
+ "node_modules/node-fetch-native-with-agent": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/node-fetch-native-with-agent/-/node-fetch-native-with-agent-1.7.2.tgz",
+ "integrity": "sha512-5MaOOCuJEvcckoz7/tjdx1M6OusOY6Xc5f459IaruGStWnKzlI1qpNgaAwmn4LmFYcsSlj+jBMk84wmmRxfk5g==",
+ "license": "MIT"
+ },
"node_modules/node-gyp-build": {
"version": "4.8.4",
- "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
- "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
"license": "MIT",
"bin": {
"node-gyp-build": "bin.js",
@@ -1446,8 +1339,6 @@
},
"node_modules/on-headers": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
- "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -1484,6 +1375,8 @@
},
"node_modules/pg": {
"version": "8.16.3",
+ "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
+ "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
"license": "MIT",
"dependencies": {
"pg-connection-string": "^2.9.1",
@@ -1509,11 +1402,15 @@
},
"node_modules/pg-cloudflare": {
"version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz",
+ "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==",
"license": "MIT",
"optional": true
},
"node_modules/pg-connection-string": {
"version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz",
+ "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==",
"license": "MIT"
},
"node_modules/pg-format": {
@@ -1525,6 +1422,8 @@
},
"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==",
"license": "ISC",
"engines": {
"node": ">=4.0.0"
@@ -1532,6 +1431,8 @@
},
"node_modules/pg-pool": {
"version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz",
+ "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==",
"license": "MIT",
"peerDependencies": {
"pg": ">=8.0"
@@ -1539,10 +1440,14 @@
},
"node_modules/pg-protocol": {
"version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz",
+ "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==",
"license": "MIT"
},
"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==",
"license": "MIT",
"dependencies": {
"pg-int8": "1.0.1",
@@ -1557,6 +1462,8 @@
},
"node_modules/pgpass": {
"version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
+ "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
"license": "MIT",
"dependencies": {
"split2": "^4.1.0"
@@ -1579,6 +1486,8 @@
},
"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==",
"license": "MIT",
"engines": {
"node": ">=4"
@@ -1586,6 +1495,8 @@
},
"node_modules/postgres-bytea": {
"version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
+ "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -1593,6 +1504,8 @@
},
"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==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -1600,6 +1513,8 @@
},
"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==",
"license": "MIT",
"dependencies": {
"xtend": "^4.0.0"
@@ -1639,8 +1554,6 @@
},
"node_modules/random-bytes": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
- "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -1679,8 +1592,6 @@
},
"node_modules/redis": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/redis/-/redis-5.8.2.tgz",
- "integrity": "sha512-31vunZj07++Y1vcFGcnNWEf5jPoTkGARgfWI4+Tk55vdwHxhAvug8VEtW7Cx+/h47NuJTEg/JL77zAwC6E0OeA==",
"license": "MIT",
"dependencies": {
"@redis/bloom": "5.8.2",
@@ -1695,8 +1606,6 @@
},
"node_modules/redis-errors": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
- "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
"license": "MIT",
"engines": {
"node": ">=4"
@@ -1704,8 +1613,6 @@
},
"node_modules/redis-parser": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
- "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
"license": "MIT",
"dependencies": {
"redis-errors": "^1.0.0"
@@ -1914,6 +1821,8 @@
},
"node_modules/split2": {
"version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+ "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
"license": "ISC",
"engines": {
"node": ">= 10.x"
@@ -1921,8 +1830,6 @@
},
"node_modules/standard-as-callback": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
- "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
"license": "MIT"
},
"node_modules/statuses": {
@@ -1983,8 +1890,6 @@
},
"node_modules/uid-safe": {
"version": "2.1.5",
- "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
- "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
"license": "MIT",
"dependencies": {
"random-bytes": "~1.0.0"
@@ -2000,8 +1905,6 @@
},
"node_modules/undici-types": {
"version": "7.10.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
- "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
"license": "MIT"
},
"node_modules/unpipe": {
@@ -2020,8 +1923,6 @@
},
"node_modules/web-streams-polyfill": {
"version": "3.3.3",
- "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
- "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"license": "MIT",
"engines": {
"node": ">= 8"
@@ -2047,6 +1948,8 @@
},
"node_modules/xtend": {
"version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"license": "MIT",
"engines": {
"node": ">=0.4"
@@ -2054,8 +1957,6 @@
},
"node_modules/yallist": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"license": "ISC"
}
}
diff --git a/services/app/package.json b/services/app/package.json
index 9ae6e52..6b65566 100644
--- a/services/app/package.json
+++ b/services/app/package.json
@@ -1,11 +1,11 @@
{
"name": "aplication",
"version": "1.0.0",
- "main": "src/index.js",
+ "main": "src/index.mjs",
"scripts": {
- "start": "NODE_ENV=production node ./src/index.js",
- "dev": "NODE_ENV=development npx nodemon ./src/index.js",
- "test": "NODE_ENV=stage node ./src/index.js"
+ "start": "NODE_ENV=production node ./src/index.mjs",
+ "dev": "NODE_ENV=development npx nodemon ./src/index.mjs",
+ "test": "NODE_ENV=stage node ./src/index.mjs"
},
"author": "Mateo Saldain",
"license": "ISC",
@@ -30,12 +30,18 @@
"jsonwebtoken": "^9.0.2",
"jwks-rsa": "^3.2.0",
"morgan": "^1.10.1",
+ "node-appwrite": "^20.2.1",
"node-fetch": "^3.3.2",
"pg": "^8.16.3",
"pg-format": "^1.0.4",
"redis": "^5.8.2",
"serve-favicon": "^2.5.1"
},
- "keywords": [],
+ "imports": {
+ "#v1Router": "./src/api/v1/routes/routes.js",
+ "#pages": "./src/pages/pages.js",
+ "#db": "./src/db/poolSingleton.js"
+ },
+ "keywords": [],
"description": ""
}
diff --git a/services/app/src/api/v1/routes/routes.js b/services/app/src/api/v1/routes/routes.js
new file mode 100644
index 0000000..c17f2cc
--- /dev/null
+++ b/services/app/src/api/v1/routes/routes.js
@@ -0,0 +1,340 @@
+// services/manso/src/api/v1/routes/routes.js
+
+import { Router } from 'express';
+import pool from '#db'; // Pool Singleton
+const router = Router();
+
+// ==========================================================
+// Rutas de API v1
+// ==========================================================
+
+
+
+// ----------------------------------------------------------
+// API Comandas
+// ----------------------------------------------------------
+
+router.route('/comandas').get( async (req, res, next) => {
+ try {
+ var client = await pool.getClient()
+ const estado = (req.query.estado || '').trim() || null;
+ const limit = Math.min(parseInt(req.query.limit || '200', 10), 1000);
+
+ const { rows } = await client.query(
+ `SELECT * FROM public.f_comandas_resumen($1, $2)`,
+ [estado, limit]
+ );
+ res.json(rows);
+ } catch (e) {
+ next(e);
+ } finally {
+ client.release();
+ }
+});
+
+router.route('/comandas/:id/detalle').get( async (req, res, next) => {
+ try {
+ const client = await pool.getClient()
+ client.query(
+ `SELECT id_det_comanda, id_producto, producto_nombre,
+ cantidad, pre_unitario, subtotal, observaciones
+ FROM public.v_comandas_detalle_items
+ WHERE id_comanda = $1::int
+ ORDER BY id_det_comanda`,
+ [req.params.id]
+ )
+ .then(r => res.json(r.rows))
+ .catch(next)
+ client.release();
+ } catch (error) {
+ next(e);
+ }
+});
+
+router.route('/comandas/:id/cerrar').post( async (req, res, next) => {
+ try {
+ const client = await pool.getClient()
+ const id = Number(req.params.id);
+ if (!Number.isInteger(id) || id <= 0) {
+ return res.status(400).json({ error: 'id inválido' });
+ }
+ const { rows } = await client.query(
+ `SELECT public.f_cerrar_comanda($1) AS data`,
+ [id]
+ );
+ if (!rows.length || rows[0].data === null) {
+ return res.status(404).json({ error: 'Comanda no encontrada' });
+ }
+ res.json(rows[0].data);
+ client.release();
+ } catch (err) { next(err); }
+});
+
+router.route('/comandas/:id/abrir').post( async (req, res, next) => {
+ try {
+ const client = await pool.getClient()
+ const id = Number(req.params.id);
+ if (!Number.isInteger(id) || id <= 0) {
+ return res.status(400).json({ error: 'id inválido' });
+ }
+ const { rows } = await client.query(
+ `SELECT public.f_abrir_comanda($1) AS data`,
+ [id]
+ );
+ if (!rows.length || rows[0].data === null) {
+ return res.status(404).json({ error: 'Comanda no encontrada' });
+ }
+ res.json(rows[0].data);
+ client.release();
+ } catch (err) { next(err); }
+});
+
+
+
+// ----------------------------------------------------------
+// API Productos
+// ----------------------------------------------------------
+
+// GET producto + receta
+router.route('/rpc/get_producto/:id').get( async (req, res) => {
+ const client = await pool.getClient()
+ const id = Number(req.params.id);
+ const { rows } = await client.query('SELECT public.get_producto($1) AS data', [id]);
+ res.json(rows[0]?.data || {});
+ client.release();
+});
+
+// POST guardar producto + receta
+router.route('/rpc/save_producto').post(async (req, res) => {
+ try {
+ // console.debug('receta payload:', req.body?.receta); // habilitalo si lo necesitás
+ const client = await pool.getClient()
+ const q = 'SELECT public.save_producto($1,$2,$3,$4,$5,$6,$7::jsonb) AS id_producto';
+ const { id_producto=null, nombre, img_producto=null, precio=0, activo=true, id_categoria=null, receta=[] } = req.body || {};
+ const params = [id_producto, nombre, img_producto, precio, activo, id_categoria, JSON.stringify(receta||[])];
+ const { rows } = await client.query(q, params);
+ res.json(rows[0] || {});
+ client.release();
+ } catch(e) {
+ console.error(e);
+ res.status(500).json({ error: 'save_producto failed' });
+ }
+});
+
+
+
+// ----------------------------------------------------------
+// API Materias Primas
+// ----------------------------------------------------------
+
+// GET MP + proveedores
+router.route('/rpc/get_materia/:id').get(async (req, res) => {
+ const id = Number(req.params.id);
+ try {
+ const client = await pool.getClient()
+ const { rows } = await client.query('SELECT public.get_materia_prima($1) AS data', [id]);
+ res.json(rows[0]?.data || {});
+ client.release();
+ } catch (e) {
+ console.error(e);
+ res.status(500).json({ error: 'get_materia failed' });
+ }
+});
+
+// SAVE MP + proveedores (array)
+router.route('/rpc/save_materia').post( async (req, res) => {
+ const { id_mat_prima=null, nombre, unidad, activo=true, proveedores=[] } = req.body || {};
+ try {
+ const q = 'SELECT public.save_materia_prima($1,$2,$3,$4,$5::jsonb) AS id_mat_prima';
+ const params = [id_mat_prima, nombre, unidad, activo, JSON.stringify(proveedores||[])];
+ const { rows } = await pool.query(q, params);
+ res.json(rows[0] || {});
+ } catch (e) {
+ console.error(e);
+ res.status(500).json({ error: 'save_materia failed' });
+ }
+});
+
+
+
+// ----------------------------------------------------------
+// API Usuarios y Asistencias
+// ----------------------------------------------------------
+
+// POST /api/rpc/find_usuarios_por_documentos { docs: ["12345678","09123456", ...] }
+router.route('/rpc/find_usuarios_por_documentos').post( async (req, res) => {
+ try {
+ const docs = Array.isArray(req.body?.docs) ? req.body.docs : [];
+ const sql = 'SELECT public.find_usuarios_por_documentos($1::jsonb) AS data';
+ const { rows } = await pool.query(sql, [JSON.stringify(docs)]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e);
+ res.status(500).json({ error: 'find_usuarios_por_documentos failed' });
+ }
+});
+
+// POST /api/rpc/import_asistencia { registros: [...], origen?: "AGL_001.txt" }
+router.route('/rpc/import_asistencia').post( async (req, res) => {
+ try {
+ const registros = Array.isArray(req.body?.registros) ? req.body.registros : [];
+ const origen = req.body?.origen || null;
+ const sql = 'SELECT public.import_asistencia($1::jsonb,$2) AS data';
+ const { rows } = await pool.query(sql, [JSON.stringify(registros), origen]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e);
+ res.status(500).json({ error: 'import_asistencia failed' });
+ }
+});
+
+// Consultar datos de asistencia (raw + pares) para un usuario y rango
+router.route('/rpc/asistencia_get').post( async (req, res) => {
+ try {
+ const { doc, desde, hasta } = req.body || {};
+ const sql = 'SELECT public.asistencia_get($1::text,$2::date,$3::date) AS data';
+ const { rows } = await pool.query(sql, [doc, desde, hasta]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e); res.status(500).json({ error: 'asistencia_get failed' });
+ }
+});
+
+// Editar un registro crudo y recalcular pares
+router.route('/rpc/asistencia_update_raw').post( async (req, res) => {
+ try {
+ const { id_raw, fecha, hora, modo } = req.body || {};
+ const sql = 'SELECT public.asistencia_update_raw($1::bigint,$2::date,$3::text,$4::text) AS data';
+ const { rows } = await pool.query(sql, [id_raw, fecha, hora, modo ?? null]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e); res.status(500).json({ error: 'asistencia_update_raw failed' });
+ }
+});
+
+// Eliminar un registro crudo y recalcular pares
+router.route('/rpc/asistencia_delete_raw').post( async (req, res) => {
+ try {
+ const { id_raw } = req.body || {};
+ const sql = 'SELECT public.asistencia_delete_raw($1::bigint) AS data';
+ const { rows } = await pool.query(sql, [id_raw]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e); res.status(500).json({ error: 'asistencia_delete_raw failed' });
+ }
+});
+
+
+// ----------------------------------------------------------
+// API Reportes
+// ----------------------------------------------------------
+
+// POST /api/rpc/report_tickets { year }
+router.route('/rpc/report_tickets').post( async (req, res) => {
+ try {
+ const y = parseInt(req.body?.year ?? req.query?.year, 10);
+ const year = (Number.isFinite(y) && y >= 2000 && y <= 2100)
+ ? y
+ : (new Date()).getFullYear();
+
+ const { rows } = await pool.query(
+ 'SELECT public.report_tickets_year($1::int) AS j', [year]
+ );
+ res.json(rows[0].j);
+ } catch (e) {
+ console.error('report_tickets error:', e);
+ res.status(500).json({
+ error: 'report_tickets failed',
+ message: e.message, detail: e.detail, where: e.where, code: e.code
+ });
+ }
+});
+
+// POST /api/rpc/report_asistencia { desde: 'YYYY-MM-DD', hasta: 'YYYY-MM-DD' }
+router.route('/rpc/report_asistencia').post( async (req, res) => {
+ try {
+ let { desde, hasta } = req.body || {};
+ // defaults si vienen vacíos/invalidos
+ const re = /^\d{4}-\d{2}-\d{2}$/;
+ if (!re.test(desde) || !re.test(hasta)) {
+ const end = new Date();
+ const start = new Date(end); start.setDate(end.getDate()-30);
+ desde = start.toISOString().slice(0,10);
+ hasta = end.toISOString().slice(0,10);
+ }
+
+ const { rows } = await pool.query(
+ 'SELECT public.report_asistencia($1::date,$2::date) AS j', [desde, hasta]
+ );
+ res.json(rows[0].j);
+ } catch (e) {
+ console.error('report_asistencia error:', e);
+ res.status(500).json({
+ error: 'report_asistencia failed',
+ message: e.message, detail: e.detail, where: e.where, code: e.code
+ });
+ }
+});
+
+// ----------------------------------------------------------
+// API Compras y Gastos
+// ----------------------------------------------------------
+
+// Guardar (insert/update)
+router.route('/rpc/save_compra').post( async (req, res) => {
+ try {
+ const { id_compra, id_proveedor, fec_compra, detalles } = req.body || {};
+ const sql = 'SELECT * FROM public.save_compra($1::int,$2::int,$3::timestamptz,$4::jsonb)';
+ const args = [id_compra ?? null, id_proveedor, fec_compra ? new Date(fec_compra) : null, JSON.stringify(detalles)];
+ const { rows } = await pool.query(sql, args);
+ res.json(rows[0]); // { id_compra, total }
+ } catch (e) {
+ console.error('save_compra error:', e);
+ res.status(500).json({ error: 'save_compra failed', message: e.message, detail: e.detail, where: e.where, code: e.code });
+ }
+});
+
+
+// Obtener para editar
+router.route('/rpc/get_compra').post( async (req, res) => {
+ try {
+ const { id_compra } = req.body || {};
+ const sql = `SELECT public.get_compra($1::int) AS data`;
+ const { rows } = await pool.query(sql, [id_compra]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e); res.status(500).json({ error: 'get_compra failed' });
+ }
+});
+
+// Eliminar
+router.route('/rpc/delete_compra').post( async (req, res) => {
+ try {
+ const { id_compra } = req.body || {};
+ await pool.query(`SELECT public.delete_compra($1::int)`, [id_compra]);
+ res.json({ ok: true });
+ } catch (e) {
+ console.error(e); res.status(500).json({ error: 'delete_compra failed' });
+ }
+});
+
+
+// POST /api/rpc/report_gastos { year: 2025 }
+router.route('/rpc/report_gastos').post( async (req, res) => {
+ try {
+ const year = parseInt(req.body?.year ?? new Date().getFullYear(), 10);
+ const { rows } = await pool.query(
+ 'SELECT public.report_gastos($1::int) AS j', [year]
+ );
+ res.json(rows[0].j);
+ } catch (e) {
+ console.error('report_gastos error:', e);
+ res.status(500).json({
+ error: 'report_gastos failed',
+ message: e.message, detail: e.detail, code: e.code
+ });
+ }
+});
+
+
+export default router;
\ No newline at end of file
diff --git a/services/app/src/db/poolSingleton.js b/services/app/src/db/poolSingleton.js
new file mode 100644
index 0000000..a0935c2
--- /dev/null
+++ b/services/app/src/db/poolSingleton.js
@@ -0,0 +1,83 @@
+// Coneción Singleton a base de datos.
+
+import { Pool } from 'pg';
+
+class DatabaseCore {
+ constructor() {
+
+ if (DatabaseCore.instance) {
+ return Database.instance;
+ }
+
+ const config = {
+ host: process.env.DB_HOST,
+ user: process.env.DB_USER,
+ password: process.env.DB_PASS,
+ database: process.env.DB_NAME,
+ port: process.env.DB_LOCAL_PORT ? Number(process.env.DB_LOCAL_PORT) : undefined,
+ ssl: process.env.PGSSL === 'true' ? { rejectUnauthorized: false } : undefined,
+ };
+
+ this.connection = new Pool(config);
+
+ DatabaseCore.instance = this;
+ }
+ async query(sql, params) {
+ return this.connection.query(sql,params);
+ }
+
+ async connect() { /* Definida solo para evitar errores */
+ return this.connection.connect();
+ }
+ async getClient() {
+ return this.connection.connect();
+ }
+
+ async release() {
+ await this.connection.end();
+ }
+}
+class DatabaseTenants {
+ constructor() {
+
+ if (DatabaseTenants.instance) {
+ return Database.instance;
+ }
+
+ const config = {
+ host: process.env.DB_HOST,
+ user: process.env.DB_USER,
+ password: process.env.DB_PASS,
+ database: process.env.DB_NAME,
+ port: process.env.DB_LOCAL_PORT ? Number(process.env.DB_LOCAL_PORT) : undefined,
+ ssl: process.env.PGSSL === 'true' ? { rejectUnauthorized: false } : undefined,
+ };
+
+ this.connection = new Pool(config);
+
+ DatabaseTenants.instance = this;
+ }
+ async query(sql, params) {
+ return this.connection.query(sql,params);
+ }
+
+ async connect() { /* Definida solo para evitar errores */
+ return this.connection.connect();
+ }
+ async getClient() {
+ return this.connection.connect();
+ }
+
+ async release() {
+ await this.connection.end();
+ }
+}
+
+// const db = new Database();
+// db.query('SELECT * FROM users');
+
+const poolCore = new DatabaseCore();
+const poolTenants = new DatabaseTenants();
+export default {poolCore, poolTenants};
+export { poolCore, poolTenants };
+//export { DatabaseCore, DatabaseTenants };
\ No newline at end of file
diff --git a/services/app/src/index.js b/services/app/src/index.js
deleted file mode 100644
index 174a4af..0000000
--- a/services/app/src/index.js
+++ /dev/null
@@ -1,377 +0,0 @@
-// // services/app/src/index.js
-// // ------------------------------------------------------------
-// // SuiteCoffee — Servicio APP (UI + APIs negocio)
-// // - Vistas EJS en ./views (dashboard.ejs, comandas.ejs, etc.)
-// // - Sesión compartida con AUTH (cookie: sc.sid, Redis)
-// // ------------------------------------------------------------
-import 'dotenv/config'; // Variables de entorno directamente
-// import dotenv from 'dotenv';
-import favicon from 'serve-favicon'; // Favicon
-
-import cors from 'cors'; // Seguridad en solicitudes de orige
-import { Pool } from 'pg'; // Controlador node-postgres
-import path from 'node:path'; // Rutas del servidor
-import { fileURLToPath } from 'url'; // Converts a file:// URL string or URL object into a platform-specific file
-
-import expressLayouts from 'express-ejs-layouts';
-import express from 'express'; // Framework para enderizado de apps Web
-import { jwtVerify, createRemoteJWKSet } from "jose";
-
-import cookieParser from 'cookie-parser';
-
-import { loadColumns, loadForeignKeys, loadPrimaryKey, pickLabelColumn } from "./utilities/cargaEnVista.js";
-
-import { createRedisSession } from "../shared/middlewares/redisConnect.js";
-// // ----------------------------------------------------------
-// // Utilidades
-// // ----------------------------------------------------------
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-// const url = v => !v ? "" : (v.startsWith("http") ? v : `/img/productos/${v}`);
-// const VALID_IDENT = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
-
-// // Identificadores SQL -> comillas dobles y escape correcto
-// const q = (s) => `"${String(s).replace(/"/g, '""')}"`;
-// const qi = (ident) => `"${String(ident).replace(/"/g, '""')}"`;
-// const CLEAN_HEX = (s) => (String(s || '').toLowerCase().replace(/[^0-9a-f]/g, '') || null);
-
-// Función para verificar que ciertas variables de entorno estén definida
-function checkRequiredEnvVars(...requiredKeys) {
- const missingKeys = requiredKeys.filter((key) => !process.env[key]); // Filtramos las que NO existen en process.env
- if (missingKeys.length > 0) { // Si falta alguna, mostramos una advertencia
- console.warn(
- `[APP] No se encontraron las siguientes variables de entorno: ${missingKeys.join(', ')}`
- );
- }
-}
-
-// ¿Está permitida la tabla?
-function ensureTable(name) {
- const t = String(name || '').toLowerCase();
- if (!ALLOWED_TABLES.includes(t)) throw new Error(`Tabla ${t} no permitida`);
- return t;
-}
-
-//
-async function getClient() {
- const client = await mainPool.connect();
- return client;
-}
-
-// -----------------------------------------------------------------------------
-// Validación de entorno mínimo (ajusta nombres si difieren)
-// -----------------------------------------------------------------------------
-checkRequiredEnvVars(
- // Sesión
- 'SESSION_SECRET', 'REDIS_URL',
- // DB principal
- 'DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASS',
- // DB de tenants
- 'TENANTS_HOST', 'TENANTS_DB', 'TENANTS_USER', 'TENANTS_PASS'
-);
-
-// ----------------------------------------------------------
-// App
-// ----------------------------------------------------------
-const app = express();
-app.set('trust proxy', Number(process.env.TRUST_PROXY_HOPS || 2));
-app.disable("x-powered-by");
-app.use(cors({ origin: true, credentials: true }));
-app.use(express.json());
-app.use(express.json({ limit: '1mb' }));
-app.use(express.urlencoded({ extended: true }));
-app.use(express.static(path.join(__dirname, 'pages')));
-
-
-// ----------------------------------------------------------
-// Motor de vistas EJS
-// ----------------------------------------------------------
-app.set("views", path.join(__dirname, "views"));
-app.set("view engine", "ejs");
-app.set("layout", "layouts/main");
-app.use(expressLayouts);
-app.use(cookieParser(process.env.SESSION_SECRET));
-
-// Archivos estáticos que fuerzan la re-descarga de arhivos
-app.use(express.static(path.join(__dirname, "public"), {
- etag: false, maxAge: 0,
- setHeaders: (res, path) => {
- res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
- }
-}));
-
-app.use('/favicon', express.static(path.join(__dirname, 'public', 'favicon'), { maxAge: '1y' }));
-app.use(favicon(path.join(__dirname, 'public', 'favicon', 'favicon.ico'), { maxAge: '1y' }));
-
-// ----------------------------------------------------------
-// Middleware para datos globales
-// ----------------------------------------------------------
-app.use((req, res, next) => {
- res.locals.currentPath = req.path;
- res.locals.pageTitle = "SuiteCoffee";
- res.locals.pageId = "";
- next();
-});
-
-// ----------------------------------------------------------
-// Configuración de Pool principal a PostgreSQL
-// ----------------------------------------------------------
-const mainPool = new Pool({
- host: process.env.DB_HOST || '',
- database: process.env.DB_NAME || '',
- port: Number(process.env.DB_PORT || 5432),
- user: process.env.DB_USER || '',
- password: process.env.DB_PASS || '',
- // ssl: process.env.PGSSL === 'true' ? { rejectUnauthorized: false } : undefined,
- max: -1,
- idleTimeoutMillis: 30_000,
-});
-
-// ----------------------------------------------------------
-// Configuración Pool de Tenants a PostgreSQL
-// ----------------------------------------------------------
-const tenantsPool = new Pool({
- host: process.env.TENANTS_HOST,
- database: process.env.TENANTS_DB,
- port: Number(process.env.TENANTS_PORT || 5432),
- user: process.env.TENANTS_USER,
- password: process.env.TENANTS_PASS,
- max: -1,
- idleTimeoutMillis: 30_000,
-});
-
-// ----------------------------------------------------------
-// Seguridad: Tablas permitidas
-// ----------------------------------------------------------
-
-// const ALLOWED_TABLES = [
-// 'roles', 'usuarios', 'usua_roles',
-// 'categorias', 'productos',
-// 'clientes', 'mesas',
-// 'comandas', 'deta_comandas',
-// 'proveedores', 'compras', 'deta_comp_producto',
-// 'mate_primas', 'deta_comp_materias',
-// 'prov_producto', 'prov_mate_prima',
-// 'receta_producto', 'asistencia_resumen_diario',
-// 'asistencia_intervalo', 'vw_compras'
-// ];
-
-
-// -----------------------------------------------------------------------------
-// Sesión (Redis) — misma cookie que AUTH
-// -----------------------------------------------------------------------------
-
- const PORT = process.env.PORT || 3030;
- const ISSUER = process.env.AUTHENTIK_ISSUER?.replace(/\/?$/, "/");
- const CLIENT_ID = process.env.OIDC_CLIENT_ID;
- const SSO_ENTRY_URL = process.env.SSO_ENTRY_URL || "https://sso.suitecoffee.uy";
-
- // 1) SIEMPRE montar sesión ANTES de las rutas
- const { sessionMw, trustProxy } = await createRedisSession();
-
- app.use(sessionMw);
-
- const JWKS = createRemoteJWKSet(new URL(`${ISSUER}jwks/`));
-
- async function verifyIdToken(idToken) {
- const { payload } = await jwtVerify(idToken, JWKS, {
- issuer: ISSUER.replace(/\/$/, ""),
- audience: CLIENT_ID,
- });
- return payload;
- }
-
- function requireToken(req, res, next) {
- const id = req.session?.tokens?.id_token; // <- defensivo
- if (!id) return res.redirect(302, SSO_ENTRY_URL);
- next();
- }
-
- app.get("/", requireToken, async (req, res) => {
- try {
- const idToken = req.session?.tokens?.id_token; // <- defensivo
- if (!idToken) return res.redirect(302, SSO_ENTRY_URL);
- const claims = await verifyIdToken(idToken);
- const email = claims.email || claims.preferred_username || "sin-email";
- res.json({ usuario: { email, sub: claims.sub } });
- } catch (e) {
- console.error("/ verificación ID token", e);
- res.redirect(302, SSO_ENTRY_URL);
- }
- });
-
-
-// // -----------------------------------------------------------------------------
-// // Comprobaciones de tenants en DB principal
-// // -----------------------------------------------------------------------------
-
-
-
-
-
-
-// // Abre un client al DB de tenants y fija search_path al esquema del usuario
-// async function withTenant(req, res, next) {
-// try {
-// const hex = CLEAN_HEX(req.session?.user?.tenant_uuid);
-// if (!hex) return res.status(400).json({ error: 'tenant-missing' });
-
-// const schema = `schema_tenant_${hex}`;
-// const client = await tenantsPool.connect();
-
-// // Fijar search_path para que las consultas apunten al esquema del tenant
-// await client.query(`SET SESSION search_path TO ${qi(schema)}, public`);
-
-// // Hacemos el client accesible para los handlers de routes.legacy.js
-// req.pg = client;
-
-// // Liberar el client al finalizar la respuesta
-// const release = () => {
-// try { client.release(); } catch {}
-// };
-// res.on('finish', release);
-// res.on('close', release);
-
-// next();
-// } catch (e) {
-// next(e);
-// }
-// }
-
-
-
-// // ----------------------------------------------------------
-// // Rutas de UI
-// // ----------------------------------------------------------
-
-
-// app.get("/inicio", (req, res) => {
-// try {
-// const safeUser = req.session?.user || null;
-// const safeCookies = req.cookies || {};
-// const safeSession = req.session ? JSON.parse(JSON.stringify(req.session)) : {};
-// res.locals.pageTitle = "Inicio";
-// res.locals.pageId = "inicio"; // <- importante
-// return res.render('inicio', {
-// user: safeUser,
-// cookies: safeCookies,
-// session: safeSession,
-// });
-// } catch (e) {
-// next(e);
-// }
-// });
-
-// app.get("/dashboard", requireToken,(req, res) => {
-// res.locals.pageTitle = "Dashboard";
-// res.locals.pageId = "dashboard"; // <- importante
-// res.render("dashboard");
-// });
-
-// app.get("/comandas", requireToken,(req, res) => {
-// res.locals.pageTitle = "Comandas";
-// res.locals.pageId = "comandas"; // <- importante para el sidebar contextual
-// res.render("comandas");
-// });
-
-// app.get("/estadoComandas", requireToken,(req, res) => {
-// res.locals.pageTitle = "Estado de Comandas";
-// res.locals.pageId = "estadoComandas";
-// res.render("estadoComandas");
-// });
-
-// app.get("/productos", requireToken,(req, res) => {
-// res.locals.pageTitle = "Productos";
-// res.locals.pageId = "productos";
-// res.render("productos");
-// });
-
-// app.get('/usuarios', requireToken,(req, res) => {
-// res.locals.pageTitle = 'Usuarios';
-// res.locals.pageId = 'usuarios';
-// res.render('usuarios');
-// });
-
-// app.get('/reportes', requireToken,(req, res) => {
-// res.locals.pageTitle = 'Reportes';
-// res.locals.pageId = 'reportes';
-// res.render('reportes');
-// });
-
-// app.get('/compras', requireToken,(req, res) => {
-// res.locals.pageTitle = 'Compras';
-// res.locals.pageId = 'compras';
-// res.render('compras');
-// });
-
-// // Página para definir contraseña (el form envía al servicio AUTH)
-// app.get('/set-password', (req, res) => {
-// const pp = req.session?.pendingPassword;
-// if (!pp) return req.session?.user ? res.redirect('/') : res.redirect('https://sso.suitecoffee.uy/if/flow/default-authentication-flow/');
-
-// res.type('html').send(`
-//
-//
SuiteCoffee · Definir contraseña
-//
-//
-//
Definir contraseña
-//
-//
-// `);
-// });
-
-
-
-
-
-
-
-
-
-
-// ----------------------------------------------------------
-// Verificación de conexión
-// ----------------------------------------------------------
-async function verificarConexion() {
- try {
- console.log(`[APP] Comprobando accesibilidad a la db ${process.env.DB_NAME} del host ${process.env.DB_HOST} ...`);
- const client = await mainPool.connect();
- const { rows } = await client.query('SELECT NOW() AS ahora');
- console.log(`\n[APP] Conexión con ${process.env.DB_NAME} OK. Hora DB:`, rows[0].ahora);
- client.release();
- } catch (error) {
- console.error('[APP] Error al conectar con la base de datos al iniciar:', error.message);
- console.error('[APP] Revisar DB_HOST/USER/PASS/NAME, accesos de red y firewall.');
- }
-}
-
-// // -----------------------------------------------------------------------------
-// // Healthcheck
-// -----------------------------------------------------------------------------
-app.get('/health', (_req, res) => res.status(200).json({ status: 'ok'}));
-
-// -----------------------------------------------------------------------------
-// 404 + Manejo de errores
-// -----------------------------------------------------------------------------
-app.use((req, res) => res.status(404).json({ error: 'Error 404, No se encontró la página', path: req.originalUrl }));
-
-app.use((err, _req, res, _next) => {
- console.error('[APP] ', err);
- if (res.headersSent) return;
- res.status(500).json({ error: '¡Oh! A ocurrido un error en el servidor app.', detail: err.stack || String(err) });
-});
-
-// ----------------------------------------------------------
-// Inicio del servidor
-// ----------------------------------------------------------
-app.listen(3030, () => {
- console.log(`[APP] SuiteCoffee corriendo en http://localhost:${3030}`);
- verificarConexion();
-});
-
diff --git a/services/app/src/index.mjs b/services/app/src/index.mjs
new file mode 100644
index 0000000..26f334e
--- /dev/null
+++ b/services/app/src/index.mjs
@@ -0,0 +1,437 @@
+// services/app/src/index.js
+// ------------------------------------------------------------
+// SuiteCoffee — Aplicación Principal (Express)
+// ------------------------------------------------------------
+
+import 'dotenv/config';
+import favicon from 'serve-favicon'; // Favicon
+import express from 'express'; // Framework para enderizado de apps Web
+import expressLayouts from 'express-ejs-layouts';
+// import { poolCore, poolTenants } from '@suitecoffee/db'; // dbCore y dbTenants desde módulo
+import { poolCore, poolTenants } from '#db'; // dbCore y dbTenants
+import v1Router from '#v1Router'; // Rutas API v1
+import expressPages from '#pages'; // Rutas "/", "/dashboard", ...
+
+
+import path from 'path';
+import { fileURLToPath } from 'url'; // Converts a file:// URL string or URL object into a platform-specific file
+import cookieParser from 'cookie-parser';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+
+
+
+
+
+
+
+// -----------------------------------------------------------------------------
+// Validación de entorno mínimo (ajusta nombres si difieren)
+// -----------------------------------------------------------------------------
+
+// Función para verificar que ciertas variables de entorno estén definida
+function checkRequiredEnvVars(...requiredKeys) {
+ const missingKeys = requiredKeys.filter((key) => !process.env[key]); // Filtramos las que NO existen en process.env
+ if (missingKeys.length > 0) { // Si falta alguna, mostramos una advertencia
+ console.warn(
+ `[APP] No se encontraron las siguientes variables de entorno: \n\n-> ${missingKeys.join('\n-> ')}`+
+ `\n`
+ );
+ }
+}
+
+checkRequiredEnvVars(
+ 'PORT', 'APP_BASE_URL',
+ 'CORE_DB_HOST', 'CORE_DB_PORT', 'CORE_DB_NAME',
+ 'TENANTS_DB_HOST', 'TENANTS_DB_PORT', 'TENANTS_DB_NAME',
+
+ 'OIDC_LOGIN_URL', 'OIDC_REDIRECT_URI',
+ 'OIDC_CLIEN_ID', 'OIDC_CONFIG_URL', 'OIDC_ISSUER',
+ 'OIDC_ISSUER_DISCOVERY', 'OIDC_AUTHORIZE_URL', 'OIDC_TOKEN_URL',
+ 'OIDC_USERINFO_URL', 'OIDC_LOGOUT_URL', 'OIDC_JWKS_URL',
+
+ 'SESSION_SECRET', 'SESSION_COOKIE_NAME',
+ 'AK_REDIS_URL', 'AK_TOKEN'
+);
+
+
+
+
+
+// ----------------------------------------------------------
+// Variables del sistema
+// ----------------------------------------------------------
+
+// De entorno
+const PORT = process.env.PORT;
+const APP_BASE_URL = process.env.APP_BASE_URL;
+
+const CORE_DB_HOST = process.env.CORE_DB_HOST;
+const CORE_DB_PORT = process.env.CORE_DB_PORT;
+const CORE_DB_NAME = process.env.CORE_DB_NAME;
+
+const TENANTS_DB_HOST = process.env.TENANTS_DB_HOST;
+const TENANTS_DB_PORT = process.env.TENANTS_DB_PORT;
+const TENANTS_DB_NAME = process.env.TENANTS_DB_NAME;
+
+const OIDC_LOGIN_URL = process.env.OIDC_LOGIN_URL;
+const OIDC_REDIRECT_URI = process.env.OIDC_REDIRECT_URI;
+
+const OIDC_CLIEN_ID = process.env.OIDC_CLIEN_ID;
+const OIDC_CONFIG_URL = process.env.OIDC_CONFIG_URL;
+const OIDC_ISSUER = process.env.OIDC_ISSUER;
+const OIDC_ISSUER_DISCOVERY = process.env.OIDC_ISSUER_DISCOVERY;
+const OIDC_AUTHORIZE_URL = process.env.OIDC_AUTHORIZE_URL;
+const OIDC_TOKEN_URL = process.env.OIDC_TOKEN_URL;
+const OIDC_USERINFO_URL = process.env.OIDC_USERINFO_URL;
+const OIDC_LOGOUT_URL = process.env.OIDC_LOGOUT_URL;
+const OIDC_JWKS_URL = process.env.OIDC_JWKS_URL;
+
+const AK_SESSION_SECRET = process.env.AK_SESSION_SECRET;
+const AK_SESSION_COOKIE_NAME = process.env.AK_SESSION_COOKIE_NAME;
+const AK_REDIS_URL = process.env.AK_REDIS_URL;
+
+
+
+const url = v => !v ? "" : (v.startsWith("http") ? v : `/img/productos/${v}`);
+const VALID_IDENT = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
+const q = (s) => `"${String(s).replace(/"/g, '""')}"`; // Identificadores SQL -> comillas dobles y escape correcto
+
+
+
+// ----------------------------------------------------------
+// App + Motor de vistas EJS
+// ----------------------------------------------------------
+
+const app = express();
+app.set('trust proxy', true);
+app.set("views", path.join(__dirname, "views"));
+app.set("view engine", "ejs");
+app.set("layout", "layouts/main");
+app.disable("x-powered-by");
+
+app.use(express.json());
+app.use(express.json({ limit: '1mb' }));
+app.use(express.urlencoded({ extended: true }));
+// Archivos estáticos que fuerzan la re-descarga de arhivos
+app.use(favicon(path.join(__dirname, 'public', 'favicon', 'favicon.ico'), { maxAge: '1y' }));
+app.use(express.static(path.join(__dirname, "public"), {
+ etag: false, maxAge: 0,
+ setHeaders: (res, path) => {
+ res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
+ }
+}));
+app.use(expressLayouts);
+app.use(cookieParser(process.env.SESSION_SECRET));
+app.use(expressPages); // Renderizado trae las paginas desde ./services/manso/src/routes/routes.js
+
+
+// ----------------------------------------------------------
+// Uso de API v1
+// ----------------------------------------------------------
+app.use("/api/v1", v1Router);
+
+// /api/rpc/get_producto/:id
+// /api/v1/rpc/get_producto/:id -> /rpc/get_producto/:id
+
+
+// ----------------------------------------------------------
+// Seguridad: Tablas permitidas
+// ----------------------------------------------------------
+const ALLOWED_TABLES = [
+ 'roles','usuarios','usua_roles',
+ 'categorias','productos',
+ 'clientes','mesas',
+ 'comandas','deta_comandas',
+ 'proveedores','compras','deta_comp_producto',
+ 'mate_primas','deta_comp_materias',
+ 'prov_producto','prov_mate_prima',
+ 'receta_producto', 'asistencia_resumen_diario',
+ 'asistencia_intervalo', 'asistencia_detalle',
+ 'vw_compras'
+];
+
+function ensureTable(name) {
+ const t = String(name || '').toLowerCase();
+ if (!ALLOWED_TABLES.includes(t)) throw new Error('Tabla no permitida');
+ return t;
+}
+
+
+
+
+// ----------------------------------------------------------
+// Introspección de esquema
+// ----------------------------------------------------------
+async function loadColumns(client, table) {
+ const sql = `
+ SELECT
+ c.column_name,
+ c.data_type,
+ c.is_nullable = 'YES' AS is_nullable,
+ c.column_default,
+ (SELECT EXISTS (
+ SELECT 1 FROM pg_attribute a
+ JOIN pg_class t ON t.oid = a.attrelid
+ JOIN pg_index i ON i.indrelid = t.oid AND a.attnum = ANY(i.indkey)
+ WHERE t.relname = $1 AND i.indisprimary AND a.attname = c.column_name
+ )) AS is_primary,
+ (SELECT a.attgenerated = 's' OR a.attidentity IN ('a','d')
+ FROM pg_attribute a
+ JOIN pg_class t ON t.oid = a.attrelid
+ WHERE t.relname = $1 AND a.attname = c.column_name
+ ) AS is_identity
+ FROM information_schema.columns c
+ WHERE c.table_schema='public' AND c.table_name=$1
+ ORDER BY c.ordinal_position
+ `;
+ const { rows } = await client.query(sql, [table]);
+ return rows;
+}
+
+async function loadForeignKeys(client, table) {
+ const sql = `
+ SELECT
+ kcu.column_name,
+ ccu.table_name AS foreign_table,
+ ccu.column_name AS foreign_column
+ FROM information_schema.table_constraints tc
+ JOIN information_schema.key_column_usage kcu
+ ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema
+ JOIN information_schema.constraint_column_usage ccu
+ ON ccu.constraint_name = tc.constraint_name AND ccu.table_schema = tc.table_schema
+ WHERE tc.table_schema='public' AND tc.table_name=$1 AND tc.constraint_type='FOREIGN KEY'
+ `;
+ const { rows } = await client.query(sql, [table]);
+ const map = {};
+ for (const r of rows) map[r.column_name] = { foreign_table: r.foreign_table, foreign_column: r.foreign_column };
+ return map;
+}
+
+async function loadPrimaryKey(client, table) {
+ const sql = `
+ SELECT a.attname AS column_name
+ FROM pg_index i
+ JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
+ JOIN pg_class t ON t.oid = i.indrelid
+ WHERE t.relname = $1 AND i.indisprimary
+ `;
+ const { rows } = await client.query(sql, [table]);
+ return rows.map(r => r.column_name);
+}
+
+// label column for FK options
+async function pickLabelColumn(client, refTable) {
+ const preferred = ['nombre','raz_social','apodo','documento','correo','telefono'];
+ const { rows } = await client.query(
+ `SELECT column_name, data_type
+ FROM information_schema.columns
+ WHERE table_schema='public' AND table_name=$1
+ ORDER BY ordinal_position`, [refTable]
+ );
+ for (const cand of preferred) {
+ if (rows.find(r => r.column_name === cand)) return cand;
+ }
+ const textish = rows.find(r => /text|character varying|varchar/i.test(r.data_type));
+ if (textish) return textish.column_name;
+ return rows[0]?.column_name || 'id';
+}
+
+// ----------------------------------------------------------
+// Middleware para datos globales
+// ----------------------------------------------------------
+app.use((req, res, next) => {
+ res.locals.currentPath = req.path;
+ res.locals.pageTitle = "SuiteCoffee";
+ res.locals.pageId = "";
+ next();
+});
+
+
+
+
+// ----------------------------------------------------------
+// API
+// ----------------------------------------------------------
+app.get('/api/tables', async (_req, res) => {
+ res.json(ALLOWED_TABLES);
+});
+
+app.get('/api/schema/:table', async (req, res) => {
+ try {
+ const table = ensureTable(req.params.table);
+ const client = await pool.getClient();
+ try {
+ const columns = await loadColumns(client, table);
+ const fks = await loadForeignKeys(client, table);
+ const enriched = columns.map(c => ({ ...c, foreign: fks[c.column_name] || null }));
+ res.json({ table, columns: enriched });
+ } finally { client.release(); }
+ } catch (e) {
+ res.status(400).json({ error: e.message });
+ }
+});
+
+app.get('/api/options/:table/:column', async (req, res) => {
+ try {
+ const table = ensureTable(req.params.table);
+ const column = req.params.column;
+ if (!VALID_IDENT.test(column)) throw new Error('Columna inválida');
+
+ const client = await pool.getClient();
+ try {
+ const fks = await loadForeignKeys(client, table);
+ const fk = fks[column];
+ if (!fk) return res.json([]);
+
+ const refTable = fk.foreign_table;
+ const refId = fk.foreign_column;
+ const labelCol = await pickLabelColumn(client, refTable);
+
+ const sql = `SELECT ${q(refId)} AS id, ${q(labelCol)} AS label FROM ${q(refTable)} ORDER BY ${q(labelCol)} LIMIT 1000`;
+ const result = await client.query(sql);
+ res.json(result.rows);
+ } finally { client.release(); }
+ } catch (e) {
+ res.status(400).json({ error: e.message });
+ }
+});
+
+app.get('/api/table/:table', async (req, res) => {
+ try {
+ const table = ensureTable(req.params.table);
+ const limit = Math.min(parseInt(req.query.limit || '100', 10), 1000);
+ const client = await pool.getClient();
+ try {
+ const pks = await loadPrimaryKey(client, table);
+ const orderBy = pks.length ? `ORDER BY ${pks.map(q).join(', ')} DESC` : '';
+ const sql = `SELECT * FROM ${q(table)} ${orderBy} LIMIT ${limit}`;
+ const result = await client.query(sql);
+
+ // Normalizar: siempre devolver objetos {col: valor}
+ const colNames = result.fields.map(f => f.name);
+ let rows = result.rows;
+ if (rows.length && Array.isArray(rows[0])) {
+ rows = rows.map(r => Object.fromEntries(r.map((v, i) => [colNames[i], v])));
+ }
+ res.json(rows);
+ } finally { client.release(); }
+ } catch (e) {
+ res.status(400).json({ error: e.message, code: e.code, detail: e.detail });
+ }
+});
+
+app.post('/api/table/:table', async (req, res) => {
+ const table = ensureTable(req.params.table);
+ const payload = req.body || {};
+ try {
+ const client = await pool.getClient();
+ try {
+ const columns = await loadColumns(client, table);
+ const insertable = columns.filter(c =>
+ !c.is_primary && !c.is_identity && !(c.column_default || '').startsWith('nextval(')
+ );
+ const allowedCols = new Set(insertable.map(c => c.column_name));
+
+ const cols = [];
+ const vals = [];
+ const params = [];
+ let idx = 1;
+ for (const [k, v] of Object.entries(payload)) {
+ if (!allowedCols.has(k)) continue;
+ if (!VALID_IDENT.test(k)) continue;
+ cols.push(q(k));
+ vals.push(`$${idx++}`);
+ params.push(v);
+ }
+
+ if (!cols.length) {
+ const { rows } = await client.query(`INSERT INTO ${q(table)} DEFAULT VALUES RETURNING *`);
+ res.status(201).json({ inserted: rows[0] });
+ } else {
+ const { rows } = await client.query(
+ `INSERT INTO ${q(table)} (${cols.join(', ')}) VALUES (${vals.join(', ')}) RETURNING *`,
+ params
+ );
+ res.status(201).json({ inserted: rows[0] });
+ }
+ } catch (e) {
+ if (e.code === '23503') return res.status(400).json({ error: 'Violación de clave foránea', detail: e.detail });
+ if (e.code === '23505') return res.status(400).json({ error: 'Violación de unicidad', detail: e.detail });
+ if (e.code === '23514') return res.status(400).json({ error: 'Violación de CHECK', detail: e.detail });
+ if (e.code === '23502') return res.status(400).json({ error: 'Campo NOT NULL faltante', detail: e.detail });
+ throw e;
+ } finally { client.release(); }
+ } catch (e) {
+ res.status(400).json({ error: e.message });
+ }
+});
+
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------
+// Verificación de conexión
+// ----------------------------------------------------------
+
+async function verificarConexionCore() {
+ try {
+ console.log(`[APP] Comprobando accesibilidad a la db ${CORE_DB_NAME} del host ${CORE_DB_HOST} ...`);
+ const client = await poolCore.connect();
+ const { rows } = await client.query('SELECT NOW() AS ahora');
+ console.log(`\n[APP] Conexión con ${CORE_DB_NAME} OK. Hora DB:`, rows[0].ahora);
+ client.release();
+ } catch (error) {
+ console.error('[APP] Error al conectar con la base de datos al iniciar:', error.message);
+ console.error('[APP] Revisar credenciales, accesos de red y firewall.');
+ }
+}
+async function verificarConexionTenants() {
+ try {
+ console.log(`[APP] Comprobando accesibilidad a la db ${TENANTS_DB_NAME} del host ${TENANTS_DB_HOST} ...`);
+ const client = await poolTenants.connect();
+ const { rows } = await client.query('SELECT NOW() AS ahora');
+ console.log(`\n[APP] Conexión con ${TENANTS_DB_NAME} OK. Hora DB:`, rows[0].ahora);
+ client.release();
+ } catch (error) {
+ console.error('[APP] Error al conectar con la base de datos al iniciar:', error.message);
+ console.error('[APP] Revisar credenciales, accesos de red y firewall.');
+ }
+}
+
+// -----------------------------------------------------------------------------
+// 404 + Manejo de errores
+// -----------------------------------------------------------------------------
+
+/*app.use((req, res) => res.status(404).json({ error: 'Error 404, No se encontró la página', path: req.originalUrl }));
+
+app.use((err, _req, res, _next) => {
+ console.error('[APP] ', err);
+ if (res.headersSent) return;
+ res.status(500).json({ error: '¡Oh! A ocurrido un error en el servidor app.', detail: err.stack || String(err) });
+});*/
+
+// ----------------------------------------------------------
+// Inicio del servidor
+// ----------------------------------------------------------
+
+app.listen(PORT, () => {
+ console.log(`[APP] SuiteCoffee corriendo en http://localhost:${PORT}`);
+ verificarConexionCore();
+ verificarConexionTenants();
+});
+
+// -----------------------------------------------------------------------------
+// Healthcheck
+// -----------------------------------------------------------------------------
+app.get('/health', (_req, res) => {
+ res.status(200).json({ status: 'ok'}),
+ console.log(`[APP] Saludable`)
+});
\ No newline at end of file
diff --git a/services/app/src/pages/pages.js b/services/app/src/pages/pages.js
new file mode 100644
index 0000000..68d657a
--- /dev/null
+++ b/services/app/src/pages/pages.js
@@ -0,0 +1,67 @@
+// services/manso/src/api/v1/routes/routes.js
+
+import { Router } from 'express';
+
+const router = Router();
+
+// ----------------------------------------------------------
+// Rutas de UI
+// ----------------------------------------------------------
+
+router.get('/', (req, res) => {
+ res.locals.pageTitle = "Inicio"; // Título de pestaña
+ res.locals.pageId = "home"; // Sidebar contextual
+ res.render("dashboard"); // Archivo .ejs a renderizar
+ // res.json({ ok: true, route: '/inicio' }); // Debug json
+});
+
+router.get('/dashboard', (req, res) => {
+ res.locals.pageTitle = "Dashboard";
+ res.locals.pageId = "dashboard";
+ res.render("dashboard");
+ // res.json({ ok: true, route: '/dashboard' });
+});
+
+router.get('/comandas', (req, res) => {
+ res.locals.pageTitle = "Comandas";
+ res.locals.pageId = "comandas";
+ res.render("comandas");
+ // res.json({ ok: true, route: '/comandas' });
+});
+
+router.get('/estadoComandas', (req, res) => {
+ res.locals.pageTitle = "Estado";
+ res.locals.pageId = "estadoComandas";
+ res.render("estadoComandas");
+ // res.json({ ok: true, route: '/estadoComandas' });
+});
+
+router.get('/productos', (req, res) => {
+ res.locals.pageTitle = "Propductos";
+ res.locals.pageId = "productos";
+ res.render("productos");
+ // res.json({ ok: true, route: '/productos' });
+});
+
+router.get('/usuarios', (req, res) => {
+ res.locals.pageTitle = "Usuarios";
+ res.locals.pageId = "usuarios";
+ res.render("usuarios");
+ // res.json({ ok: true, route: '/usuarios' });
+});
+
+router.get('/reportes', (req, res) => {
+ res.locals.pageTitle = "Reportes";
+ res.locals.pageId = "reportes";
+ res.render("reportes");
+ // res.json({ ok: true, route: '/reportes' });
+});
+
+router.get('/compras', (req, res) => {
+ res.locals.pageTitle = "Compras";
+ res.locals.pageId = "compras";
+ res.render("compras");
+ // res.json({ ok: true, route: '/compras' });
+});
+
+export default router;
\ No newline at end of file
diff --git a/services/auth/.env.development b/services/auth/.env.development
index 8775b30..79f86e5 100644
--- a/services/auth/.env.development
+++ b/services/auth/.env.development
@@ -2,43 +2,61 @@
NODE_ENV=development
PORT=4040
+
# ===== Session (usa el Redis del stack) =====
# Para DEV podemos reutilizar el Redis de Authentik. En prod conviene uno separado.
SESSION_SECRET=Neon*Mammal*Boaster*Ludicrous*Fender8*Crablike
SESSION_COOKIE_NAME=sc.sid
-REDIS_URL=redis://ak-redis:6379
# ===== DB principal (metadatos de SuiteCoffee) =====
# Usa el alias de red del servicio 'db' (compose: aliases [dev-db])
DB_HOST=dev-db
+DB_NAME=dev_suitecoffee_core
DB_PORT=5432
-DB_NAME=dev-suitecoffee
DB_USER=dev-user-suitecoffee
DB_PASS=dev-pass-suitecoffee
+CORE_DB_HOST=dev-db
+CORE_DB_NAME=dev_suitecoffee_core
+CORE_DB_PORT=5432
+CORE_DB_USER=dev-user-suitecoffee
+CORE_DB_PASS=dev-pass-suitecoffee
+
# ===== DB tenants (Tenants de SuiteCoffee) =====
TENANTS_HOST=dev-tenants
-TENANTS_DB=dev-postgres
-TENANTS_USER=dev-user-postgres
-TENANTS_PASS=dev-pass-postgres
+TENANTS_DB=dev_suitecoffee_tenants
TENANTS_PORT=5432
+TENANTS_USER=suitecoffee
+TENANTS_PASS=suitecoffee
+
+TENANTS_DB_HOST=dev-tenants
+TENANTS_DB_NAME=dev_suitecoffee_tenants
+TENANTS_DB_PORT=5432
+TENANTS_DB_USER=suitecoffee
+TENANTS_DB_PASS=suitecoffee
-TENANT_INIT_SQL=/app/src/db/initTenant_v2.sql
# ===== Authentik — Admin API (server-to-server dentro de la red) =====
# Usa el alias de red del servicio 'authentik' y su puerto interno 9000
-AUTHENTIK_TOKEN=h2apVHbd3ApMcnnSwfQPXbvximkvP8HnUE25ot3zXWuEEtJFaNCcOzDHB6Xw
-AUTH_CALLBACK_URL=https://suitecoffee.uy/auth/callback
+AK_TOKEN=h2apVHbd3ApMcnnSwfQPXbvximkvP8HnUE25ot3zXWuEEtJFaNCcOzDHB6Xw
+AK_REDIS_URL=redis://ak-redis:6379
# ===== OIDC (DEBE coincidir con el Provider) =====
# DEV (todo dentro de la red de Docker):
# - El auth service redirige al navegador a este issuer. Si NO tenés reverse proxy hacia Authentik,
# esta URL interna NO será accesible desde el navegador del host. En ese caso, ver nota más abajo.
-# AUTHENTIK_ISSUER=https://sso.suitecoffee.mateosaldain.uy/application/o/suitecoffee/
-AUTHENTIK_ISSUER=https://sso.suitecoffee.uy/application/o/suitecoffee/
-OIDC_CLIENT_ID=1orMM8vOvf3WkN2FejXYvUFpPtONG0Lx1eMlwIpW
-OIDC_CLIENT_SECRET=t5wx13qBcM0EFQ3cGnUIAmLzvbdsQrUVPv1OGWjszWkEp35pJQ55t7vZeeShqG49kuRAaiXv6PSGJLhRfGaponGaJl8gH1uCL7KIxdmm7UihgYoAXB2dFhZV4zRxfze2
-OIDC_REDIRECT_URI=https://suitecoffee.uy/auth/callback
+APP_BASE_URL=https://suitecoffee.uy
-OIDC_ENROLLMENT_URL=https://sso.suitecoffee.uy/if/flow/registro-suitecoffee/
\ No newline at end of file
+OIDC_LOGIN_URL=https://sso.suitecoffee.uy
+OIDC_REDIRECT_URI = https://suitecoffee.uy/auth/callback
+
+OIDC_CLIEN_ID=1orMM8vOvf3WkN2FejXYvUFpPtONG0Lx1eMlwIpW
+OIDC_CONFIG_URL=https://sso.suitecoffee.uy/application/o/suitecoffee/.well-known/openid-configuration
+OIDC_ISSUER=https://sso.suitecoffee.uy/application/o/suitecoffee/
+OIDC_ISSUER_DISCOVERY=https://sso.suitecoffee.uy/application/o/suitecoffee/.well-known/openid-configuration
+OIDC_AUTHORIZE_URL=https://sso.suitecoffee.uy/application/o/authorize/
+OIDC_TOKEN_URL=https://sso.suitecoffee.uy/application/o/token/
+OIDC_USERINFO_URL=https://sso.suitecoffee.uy/application/o/userinfo/
+OIDC_LOGOUT_URL=https://sso.suitecoffee.uy/application/o/suitecoffee/end-session/
+OIDC_JWKS_URL=https://sso.suitecoffee.uy/application/o/suitecoffee/jwks/
\ No newline at end of file
diff --git a/services/auth/Dockerfile.production b/services/auth/Dockerfile.production
index 0cd75d0..b4d514f 100644
--- a/services/auth/Dockerfile.production
+++ b/services/auth/Dockerfile.production
@@ -1,5 +1,5 @@
# Dockerfile.dev
-FROM node:22.18
+FROM node:20.19.5-bookworm
# Definir variables de entorno con valores predeterminados
# ARG NODE_ENV=production
diff --git a/services/auth/package-lock.json b/services/auth/package-lock.json
index 0955b96..cb73938 100644
--- a/services/auth/package-lock.json
+++ b/services/auth/package-lock.json
@@ -13,6 +13,7 @@
"bcrypt": "^5.1.1",
"chalk": "^5.6.0",
"connect-redis": "^9.0.0",
+ "cookie-parser": "^1.4.7",
"cookie-session": "^2.0.0",
"cors": "^2.8.5",
"dotenv": "^17.2.1",
@@ -24,6 +25,7 @@
"jose": "^6.1.0",
"jsonwebtoken": "^9.0.2",
"jwks-rsa": "^3.2.0",
+ "node-appwrite": "^20.2.1",
"node-fetch": "^3.3.2",
"openid-client": "^5.7.1",
"pg": "^8.16.3",
@@ -37,21 +39,15 @@
},
"node_modules/@epic-web/invariant": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
- "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
"dev": true,
"license": "MIT"
},
"node_modules/@ioredis/commands": {
"version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.3.1.tgz",
- "integrity": "sha512-bYtU8avhGIcje3IhvF9aSjsa5URMZBHnwKtOvXsT4sfYy9gppW11gLPT/9oNqlJZD47yPKveQFTAFWpHjKvUoQ==",
"license": "MIT"
},
"node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.11",
- "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
- "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==",
"license": "BSD-3-Clause",
"dependencies": {
"detect-libc": "^2.0.0",
@@ -70,8 +66,6 @@
},
"node_modules/@mapbox/node-pre-gyp/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==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
@@ -90,8 +84,6 @@
},
"node_modules/@redis/bloom": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.8.2.tgz",
- "integrity": "sha512-855DR0ChetZLarblio5eM0yLwxA9Dqq50t8StXKp5bAtLT0G+rZ+eRzzqxl37sPqQKjUudSYypz55o6nNhbz0A==",
"license": "MIT",
"engines": {
"node": ">= 18"
@@ -102,8 +94,6 @@
},
"node_modules/@redis/client": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.8.2.tgz",
- "integrity": "sha512-WtMScno3+eBpTac1Uav2zugXEoXqaU23YznwvFgkPwBQVwEHTDgOG7uEAObtZ/Nyn8SmAMbqkEubJaMOvnqdsQ==",
"license": "MIT",
"dependencies": {
"cluster-key-slot": "1.1.2"
@@ -114,8 +104,6 @@
},
"node_modules/@redis/json": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.8.2.tgz",
- "integrity": "sha512-uxpVfas3I0LccBX9rIfDgJ0dBrUa3+0Gc8sEwmQQH0vHi7C1Rx1Qn8Nv1QWz5bohoeIXMICFZRcyDONvum2l/w==",
"license": "MIT",
"engines": {
"node": ">= 18"
@@ -126,8 +114,6 @@
},
"node_modules/@redis/search": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.8.2.tgz",
- "integrity": "sha512-cNv7HlgayavCBXqPXgaS97DRPVWFznuzsAmmuemi2TMCx5scwLiP50TeZvUS06h/MG96YNPe6A0Zt57yayfxwA==",
"license": "MIT",
"engines": {
"node": ">= 18"
@@ -138,8 +124,6 @@
},
"node_modules/@redis/time-series": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.8.2.tgz",
- "integrity": "sha512-g2NlHM07fK8H4k+613NBsk3y70R2JIM2dPMSkhIjl2Z17SYvaYKdusz85d7VYOrZBWtDrHV/WD2E3vGu+zni8A==",
"license": "MIT",
"engines": {
"node": ">= 18"
@@ -150,8 +134,6 @@
},
"node_modules/@types/body-parser": {
"version": "1.19.6",
- "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
- "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
"license": "MIT",
"dependencies": {
"@types/connect": "*",
@@ -160,8 +142,6 @@
},
"node_modules/@types/connect": {
"version": "3.4.38",
- "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
- "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
@@ -169,8 +149,6 @@
},
"node_modules/@types/express": {
"version": "4.17.23",
- "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz",
- "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==",
"license": "MIT",
"dependencies": {
"@types/body-parser": "*",
@@ -181,8 +159,6 @@
},
"node_modules/@types/express-serve-static-core": {
"version": "4.19.6",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz",
- "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==",
"license": "MIT",
"dependencies": {
"@types/node": "*",
@@ -193,14 +169,10 @@
},
"node_modules/@types/http-errors": {
"version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
- "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
"license": "MIT"
},
"node_modules/@types/jsonwebtoken": {
"version": "9.0.10",
- "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
- "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==",
"license": "MIT",
"dependencies": {
"@types/ms": "*",
@@ -209,20 +181,14 @@
},
"node_modules/@types/mime": {
"version": "1.3.5",
- "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
- "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
"license": "MIT"
},
"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/node": {
"version": "24.3.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz",
- "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==",
"license": "MIT",
"dependencies": {
"undici-types": "~7.10.0"
@@ -230,20 +196,14 @@
},
"node_modules/@types/qs": {
"version": "6.14.0",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
- "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
"license": "MIT"
},
"node_modules/@types/range-parser": {
"version": "1.2.7",
- "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
- "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
"license": "MIT"
},
"node_modules/@types/send": {
"version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz",
- "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==",
"license": "MIT",
"dependencies": {
"@types/mime": "^1",
@@ -252,8 +212,6 @@
},
"node_modules/@types/serve-static": {
"version": "1.15.8",
- "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz",
- "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==",
"license": "MIT",
"dependencies": {
"@types/http-errors": "*",
@@ -263,14 +221,10 @@
},
"node_modules/abbrev": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
- "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"license": "ISC"
},
"node_modules/accepts": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
- "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
"license": "MIT",
"dependencies": {
"mime-types": "^3.0.0",
@@ -282,8 +236,6 @@
},
"node_modules/agent-base": {
"version": "6.0.2",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
- "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"dependencies": {
"debug": "4"
@@ -294,8 +246,6 @@
},
"node_modules/ansi-regex": {
"version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
@@ -303,8 +253,6 @@
},
"node_modules/anymatch": {
"version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -317,15 +265,10 @@
},
"node_modules/aproba": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz",
- "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==",
"license": "ISC"
},
"node_modules/are-we-there-yet": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
- "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
- "deprecated": "This package is no longer supported.",
"license": "ISC",
"dependencies": {
"delegates": "^1.0.0",
@@ -337,8 +280,6 @@
},
"node_modules/async": {
"version": "3.2.6",
- "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
- "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
"license": "MIT"
},
"node_modules/asynckit": {
@@ -348,9 +289,9 @@
"license": "MIT"
},
"node_modules/axios": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",
- "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
+ "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
@@ -360,14 +301,10 @@
},
"node_modules/balanced-match": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/bcrypt": {
"version": "5.1.1",
- "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz",
- "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -380,8 +317,6 @@
},
"node_modules/binary-extensions": {
"version": "2.3.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
- "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -393,8 +328,6 @@
},
"node_modules/body-parser": {
"version": "2.2.0",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
- "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
"license": "MIT",
"dependencies": {
"bytes": "^3.1.2",
@@ -413,8 +346,6 @@
},
"node_modules/brace-expansion": {
"version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -423,8 +354,6 @@
},
"node_modules/braces": {
"version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -436,14 +365,10 @@
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
- "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
"license": "BSD-3-Clause"
},
"node_modules/bytes": {
"version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -464,8 +389,6 @@
},
"node_modules/call-bound": {
"version": "1.0.4",
- "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
- "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@@ -480,8 +403,6 @@
},
"node_modules/chalk": {
"version": "5.6.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz",
- "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==",
"license": "MIT",
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
@@ -492,8 +413,6 @@
},
"node_modules/chokidar": {
"version": "3.6.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
- "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -517,8 +436,6 @@
},
"node_modules/chownr": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
- "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
"license": "ISC",
"engines": {
"node": ">=10"
@@ -526,8 +443,6 @@
},
"node_modules/cluster-key-slot": {
"version": "1.1.2",
- "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
- "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10.0"
@@ -535,8 +450,6 @@
},
"node_modules/color-support": {
"version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
- "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
"license": "ISC",
"bin": {
"color-support": "bin.js"
@@ -556,14 +469,10 @@
},
"node_modules/concat-map": {
"version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"license": "MIT"
},
"node_modules/connect-redis": {
"version": "9.0.0",
- "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-9.0.0.tgz",
- "integrity": "sha512-QwzyvUePTMvEzG1hy45gZYw3X3YHrjmEdSkayURlcZft7hqadQ3X39wYkmCqblK2rGlw+XItELYt6GnyG6DEIQ==",
"license": "MIT",
"engines": {
"node": ">=18"
@@ -575,14 +484,10 @@
},
"node_modules/console-control-strings": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
- "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"license": "ISC"
},
"node_modules/content-disposition": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
- "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
"license": "MIT",
"dependencies": {
"safe-buffer": "5.2.1"
@@ -593,8 +498,6 @@
},
"node_modules/content-type": {
"version": "1.0.5",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
- "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -609,10 +512,27 @@
"node": ">= 0.6"
}
},
+ "node_modules/cookie-parser": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
+ "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "0.7.2",
+ "cookie-signature": "1.0.6"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/cookie-parser/node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
+ "license": "MIT"
+ },
"node_modules/cookie-session": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.1.1.tgz",
- "integrity": "sha512-ji3kym/XZaFVew1+tIZk5ZLp9Z/fLv9rK1aZmpug0FsgE7Cu3ZDrUdRo7FT9vFjMYfNimrrUHJzywDwT7XEFlg==",
"license": "MIT",
"dependencies": {
"cookies": "0.9.1",
@@ -626,8 +546,6 @@
},
"node_modules/cookie-session/node_modules/debug": {
"version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.1"
@@ -635,8 +553,6 @@
},
"node_modules/cookie-signature": {
"version": "1.2.2",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
- "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
"license": "MIT",
"engines": {
"node": ">=6.6.0"
@@ -644,8 +560,6 @@
},
"node_modules/cookies": {
"version": "0.9.1",
- "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.9.1.tgz",
- "integrity": "sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==",
"license": "MIT",
"dependencies": {
"depd": "~2.0.0",
@@ -657,8 +571,6 @@
},
"node_modules/cors": {
"version": "2.8.5",
- "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
- "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
@@ -670,8 +582,6 @@
},
"node_modules/cross-env": {
"version": "10.0.0",
- "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.0.0.tgz",
- "integrity": "sha512-aU8qlEK/nHYtVuN4p7UQgAwVljzMg8hB4YK5ThRqD2l/ziSnryncPNn7bMLt5cFYsKVKBh8HqLqyCoTupEUu7Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -688,8 +598,6 @@
},
"node_modules/cross-spawn": {
"version": "7.0.6",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
- "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -703,8 +611,6 @@
},
"node_modules/data-uri-to-buffer": {
"version": "4.0.1",
- "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
- "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
"license": "MIT",
"engines": {
"node": ">= 12"
@@ -712,8 +618,6 @@
},
"node_modules/debug": {
"version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -738,14 +642,10 @@
},
"node_modules/delegates": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
- "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
"license": "MIT"
},
"node_modules/denque": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
- "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
@@ -753,8 +653,6 @@
},
"node_modules/depd": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -762,8 +660,6 @@
},
"node_modules/detect-libc": {
"version": "2.0.4",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
- "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
"license": "Apache-2.0",
"engines": {
"node": ">=8"
@@ -771,8 +667,6 @@
},
"node_modules/dotenv": {
"version": "17.2.1",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz",
- "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
@@ -797,8 +691,6 @@
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
- "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
- "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
@@ -806,14 +698,10 @@
},
"node_modules/ee-first": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"license": "MIT"
},
"node_modules/ejs": {
"version": "3.1.10",
- "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
- "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
"license": "Apache-2.0",
"dependencies": {
"jake": "^10.8.5"
@@ -827,14 +715,10 @@
},
"node_modules/emoji-regex": {
"version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/encodeurl": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
- "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -887,14 +771,10 @@
},
"node_modules/escape-html": {
"version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
"node_modules/etag": {
"version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -902,8 +782,6 @@
},
"node_modules/express": {
"version": "5.1.0",
- "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
- "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
"license": "MIT",
"dependencies": {
"accepts": "^2.0.0",
@@ -943,14 +821,10 @@
}
},
"node_modules/express-ejs-layouts": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/express-ejs-layouts/-/express-ejs-layouts-2.5.1.tgz",
- "integrity": "sha512-IXROv9n3xKga7FowT06n1Qn927JR8ZWDn5Dc9CJQoiiaaDqbhW5PDmWShzbpAa2wjWT1vJqaIM1S6vJwwX11gA=="
+ "version": "2.5.1"
},
"node_modules/express-session": {
"version": "1.18.2",
- "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz",
- "integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==",
"license": "MIT",
"dependencies": {
"cookie": "0.7.2",
@@ -968,14 +842,10 @@
},
"node_modules/express-session/node_modules/cookie-signature": {
"version": "1.0.7",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
- "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
"license": "MIT"
},
"node_modules/express-session/node_modules/debug": {
"version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
@@ -983,14 +853,10 @@
},
"node_modules/express-session/node_modules/ms": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/fetch-blob": {
"version": "3.2.0",
- "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
- "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
"funding": [
{
"type": "github",
@@ -1012,8 +878,6 @@
},
"node_modules/filelist": {
"version": "1.0.4",
- "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
- "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
"license": "Apache-2.0",
"dependencies": {
"minimatch": "^5.0.1"
@@ -1021,8 +885,6 @@
},
"node_modules/filelist/node_modules/brace-expansion": {
"version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -1030,8 +892,6 @@
},
"node_modules/filelist/node_modules/minimatch": {
"version": "5.1.6",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
- "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
@@ -1042,8 +902,6 @@
},
"node_modules/fill-range": {
"version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1055,8 +913,6 @@
},
"node_modules/finalhandler": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
- "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.0",
@@ -1129,8 +985,6 @@
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
- "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
- "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"license": "MIT",
"dependencies": {
"fetch-blob": "^3.1.2"
@@ -1141,8 +995,6 @@
},
"node_modules/forwarded": {
"version": "0.2.0",
- "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
- "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -1150,8 +1002,6 @@
},
"node_modules/fresh": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
- "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -1159,8 +1009,6 @@
},
"node_modules/fs-minipass": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
- "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
"license": "ISC",
"dependencies": {
"minipass": "^3.0.0"
@@ -1171,8 +1019,6 @@
},
"node_modules/fs-minipass/node_modules/minipass": {
"version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
@@ -1183,25 +1029,8 @@
},
"node_modules/fs.realpath": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"license": "ISC"
},
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -1213,9 +1042,6 @@
},
"node_modules/gauge": {
"version": "3.0.2",
- "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
- "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
- "deprecated": "This package is no longer supported.",
"license": "ISC",
"dependencies": {
"aproba": "^1.0.3 || ^2.0.0",
@@ -1271,9 +1097,6 @@
},
"node_modules/glob": {
"version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "deprecated": "Glob versions prior to v9 are no longer supported",
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
@@ -1292,8 +1115,6 @@
},
"node_modules/glob-parent": {
"version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -1317,8 +1138,6 @@
},
"node_modules/has-flag": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1354,8 +1173,6 @@
},
"node_modules/has-unicode": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
- "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
"license": "ISC"
},
"node_modules/hasown": {
@@ -1372,8 +1189,6 @@
},
"node_modules/http-errors": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"license": "MIT",
"dependencies": {
"depd": "2.0.0",
@@ -1388,8 +1203,6 @@
},
"node_modules/http-errors/node_modules/statuses": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -1397,8 +1210,6 @@
},
"node_modules/https-proxy-agent": {
"version": "5.0.1",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
- "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"license": "MIT",
"dependencies": {
"agent-base": "6",
@@ -1410,8 +1221,6 @@
},
"node_modules/iconv-lite": {
"version": "0.6.3",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
- "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
@@ -1422,16 +1231,11 @@
},
"node_modules/ignore-by-default": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
- "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
"dev": true,
"license": "ISC"
},
"node_modules/inflight": {
"version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"license": "ISC",
"dependencies": {
"once": "^1.3.0",
@@ -1440,14 +1244,10 @@
},
"node_modules/inherits": {
"version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/ioredis": {
"version": "5.7.0",
- "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.7.0.tgz",
- "integrity": "sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g==",
"license": "MIT",
"dependencies": {
"@ioredis/commands": "^1.3.0",
@@ -1470,8 +1270,6 @@
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
- "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
@@ -1479,8 +1277,6 @@
},
"node_modules/is-binary-path": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1492,8 +1288,6 @@
},
"node_modules/is-extglob": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1502,8 +1296,6 @@
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"license": "MIT",
"engines": {
"node": ">=8"
@@ -1511,8 +1303,6 @@
},
"node_modules/is-glob": {
"version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1524,8 +1314,6 @@
},
"node_modules/is-number": {
"version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1534,21 +1322,15 @@
},
"node_modules/is-promise": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
- "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
"node_modules/isexe": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true,
"license": "ISC"
},
"node_modules/jake": {
"version": "10.9.4",
- "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz",
- "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==",
"license": "Apache-2.0",
"dependencies": {
"async": "^3.2.6",
@@ -1564,8 +1346,6 @@
},
"node_modules/jose": {
"version": "6.1.0",
- "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz",
- "integrity": "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
@@ -1573,8 +1353,6 @@
},
"node_modules/jsonwebtoken": {
"version": "9.0.2",
- "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
- "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
"license": "MIT",
"dependencies": {
"jws": "^3.2.2",
@@ -1595,8 +1373,6 @@
},
"node_modules/jwa": {
"version": "1.4.2",
- "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
- "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
"license": "MIT",
"dependencies": {
"buffer-equal-constant-time": "^1.0.1",
@@ -1606,8 +1382,6 @@
},
"node_modules/jwks-rsa": {
"version": "3.2.0",
- "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.2.0.tgz",
- "integrity": "sha512-PwchfHcQK/5PSydeKCs1ylNym0w/SSv8a62DgHJ//7x2ZclCoinlsjAfDxAAbpoTPybOum/Jgy+vkvMmKz89Ww==",
"license": "MIT",
"dependencies": {
"@types/express": "^4.17.20",
@@ -1623,8 +1397,6 @@
},
"node_modules/jwks-rsa/node_modules/jose": {
"version": "4.15.9",
- "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
- "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
@@ -1632,8 +1404,6 @@
},
"node_modules/jws": {
"version": "3.2.2",
- "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
- "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"license": "MIT",
"dependencies": {
"jwa": "^1.4.1",
@@ -1642,8 +1412,6 @@
},
"node_modules/keygrip": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
- "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==",
"license": "MIT",
"dependencies": {
"tsscmp": "1.0.6"
@@ -1653,74 +1421,50 @@
}
},
"node_modules/limiter": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz",
- "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="
+ "version": "1.1.5"
},
"node_modules/lodash.clonedeep": {
"version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
- "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
"license": "MIT"
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
- "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
"license": "MIT"
},
"node_modules/lodash.includes": {
"version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
- "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
"license": "MIT"
},
"node_modules/lodash.isarguments": {
"version": "3.1.0",
- "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
- "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
"license": "MIT"
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
- "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
- "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
"license": "MIT"
},
"node_modules/lodash.isinteger": {
"version": "4.0.4",
- "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
- "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
"license": "MIT"
},
"node_modules/lodash.isnumber": {
"version": "3.0.3",
- "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
- "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
- "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
- "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"license": "MIT"
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
- "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
- "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"license": "MIT"
},
"node_modules/lodash.once": {
"version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
- "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/lru-cache": {
"version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
@@ -1731,8 +1475,6 @@
},
"node_modules/lru-memoizer": {
"version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz",
- "integrity": "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==",
"license": "MIT",
"dependencies": {
"lodash.clonedeep": "^4.5.0",
@@ -1741,8 +1483,6 @@
},
"node_modules/make-dir": {
"version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"license": "MIT",
"dependencies": {
"semver": "^6.0.0"
@@ -1756,8 +1496,6 @@
},
"node_modules/make-dir/node_modules/semver": {
"version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -1774,8 +1512,6 @@
},
"node_modules/media-typer": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
- "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -1783,8 +1519,6 @@
},
"node_modules/merge-descriptors": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
- "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
"license": "MIT",
"engines": {
"node": ">=18"
@@ -1795,8 +1529,6 @@
},
"node_modules/mime-db": {
"version": "1.54.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
- "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -1804,8 +1536,6 @@
},
"node_modules/mime-types": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
- "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
"license": "MIT",
"dependencies": {
"mime-db": "^1.54.0"
@@ -1816,8 +1546,6 @@
},
"node_modules/minimatch": {
"version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -1828,8 +1556,6 @@
},
"node_modules/minipass": {
"version": "5.0.0",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
- "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
"license": "ISC",
"engines": {
"node": ">=8"
@@ -1837,8 +1563,6 @@
},
"node_modules/minizlib": {
"version": "2.1.2",
- "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
- "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
"license": "MIT",
"dependencies": {
"minipass": "^3.0.0",
@@ -1850,8 +1574,6 @@
},
"node_modules/minizlib/node_modules/minipass": {
"version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
@@ -1862,8 +1584,6 @@
},
"node_modules/mkdirp": {
"version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"license": "MIT",
"bin": {
"mkdirp": "bin/cmd.js"
@@ -1874,14 +1594,10 @@
},
"node_modules/ms": {
"version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/negotiator": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
- "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -1889,15 +1605,19 @@
},
"node_modules/node-addon-api": {
"version": "5.1.0",
- "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
- "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==",
"license": "MIT"
},
+ "node_modules/node-appwrite": {
+ "version": "20.2.1",
+ "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-20.2.1.tgz",
+ "integrity": "sha512-RweIh+3RHjprsxhWaJzcQr/UDMBMsZCma50TIJ9t3onVgs5jAT9aqFnsMlaaC9QZn1sXpPUQV90W6uvtm64DnQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "node-fetch-native-with-agent": "1.7.2"
+ }
+ },
"node_modules/node-domexception": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
- "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
- "deprecated": "Use your platform's native DOMException instead",
"funding": [
{
"type": "github",
@@ -1915,8 +1635,6 @@
},
"node_modules/node-fetch": {
"version": "3.3.2",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
- "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
"license": "MIT",
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
@@ -1931,10 +1649,14 @@
"url": "https://opencollective.com/node-fetch"
}
},
+ "node_modules/node-fetch-native-with-agent": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/node-fetch-native-with-agent/-/node-fetch-native-with-agent-1.7.2.tgz",
+ "integrity": "sha512-5MaOOCuJEvcckoz7/tjdx1M6OusOY6Xc5f459IaruGStWnKzlI1qpNgaAwmn4LmFYcsSlj+jBMk84wmmRxfk5g==",
+ "license": "MIT"
+ },
"node_modules/nodemon": {
"version": "3.1.10",
- "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
- "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1962,8 +1684,6 @@
},
"node_modules/nopt": {
"version": "5.0.0",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
- "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
"license": "ISC",
"dependencies": {
"abbrev": "1"
@@ -1977,8 +1697,6 @@
},
"node_modules/normalize-path": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1987,9 +1705,6 @@
},
"node_modules/npmlog": {
"version": "5.0.1",
- "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
- "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
- "deprecated": "This package is no longer supported.",
"license": "ISC",
"dependencies": {
"are-we-there-yet": "^2.0.0",
@@ -2000,8 +1715,6 @@
},
"node_modules/object-assign": {
"version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -2009,8 +1722,6 @@
},
"node_modules/object-hash": {
"version": "2.2.0",
- "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
- "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
"license": "MIT",
"engines": {
"node": ">= 6"
@@ -2018,8 +1729,6 @@
},
"node_modules/object-inspect": {
"version": "1.13.4",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
- "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -2030,8 +1739,6 @@
},
"node_modules/oidc-token-hash": {
"version": "5.1.1",
- "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.1.1.tgz",
- "integrity": "sha512-D7EmwxJV6DsEB6vOFLrBM2OzsVgQzgPWyHlV2OOAVj772n+WTXpudC9e9u5BVKQnYwaD30Ivhi9b+4UeBcGu9g==",
"license": "MIT",
"engines": {
"node": "^10.13.0 || >=12.0.0"
@@ -2039,8 +1746,6 @@
},
"node_modules/on-finished": {
"version": "2.4.1",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
- "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
@@ -2051,8 +1756,6 @@
},
"node_modules/on-headers": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
- "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -2060,8 +1763,6 @@
},
"node_modules/once": {
"version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"license": "ISC",
"dependencies": {
"wrappy": "1"
@@ -2069,8 +1770,6 @@
},
"node_modules/openid-client": {
"version": "5.7.1",
- "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz",
- "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==",
"license": "MIT",
"dependencies": {
"jose": "^4.15.9",
@@ -2084,8 +1783,6 @@
},
"node_modules/openid-client/node_modules/jose": {
"version": "4.15.9",
- "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
- "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
@@ -2093,8 +1790,6 @@
},
"node_modules/parseurl": {
"version": "1.3.3",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -2102,8 +1797,6 @@
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -2111,8 +1804,6 @@
},
"node_modules/path-key": {
"version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2121,8 +1812,6 @@
},
"node_modules/path-to-regexp": {
"version": "8.2.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
- "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
"license": "MIT",
"engines": {
"node": ">=16"
@@ -2170,8 +1859,6 @@
},
"node_modules/pg-format": {
"version": "1.0.4",
- "resolved": "https://registry.npmjs.org/pg-format/-/pg-format-1.0.4.tgz",
- "integrity": "sha512-YyKEF78pEA6wwTAqOUaHIN/rWpfzzIuMh9KdAhc3rSLQ/7zkRFcCgYBAEGatDstLyZw4g0s9SNICmaTGnBVeyw==",
"license": "MIT",
"engines": {
"node": ">=4.0"
@@ -2228,14 +1915,10 @@
},
"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/picomatch": {
"version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2286,8 +1969,6 @@
},
"node_modules/proxy-addr": {
"version": "2.0.7",
- "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
- "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"license": "MIT",
"dependencies": {
"forwarded": "0.2.0",
@@ -2305,15 +1986,11 @@
},
"node_modules/pstree.remy": {
"version": "1.1.8",
- "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
- "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
"dev": true,
"license": "MIT"
},
"node_modules/qs": {
"version": "6.14.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
- "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
@@ -2327,8 +2004,6 @@
},
"node_modules/random-bytes": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
- "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -2336,8 +2011,6 @@
},
"node_modules/range-parser": {
"version": "1.2.1",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -2345,8 +2018,6 @@
},
"node_modules/raw-body": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
- "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
@@ -2360,8 +2031,6 @@
},
"node_modules/readable-stream": {
"version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
@@ -2374,8 +2043,6 @@
},
"node_modules/readdirp": {
"version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2387,8 +2054,6 @@
},
"node_modules/redis": {
"version": "5.8.2",
- "resolved": "https://registry.npmjs.org/redis/-/redis-5.8.2.tgz",
- "integrity": "sha512-31vunZj07++Y1vcFGcnNWEf5jPoTkGARgfWI4+Tk55vdwHxhAvug8VEtW7Cx+/h47NuJTEg/JL77zAwC6E0OeA==",
"license": "MIT",
"dependencies": {
"@redis/bloom": "5.8.2",
@@ -2403,8 +2068,6 @@
},
"node_modules/redis-errors": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
- "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
"license": "MIT",
"engines": {
"node": ">=4"
@@ -2412,8 +2075,6 @@
},
"node_modules/redis-parser": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
- "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
"license": "MIT",
"dependencies": {
"redis-errors": "^1.0.0"
@@ -2424,9 +2085,6 @@
},
"node_modules/rimraf": {
"version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "deprecated": "Rimraf versions prior to v4 are no longer supported",
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
@@ -2440,8 +2098,6 @@
},
"node_modules/router": {
"version": "2.2.0",
- "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
- "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.0",
@@ -2456,8 +2112,6 @@
},
"node_modules/safe-buffer": {
"version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
@@ -2476,14 +2130,10 @@
},
"node_modules/safer-buffer": {
"version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/semver": {
"version": "7.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
- "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -2494,8 +2144,6 @@
},
"node_modules/send": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
- "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
"license": "MIT",
"dependencies": {
"debug": "^4.3.5",
@@ -2516,8 +2164,6 @@
},
"node_modules/serve-static": {
"version": "2.2.0",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
- "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
"license": "MIT",
"dependencies": {
"encodeurl": "^2.0.0",
@@ -2531,20 +2177,14 @@
},
"node_modules/set-blocking": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"license": "ISC"
},
"node_modules/setprototypeof": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
"node_modules/shebang-command": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2556,8 +2196,6 @@
},
"node_modules/shebang-regex": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2566,8 +2204,6 @@
},
"node_modules/side-channel": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
- "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -2585,8 +2221,6 @@
},
"node_modules/side-channel-list": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
- "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -2601,8 +2235,6 @@
},
"node_modules/side-channel-map": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
- "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
@@ -2619,8 +2251,6 @@
},
"node_modules/side-channel-weakmap": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
- "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
@@ -2638,14 +2268,10 @@
},
"node_modules/signal-exit": {
"version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC"
},
"node_modules/simple-update-notifier": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
- "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2666,14 +2292,10 @@
},
"node_modules/standard-as-callback": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
- "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
"license": "MIT"
},
"node_modules/statuses": {
"version": "2.0.2",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
- "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -2681,8 +2303,6 @@
},
"node_modules/string_decoder": {
"version": "1.3.0",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
- "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.2.0"
@@ -2690,8 +2310,6 @@
},
"node_modules/string-width": {
"version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
@@ -2704,8 +2322,6 @@
},
"node_modules/strip-ansi": {
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -2716,8 +2332,6 @@
},
"node_modules/supports-color": {
"version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2729,8 +2343,6 @@
},
"node_modules/tar": {
"version": "6.2.1",
- "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
- "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
"license": "ISC",
"dependencies": {
"chownr": "^2.0.0",
@@ -2746,8 +2358,6 @@
},
"node_modules/to-regex-range": {
"version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2759,8 +2369,6 @@
},
"node_modules/toidentifier": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"license": "MIT",
"engines": {
"node": ">=0.6"
@@ -2768,8 +2376,6 @@
},
"node_modules/touch": {
"version": "3.1.1",
- "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
- "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
"dev": true,
"license": "ISC",
"bin": {
@@ -2778,14 +2384,10 @@
},
"node_modules/tr46": {
"version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT"
},
"node_modules/tsscmp": {
"version": "1.0.6",
- "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
- "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==",
"license": "MIT",
"engines": {
"node": ">=0.6.x"
@@ -2793,8 +2395,6 @@
},
"node_modules/type-is": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
- "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
"license": "MIT",
"dependencies": {
"content-type": "^1.0.5",
@@ -2807,8 +2407,6 @@
},
"node_modules/uid-safe": {
"version": "2.1.5",
- "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
- "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
"license": "MIT",
"dependencies": {
"random-bytes": "~1.0.0"
@@ -2819,21 +2417,15 @@
},
"node_modules/undefsafe": {
"version": "2.0.5",
- "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
- "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
"dev": true,
"license": "MIT"
},
"node_modules/undici-types": {
"version": "7.10.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
- "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
"license": "MIT"
},
"node_modules/unpipe": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -2841,14 +2433,10 @@
},
"node_modules/util-deprecate": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/vary": {
"version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -2856,8 +2444,6 @@
},
"node_modules/web-streams-polyfill": {
"version": "3.3.3",
- "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
- "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"license": "MIT",
"engines": {
"node": ">= 8"
@@ -2865,14 +2451,10 @@
},
"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==",
"license": "BSD-2-Clause"
},
"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==",
"license": "MIT",
"dependencies": {
"tr46": "~0.0.3",
@@ -2881,8 +2463,6 @@
},
"node_modules/which": {
"version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -2897,8 +2477,6 @@
},
"node_modules/wide-align": {
"version": "1.1.5",
- "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
- "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
"license": "ISC",
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
@@ -2906,8 +2484,6 @@
},
"node_modules/wrappy": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"license": "ISC"
},
"node_modules/xtend": {
@@ -2921,8 +2497,6 @@
},
"node_modules/yallist": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"license": "ISC"
}
}
diff --git a/services/auth/package.json b/services/auth/package.json
index 41dcffa..add584b 100644
--- a/services/auth/package.json
+++ b/services/auth/package.json
@@ -1,11 +1,11 @@
{
"name": "authentication",
"version": "1.0.0",
- "main": "src/index.js",
+ "main": "src/index.mjs",
"scripts": {
- "start": "NODE_ENV=production node ./src/index.js",
- "dev": "NODE_ENV=development npx nodemon ./src/index.js",
- "test": "NODE_ENV=stage node ./src/index.js"
+ "start": "NODE_ENV=production node ./src/index.mjs",
+ "dev": "NODE_ENV=development npx nodemon ./src/index.mjs",
+ "test": "NODE_ENV=stage node ./src/index.mjs"
},
"author": "Mateo Saldain",
"license": "ISC",
@@ -19,6 +19,7 @@
"bcrypt": "^5.1.1",
"chalk": "^5.6.0",
"connect-redis": "^9.0.0",
+ "cookie-parser": "^1.4.7",
"cookie-session": "^2.0.0",
"cors": "^2.8.5",
"dotenv": "^17.2.1",
@@ -30,12 +31,18 @@
"jose": "^6.1.0",
"jsonwebtoken": "^9.0.2",
"jwks-rsa": "^3.2.0",
+ "node-appwrite": "^20.2.1",
"node-fetch": "^3.3.2",
"openid-client": "^5.7.1",
"pg": "^8.16.3",
"pg-format": "^1.0.4",
"redis": "^5.8.2"
},
+ "imports": {
+ "#v1Router": "./src/api/v1/routes/routes.js",
+ "#pages": "./src/pages/pages.js",
+ "#db": "./src/db/poolSingleton.js"
+ },
"keywords": [],
"description": ""
}
diff --git a/services/auth/src/api/api.js b/services/auth/src/api/api.js
new file mode 100644
index 0000000..d65d8b8
--- /dev/null
+++ b/services/auth/src/api/api.js
@@ -0,0 +1,181 @@
+// // ----------------------------------------------------------
+// // API
+// // ----------------------------------------------------------
+// app.get('/api/tables', async (_req, res) => {
+// res.json(ALLOWED_TABLES);
+// });
+
+// app.get('/api/schema/:table', async (req, res) => {
+// try {
+// const table = ensureTable(req.params.table);
+// const client = await getClient();
+// try {
+// const columns = await loadColumns(client, table);
+// const fks = await loadForeignKeys(client, table);
+// const enriched = columns.map(c => ({ ...c, foreign: fks[c.column_name] || null }));
+// res.json({ table, columns: enriched });
+// } finally { client.release(); }
+// } catch (e) {
+// res.status(400).json({ error: e.message });
+// }
+// });
+
+// app.get('/api/options/:table/:column', async (req, res) => {
+// try {
+// const table = ensureTable(req.params.table);
+// const column = req.params.column;
+// if (!VALID_IDENT.test(column)) throw new Error('Columna inválida');
+
+// const client = await getClient();
+// try {
+// const fks = await loadForeignKeys(client, table);
+// const fk = fks[column];
+// if (!fk) return res.json([]);
+
+// const refTable = fk.foreign_table;
+// const refId = fk.foreign_column;
+// const labelCol = await pickLabelColumn(client, refTable);
+
+// const sql = `SELECT ${q(refId)} AS id, ${q(labelCol)} AS label FROM ${q(refTable)} ORDER BY ${q(labelCol)} LIMIT 1000`;
+// const result = await client.query(sql);
+// res.json(result.rows);
+// } finally { client.release(); }
+// } catch (e) {
+// res.status(400).json({ error: e.message });
+// }
+// });
+
+// app.get('/api/table/:table', async (req, res) => {
+// try {
+// const table = ensureTable(req.params.table);
+// const limit = Math.min(parseInt(req.query.limit || '100', 10), 1000);
+// const client = await getClient();
+// try {
+// const pks = await loadPrimaryKey(client, table);
+// const orderBy = pks.length ? `ORDER BY ${pks.map(q).join(', ')} DESC` : '';
+// const sql = `SELECT * FROM ${q(table)} ${orderBy} LIMIT ${limit}`;
+// const result = await client.query(sql);
+
+// // Normalizar: siempre devolver objetos {col: valor}
+// const colNames = result.fields.map(f => f.name);
+// let rows = result.rows;
+// if (rows.length && Array.isArray(rows[0])) {
+// rows = rows.map(r => Object.fromEntries(r.map((v, i) => [colNames[i], v])));
+// }
+// res.json(rows);
+// } finally { client.release(); }
+// } catch (e) {
+// res.status(400).json({ error: e.message, code: e.code, detail: e.detail });
+// }
+// });
+
+// app.post('/api/table/:table', async (req, res) => {
+// const table = ensureTable(req.params.table);
+// const payload = req.body || {};
+// try {
+// const client = await getClient();
+// try {
+// const columns = await loadColumns(client, table);
+// const insertable = columns.filter(c =>
+// !c.is_primary && !c.is_identity && !(c.column_default || '').startsWith('nextval(')
+// );
+// const allowedCols = new Set(insertable.map(c => c.column_name));
+
+// const cols = [];
+// const vals = [];
+// const params = [];
+// let idx = 1;
+// for (const [k, v] of Object.entries(payload)) {
+// if (!allowedCols.has(k)) continue;
+// if (!VALID_IDENT.test(k)) continue;
+// cols.push(q(k));
+// vals.push(`$${idx++}`);
+// params.push(v);
+// }
+
+// if (!cols.length) {
+// const { rows } = await client.query(`INSERT INTO ${q(table)} DEFAULT VALUES RETURNING *`);
+// res.status(201).json({ inserted: rows[0] });
+// } else {
+// const { rows } = await client.query(
+// `INSERT INTO ${q(table)} (${cols.join(', ')}) VALUES (${vals.join(', ')}) RETURNING *`,
+// params
+// );
+// res.status(201).json({ inserted: rows[0] });
+// }
+// } catch (e) {
+// if (e.code === '23503') return res.status(400).json({ error: 'Violación de clave foránea', detail: e.detail });
+// if (e.code === '23505') return res.status(400).json({ error: 'Violación de unicidad', detail: e.detail });
+// if (e.code === '23514') return res.status(400).json({ error: 'Violación de CHECK', detail: e.detail });
+// if (e.code === '23502') return res.status(400).json({ error: 'Campo NOT NULL faltante', detail: e.detail });
+// throw e;
+// }
+// } catch (e) {
+// res.status(400).json({ error: e.message });
+// }
+// });
+
+// app.get('/api/comandas', async (req, res, next) => {
+// try {
+// const estado = (req.query.estado || '').trim() || null;
+// const limit = Math.min(parseInt(req.query.limit || '200', 10), 1000);
+
+// const { rows } = await mainPool.query(
+// `SELECT * FROM public.f_comandas_resumen($1, $2)`,
+// [estado, limit]
+// );
+// res.json(rows);
+// } catch (e) { next(e); }
+// });
+
+
+// // Detalle de una comanda (con nombres de productos)
+// // GET /api/comandas/:id/detalle
+// app.get('/api/comandas/:id/detalle', (req, res, next) =>
+// mainPool.query(
+// `SELECT id_det_comanda, id_producto, producto_nombre,
+// cantidad, pre_unitario, subtotal, observaciones
+// FROM public.v_comandas_detalle_items
+// WHERE id_comanda = $1::int
+// ORDER BY id_det_comanda`,
+// [req.params.id]
+// )
+// .then(r => res.json(r.rows))
+// .catch(next)
+// );
+
+// // Cerrar comanda (setea estado y fec_cierre en DB)
+// app.post('/api/comandas/:id/cerrar', async (req, res, next) => {
+// try {
+// const id = Number(req.params.id);
+// if (!Number.isInteger(id) || id <= 0) {
+// return res.status(400).json({ error: 'id inválido' });
+// }
+// const { rows } = await mainPool.query(
+// `SELECT public.f_cerrar_comanda($1) AS data`,
+// [id]
+// );
+// if (!rows.length || rows[0].data === null) {
+// return res.status(404).json({ error: 'Comanda no encontrada' });
+// }
+// res.json(rows[0].data);
+// } catch (err) { next(err); }
+// });
+
+// Abrir (reabrir) comanda
+app.post('/api/comandas/:id/abrir', async (req, res, next) => {
+ try {
+ const id = Number(req.params.id);
+ if (!Number.isInteger(id) || id <= 0) {
+ return res.status(400).json({ error: 'id inválido' });
+ }
+ const { rows } = await mainPool.query(
+ `SELECT public.f_abrir_comanda($1) AS data`,
+ [id]
+ );
+ if (!rows.length || rows[0].data === null) {
+ return res.status(404).json({ error: 'Comanda no encontrada' });
+ }
+ res.json(rows[0].data);
+ } catch (err) { next(err); }
+});
\ No newline at end of file
diff --git a/services/auth/src/api/rpc.js b/services/auth/src/api/rpc.js
new file mode 100644
index 0000000..56766d1
--- /dev/null
+++ b/services/auth/src/api/rpc.js
@@ -0,0 +1,230 @@
+// // GET producto + receta
+// app.get('/api/rpc/get_producto/:id', async (req, res) => {
+// const id = Number(req.params.id);
+// const { rows } = await mainPool.query('SELECT public.get_producto($1) AS data', [id]);
+// res.json(rows[0]?.data || {});
+// });
+
+// // POST guardar producto + receta
+
+// app.post('/api/rpc/save_producto', async (req, res) => {
+// try {
+// // console.debug('receta payload:', req.body?.receta); // habilitalo si lo necesitás
+// const q = 'SELECT public.save_producto($1,$2,$3,$4,$5,$6,$7::jsonb) AS id_producto';
+// const { id_producto = null, nombre, img_producto = null, precio = 0, activo = true, id_categoria = null, receta = [] } = req.body || {};
+// const params = [id_producto, nombre, img_producto, precio, activo, id_categoria, JSON.stringify(receta || [])];
+// const { rows } = await mainPool.query(q, params);
+// res.json(rows[0] || {});
+// } catch (e) {
+// console.error(e);
+// res.status(500).json({ error: 'save_producto failed' });
+// }
+// });
+
+// // GET MP + proveedores
+// app.get('/api/rpc/get_materia/:id', async (req, res) => {
+// const id = Number(req.params.id);
+// try {
+// const { rows } = await mainPool.query('SELECT public.get_materia_prima($1) AS data', [id]);
+// res.json(rows[0]?.data || {});
+// } catch (e) {
+// console.error(e);
+// res.status(500).json({ error: 'get_materia failed' });
+// }
+// });
+
+// // SAVE MP + proveedores (array)
+// app.post('/api/rpc/save_materia', async (req, res) => {
+// const { id_mat_prima = null, nombre, unidad, activo = true, proveedores = [] } = req.body || {};
+// try {
+// const q = 'SELECT public.save_materia_prima($1,$2,$3,$4,$5::jsonb) AS id_mat_prima';
+// const params = [id_mat_prima, nombre, unidad, activo, JSON.stringify(proveedores || [])];
+// const { rows } = await mainPool.query(q, params);
+// res.json(rows[0] || {});
+// } catch (e) {
+// console.error(e);
+// res.status(500).json({ error: 'save_materia failed' });
+// }
+// });
+
+// // POST /api/rpc/find_usuarios_por_documentos { docs: ["12345678","09123456", ...] }
+// app.post('/api/rpc/find_usuarios_por_documentos', async (req, res) => {
+// try {
+// const docs = Array.isArray(req.body?.docs) ? req.body.docs : [];
+// const sql = 'SELECT public.find_usuarios_por_documentos($1::jsonb) AS data';
+// const { rows } = await mainPool.query(sql, [JSON.stringify(docs)]);
+// res.json(rows[0]?.data || {});
+// } catch (e) {
+// console.error(e);
+// res.status(500).json({ error: 'find_usuarios_por_documentos failed' });
+// }
+// });
+
+// // POST /api/rpc/import_asistencia { registros: [...], origen?: "AGL_001.txt" }
+// app.post('/api/rpc/import_asistencia', async (req, res) => {
+// try {
+// const registros = Array.isArray(req.body?.registros) ? req.body.registros : [];
+// const origen = req.body?.origen || null;
+// const sql = 'SELECT public.import_asistencia($1::jsonb,$2) AS data';
+// const { rows } = await mainPool.query(sql, [JSON.stringify(registros), origen]);
+// res.json(rows[0]?.data || {});
+// } catch (e) {
+// console.error(e);
+// res.status(500).json({ error: 'import_asistencia failed' });
+// }
+// });
+
+// // Consultar datos de asistencia (raw + pares) para un usuario y rango
+// app.post('/api/rpc/asistencia_get', async (req, res) => {
+// try {
+// const { doc, desde, hasta } = req.body || {};
+// const sql = 'SELECT public.asistencia_get($1::text,$2::date,$3::date) AS data';
+// const { rows } = await mainPool.query(sql, [doc, desde, hasta]);
+// res.json(rows[0]?.data || {});
+// } catch (e) {
+// console.error(e); res.status(500).json({ error: 'asistencia_get failed' });
+// }
+// });
+
+// // Editar un registro crudo y recalcular pares
+// app.post('/api/rpc/asistencia_update_raw', async (req, res) => {
+// try {
+// const { id_raw, fecha, hora, modo } = req.body || {};
+// const sql = 'SELECT public.asistencia_update_raw($1::bigint,$2::date,$3::text,$4::text) AS data';
+// const { rows } = await mainPool.query(sql, [id_raw, fecha, hora, modo ?? null]);
+// res.json(rows[0]?.data || {});
+// } catch (e) {
+// console.error(e); res.status(500).json({ error: 'asistencia_update_raw failed' });
+// }
+// });
+
+// // Eliminar un registro crudo y recalcular pares
+// app.post('/api/rpc/asistencia_delete_raw', async (req, res) => {
+// try {
+// const { id_raw } = req.body || {};
+// const sql = 'SELECT public.asistencia_delete_raw($1::bigint) AS data';
+// const { rows } = await mainPool.query(sql, [id_raw]);
+// res.json(rows[0]?.data || {});
+// } catch (e) {
+// console.error(e); res.status(500).json({ error: 'asistencia_delete_raw failed' });
+// }
+// });
+
+// // POST /api/rpc/report_tickets { year }
+// app.post('/api/rpc/report_tickets', async (req, res) => {
+// try {
+// const y = parseInt(req.body?.year ?? req.query?.year, 10);
+// const year = (Number.isFinite(y) && y >= 2000 && y <= 2100)
+// ? y
+// : (new Date()).getFullYear();
+
+// const { rows } = await mainPool.query(
+// 'SELECT public.report_tickets_year($1::int) AS j', [year]
+// );
+// res.json(rows[0].j);
+// } catch (e) {
+// console.error('report_tickets error:', e);
+// res.status(500).json({
+// error: 'report_tickets failed',
+// message: e.message, detail: e.detail, where: e.where, code: e.code
+// });
+// }
+// });
+
+// // POST /api/rpc/report_asistencia { desde: 'YYYY-MM-DD', hasta: 'YYYY-MM-DD' }
+// app.post('/api/rpc/report_asistencia', async (req, res) => {
+// try {
+// let { desde, hasta } = req.body || {};
+// // defaults si vienen vacíos/invalidos
+// const re = /^\d{4}-\d{2}-\d{2}$/;
+// if (!re.test(desde) || !re.test(hasta)) {
+// const end = new Date();
+// const start = new Date(end); start.setDate(end.getDate() - 30);
+// desde = start.toISOString().slice(0, 10);
+// hasta = end.toISOString().slice(0, 10);
+// }
+
+// const { rows } = await mainPool.query(
+// 'SELECT public.report_asistencia($1::date,$2::date) AS j', [desde, hasta]
+// );
+// res.json(rows[0].j);
+// } catch (e) {
+// console.error('report_asistencia error:', e);
+// res.status(500).json({
+// error: 'report_asistencia failed',
+// message: e.message, detail: e.detail, where: e.where, code: e.code
+// });
+// }
+// });
+
+// // Guardar (insert/update)
+// app.post('/api/rpc/save_compra', async (req, res) => {
+// try {
+// const { id_compra, id_proveedor, fec_compra, detalles } = req.body || {};
+// const sql = 'SELECT * FROM public.save_compra($1::int,$2::int,$3::timestamptz,$4::jsonb)';
+// const args = [id_compra ?? null, id_proveedor, fec_compra ? new Date(fec_compra) : null, JSON.stringify(detalles)];
+// const { rows } = await mainPool.query(sql, args);
+// res.json(rows[0]); // { id_compra, total }
+// } catch (e) {
+// console.error('save_compra error:', e);
+// res.status(500).json({ error: 'save_compra failed', message: e.message, detail: e.detail, where: e.where, code: e.code });
+// }
+// });
+
+// // Obtener para editar
+// app.post('/api/rpc/get_compra', async (req, res) => {
+// try {
+// const { id_compra } = req.body || {};
+// const sql = `SELECT public.get_compra($1::int) AS data`;
+// const { rows } = await mainPool.query(sql, [id_compra]);
+// res.json(rows[0]?.data || {});
+// } catch (e) {
+// console.error(e); res.status(500).json({ error: 'get_compra failed' });
+// }
+// });
+
+// // Eliminar
+// app.post('/api/rpc/delete_compra', async (req, res) => {
+// try {
+// const { id_compra } = req.body || {};
+// await mainPool.query(`SELECT public.delete_compra($1::int)`, [id_compra]);
+// res.json({ ok: true });
+// } catch (e) {
+// console.error(e); res.status(500).json({ error: 'delete_compra failed' });
+// }
+// });
+
+// // POST /api/rpc/report_gastos { year: 2025 }
+// app.post('/api/rpc/report_gastos', async (req, res) => {
+// try {
+// const year = parseInt(req.body?.year ?? new Date().getFullYear(), 10);
+// const { rows } = await mainPool.query(
+// 'SELECT public.report_gastos($1::int) AS j', [year]
+// );
+// res.json(rows[0].j);
+// } catch (e) {
+// console.error('report_gastos error:', e);
+// res.status(500).json({
+// error: 'report_gastos failed',
+// message: e.message, detail: e.detail, code: e.code
+// });
+// }
+// });
+
+// // (Opcional) GET para probar rápido desde el navegador:
+// // /api/rpc/report_gastos?year=2025
+// app.get('/api/rpc/report_gastos', async (req, res) => {
+// try {
+// const year = parseInt(req.query.year ?? new Date().getFullYear(), 10);
+// const { rows } = await mainPool.query(
+// 'SELECT public.report_gastos($1::int) AS j', [year]
+// );
+// res.json(rows[0].j);
+// } catch (e) {
+// console.error('report_gastos error:', e);
+// res.status(500).json({
+// error: 'report_gastos failed',
+// message: e.message, detail: e.detail, code: e.code
+// });
+// }
+// });
\ No newline at end of file
diff --git a/services/auth/src/api/v1/routes/routes.js b/services/auth/src/api/v1/routes/routes.js
new file mode 100644
index 0000000..c17f2cc
--- /dev/null
+++ b/services/auth/src/api/v1/routes/routes.js
@@ -0,0 +1,340 @@
+// services/manso/src/api/v1/routes/routes.js
+
+import { Router } from 'express';
+import pool from '#db'; // Pool Singleton
+const router = Router();
+
+// ==========================================================
+// Rutas de API v1
+// ==========================================================
+
+
+
+// ----------------------------------------------------------
+// API Comandas
+// ----------------------------------------------------------
+
+router.route('/comandas').get( async (req, res, next) => {
+ try {
+ var client = await pool.getClient()
+ const estado = (req.query.estado || '').trim() || null;
+ const limit = Math.min(parseInt(req.query.limit || '200', 10), 1000);
+
+ const { rows } = await client.query(
+ `SELECT * FROM public.f_comandas_resumen($1, $2)`,
+ [estado, limit]
+ );
+ res.json(rows);
+ } catch (e) {
+ next(e);
+ } finally {
+ client.release();
+ }
+});
+
+router.route('/comandas/:id/detalle').get( async (req, res, next) => {
+ try {
+ const client = await pool.getClient()
+ client.query(
+ `SELECT id_det_comanda, id_producto, producto_nombre,
+ cantidad, pre_unitario, subtotal, observaciones
+ FROM public.v_comandas_detalle_items
+ WHERE id_comanda = $1::int
+ ORDER BY id_det_comanda`,
+ [req.params.id]
+ )
+ .then(r => res.json(r.rows))
+ .catch(next)
+ client.release();
+ } catch (error) {
+ next(e);
+ }
+});
+
+router.route('/comandas/:id/cerrar').post( async (req, res, next) => {
+ try {
+ const client = await pool.getClient()
+ const id = Number(req.params.id);
+ if (!Number.isInteger(id) || id <= 0) {
+ return res.status(400).json({ error: 'id inválido' });
+ }
+ const { rows } = await client.query(
+ `SELECT public.f_cerrar_comanda($1) AS data`,
+ [id]
+ );
+ if (!rows.length || rows[0].data === null) {
+ return res.status(404).json({ error: 'Comanda no encontrada' });
+ }
+ res.json(rows[0].data);
+ client.release();
+ } catch (err) { next(err); }
+});
+
+router.route('/comandas/:id/abrir').post( async (req, res, next) => {
+ try {
+ const client = await pool.getClient()
+ const id = Number(req.params.id);
+ if (!Number.isInteger(id) || id <= 0) {
+ return res.status(400).json({ error: 'id inválido' });
+ }
+ const { rows } = await client.query(
+ `SELECT public.f_abrir_comanda($1) AS data`,
+ [id]
+ );
+ if (!rows.length || rows[0].data === null) {
+ return res.status(404).json({ error: 'Comanda no encontrada' });
+ }
+ res.json(rows[0].data);
+ client.release();
+ } catch (err) { next(err); }
+});
+
+
+
+// ----------------------------------------------------------
+// API Productos
+// ----------------------------------------------------------
+
+// GET producto + receta
+router.route('/rpc/get_producto/:id').get( async (req, res) => {
+ const client = await pool.getClient()
+ const id = Number(req.params.id);
+ const { rows } = await client.query('SELECT public.get_producto($1) AS data', [id]);
+ res.json(rows[0]?.data || {});
+ client.release();
+});
+
+// POST guardar producto + receta
+router.route('/rpc/save_producto').post(async (req, res) => {
+ try {
+ // console.debug('receta payload:', req.body?.receta); // habilitalo si lo necesitás
+ const client = await pool.getClient()
+ const q = 'SELECT public.save_producto($1,$2,$3,$4,$5,$6,$7::jsonb) AS id_producto';
+ const { id_producto=null, nombre, img_producto=null, precio=0, activo=true, id_categoria=null, receta=[] } = req.body || {};
+ const params = [id_producto, nombre, img_producto, precio, activo, id_categoria, JSON.stringify(receta||[])];
+ const { rows } = await client.query(q, params);
+ res.json(rows[0] || {});
+ client.release();
+ } catch(e) {
+ console.error(e);
+ res.status(500).json({ error: 'save_producto failed' });
+ }
+});
+
+
+
+// ----------------------------------------------------------
+// API Materias Primas
+// ----------------------------------------------------------
+
+// GET MP + proveedores
+router.route('/rpc/get_materia/:id').get(async (req, res) => {
+ const id = Number(req.params.id);
+ try {
+ const client = await pool.getClient()
+ const { rows } = await client.query('SELECT public.get_materia_prima($1) AS data', [id]);
+ res.json(rows[0]?.data || {});
+ client.release();
+ } catch (e) {
+ console.error(e);
+ res.status(500).json({ error: 'get_materia failed' });
+ }
+});
+
+// SAVE MP + proveedores (array)
+router.route('/rpc/save_materia').post( async (req, res) => {
+ const { id_mat_prima=null, nombre, unidad, activo=true, proveedores=[] } = req.body || {};
+ try {
+ const q = 'SELECT public.save_materia_prima($1,$2,$3,$4,$5::jsonb) AS id_mat_prima';
+ const params = [id_mat_prima, nombre, unidad, activo, JSON.stringify(proveedores||[])];
+ const { rows } = await pool.query(q, params);
+ res.json(rows[0] || {});
+ } catch (e) {
+ console.error(e);
+ res.status(500).json({ error: 'save_materia failed' });
+ }
+});
+
+
+
+// ----------------------------------------------------------
+// API Usuarios y Asistencias
+// ----------------------------------------------------------
+
+// POST /api/rpc/find_usuarios_por_documentos { docs: ["12345678","09123456", ...] }
+router.route('/rpc/find_usuarios_por_documentos').post( async (req, res) => {
+ try {
+ const docs = Array.isArray(req.body?.docs) ? req.body.docs : [];
+ const sql = 'SELECT public.find_usuarios_por_documentos($1::jsonb) AS data';
+ const { rows } = await pool.query(sql, [JSON.stringify(docs)]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e);
+ res.status(500).json({ error: 'find_usuarios_por_documentos failed' });
+ }
+});
+
+// POST /api/rpc/import_asistencia { registros: [...], origen?: "AGL_001.txt" }
+router.route('/rpc/import_asistencia').post( async (req, res) => {
+ try {
+ const registros = Array.isArray(req.body?.registros) ? req.body.registros : [];
+ const origen = req.body?.origen || null;
+ const sql = 'SELECT public.import_asistencia($1::jsonb,$2) AS data';
+ const { rows } = await pool.query(sql, [JSON.stringify(registros), origen]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e);
+ res.status(500).json({ error: 'import_asistencia failed' });
+ }
+});
+
+// Consultar datos de asistencia (raw + pares) para un usuario y rango
+router.route('/rpc/asistencia_get').post( async (req, res) => {
+ try {
+ const { doc, desde, hasta } = req.body || {};
+ const sql = 'SELECT public.asistencia_get($1::text,$2::date,$3::date) AS data';
+ const { rows } = await pool.query(sql, [doc, desde, hasta]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e); res.status(500).json({ error: 'asistencia_get failed' });
+ }
+});
+
+// Editar un registro crudo y recalcular pares
+router.route('/rpc/asistencia_update_raw').post( async (req, res) => {
+ try {
+ const { id_raw, fecha, hora, modo } = req.body || {};
+ const sql = 'SELECT public.asistencia_update_raw($1::bigint,$2::date,$3::text,$4::text) AS data';
+ const { rows } = await pool.query(sql, [id_raw, fecha, hora, modo ?? null]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e); res.status(500).json({ error: 'asistencia_update_raw failed' });
+ }
+});
+
+// Eliminar un registro crudo y recalcular pares
+router.route('/rpc/asistencia_delete_raw').post( async (req, res) => {
+ try {
+ const { id_raw } = req.body || {};
+ const sql = 'SELECT public.asistencia_delete_raw($1::bigint) AS data';
+ const { rows } = await pool.query(sql, [id_raw]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e); res.status(500).json({ error: 'asistencia_delete_raw failed' });
+ }
+});
+
+
+// ----------------------------------------------------------
+// API Reportes
+// ----------------------------------------------------------
+
+// POST /api/rpc/report_tickets { year }
+router.route('/rpc/report_tickets').post( async (req, res) => {
+ try {
+ const y = parseInt(req.body?.year ?? req.query?.year, 10);
+ const year = (Number.isFinite(y) && y >= 2000 && y <= 2100)
+ ? y
+ : (new Date()).getFullYear();
+
+ const { rows } = await pool.query(
+ 'SELECT public.report_tickets_year($1::int) AS j', [year]
+ );
+ res.json(rows[0].j);
+ } catch (e) {
+ console.error('report_tickets error:', e);
+ res.status(500).json({
+ error: 'report_tickets failed',
+ message: e.message, detail: e.detail, where: e.where, code: e.code
+ });
+ }
+});
+
+// POST /api/rpc/report_asistencia { desde: 'YYYY-MM-DD', hasta: 'YYYY-MM-DD' }
+router.route('/rpc/report_asistencia').post( async (req, res) => {
+ try {
+ let { desde, hasta } = req.body || {};
+ // defaults si vienen vacíos/invalidos
+ const re = /^\d{4}-\d{2}-\d{2}$/;
+ if (!re.test(desde) || !re.test(hasta)) {
+ const end = new Date();
+ const start = new Date(end); start.setDate(end.getDate()-30);
+ desde = start.toISOString().slice(0,10);
+ hasta = end.toISOString().slice(0,10);
+ }
+
+ const { rows } = await pool.query(
+ 'SELECT public.report_asistencia($1::date,$2::date) AS j', [desde, hasta]
+ );
+ res.json(rows[0].j);
+ } catch (e) {
+ console.error('report_asistencia error:', e);
+ res.status(500).json({
+ error: 'report_asistencia failed',
+ message: e.message, detail: e.detail, where: e.where, code: e.code
+ });
+ }
+});
+
+// ----------------------------------------------------------
+// API Compras y Gastos
+// ----------------------------------------------------------
+
+// Guardar (insert/update)
+router.route('/rpc/save_compra').post( async (req, res) => {
+ try {
+ const { id_compra, id_proveedor, fec_compra, detalles } = req.body || {};
+ const sql = 'SELECT * FROM public.save_compra($1::int,$2::int,$3::timestamptz,$4::jsonb)';
+ const args = [id_compra ?? null, id_proveedor, fec_compra ? new Date(fec_compra) : null, JSON.stringify(detalles)];
+ const { rows } = await pool.query(sql, args);
+ res.json(rows[0]); // { id_compra, total }
+ } catch (e) {
+ console.error('save_compra error:', e);
+ res.status(500).json({ error: 'save_compra failed', message: e.message, detail: e.detail, where: e.where, code: e.code });
+ }
+});
+
+
+// Obtener para editar
+router.route('/rpc/get_compra').post( async (req, res) => {
+ try {
+ const { id_compra } = req.body || {};
+ const sql = `SELECT public.get_compra($1::int) AS data`;
+ const { rows } = await pool.query(sql, [id_compra]);
+ res.json(rows[0]?.data || {});
+ } catch (e) {
+ console.error(e); res.status(500).json({ error: 'get_compra failed' });
+ }
+});
+
+// Eliminar
+router.route('/rpc/delete_compra').post( async (req, res) => {
+ try {
+ const { id_compra } = req.body || {};
+ await pool.query(`SELECT public.delete_compra($1::int)`, [id_compra]);
+ res.json({ ok: true });
+ } catch (e) {
+ console.error(e); res.status(500).json({ error: 'delete_compra failed' });
+ }
+});
+
+
+// POST /api/rpc/report_gastos { year: 2025 }
+router.route('/rpc/report_gastos').post( async (req, res) => {
+ try {
+ const year = parseInt(req.body?.year ?? new Date().getFullYear(), 10);
+ const { rows } = await pool.query(
+ 'SELECT public.report_gastos($1::int) AS j', [year]
+ );
+ res.json(rows[0].j);
+ } catch (e) {
+ console.error('report_gastos error:', e);
+ res.status(500).json({
+ error: 'report_gastos failed',
+ message: e.message, detail: e.detail, code: e.code
+ });
+ }
+});
+
+
+export default router;
\ No newline at end of file
diff --git a/services/auth/src/db/poolSingleton.js b/services/auth/src/db/poolSingleton.js
new file mode 100644
index 0000000..a0935c2
--- /dev/null
+++ b/services/auth/src/db/poolSingleton.js
@@ -0,0 +1,83 @@
+// Coneción Singleton a base de datos.
+
+import { Pool } from 'pg';
+
+class DatabaseCore {
+ constructor() {
+
+ if (DatabaseCore.instance) {
+ return Database.instance;
+ }
+
+ const config = {
+ host: process.env.DB_HOST,
+ user: process.env.DB_USER,
+ password: process.env.DB_PASS,
+ database: process.env.DB_NAME,
+ port: process.env.DB_LOCAL_PORT ? Number(process.env.DB_LOCAL_PORT) : undefined,
+ ssl: process.env.PGSSL === 'true' ? { rejectUnauthorized: false } : undefined,
+ };
+
+ this.connection = new Pool(config);
+
+ DatabaseCore.instance = this;
+ }
+ async query(sql, params) {
+ return this.connection.query(sql,params);
+ }
+
+ async connect() { /* Definida solo para evitar errores */
+ return this.connection.connect();
+ }
+ async getClient() {
+ return this.connection.connect();
+ }
+
+ async release() {
+ await this.connection.end();
+ }
+}
+class DatabaseTenants {
+ constructor() {
+
+ if (DatabaseTenants.instance) {
+ return Database.instance;
+ }
+
+ const config = {
+ host: process.env.DB_HOST,
+ user: process.env.DB_USER,
+ password: process.env.DB_PASS,
+ database: process.env.DB_NAME,
+ port: process.env.DB_LOCAL_PORT ? Number(process.env.DB_LOCAL_PORT) : undefined,
+ ssl: process.env.PGSSL === 'true' ? { rejectUnauthorized: false } : undefined,
+ };
+
+ this.connection = new Pool(config);
+
+ DatabaseTenants.instance = this;
+ }
+ async query(sql, params) {
+ return this.connection.query(sql,params);
+ }
+
+ async connect() { /* Definida solo para evitar errores */
+ return this.connection.connect();
+ }
+ async getClient() {
+ return this.connection.connect();
+ }
+
+ async release() {
+ await this.connection.end();
+ }
+}
+
+// const db = new Database();
+// db.query('SELECT * FROM users');
+
+const poolCore = new DatabaseCore();
+const poolTenants = new DatabaseTenants();
+export default {poolCore, poolTenants};
+export { poolCore, poolTenants };
+//export { DatabaseCore, DatabaseTenants };
\ No newline at end of file
diff --git a/services/auth/src/index.js b/services/auth/src/index.js
deleted file mode 100644
index d596bb8..0000000
--- a/services/auth/src/index.js
+++ /dev/null
@@ -1,374 +0,0 @@
-// services/auth/src/index.js
-// ------------------------------------------------------------
-// SuiteCoffee — Servicio de Autenticación (Express + OIDC)
-// - ESM compatible (Node >=18)
-// - Sesiones con Redis (compartibles con otros servicios)
-// - Vistas EJS (login)
-// - Registro de usuario: /auth/api/users/register (DB + Authentik)
-// ------------------------------------------------------------
-
-import 'dotenv/config';
-import path from 'node:path';
-import fs from 'node:fs/promises';
-import { fileURLToPath } from 'node:url';
-import { Pool } from 'pg';
-import express from 'express';
-
-import crypto from 'node:crypto';
-import fetch from "node-fetch";
-
-import { createRedisSession } from "../shared/middlewares/redisConnect.js";
-
-// -----------------------------------------------------------------------------
-// Variables globales
-// -----------------------------------------------------------------------------
-const PORT = process.env.PORT || 4040;
-const ISSUER = process.env.AUTHENTIK_ISSUER?.replace(/\/?$/, "/"); // asegura barra final
-const CLIENT_ID = process.env.OIDC_CLIENT_ID;
-const CLIENT_SECRET = process.env.OIDC_CLIENT_SECRET;
-const REDIRECT_URI = process.env.OIDC_REDIRECT_URI || process.env.AUTH_CALLBACK_URL;
-const APP_BASE_URL = process.env.APP_BASE_URL || "http://localhost:3030";
-
-// -----------------------------------------------------------------------------
-// Utilidades / Helpers
-// -----------------------------------------------------------------------------
-
-
-// -----------------------------------------------------------------------------
-// Utilidades
-// -----------------------------------------------------------------------------
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-
-function requiredEnv(keys) {
- const missing = keys.filter((k) => !process.env[k]);
- if (missing.length) {
- console.warn(`Falta configurar variables de entorno: ${missing.join(', ')}`);
- }
-}
-
-
-
-// -----------------------------------------------------------------------------
-// Configuración Express
-// -----------------------------------------------------------------------------
-const app = express();
-app.set('trust proxy', Number(process.env.TRUST_PROXY_HOPS || 2));
-app.disable("x-powered-by");
-app.use(express.json());
-app.use(express.urlencoded({ extended: true }));
-
-// Vistas EJS
-app.set('views', path.join(__dirname, 'views'));
-app.set('view engine', 'ejs');
-
-// Archivos estáticos opcionales (ajusta si tu estructura difiere)
-app.use(express.static(path.join(__dirname, 'public')));
-app.use('/pages', express.static(path.join(__dirname, 'pages')));
-
-
-// -----------------------------------------------------------------------------
-// Sesión (Redis)
-// -----------------------------------------------------------------------------
-// --- Sesión/Redis ---
-const { sessionMw, trustProxy } = await createRedisSession();
-if (trustProxy) app.set("trust proxy", 1);
-app.use(sessionMw);
-app.use(express.json());
-
-
-// --- Utiles OIDC ---
-function base64url(buf) {
-return Buffer.from(buf).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
-}
-
-
-function genPKCE() {
-const verifier = base64url(crypto.randomBytes(32));
-const challenge = base64url(crypto.createHash("sha256").update(verifier).digest());
-return { verifier, challenge };
-}
-
-
-function authorizeUrl({ state, challenge }) {
-const u = new URL(`${ISSUER}authorize/`);
-u.searchParams.set("client_id", CLIENT_ID);
-u.searchParams.set("redirect_uri", REDIRECT_URI);
-u.searchParams.set("response_type", "code");
-u.searchParams.set("scope", "openid email profile");
-u.searchParams.set("state", state);
-u.searchParams.set("code_challenge", challenge);
-u.searchParams.set("code_challenge_method", "S256");
-return u.toString();
-}
-
-
-async function exchangeCodeForTokens({ code, verifier }) {
-const tokenUrl = `${ISSUER}token/`;
-const body = new URLSearchParams({
-grant_type: "authorization_code",
-code,
-redirect_uri: REDIRECT_URI,
-client_id: CLIENT_ID,
-code_verifier: verifier,
-});
-// auth básica si el proveedor la requiere (Authentik soporta ambos modos)
-const basic = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64");
-const res = await fetch(tokenUrl, {
-method: "POST",
-headers: {
-"content-type": "application/x-www-form-urlencoded",
-"authorization": `Basic ${basic}`,
-},
-body,
-});
-if (!res.ok) throw new Error(`Token endpoint ${res.status}`);
-return res.json();
-}
-
-// ----------------------------------------------------------
-// Middleware para datos globales
-// ----------------------------------------------------------
-app.use((req, res, next) => {
- res.locals.currentPath = req.path;
- res.locals.pageTitle = "SuiteCoffee";
- res.locals.pageId = "";
- next();
-});
-
-
-// -----------------------------------------------------------------------------
-// PostgreSQL — DB tenants (usuarios de suitecoffee)
-// -----------------------------------------------------------------------------
-const tenantsPool = new Pool({
- host: process.env.TENANTS_HOST || 'dev-tenants',
- port: Number(process.env.TENANTS_PORT || 5432),
- user: process.env.TENANTS_USER || 'dev-user-postgres',
- password: process.env.TENANTS_PASS || 'dev-pass-postgres',
- database: process.env.TENANTS_DB || 'dev-postgres',
- max: 10,
-});
-
-// -----------------------------------------------------------------------------
-// PostgreSQL — DB principal (metadatos de negocio)
-// -----------------------------------------------------------------------------
-requiredEnv(['DB_HOST', 'DB_USER', 'DB_PASS', 'DB_NAME']);
-const mainPool = new Pool({
- host: process.env.DB_HOST || 'dev-db',
- port: Number(process.env.DB_PORT || 5432),
- user: process.env.DB_USER || 'dev-user-suitecoffee',
- password: process.env.DB_PASS || 'dev-pass-suitecoffee',
- database: process.env.DB_NAME || 'dev-suitecoffee',
- max: 10,
- idleTimeoutMillis: 30_000,
-});
-
-// ----------------------------------------------------------
-// Verificación de conexión
-// ----------------------------------------------------------
-
-async function verificarConexion() {
- try {
- console.log(`[AUTH] Comprobando accesibilidad a la db ${process.env.DB_NAME} del host ${process.env.DB_HOST} ...`);
- var client = await mainPool.connect();
- var { rows } = await client.query('SELECT NOW() AS ahora');
- console.log(`\n[AUTH] Conexión con ${process.env.DB_NAME} OK. Hora DB:`, rows[0].ahora);
- } catch (error) {
- console.error('[AUTH] Error al conectar con la base de datos al iniciar:', error.message);
- console.error('[AUTH] Revisar DB_HOST/USER/PASS/NAME, accesos de red y firewall.');
- } finally {
- client.release();
- }
-}
-
-
-// -----------------------------------------------------------------------------
-// Vistas
-// -----------------------------------------------------------------------------
-
-
-// =============================================
-// Registro de usuario (DB principal)
-// =============================================
-
-requiredEnv(['TENANT_INIT_SQL']);
-async function loadInitSqlFromEnv() {
- const v = process.env.TENANT_INIT_SQL?.trim();
- if (!v) return '';
- try {
- // ¿Es una ruta existente?
- const p = path.isAbsolute(v) ? v : path.resolve(__dirname, v);
- const txt = await fs.readFile(p, 'utf8');
- console.log(`[TENANT INIT] Cargado desde archivo: ${p} (${txt.length} bytes)`);
- return String(txt || '');
- } catch {
- // Tratar como literal
- console.log(`[TENANT INIT] Usando SQL literal desde TENANT_INIT_SQL (${v.length} chars).`);
- return v;
- }
-}
-
-// Reemplaza placeholders simples en la plantilla de SQL (opcional)
-function renderInitSqlTemplate(sql, { schema, owner }) {
- return sql
- .replaceAll(':TENANT_SCHEMA', `"${schema}"`)
- .replaceAll(':OWNER', `"${owner}"`);
-}
-// Genera ids sencillos
-function newTenantIds() {
- return {
- tenant_uuid: crypto.randomUUID(),
- tenant_role: null, // lo decidirás luego (owner, barman, staff)
- };
-}
-
-async function createTenantUserAndSchema(tenClient, { tenant_uuid, password }) {
- const roleName = `tenant_${tenant_uuid.replace(/-/g, '')}`;
- const schemaName = `t_${tenant_uuid.replace(/-/g, '')}`;
- const escapedPassword = `'${String(password).replace(/'/g, "''")}'`;
-
- // 1) crear role y schema (misma conexión que ya viene en BEGIN desde la ruta)
- await tenClient.query(`CREATE ROLE "${roleName}" LOGIN PASSWORD ${escapedPassword}`);
- await tenClient.query(`CREATE SCHEMA "${schemaName}" AUTHORIZATION "${roleName}"`);
- await tenClient.query(`GRANT USAGE ON SCHEMA "${schemaName}" TO "${roleName}"`);
- await tenClient.query(`ALTER ROLE "${roleName}" INHERIT`);
- // (idempotente)
- await tenClient.query(`CREATE SCHEMA IF NOT EXISTS "${schemaName}"`);
-
- // 2) cargar y sanear la plantilla
- let sql = await loadInitSqlFromEnv();
- if (!sql?.trim()) {
- console.log('[TENANT INIT] No hay SQL de plantilla; se omite.');
- return { roleName, schemaName };
- }
-
- // 👉 quita metacomandos psql '\' (por si alguno quedó) y cualquier cambio de search_path dentro del dump
- sql = sql
- .split(/\r?\n/)
- .filter(line => !line.trim().startsWith('\\')) // \restrict, \unrestrict, \i, etc.
- .filter(line => !/^SET\s+search_path\b/i.test(line)) // SET search_path = ...
- .filter(line => !/set_config\(\s*'search_path'/i.test(line)) // SELECT set_config('search_path',...
- .join('\n');
-
- // si usás placeholders, renderealos acá (opcional)
- // sql = renderInitSqlTemplate(sql, { schema: schemaName, owner: roleName });
-
- // 3) forzá el search_path SOLO dentro de esta transacción
- await tenClient.query(`SET LOCAL search_path TO "${schemaName}", public`);
-
- // 4) ejecutar el dump (una sola vez, no lo partas por ';' para no romper $$...$$)
- await tenClient.query(sql);
-
- console.log(`[TENANT INIT] OK usuario="${roleName}" schema="${schemaName}"`);
- return { roleName, schemaName };
-}
-
-//=============================================
-// ---------- Authentik (API & OIDC) ----------
-//=============================================
-
-
-// ===========================
-// GET /auth/users/register
-// ===========================
-
-// ===========================
-// POST /auth/login
-// ===========================
-app.get("/auth/login", (req, res) => {
-const { verifier, challenge } = genPKCE();
-const state = base64url(crypto.randomBytes(24));
-req.session.pkce_verifier = verifier;
-req.session.oidc_state = state;
-const url = authorizeUrl({ state, challenge });
-res.redirect(302, url);
-});
-// ===========================
-// GET /auth/callback
-// ===========================
-app.get("/auth/callback", async (req, res) => {
-try {
-const { code, state } = req.query;
-if (!code || !state) return res.status(400).send("Faltan parámetros");
-if (state !== req.session.oidc_state) return res.status(400).send("State inválido");
-
-
-const verifier = req.session.pkce_verifier;
-if (!verifier) return res.status(400).send("PKCE verifier faltante");
-
-
-const tokens = await exchangeCodeForTokens({ code, verifier });
-// Guarda en sesión (ID Token, Access Token, Refresh Token si viene)
-req.session.tokens = {
-id_token: tokens.id_token,
-access_token: tokens.access_token,
-refresh_token: tokens.refresh_token,
-token_type: tokens.token_type,
-expires_in: tokens.expires_in,
-received_at: Date.now(),
-};
-// Limpia PKCE/state
-delete req.session.pkce_verifier;
-delete req.session.oidc_state;
-
-
-// Redirige al home de App
-res.redirect(303, `${APP_BASE_URL}/`);
-} catch (e) {
-console.error("/auth/callback error", e);
-res.status(500).send("Error en callback");
-}
-});
-
-
-// ===========================
-// POST /auth/logout
-// ===========================
-app.get("/auth/logout", (req, res) => {
-req.session.destroy(() => {
-res.clearCookie(process.env.SESSION_COOKIE_NAME || "sc.sid");
-res.redirect(303, APP_BASE_URL || "/");
-});
-});
-
-
-// =============================================
-// Healthcheck
-// =============================================
-app.get('/health', (_req, res) => res.status(200).json({ status: 'ok'}));
-
-// =============================================
-// 404 + Manejo de errores
-// =============================================
-app.use((req, res) => res.status(404).json({ error: 'Error 404, No se encontró la página', path: req.originalUrl }));
-
-app.use((err, _req, res, _next) => {
- console.error('[AUTH] ', err);
- if (res.headersSent) return;
- res.status(500).json({ error: '¡Oh! A ocurrido un error en el servidor auth.', detail: err.stack || String(err) });
-});
-
-/*
------------------------------------------------------------------------------
-Exportación principal del módulo.
-Es típico exportar la instancia (app) y arrancarla en otro archivo.
-- Facilita tests (p.ej. con supertest: import app from './app.js')
-- Evita que el servidor se inicie al importar el módulo.
-
-# Default
- export default app; // importar: import app from './app.js'
-
-# Con nombre
- export const app = express(); // importar: import { app } from './app.js'
------------------------------------------------------------------------------
-*/
-export default app;
-
-// -----------------------------------------------------------------------------
-// Arranque
-// -----------------------------------------------------------------------------
-app.listen(PORT, () => {
- console.log(`[AUTH] Servicio de autenticación escuchando en http://localhost:${PORT}`);
- verificarConexion();
- // OIDCdiscover();
-});
\ No newline at end of file
diff --git a/services/auth/src/index.mjs b/services/auth/src/index.mjs
new file mode 100644
index 0000000..3f3442d
--- /dev/null
+++ b/services/auth/src/index.mjs
@@ -0,0 +1,240 @@
+// services/auth/src/index.js
+// ------------------------------------------------------------
+// SuiteCoffee — Servicio de Autenticación (Express + OIDC)
+// ------------------------------------------------------------
+
+import 'dotenv/config';
+import express from 'express'; // Framework para enderizado de apps Web
+import expressLayouts from 'express-ejs-layouts';
+// import { poolCore, poolTenants } from '@suitecoffee/db'; // dbCore y dbTenants desde módulo
+import { poolCore, poolTenants } from '#db'; // dbCore y dbTenants
+import v1Router from '#v1Router'; // Rutas API v1
+import expressPages from '#pages'; // Rutas "/", "/dashboard", ...
+
+import path from 'path';
+import { fileURLToPath } from 'url'; // Converts a file:// URL string or URL object into a platform-specific file
+import cookieParser from 'cookie-parser';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+import fs from 'node:fs/promises';
+import crypto from 'node:crypto';
+import fetch from "node-fetch";
+
+
+// -----------------------------------------------------------------------------
+// Validación de entorno mínimo (ajusta nombres si difieren)
+// -----------------------------------------------------------------------------
+// Función para verificar que ciertas variables de entorno estén definida
+function checkRequiredEnvVars(...requiredKeys) {
+ const missingKeys = requiredKeys.filter((key) => !process.env[key]); // Filtramos las que NO existen en process.env
+ if (missingKeys.length > 0) { // Si falta alguna, mostramos una advertencia
+ console.warn(
+ `[APP] No se encontraron las siguientes variables de entorno: \n\n-> ${missingKeys.join('\n-> ')}`+
+ `\n`
+ );
+ }
+}
+
+checkRequiredEnvVars(
+ 'PORT', 'APP_BASE_URL',
+ 'CORE_DB_HOST', 'CORE_DB_PORT', 'CORE_DB_NAME',
+ 'TENANTS_DB_HOST', 'TENANTS_DB_PORT', 'TENANTS_DB_NAME',
+
+ 'OIDC_LOGIN_URL', 'OIDC_REDIRECT_URI',
+ 'OIDC_CLIEN_ID', 'OIDC_CONFIG_URL', 'OIDC_ISSUER',
+ 'OIDC_ISSUER_DISCOVERY', 'OIDC_AUTHORIZE_URL', 'OIDC_TOKEN_URL',
+ 'OIDC_USERINFO_URL', 'OIDC_LOGOUT_URL', 'OIDC_JWKS_URL',
+
+ 'SESSION_SECRET', 'SESSION_COOKIE_NAME',
+ 'AK_REDIS_URL', 'AK_TOKEN'
+);
+
+
+
+
+
+// ----------------------------------------------------------
+// Variables del sistema
+// ----------------------------------------------------------
+
+// De entorno
+const PORT = process.env.PORT;
+const APP_BASE_URL = process.env.APP_BASE_URL;
+
+const CORE_DB_HOST = process.env.CORE_DB_HOST;
+const CORE_DB_PORT = process.env.CORE_DB_PORT;
+const CORE_DB_NAME = process.env.CORE_DB_NAME;
+
+const TENANTS_DB_HOST = process.env.TENANTS_DB_HOST;
+const TENANTS_DB_PORT = process.env.TENANTS_DB_PORT;
+const TENANTS_DB_NAME = process.env.TENANTS_DB_NAME;
+
+const OIDC_LOGIN_URL = process.env.OIDC_LOGIN_URL;
+const OIDC_REDIRECT_URI = process.env.OIDC_REDIRECT_URI;
+
+const OIDC_CLIEN_ID = process.env.OIDC_CLIEN_ID;
+const OIDC_CONFIG_URL = process.env.OIDC_CONFIG_URL;
+const OIDC_ISSUER = process.env.OIDC_ISSUER;
+const OIDC_ISSUER_DISCOVERY = process.env.OIDC_ISSUER_DISCOVERY;
+const OIDC_AUTHORIZE_URL = process.env.OIDC_AUTHORIZE_URL;
+const OIDC_TOKEN_URL = process.env.OIDC_TOKEN_URL;
+const OIDC_USERINFO_URL = process.env.OIDC_USERINFO_URL;
+const OIDC_LOGOUT_URL = process.env.OIDC_LOGOUT_URL;
+const OIDC_JWKS_URL = process.env.OIDC_JWKS_URL;
+
+const AK_SESSION_SECRET = process.env.AK_SESSION_SECRET;
+const AK_SESSION_COOKIE_NAME = process.env.AK_SESSION_COOKIE_NAME;
+const AK_REDIS_URL = process.env.AK_REDIS_URL;
+
+
+
+// -----------------------------------------------------------------------------
+// Utilidades / Helpers
+// -----------------------------------------------------------------------------
+
+
+
+
+
+// -----------------------------------------------------------------------------
+// Configuración Express
+// -----------------------------------------------------------------------------
+
+const app = express();
+app.set('trust proxy', true);
+app.set("views", path.join(__dirname, "views"));
+app.set("view engine", "ejs");
+app.set("layout", "layouts/main");
+app.disable("x-powered-by");
+
+app.use(express.json());
+app.use(express.json({ limit: '1mb' }));
+app.use(express.urlencoded({ extended: true }));
+// Archivos estáticos que fuerzan la re-descarga de arhivos
+app.use(express.static(path.join(__dirname, "public"), {
+ etag: false, maxAge: 0,
+ setHeaders: (res, path) => {
+ res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
+ }
+}));
+app.use(cookieParser(process.env.SESSION_SECRET));
+app.use(expressPages); // Renderizado trae las paginas desde ./services/manso/src/routes/routes.js
+
+
+
+
+
+
+
+// ----------------------------------------------------------
+// Middleware para datos globales
+// ----------------------------------------------------------
+app.use((req, res, next) => {
+ res.locals.currentPath = req.path;
+ res.locals.pageTitle = "SuiteCoffee";
+ res.locals.pageId = "";
+ next();
+});
+
+
+
+// ----------------------------------------------------------
+// Verificación de conexión
+// ----------------------------------------------------------
+
+async function verificarConexionCore() {
+ try {
+ console.log(`[APP] Comprobando accesibilidad a la db ${CORE_DB_NAME} del host ${CORE_DB_HOST} ...`);
+ const client = await poolCore.connect();
+ const { rows } = await client.query('SELECT NOW() AS ahora');
+ console.log(`\n[APP] Conexión con ${CORE_DB_NAME} OK. Hora DB:`, rows[0].ahora);
+ client.release();
+ } catch (error) {
+ console.error('[APP] Error al conectar con la base de datos al iniciar:', error.message);
+ console.error('[APP] Revisar credenciales, accesos de red y firewall.');
+ }
+}
+async function verificarConexionTenants() {
+ try {
+ console.log(`[APP] Comprobando accesibilidad a la db ${TENANTS_DB_NAME} del host ${TENANTS_DB_HOST} ...`);
+ const client = await poolTenants.connect();
+ const { rows } = await client.query('SELECT NOW() AS ahora');
+ console.log(`\n[APP] Conexión con ${TENANTS_DB_NAME} OK. Hora DB:`, rows[0].ahora);
+ client.release();
+ } catch (error) {
+ console.error('[APP] Error al conectar con la base de datos al iniciar:', error.message);
+ console.error('[APP] Revisar credenciales, accesos de red y firewall.');
+ }
+}
+
+
+
+// =============================================
+// Registro de usuario (DB principal)
+// =============================================
+
+
+
+
+//=============================================
+// ---------- Authentik (API & OIDC) ----------
+//=============================================
+
+
+// ===========================
+// GET /auth/users/register
+// ===========================
+
+// ===========================
+// POST /auth/login
+// ===========================
+
+app.get("/auth/login", (req, res) => {
+ const { verifier, challenge } = genPKCE();
+ const state = base64url(crypto.randomBytes(24));
+ req.session.pkce_verifier = verifier;
+ req.session.oidc_state = state;
+ const url = authorizeUrl({ state, challenge });
+ res.redirect(302, url);
+});
+
+
+// ===========================
+// GET /auth/callback
+// ===========================
+
+
+// -----------------------------------------------------------------------------
+// Healthcheck
+// -----------------------------------------------------------------------------
+app.get('/health', (_req, res) => {
+ res.status(200).json({ status: 'ok'}),
+ console.log(`[AUTH] Saludable`)
+});
+
+
+
+// =============================================
+// 404 + Manejo de errores
+// =============================================
+app.use((req, res) => res.status(404).json({ error: 'Error 404, No se encontró la página', path: req.originalUrl }));
+
+app.use((err, _req, res, _next) => {
+ console.error('[AUTH] ', err);
+ if (res.headersSent) return;
+ res.status(500).json({ error: '¡Oh! A ocurrido un error en el servidor auth.', detail: err.stack || String(err) });
+});
+
+
+
+
+// -----------------------------------------------------------------------------
+// Arranque
+// -----------------------------------------------------------------------------
+app.listen(PORT, () => {
+ console.log(`[AUTH] Servicio de autenticación escuchando en http://localhost:${PORT}`);
+ verificarConexionCore();
+ verificarConexionTenants();
+});
\ No newline at end of file
diff --git a/services/auth/src/pages/index.html b/services/auth/src/pages/index.html.bak
similarity index 100%
rename from services/auth/src/pages/index.html
rename to services/auth/src/pages/index.html.bak
diff --git a/services/auth/src/pages/pages.js b/services/auth/src/pages/pages.js
new file mode 100644
index 0000000..bbf228c
--- /dev/null
+++ b/services/auth/src/pages/pages.js
@@ -0,0 +1,20 @@
+// services/manso/src/api/v1/routes/routes.js
+
+import { Router } from 'express';
+
+const router = Router();
+
+// ----------------------------------------------------------
+// Rutas de UI
+// ----------------------------------------------------------
+
+/*router.get('/', (req, res) => {
+ res.locals.pageTitle = "Inicio"; // Título de pestaña
+ res.locals.pageId = "home"; // Sidebar contextual
+ res.render("dashboard"); // Archivo .ejs a renderizar
+ // res.json({ ok: true, route: '/inicio' }); // Debug json
+});*/
+
+
+
+export default router;
\ No newline at end of file
diff --git a/services/manso/.env.development b/services/manso/.env.development
index 653f03e..93453b3 100644
--- a/services/manso/.env.development
+++ b/services/manso/.env.development
@@ -1,6 +1,6 @@
NODE_ENV=development
-PORT=3030
+PORT=1010
DB_HOST=dev-tenants
DB_NAME=manso
diff --git a/services/manso/package-lock.json b/services/manso/package-lock.json
index 62c66bd..3b7c347 100644
--- a/services/manso/package-lock.json
+++ b/services/manso/package-lock.json
@@ -10,6 +10,7 @@
"license": "ISC",
"dependencies": {
"chalk": "^5.6.0",
+ "cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"dotenv": "^17.2.1",
"ejs": "^3.1.10",
@@ -239,6 +240,25 @@
"node": ">= 0.6"
}
},
+ "node_modules/cookie-parser": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
+ "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "0.7.2",
+ "cookie-signature": "1.0.6"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/cookie-parser/node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
+ "license": "MIT"
+ },
"node_modules/cookie-signature": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
diff --git a/services/manso/package.json b/services/manso/package.json
index aac4b30..94aa1c1 100644
--- a/services/manso/package.json
+++ b/services/manso/package.json
@@ -16,6 +16,7 @@
},
"dependencies": {
"chalk": "^5.6.0",
+ "cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"dotenv": "^17.2.1",
"ejs": "^3.1.10",
diff --git a/services/manso/src/index.mjs b/services/manso/src/index.mjs
index 4df8237..b264a5c 100644
--- a/services/manso/src/index.mjs
+++ b/services/manso/src/index.mjs
@@ -1,8 +1,10 @@
// ./services/manso/src/index.mjs
+// ------------------------------------------------------------
+// MVP Manso de SuiteCoffee — Aplicación MVP
+// ------------------------------------------------------------
-import 'dotenv/config';// Variables de Entorno
-
-import favicon from 'serve-favicon'; // Favicon
+import 'dotenv/config'; // Variables de Entorno
+import favicon from 'serve-favicon'; // Favicon
import express from 'express';
import expressLayouts from 'express-ejs-layouts';
@@ -13,10 +15,34 @@ import expressPages from '#pages'; // Rutas "/", "/dashboard", ...
import path from 'path';
import { fileURLToPath } from 'url';
+import cookieParser from 'cookie-parser';
+
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
+// -----------------------------------------------------------------------------
+// Validación de entorno mínimo (ajusta nombres si difieren)
+// -----------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
// ----------------------------------------------------------
// Variables del sistema
@@ -39,9 +65,13 @@ app.set("layout", "layouts/main");
app.use(express.json());
app.use(express.json({ limit: '1mb' }));
-app.use(express.static(path.join(__dirname, 'public'))); // Carga de archivos estaticos
-app.use(expressLayouts); // Carga los layouts que usara el renderizado
+app.use(express.urlencoded({ extended: true }));
app.use(favicon(path.join(__dirname, 'public', 'favicon', 'favicon.ico'), {maxAge: '1y'}));
+app.use(express.static(path.join(__dirname, 'public'))); // Carga de archivos estaticos
+
+
+app.use(expressLayouts); // Carga los layouts que usara el renderizado
+app.use(cookieParser(process.env.SESSION_SECRET));
app.use(expressPages); // Renderizado trae las paginas desde ./services/manso/src/routes/routes.js
@@ -291,31 +321,77 @@ app.post('/api/table/:table', async (req, res) => {
// ----------------------------------------------------------
// Verificación de conexión
// ----------------------------------------------------------
+
async function verificarConexion() {
+ try {
+ console.log(`[Manso] Comprobando accesibilidad a la db ${process.env.DB_NAME} ...`);
+ const client = await pool.connect();
+ const { rows } = await client.query('SELECT NOW() AS ahora');
+ console.log(`\n[Manso] Conexión con ${process.env.DB_NAME} OK. Hora DB:`, rows[0].ahora);
+ client.release();
+ } catch (error) {
+ console.error('[Manso] Error al conectar con la base de datos al iniciar:', error.message);
+ console.error('[Manso] Revisar credenciales, accesos de red y firewall.');
+ }
+}
+/*async function verificarConexion() {
try {
var client = await pool.getClient();
let res = await client.query('SELECT NOW() AS hora');
- console.log(`\nConexión con la base de datos ${process.env.DB_NAME} fue exitosa.`);
- console.log('Fecha y hora actual de la base de datos:\n ->', res.rows[0].hora);
+ console.log(`\n[Manso] Conexión con la base de datos ${process.env.DB_NAME} fue exitosa.`);
+ console.log('[Manso] Fecha y hora actual de la base de datos:\n ->', res.rows[0].hora);
} catch (error) {
- console.error('Error al conectar con la base de datos al iniciar: \n ->', error.message);
- console.error('Revisar credenciales y accesos de red.');
+ console.error('[Manso] Error al conectar con la base de datos al iniciar: \n ->', error.message);
+ console.error('[Manso] Revisar credenciales y accesos de red.');
} finally{
client.release();
}
-}
+}*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// -----------------------------------------------------------------------------
+// 404 + Manejo de errores
+// -----------------------------------------------------------------------------
+
+app.use((req, res) => res.status(404).json({ error: 'Error 404, No se encontró la página', path: req.originalUrl }));
+
+app.use((err, _req, res, _next) => {
+ console.error('[APP] ', err);
+ if (res.headersSent) return;
+ res.status(500).json({ error: '¡Oh! A ocurrido un error en el servidor app.', detail: err.stack || String(err) });
+});
+
// ----------------------------------------------------------
// Inicio del servidor
// ----------------------------------------------------------
app.listen(PORT, () => {
- console.log(`Servidor de aplicación escuchando en ${`http://localhost:${PORT}`}`);
- console.log(`Comprobando accesibilidad a la db ${process.env.DB_NAME} del host ${process.env.DB_HOST} ...`);
+ console.log(`[Manso] Servidor de aplicación escuchando en ${`http://localhost:${PORT}`}`);
+ console.log(`[Manso] Comprobando accesibilidad a la db ${process.env.DB_NAME} del host ${process.env.DB_HOST} ...`);
verificarConexion();
});
+// -----------------------------------------------------------------------------
// Healthcheck
-app.get('/health', (_req, res) => res.status(200).json({ status: 'ok'}));
+// -----------------------------------------------------------------------------
+app.get('/health', (_req, res) => {
+ res.status(200).json({ status: 'ok'}),
+ console.log(`[Manso] Saludable`)
+});
\ No newline at end of file
diff --git a/services/manso/src/views/reportes.ejs b/services/manso/src/views/reportes.ejs
index 96640e8..c936d42 100644
--- a/services/manso/src/views/reportes.ejs
+++ b/services/manso/src/views/reportes.ejs
@@ -469,7 +469,7 @@ async function loadAsist(){
const key = `${r.documento}::${r.nombre||''}::${r.apellido||''}`;
if (!byKey.has(key)) byKey.set(key, { doc:r.documento, nombre:r.nombre||'', apellido:r.apellido||'', rows:[] });
byKey.get(key).rows.push({
- fecha: fStr,
+ fecha: fStr,
horas: Number(r.horas_dia ?? r.horas ?? (r.minutos_dia||0)/60),
pares: Number(r.pares_dia ?? r.pares ?? 0)
});
diff --git a/services/plugins/.env.development b/services/plugins/.env.development
new file mode 100644
index 0000000..0b8c0aa
--- /dev/null
+++ b/services/plugins/.env.development
@@ -0,0 +1,62 @@
+# ===== Runtime =====
+NODE_ENV=development
+PORT=5050
+
+
+# ===== Session (usa el Redis del stack) =====
+# Para DEV podemos reutilizar el Redis de Authentik. En prod conviene uno separado.
+SESSION_SECRET=Neon*Mammal*Boaster*Ludicrous*Fender8*Crablike
+SESSION_COOKIE_NAME=sc.sid
+
+# ===== DB principal (metadatos de SuiteCoffee) =====
+# Usa el alias de red del servicio 'db' (compose: aliases [dev-db])
+DB_HOST=dev-db
+DB_NAME=dev_suitecoffee_core
+DB_PORT=5432
+DB_USER=dev-user-suitecoffee
+DB_PASS=dev-pass-suitecoffee
+
+CORE_DB_HOST=dev-db
+CORE_DB_NAME=dev_suitecoffee_core
+CORE_DB_PORT=5432
+CORE_DB_USER=dev-user-suitecoffee
+CORE_DB_PASS=dev-pass-suitecoffee
+
+# ===== DB tenants (Tenants de SuiteCoffee) =====
+TENANTS_HOST=dev-tenants
+TENANTS_DB=dev_suitecoffee_tenants
+TENANTS_PORT=5432
+TENANTS_USER=suitecoffee
+TENANTS_PASS=suitecoffee
+
+TENANTS_DB_HOST=dev-tenants
+TENANTS_DB_NAME=dev_suitecoffee_tenants
+TENANTS_DB_PORT=5432
+TENANTS_DB_USER=suitecoffee
+TENANTS_DB_PASS=suitecoffee
+
+
+# ===== Authentik — Admin API (server-to-server dentro de la red) =====
+# Usa el alias de red del servicio 'authentik' y su puerto interno 9000
+AK_TOKEN=h2apVHbd3ApMcnnSwfQPXbvximkvP8HnUE25ot3zXWuEEtJFaNCcOzDHB6Xw
+AK_REDIS_URL=redis://ak-redis:6379
+
+# ===== OIDC (DEBE coincidir con el Provider) =====
+# DEV (todo dentro de la red de Docker):
+# - El auth service redirige al navegador a este issuer. Si NO tenés reverse proxy hacia Authentik,
+# esta URL interna NO será accesible desde el navegador del host. En ese caso, ver nota más abajo.
+
+APP_BASE_URL=https://suitecoffee.uy
+
+OIDC_LOGIN_URL=https://sso.suitecoffee.uy
+OIDC_REDIRECT_URI = https://suitecoffee.uy/auth/callback
+
+OIDC_CLIEN_ID=1orMM8vOvf3WkN2FejXYvUFpPtONG0Lx1eMlwIpW
+OIDC_CONFIG_URL=https://sso.suitecoffee.uy/application/o/suitecoffee/.well-known/openid-configuration
+OIDC_ISSUER=https://sso.suitecoffee.uy/application/o/suitecoffee/
+OIDC_ISSUER_DISCOVERY=https://sso.suitecoffee.uy/application/o/suitecoffee/.well-known/openid-configuration
+OIDC_AUTHORIZE_URL=https://sso.suitecoffee.uy/application/o/authorize/
+OIDC_TOKEN_URL=https://sso.suitecoffee.uy/application/o/token/
+OIDC_USERINFO_URL=https://sso.suitecoffee.uy/application/o/userinfo/
+OIDC_LOGOUT_URL=https://sso.suitecoffee.uy/application/o/suitecoffee/end-session/
+OIDC_JWKS_URL=https://sso.suitecoffee.uy/application/o/suitecoffee/jwks/
\ No newline at end of file
diff --git a/services/plugins/.env.production b/services/plugins/.env.production
new file mode 100644
index 0000000..e69de29
diff --git a/services/plugins/package-lock.json b/services/plugins/package-lock.json
new file mode 100644
index 0000000..8051c8f
--- /dev/null
+++ b/services/plugins/package-lock.json
@@ -0,0 +1,2381 @@
+{
+ "name": "plugins",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "plugins",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "bcrypt": "^6.0.0",
+ "chalk": "^5.6.0",
+ "connect-redis": "^9.0.0",
+ "cookie-parser": "^1.4.7",
+ "cors": "^2.8.5",
+ "dotenv": "^17.2.1",
+ "ejs": "^3.1.10",
+ "express": "^5.1.0",
+ "express-ejs-layouts": "^2.5.1",
+ "express-session": "^1.18.2",
+ "ioredis": "^5.7.0",
+ "jose": "^6.1.0",
+ "jsonwebtoken": "^9.0.2",
+ "jwks-rsa": "^3.2.0",
+ "morgan": "^1.10.1",
+ "node-appwrite": "^20.2.1",
+ "node-fetch": "^3.3.2",
+ "pg": "^8.16.3",
+ "pg-format": "^1.0.4",
+ "redis": "^5.8.2",
+ "serve-favicon": "^2.5.1"
+ },
+ "devDependencies": {
+ "cross-env": "^10.0.0",
+ "nodemon": "^3.1.10"
+ }
+ },
+ "node_modules/@epic-web/invariant": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
+ "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@ioredis/commands": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.4.0.tgz",
+ "integrity": "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==",
+ "license": "MIT"
+ },
+ "node_modules/@redis/bloom": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.8.3.tgz",
+ "integrity": "sha512-1eldTzHvdW3Oi0TReb8m1yiFt8ZwyF6rv1NpZyG5R4TpCwuAdKQetBKoCw7D96tNFgsVVd6eL+NaGZZCqhRg4g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "@redis/client": "^5.8.3"
+ }
+ },
+ "node_modules/@redis/client": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.8.3.tgz",
+ "integrity": "sha512-MZVUE+l7LmMIYlIjubPosruJ9ltSLGFmJqsXApTqPLyHLjsJUSAbAJb/A3N34fEqean4ddiDkdWzNu4ZKPvRUg==",
+ "license": "MIT",
+ "dependencies": {
+ "cluster-key-slot": "1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/@redis/json": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.8.3.tgz",
+ "integrity": "sha512-DRR09fy/u8gynHGJ4gzXYeM7D8nlS6EMv5o+h20ndTJiAc7RGR01fdk2FNjnn1Nz5PjgGGownF+s72bYG4nZKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "@redis/client": "^5.8.3"
+ }
+ },
+ "node_modules/@redis/search": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.8.3.tgz",
+ "integrity": "sha512-EMIvEeGRR2I0BJEz4PV88DyCuPmMT1rDtznlsHY3cKSDcc9vj0Q411jUnX0iU2vVowUgWn/cpySKjpXdZ8m+5g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "@redis/client": "^5.8.3"
+ }
+ },
+ "node_modules/@redis/time-series": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.8.3.tgz",
+ "integrity": "sha512-5Jwy3ilsUYQjzpE7WZ1lEeG1RkqQ5kHtwV1p8yxXHSEmyUbC/T/AVgyjMcm52Olj/Ov/mhDKjx6ndYUi14bXsw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "@redis/client": "^5.8.3"
+ }
+ },
+ "node_modules/@types/body-parser": {
+ "version": "1.19.6",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
+ "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.38",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/express": {
+ "version": "4.17.23",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz",
+ "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^4.17.33",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "4.19.7",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz",
+ "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
+ "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/jsonwebtoken": {
+ "version": "9.0.10",
+ "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
+ "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/ms": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/mime": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
+ "license": "MIT"
+ },
+ "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/node": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.1.tgz",
+ "integrity": "sha512-CmyhGZanP88uuC5GpWU9q+fI61j2SkhO3UGMUdfYRE6Bcy0ccyzn1Rqj9YAB/ZY4kOXmNf0ocah5GtphmLMP6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.14.0"
+ }
+ },
+ "node_modules/@types/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.15.9",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.9.tgz",
+ "integrity": "sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/node": "*",
+ "@types/send": "<1"
+ }
+ },
+ "node_modules/@types/serve-static/node_modules/@types/send": {
+ "version": "0.17.5",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz",
+ "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "license": "MIT"
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "license": "MIT"
+ },
+ "node_modules/basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/basic-auth/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "license": "MIT"
+ },
+ "node_modules/bcrypt": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
+ "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "node-addon-api": "^8.3.0",
+ "node-gyp-build": "^4.8.4"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
+ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.0",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.6.3",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.0",
+ "raw-body": "^3.0.0",
+ "type-is": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+ "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/cluster-key-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
+ "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/connect-redis": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-9.0.0.tgz",
+ "integrity": "sha512-QwzyvUePTMvEzG1hy45gZYw3X3YHrjmEdSkayURlcZft7hqadQ3X39wYkmCqblK2rGlw+XItELYt6GnyG6DEIQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "express-session": ">=1",
+ "redis": ">=5"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
+ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-parser": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
+ "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "0.7.2",
+ "cookie-signature": "1.0.6"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
+ "license": "MIT"
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/cross-env": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz",
+ "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@epic-web/invariant": "^1.0.0",
+ "cross-spawn": "^7.0.6"
+ },
+ "bin": {
+ "cross-env": "dist/bin/cross-env.js",
+ "cross-env-shell": "dist/bin/cross-env-shell.js"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/data-uri-to-buffer": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/denque": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+ "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "17.2.3",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
+ "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/ejs": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
+ "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "jake": "^10.8.5"
+ },
+ "bin": {
+ "ejs": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
+ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.0",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/express-ejs-layouts": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/express-ejs-layouts/-/express-ejs-layouts-2.5.1.tgz",
+ "integrity": "sha512-IXROv9n3xKga7FowT06n1Qn927JR8ZWDn5Dc9CJQoiiaaDqbhW5PDmWShzbpAa2wjWT1vJqaIM1S6vJwwX11gA=="
+ },
+ "node_modules/express-session": {
+ "version": "1.18.2",
+ "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz",
+ "integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "0.7.2",
+ "cookie-signature": "1.0.7",
+ "debug": "2.6.9",
+ "depd": "~2.0.0",
+ "on-headers": "~1.1.0",
+ "parseurl": "~1.3.3",
+ "safe-buffer": "5.2.1",
+ "uid-safe": "~2.1.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/express-session/node_modules/cookie-signature": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
+ "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
+ "license": "MIT"
+ },
+ "node_modules/express-session/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/express-session/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/express/node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
+ "node_modules/fetch-blob": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "node-domexception": "^1.0.0",
+ "web-streams-polyfill": "^3.0.3"
+ },
+ "engines": {
+ "node": "^12.20 || >= 14.13"
+ }
+ },
+ "node_modules/filelist": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
+ "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "minimatch": "^5.0.1"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
+ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/formdata-polyfill": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+ "license": "MIT",
+ "dependencies": {
+ "fetch-blob": "^3.1.2"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/http-errors/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ioredis": {
+ "version": "5.8.1",
+ "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.8.1.tgz",
+ "integrity": "sha512-Qho8TgIamqEPdgiMadJwzRMW3TudIg6vpg4YONokGDudy4eqRIJtDbVX72pfLBcWxvbn3qm/40TyGUObdW4tLQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@ioredis/commands": "1.4.0",
+ "cluster-key-slot": "^1.1.0",
+ "debug": "^4.3.4",
+ "denque": "^2.1.0",
+ "lodash.defaults": "^4.2.0",
+ "lodash.isarguments": "^3.1.0",
+ "redis-errors": "^1.2.0",
+ "redis-parser": "^3.0.0",
+ "standard-as-callback": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=12.22.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ioredis"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+ "license": "MIT"
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/jake": {
+ "version": "10.9.4",
+ "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz",
+ "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "async": "^3.2.6",
+ "filelist": "^1.0.4",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "jake": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jose": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz",
+ "integrity": "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
+ "node_modules/jsonwebtoken": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+ "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/jwa": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
+ "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-equal-constant-time": "^1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jwks-rsa": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.2.0.tgz",
+ "integrity": "sha512-PwchfHcQK/5PSydeKCs1ylNym0w/SSv8a62DgHJ//7x2ZclCoinlsjAfDxAAbpoTPybOum/Jgy+vkvMmKz89Ww==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/express": "^4.17.20",
+ "@types/jsonwebtoken": "^9.0.4",
+ "debug": "^4.3.4",
+ "jose": "^4.15.4",
+ "limiter": "^1.1.5",
+ "lru-memoizer": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/jwks-rsa/node_modules/jose": {
+ "version": "4.15.9",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
+ "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "license": "MIT",
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/limiter": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz",
+ "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="
+ },
+ "node_modules/lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isarguments": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+ "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lru-memoizer": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz",
+ "integrity": "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==",
+ "license": "MIT",
+ "dependencies": {
+ "lodash.clonedeep": "^4.5.0",
+ "lru-cache": "6.0.0"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/morgan": {
+ "version": "1.10.1",
+ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz",
+ "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==",
+ "license": "MIT",
+ "dependencies": {
+ "basic-auth": "~2.0.1",
+ "debug": "2.6.9",
+ "depd": "~2.0.0",
+ "on-finished": "~2.3.0",
+ "on-headers": "~1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/morgan/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/morgan/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/morgan/node_modules/on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "8.5.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz",
+ "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==",
+ "license": "MIT",
+ "engines": {
+ "node": "^18 || ^20 || >= 21"
+ }
+ },
+ "node_modules/node-appwrite": {
+ "version": "20.2.1",
+ "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-20.2.1.tgz",
+ "integrity": "sha512-RweIh+3RHjprsxhWaJzcQr/UDMBMsZCma50TIJ9t3onVgs5jAT9aqFnsMlaaC9QZn1sXpPUQV90W6uvtm64DnQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "node-fetch-native-with-agent": "1.7.2"
+ }
+ },
+ "node_modules/node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+ "deprecated": "Use your platform's native DOMException instead",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "github",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.5.0"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
+ "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
+ "license": "MIT",
+ "dependencies": {
+ "data-uri-to-buffer": "^4.0.0",
+ "fetch-blob": "^3.1.4",
+ "formdata-polyfill": "^4.0.10"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/node-fetch"
+ }
+ },
+ "node_modules/node-fetch-native-with-agent": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/node-fetch-native-with-agent/-/node-fetch-native-with-agent-1.7.2.tgz",
+ "integrity": "sha512-5MaOOCuJEvcckoz7/tjdx1M6OusOY6Xc5f459IaruGStWnKzlI1qpNgaAwmn4LmFYcsSlj+jBMk84wmmRxfk5g==",
+ "license": "MIT"
+ },
+ "node_modules/node-gyp-build": {
+ "version": "4.8.4",
+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
+ "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
+ "license": "MIT",
+ "bin": {
+ "node-gyp-build": "bin.js",
+ "node-gyp-build-optional": "optional.js",
+ "node-gyp-build-test": "build-test.js"
+ }
+ },
+ "node_modules/nodemon": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
+ "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
+ "node_modules/nodemon/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/nodemon/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/on-headers": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
+ "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
+ "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/pg": {
+ "version": "8.16.3",
+ "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
+ "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
+ "license": "MIT",
+ "dependencies": {
+ "pg-connection-string": "^2.9.1",
+ "pg-pool": "^3.10.1",
+ "pg-protocol": "^1.10.3",
+ "pg-types": "2.2.0",
+ "pgpass": "1.0.5"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "optionalDependencies": {
+ "pg-cloudflare": "^1.2.7"
+ },
+ "peerDependencies": {
+ "pg-native": ">=3.0.1"
+ },
+ "peerDependenciesMeta": {
+ "pg-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/pg-cloudflare": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz",
+ "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/pg-connection-string": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz",
+ "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==",
+ "license": "MIT"
+ },
+ "node_modules/pg-format": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/pg-format/-/pg-format-1.0.4.tgz",
+ "integrity": "sha512-YyKEF78pEA6wwTAqOUaHIN/rWpfzzIuMh9KdAhc3rSLQ/7zkRFcCgYBAEGatDstLyZw4g0s9SNICmaTGnBVeyw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "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==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/pg-pool": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz",
+ "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "pg": ">=8.0"
+ }
+ },
+ "node_modules/pg-protocol": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz",
+ "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==",
+ "license": "MIT"
+ },
+ "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==",
+ "license": "MIT",
+ "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/pgpass": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
+ "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
+ "license": "MIT",
+ "dependencies": {
+ "split2": "^4.1.0"
+ }
+ },
+ "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/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postgres-bytea": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
+ "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
+ "license": "MIT",
+ "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==",
+ "license": "MIT",
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "xtend": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/random-bytes": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
+ "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz",
+ "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.7.0",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/raw-body/node_modules/iconv-lite": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
+ "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/redis": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/redis/-/redis-5.8.3.tgz",
+ "integrity": "sha512-MfSrfV6+tEfTw8c4W0yFp6XWX8Il4laGU7Bx4kvW4uiYM1AuZ3KGqEGt1LdQHeD1nEyLpIWetZ/SpY3kkbgrYw==",
+ "license": "MIT",
+ "dependencies": {
+ "@redis/bloom": "5.8.3",
+ "@redis/client": "5.8.3",
+ "@redis/json": "5.8.3",
+ "@redis/search": "5.8.3",
+ "@redis/time-series": "5.8.3"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/redis-errors": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
+ "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/redis-parser": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
+ "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
+ "license": "MIT",
+ "dependencies": {
+ "redis-errors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.5",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "mime-types": "^3.0.1",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/serve-favicon": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.1.tgz",
+ "integrity": "sha512-JndLBslCLA/ebr7rS3d+/EKkzTsTi1jI2T9l+vHfAaGJ7A7NhtDpSZ0lx81HCNWnnE0yHncG+SSnVf9IMxOwXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "etag": "~1.8.1",
+ "fresh": "~0.5.2",
+ "ms": "~2.1.3",
+ "parseurl": "~1.3.2",
+ "safe-buffer": "~5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/serve-favicon/node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/split2": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+ "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
+ "node_modules/standard-as-callback": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
+ "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
+ "license": "MIT"
+ },
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/touch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
+ "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/uid-safe": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
+ "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
+ "license": "MIT",
+ "dependencies": {
+ "random-bytes": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/undici-types": {
+ "version": "7.14.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
+ "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
+ "license": "MIT"
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/web-streams-polyfill": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
+ "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "license": "ISC"
+ }
+ }
+}
diff --git a/services/plugins/package.json b/services/plugins/package.json
new file mode 100644
index 0000000..700f3d9
--- /dev/null
+++ b/services/plugins/package.json
@@ -0,0 +1,47 @@
+{
+ "name": "plugins",
+ "version": "1.0.0",
+ "main": "src/index.mjs",
+ "scripts": {
+ "start": "NODE_ENV=production node ./src/index.js",
+ "dev": "NODE_ENV=development npx nodemon ./src/index.js",
+ "test": "NODE_ENV=stage node ./src/index.js"
+ },
+ "author": "Mateo Saldain",
+ "license": "ISC",
+ "type": "module",
+ "devDependencies": {
+ "cross-env": "^10.0.0",
+ "nodemon": "^3.1.10"
+ },
+ "dependencies": {
+ "bcrypt": "^6.0.0",
+ "chalk": "^5.6.0",
+ "connect-redis": "^9.0.0",
+ "cookie-parser": "^1.4.7",
+ "cors": "^2.8.5",
+ "dotenv": "^17.2.1",
+ "ejs": "^3.1.10",
+ "express": "^5.1.0",
+ "express-ejs-layouts": "^2.5.1",
+ "express-session": "^1.18.2",
+ "ioredis": "^5.7.0",
+ "jose": "^6.1.0",
+ "jsonwebtoken": "^9.0.2",
+ "jwks-rsa": "^3.2.0",
+ "morgan": "^1.10.1",
+ "node-appwrite": "^20.2.1",
+ "node-fetch": "^3.3.2",
+ "pg": "^8.16.3",
+ "pg-format": "^1.0.4",
+ "redis": "^5.8.2",
+ "serve-favicon": "^2.5.1"
+ },
+ "imports": {
+ "#v1Router": "./src/api/v1/routes/routes.js",
+ "#pages": "./src/pages/pages.js",
+ "#db": "./src/db/poolSingleton.js"
+ },
+ "keywords": [],
+ "description": ""
+}
diff --git a/services/plugins/src/db/poolSingleton.js b/services/plugins/src/db/poolSingleton.js
new file mode 100644
index 0000000..721722f
--- /dev/null
+++ b/services/plugins/src/db/poolSingleton.js
@@ -0,0 +1,82 @@
+// Coneción Singleton a base de datos.
+
+import { Pool } from 'pg';
+
+class DatabaseCore {
+ constructor() {
+
+ if (DatabaseCore.instance) {
+ return Database.instance;
+ }
+
+ const config = {
+ host: process.env.DB_HOST,
+ user: process.env.DB_USER,
+ password: process.env.DB_PASS,
+ database: process.env.DB_NAME,
+ port: process.env.DB_LOCAL_PORT ? Number(process.env.DB_LOCAL_PORT) : undefined,
+ ssl: process.env.PGSSL === 'true' ? { rejectUnauthorized: false } : undefined,
+ };
+
+ this.connection = new Pool(config);
+
+ DatabaseCore.instance = this;
+ }
+ async query(sql, params) {
+ return this.connection.query(sql,params);
+ }
+
+ async connect() { /* Definida solo para evitar errores */
+ return this.connection.connect();
+ }
+ async getClient() {
+ return this.connection.connect();
+ }
+
+ async release() {
+ await this.connection.end();
+ }
+}
+class DatabaseTenants {
+ constructor() {
+
+ if (DatabaseTenants.instance) {
+ return Database.instance;
+ }
+
+ const config = {
+ host: process.env.DB_HOST,
+ user: process.env.DB_USER,
+ password: process.env.DB_PASS,
+ database: process.env.DB_NAME,
+ port: process.env.DB_LOCAL_PORT ? Number(process.env.DB_LOCAL_PORT) : undefined,
+ ssl: process.env.PGSSL === 'true' ? { rejectUnauthorized: false } : undefined,
+ };
+
+ this.connection = new Pool(config);
+
+ DatabaseTenants.instance = this;
+ }
+ async query(sql, params) {
+ return this.connection.query(sql,params);
+ }
+
+ async connect() { /* Definida solo para evitar errores */
+ return this.connection.connect();
+ }
+ async getClient() {
+ return this.connection.connect();
+ }
+
+ async release() {
+ await this.connection.end();
+ }
+}
+
+// const db = new Database();
+// db.query('SELECT * FROM users');
+
+const poolCore = new DatabaseCore();
+const poolTenants = new DatabaseTenants();
+export default {poolCore, poolTenants};
+export { poolCore, poolTenants };
\ No newline at end of file
diff --git a/services/plugins/src/index.mjs b/services/plugins/src/index.mjs
new file mode 100644
index 0000000..365a882
--- /dev/null
+++ b/services/plugins/src/index.mjs
@@ -0,0 +1,140 @@
+// services/plugins/asistencias/index.mjs
+
+// ------------------------------------------------------------
+
+// ------------------------------------------------------------
+
+
+import 'dotenv/config'; // Variables de Entorno
+import express from 'express';
+import expressLayouts from 'express-ejs-layouts';
+
+import { poolCore, poolTenants } from '#db'; // dbCore y dbTenants
+
+import path from 'path';
+import { fileURLToPath } from 'url';
+import cookieParser from 'cookie-parser';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+
+// -----------------------------------------------------------------------------
+// Validación de entorno mínimo (ajusta nombres si difieren)
+// -----------------------------------------------------------------------------
+
+// Función para verificar que ciertas variables de entorno estén definida
+function checkRequiredEnvVars(...requiredKeys) {
+ const missingKeys = requiredKeys.filter((key) => !process.env[key]); // Filtramos las que NO existen en process.env
+ if (missingKeys.length > 0) { // Si falta alguna, mostramos una advertencia
+ console.warn(
+ `[PLUGIN] No se encontraron las siguientes variables de entorno: \n\n-> ${missingKeys.join('\n-> ')}`+
+ `\n`
+ );
+ }
+}
+
+checkRequiredEnvVars(
+ 'PORT',
+ 'CORE_DB_HOST', 'CORE_DB_PORT', 'CORE_DB_NAME',
+ 'TENANTS_DB_HOST', 'TENANTS_DB_PORT', 'TENANTS_DB_NAME'
+);
+
+// ----------------------------------------------------------
+// Variables del sistema
+// ----------------------------------------------------------
+const PORT = process.env.PORT;
+
+const CORE_DB_HOST = process.env.CORE_DB_HOST;
+const CORE_DB_PORT = process.env.CORE_DB_PORT;
+const CORE_DB_NAME = process.env.CORE_DB_NAME;
+
+const TENANTS_DB_HOST = process.env.TENANTS_DB_HOST;
+const TENANTS_DB_PORT = process.env.TENANTS_DB_PORT;
+const TENANTS_DB_NAME = process.env.TENANTS_DB_NAME;
+
+// ----------------------------------------------------------
+// App + Motor de vistas EJS
+// ----------------------------------------------------------
+const app = express();
+app.set('trust proxy', true);
+app.set("views", path.join(__dirname, "views"));
+app.set("view engine", "ejs");
+app.set("layout", "layouts/main");
+
+app.use(express.json());
+app.use(express.json({ limit: '1mb' }));
+app.use(express.urlencoded({ extended: true }));
+app.use(express.static(path.join(__dirname, 'public'))); // Carga de archivos estaticos
+
+
+app.use(expressLayouts); // Carga los layouts que usara el renderizado
+app.use(cookieParser(process.env.SESSION_SECRET));
+
+
+// ----------------------------------------------------------
+// Verificación de conexión
+// ----------------------------------------------------------
+
+async function verificarConexionCore() {
+ try {
+ console.log(`[PLUGINS] Comprobando accesibilidad a la db ${CORE_DB_NAME} del host ${CORE_DB_HOST} ...`);
+ const client = await poolCore.connect();
+ const { rows } = await client.query('SELECT NOW() AS ahora');
+ console.log(`\n[PLUGINS] Conexión con ${CORE_DB_NAME} OK. Hora DB:`, rows[0].ahora);
+ client.release();
+ } catch (error) {
+ console.error('[PLUGINS] Error al conectar con la base de datos al iniciar:', error.message);
+ console.error('[PLUGINS] Revisar credenciales, accesos de red y firewall.');
+ }
+}
+async function verificarConexionTenants() {
+ try {
+ console.log(`[PLUGINS] Comprobando accesibilidad a la db ${TENANTS_DB_NAME} del host ${TENANTS_DB_HOST} ...`);
+ const client = await poolTenants.connect();
+ const { rows } = await client.query('SELECT NOW() AS ahora');
+ console.log(`\n[PLUGINS] Conexión con ${TENANTS_DB_NAME} OK. Hora DB:`, rows[0].ahora);
+ client.release();
+ } catch (error) {
+ console.error('[PLUGINS] Error al conectar con la base de datos al iniciar:', error.message);
+ console.error('[PLUGINS] Revisar credenciales, accesos de red y firewall.');
+ }
+}
+
+
+
+
+
+
+// ----------------------------------------------------------
+// Middleware para datos globales
+// ----------------------------------------------------------
+app.use((req, res, next) => {
+ res.locals.currentPath = req.path;
+ res.locals.pageTitle = "SuiteCoffee";
+ res.locals.pageId = "";
+ next();
+});
+
+
+
+
+// ----------------------------------------------------------
+// Inicio del servidor
+// ----------------------------------------------------------
+
+app.listen(PORT, () => {
+ console.log(`[PLUGINS] http://localhost:${PORT}`);
+ verificarConexionCore();
+ verificarConexionTenants();
+});
+
+
+
+// -----------------------------------------------------------------------------
+// Healthcheck
+// -----------------------------------------------------------------------------
+app.get('/health', (_req, res) => {
+ res.status(200).json({ status: 'ok'}),
+ console.log(`[PLUGINS] Saludable`)
+});
\ No newline at end of file
diff --git a/services/shared/middlewares/comandas.html.bak b/services/shared/middlewares/comandas.html.bak
deleted file mode 100644
index 93c6e5d..0000000
--- a/services/shared/middlewares/comandas.html.bak
+++ /dev/null
@@ -1,355 +0,0 @@
-
-
-
-
-
- Comandas
-
-
-
-
- 📋 Nueva Comanda
-
- /api/*
-
-
-
-
-
-
-
Productos
-
-
- 0 ítems
-
-
-
-
-
-
-
- Detalles
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
La fecha se completa automáticamente y los estados/activos usan sus valores por defecto.
-
-
-
Carrito
-
-
Aún no agregaste productos.
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/services/shared/middlewares/dashboard.html.bak b/services/shared/middlewares/dashboard.html.bak
deleted file mode 100644
index 78fbbb6..0000000
--- a/services/shared/middlewares/dashboard.html.bak
+++ /dev/null
@@ -1,293 +0,0 @@
-
-
-
-
-
- Dashboard
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Mostrando hasta 100 filas.
-
-
-
-
-
-
- Endpoints
- GET /api/tables • GET /api/schema/:tabla • GET /api/table/:tabla?limit=100 • POST /api/table/:tabla
-
-
-
-
-
-
diff --git a/services/shared/middlewares/estadoComandas.html.bak b/services/shared/middlewares/estadoComandas.html.bak
deleted file mode 100644
index dd69c9a..0000000
--- a/services/shared/middlewares/estadoComandas.html.bak
+++ /dev/null
@@ -1,280 +0,0 @@
-
-
-
-
-
-
- Estado de Comandas
-
-
-
-
-
-
-
-
-
-
Listado
-
-
-
-
-
-
-
-
-
-
-
Selecciona una comanda para ver el detalle.
-
-
-
-
-
-
-
-
-
diff --git a/services/shared/middlewares/redisConnect.js b/services/shared/middlewares/redisConnect.js
deleted file mode 100644
index 378cf11..0000000
--- a/services/shared/middlewares/redisConnect.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import session from "express-session";
-import { createClient } from "redis";
-
-
-export async function createRedisSession({
-redisUrl = process.env.REDIS_URL,
-cookieName = process.env.SESSION_COOKIE_NAME || "sc.sid",
-secret = process.env.SESSION_SECRET,
-trustProxy = process.env.TRUST_PROXY === "1",
-ttlSeconds = 60 * 60 * 12, // 12h
-} = {}) {
-if (!redisUrl) throw new Error("REDIS_URL no definido");
-if (!secret) throw new Error("SESSION_SECRET no definido");
-
-
-const redis = createClient({ url: redisUrl });
-redis.on("error", (err) => console.error("[Redis]", err));
-await redis.connect();
-console.log("[Redis] conectado");
-
-
-// Resolver RedisStore (v5 / v6 / v7)
-async function resolveRedisStore() {
-const mod = await import("connect-redis");
-// v6/v7: named export class
-if (typeof mod.RedisStore === "function") return mod.RedisStore;
-// v5: default factory connectRedis(session)
-if (typeof mod.default === "function") {
-const maybe = mod.default;
-if (maybe.prototype && (maybe.prototype.get || maybe.prototype.set)) return maybe; // clase
-const factory = mod.default(session);
-return factory;
-}
-throw new Error("No se pudo resolver RedisStore de connect-redis");
-}
-
-
-const RedisStore = await resolveRedisStore();
-const store = new RedisStore({ client: redis, prefix: "sc:sess:", ttl: ttlSeconds });
-
-
-const sessionMw = session({
-name: cookieName,
-secret,
-resave: false,
-saveUninitialized: false,
-store,
-cookie: {
-httpOnly: true,
-sameSite: "lax",
-secure: process.env.NODE_ENV === "production", // requiere https
-maxAge: ttlSeconds * 1000,
-},
-});
-
-
-return { sessionMw, redis, store, trustProxy };
-}
\ No newline at end of file