feat(engine): motor de resolución de flujo declarativo [4C]
This commit is contained in:
@@ -1,96 +1,143 @@
|
|||||||
# BRIEF — Sprint 4: Formulario Wizard v3
|
# BRIEF — Sprint 4: Formulario Wizard v3 (esquema declarativo)
|
||||||
|
|
||||||
> Versión objetivo: **3.0.0** · Rama de trabajo: `main` · Preservación: `v2.1.0-stable`
|
> Versión objetivo: **3.0.0** · Rama: `main` · Preservación: `v2.1.0-stable`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Objetivo en una frase
|
## Objetivo en una frase
|
||||||
Reescribir el formulario de encuesta como un wizard pregunta-por-pantalla con
|
Construir el formulario de cuidadores como un wizard pregunta-por-pantalla cuyo
|
||||||
mini-wizard anidado para vínculos familiares, sobre un nuevo instrumento de 10
|
flujo, instancias y condiciones se definen en un **esquema declarativo** (datos),
|
||||||
secciones, habilitando análisis de datos multi-instancia.
|
renderizado por un frontend sin lógica de negocio — funcionando para los dos
|
||||||
|
clientes inminentes, y en la dirección arquitectónica del motor de formularios.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Decisión arquitectónica rectora (ADR pendiente de registrar)
|
||||||
|
|
||||||
|
**El motor de formularios es el producto; la encuesta de cuidadores es su primer
|
||||||
|
caso de uso.** Por lo tanto, la lógica del flujo del formulario vive en una capa
|
||||||
|
de **definición declarativa** (datos), no en el presentador ni dispersa en columnas
|
||||||
|
sueltas de la base.
|
||||||
|
|
||||||
|
### Estrategia en dos fases (deuda intencional, registrada — no oculta)
|
||||||
|
|
||||||
|
**Fase 1 (este sprint, para el deadline de 10-20 días):**
|
||||||
|
Se construye el formulario de cuidadores con su flujo definido como esquema
|
||||||
|
declarativo persistido. El frontend es un renderer de ese esquema — sin reglas
|
||||||
|
hardcodeadas. La resolución de "qué pantalla sigue" se calcula desde esquema +
|
||||||
|
estado. NO se construye todavía el intérprete genérico universal.
|
||||||
|
|
||||||
|
**Fase 2 (sprints posteriores, post-deadline):**
|
||||||
|
Se extrae el intérprete a un motor genérico de formularios. Como el formulario de
|
||||||
|
cuidadores ya está definido como esquema declarativo, se vuelve el primer caso de
|
||||||
|
prueba del motor sin reescribir el contrato. Registrado en `BACKLOG.md`.
|
||||||
|
|
||||||
|
**Por qué esta estrategia:** entrega valor en plazo sin generar retrabajo. La
|
||||||
|
lógica en datos (no en presentación) es lo que habilita guardado parcial,
|
||||||
|
reanudación, validación consistente y progreso preciso — la mejor UX — y lo que
|
||||||
|
hace que la Fase 2 sea generalización, no reescritura.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Alcance (qué entra)
|
## Alcance (qué entra)
|
||||||
- Nuevo modelo de datos: columna `instance_id` en `answers`, nueva constraint única
|
- Esquema declarativo del formulario de cuidadores (flujo, instancias, condiciones como datos)
|
||||||
- Nuevo instrumento v3 (10 secciones, ~38 preguntas base + preguntas por instancia)
|
- Persistencia del esquema (en seed/DB, versionado)
|
||||||
- Motor de wizard: grafo de pantallas, navegación, estado, instancias dinámicas
|
- `instance_id` en `answers` (Etapa 4A — ya aplicada)
|
||||||
- Componente de pantalla única (una pregunta por pantalla)
|
- Motor de resolución de flujo para este formulario (interpreta el esquema)
|
||||||
- Mini-wizard anidado para vínculos familiares (pregunta 4.1 → instancias)
|
- Frontend wizard como renderer del esquema (sin reglas de negocio)
|
||||||
- Autocomplete de barrios desde dataset INE/DGEEC (`geo_paraguay.json`)
|
- Mini-wizard de vínculos familiares (instancias declaradas en el esquema)
|
||||||
|
- Autocomplete de barrios desde dataset INE/DGEEC
|
||||||
- Subtítulos del "porqué" por sección
|
- Subtítulos del "porqué" por sección
|
||||||
- Submit actualizado para enviar `instance_id` por answer
|
- Submit con `instance_id` por answer
|
||||||
- Barra de progreso dinámica
|
- Barra de progreso dinámica (calculada desde el esquema + estado)
|
||||||
- RPCs nuevas para preguntas de vínculo con instancias
|
- RPCs para preguntas de vínculo con instancias
|
||||||
- Seed v3 limpio (sin migración de datos v2)
|
- Seed v3 limpio (sin migración de datos v2)
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Fuera de alcance (explícito)
|
## Fuera de alcance (explícito)
|
||||||
- ❌ Migración de datos v2.1 → v3 (se decide más adelante, cuando v3 esté estable)
|
- ❌ Motor genérico universal de formularios (Fase 2 — BACKLOG)
|
||||||
|
- ❌ Backend de construcción/edición de formularios (sprint posterior)
|
||||||
|
- ❌ Migración de datos v2.1 → v3 (se decide cuando v3 esté estable)
|
||||||
- ❌ Tocar la rama `v2.1.0-stable`
|
- ❌ Tocar la rama `v2.1.0-stable`
|
||||||
- ❌ RE Index (sprint posterior)
|
- ❌ RE Index, informe descargable, auth de /admin/responses, backup S3
|
||||||
- ❌ Informe descargable (sprint posterior)
|
|
||||||
- ❌ Autenticación de `/admin/responses` (TECH-DEBT-008)
|
|
||||||
- ❌ Backup remoto S3 (TECH-DEBT-006)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Decisiones ya tomadas (no renegociar)
|
## Decisiones ya tomadas (no renegociar)
|
||||||
1. v3 se desarrolla en `main`. v2 queda preservado en `v2.1.0-stable` + tag `v2.1.0`.
|
1. v3 en `main`; v2 preservado en `v2.1.0-stable` + tag `v2.1.0`.
|
||||||
2. v3 arranca con seed limpio — sin datos migrados.
|
2. Lógica de flujo en esquema declarativo (datos), NO en el frontend.
|
||||||
3. `instance_id text DEFAULT 'default'` en `answers`. Constraint:
|
3. Frontend wizard = renderer sin reglas de negocio.
|
||||||
`UNIQUE (response_id, question_id, instance_id)`.
|
4. Estrategia dos fases: formulario-como-esquema ahora, motor genérico después.
|
||||||
4. Wizard pregunta-por-pantalla para TODO el formulario tras el consentimiento.
|
5. v3 arranca con seed limpio, sin datos migrados.
|
||||||
5. Mini-wizard de familiares: una pregunta por pantalla, con badge de contexto
|
6. `instance_id` ya implementado (4A). Instancias declaradas en el esquema.
|
||||||
"Familiar X de N".
|
7. Wizard pregunta-por-pantalla para todo el formulario tras consentimiento.
|
||||||
6. Numeración desde Sección 1 (no "Sección A").
|
8. Mini-wizard de familiares: una pregunta por pantalla, badge "Familiar X de N".
|
||||||
7. Barrio: autocomplete para ciudades con datos INE, texto libre para el resto.
|
9. Numeración desde Sección 1.
|
||||||
8. Texto de consentimiento: el del Excel del instrumento v3 (Sección 1).
|
10. Barrio: autocomplete con datos INE, texto libre para el resto.
|
||||||
9. Versionado SemVer + CHANGELOG + tags de Git en cada versión estable.
|
11. Texto de consentimiento: el del Excel del instrumento v3.
|
||||||
10. 2-3 familiares es el caso típico; soportar N sin límite duro.
|
12. SemVer + CHANGELOG + tags en cada versión estable.
|
||||||
|
13. Migraciones se aplican vía CLI del VPS (`docker exec -i supabase-db psql`).
|
||||||
---
|
14. **Motor de flujo (4C): corre en el cliente** como módulo puro y aislado (entrada→salida
|
||||||
|
determinista, testeable con Node). Interpreta el esquema declarativo; no embebe lógica
|
||||||
|
en el componente React.
|
||||||
|
15. **Validación de integridad server-side en el submit (4G): REQUISITO NO NEGOCIABLE.**
|
||||||
|
El servidor valida contra el esquema que: las preguntas existen, los valores son opciones
|
||||||
|
válidas, las instancias corresponden a un generador real, y no se inyectan respuestas a
|
||||||
|
preguntas que el flujo nunca debió mostrar. La validación de cliente es UX, NO seguridad.
|
||||||
|
Para datos sensibles de salud, confiar solo en validación de cliente sería una falla de
|
||||||
|
seguridad. Esto NO se difiere a Fase 2.
|
||||||
|
|
||||||
## Criterios de éxito (checklist)
|
## Criterios de éxito (checklist)
|
||||||
- [ ] El formulario funciona end-to-end como wizard, una pregunta por pantalla
|
- [ ] El flujo del formulario está definido como esquema declarativo persistido
|
||||||
- [ ] El mini-wizard de familiares genera instancias correctamente (verificable en DB)
|
- [ ] El frontend no contiene reglas de negocio del flujo (verificable por revisión)
|
||||||
|
- [ ] El wizard funciona end-to-end, una pregunta por pantalla
|
||||||
|
- [ ] El mini-wizard de familiares genera instancias según el esquema
|
||||||
- [ ] Los datos se guardan con `instance_id` correcto por familiar
|
- [ ] Los datos se guardan con `instance_id` correcto por familiar
|
||||||
- [ ] El dashboard sigue funcionando (las preguntas no-instancia usan `instance_id='default'`)
|
- [ ] El dashboard sigue funcionando (preguntas no-instancia con `instance_id='default'`)
|
||||||
- [ ] Las nuevas RPCs agregan datos de vínculo por instancia
|
- [ ] El autocomplete de barrios funciona para ciudades principales
|
||||||
- [ ] El autocomplete de barrios funciona para las ciudades principales
|
- [ ] La validación visual coincide con el mockup aprobado
|
||||||
- [ ] La validación visual del wizard coincide con el mockup aprobado
|
- [ ] `v2.1.0-stable` permanece intacta
|
||||||
- [ ] `v2.1.0-stable` permanece intacta y restaurable
|
- [ ] La deuda de Fase 2 está registrada en BACKLOG
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Etapas del Sprint 4
|
## Etapas del Sprint 4
|
||||||
|
|
||||||
| Etapa | Nombre | Entregable | Dependencia |
|
| Etapa | Nombre | Entregable | Estado |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| **4.0** | Preservación v2 | Tag v2.1.0, rama stable, dump, CHANGELOG | — |
|
| **4.0** | Preservación v2 | Tag, rama stable, dump, CHANGELOG | ✅ Completada |
|
||||||
| **4A** | Modelo de datos | Migración `instance_id` + constraint | 4.0 |
|
| **4A** | Persistencia instance_id | Migración + DATA_MODEL | ✅ Completada |
|
||||||
| **4B** | Seed v3 | Instrumento v3 completo en seed.sql + geo JSON | 4A |
|
| **4B** | Esquema declarativo + seed v3 | Esquema del formulario como datos + geo JSON | — |
|
||||||
| **4C** | Motor del wizard | Grafo de pantallas, estado, navegación (lógica) | 4B |
|
| **4C** | Motor de resolución de flujo | Intérprete del esquema (este formulario) | 4B |
|
||||||
| **4D** | Componente de pantalla | UI una-pregunta-por-pantalla + secciones | 4C |
|
| **4D** | Frontend renderer | Wizard que renderiza el esquema, una preg/pantalla | 4C |
|
||||||
| **4E** | Mini-wizard instancias | Vínculos 4.1 + pantallas por familiar | 4D |
|
| **4E** | Instancias de vínculo | Mini-wizard de familiares desde el esquema | 4D |
|
||||||
| **4F** | Autocomplete barrios | Campo barrio con dataset INE | 4D |
|
| **4F** | Autocomplete barrios | Campo barrio con dataset INE | 4D |
|
||||||
| **4G** | Submit con instance_id | Guardado correcto multi-instancia | 4E |
|
| **4G** | Submit con instance_id | Guardado multi-instancia | 4E |
|
||||||
| **4H** | RPCs de vínculo | Agregados de datos por instancia en dashboard | 4G |
|
| **4H** | RPCs de vínculo | Agregados por instancia en dashboard | 4G |
|
||||||
| **4I** | Validación e2e + tag v3.0.0 | QA visual completo + release | todas |
|
| **4I** | Validación e2e + tag v3.0.0 | QA visual + release + ADR + BACKLOG Fase 2 | todas |
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Orden de ejecución
|
## Orden de ejecución
|
||||||
4.0 → 4A → 4B → 4C → 4D → (4E ∥ 4F) → 4G → 4H → 4I
|
4B → 4C → 4D → (4E ∥ 4F) → 4G → 4H → 4I
|
||||||
|
|
||||||
Las etapas 4E y 4F pueden ir en paralelo si hay capacidad; si no, 4E primero
|
|
||||||
(es la más crítica), 4F después.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Notas de versionado por etapa
|
## Definición del esquema declarativo (guía para 4B)
|
||||||
- Cada etapa cierra con un commit versionado descriptivo.
|
|
||||||
- Las versiones `3.0.0-alpha.N` se pueden usar para hitos intermedios si se
|
El esquema describe el formulario como datos. Estructura conceptual:
|
||||||
despliega a un entorno de prueba.
|
|
||||||
- El tag `v3.0.0` se crea solo en la etapa 4I, cuando todo está validado.
|
```
|
||||||
|
formulario:
|
||||||
|
version, secciones[]
|
||||||
|
seccion:
|
||||||
|
numero, nombre, descripcion (el "porqué")
|
||||||
|
preguntas[]
|
||||||
|
pregunta:
|
||||||
|
codigo, tipo, enunciado, hint, opciones[], required, sensitive
|
||||||
|
flujo:
|
||||||
|
condiciones_visibilidad[] (cuándo se muestra — evaluado por el motor)
|
||||||
|
genera_instancias? (si esta pregunta crea instancias, ej. 4.1)
|
||||||
|
pertenece_a_instancia_de? (de qué generador depende, ej. 4.2/4.3 → 4.1)
|
||||||
|
validaciones[]
|
||||||
|
```
|
||||||
|
|
||||||
|
La forma técnica exacta de persistir esto (columnas en `questions` +
|
||||||
|
`conditional_rules` JSONB extendido, o tabla de definición de flujo separada)
|
||||||
|
la decide la Etapa 4B según el esquema actual. Principio: declarativo, versionado,
|
||||||
|
interpretable por el motor sin conocer el caso de uso.
|
||||||
124
sprints/sprint-4/ETAPA_4C_PROMPT.md
Normal file
124
sprints/sprint-4/ETAPA_4C_PROMPT.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
# ETAPA 4C — Motor de resolución de flujo (módulo puro, cliente)
|
||||||
|
|
||||||
|
## 1. Objetivo
|
||||||
|
Construir el motor que interpreta el esquema declarativo del formulario y resuelve
|
||||||
|
la secuencia de pantallas según el estado de respuestas. Es un módulo puro y aislado
|
||||||
|
en `lib/`, sin dependencias de React ni del DOM — entrada→salida determinista,
|
||||||
|
testeable con Node. El componente (Etapa 4D) lo consume; el motor no conoce al componente.
|
||||||
|
|
||||||
|
## 2. Contexto previo
|
||||||
|
- ADR-005: la lógica de flujo vive en el esquema (datos). El motor la interpreta.
|
||||||
|
- El esquema v3 está en la DB: questions con `type`, `conditional_rules`,
|
||||||
|
`instance_generator`, `instance_of`, `hint`, más filas `type='section'`.
|
||||||
|
- Decisión confirmada: el motor corre en el CLIENTE (interpretación de flujo, no validación
|
||||||
|
de seguridad — esa va server-side en 4G).
|
||||||
|
- Decisión confirmada: las secciones (`type='section'`) son PANTALLAS propias en el grafo.
|
||||||
|
- La lógica de v2 (`lib/conditional.ts`, `survey-form.tsx`) es INCOMPATIBLE y se reemplaza:
|
||||||
|
- v2 evalúa AND (`rules.every`); v3 necesita OR entre condiciones de ocultamiento.
|
||||||
|
- v2 solo conoce `eq`/`eq_any` y acción `show`; v3 necesita `contains`, `eq_sole`, `not_in`, acción `hide`.
|
||||||
|
- v2 infiere secciones por regex de prefijo; v3 las tiene como datos.
|
||||||
|
- El comportamiento esperado está validado en el mockup `wizard_formulario_mapeo_v3.html`
|
||||||
|
(función `buildVisible` y navegación) — usar como referencia de comportamiento, NO de arquitectura.
|
||||||
|
|
||||||
|
## 3. DECISIONES YA TOMADAS — no consultar de nuevo
|
||||||
|
- Motor puro en `lib/` (proponé el nombre: ej. `lib/form-engine.ts`), sin React/DOM.
|
||||||
|
- Vocabulario de operadores: `eq`, `eq_any`, `not_in` (escalares), `contains`, `eq_sole` (array).
|
||||||
|
- Acciones: `show`, `hide`.
|
||||||
|
- Combinación: múltiples reglas en el array de una pregunta se evalúan en OR.
|
||||||
|
(Una pregunta se oculta si CUALQUIER regla `hide` aplica; se muestra si CUALQUIER regla `show` aplica.
|
||||||
|
Definí la semántica precisa de show+hide combinados y documentala.)
|
||||||
|
- Secciones = pantallas propias en el grafo.
|
||||||
|
- Instancias: 4.1 (`instance_generator=true`) genera N instancias; las preguntas con
|
||||||
|
`instance_of='4.1'` se repiten una vez por instancia activa, en orden por familiar
|
||||||
|
(familiar1: 4.2→4.3, familiar2: 4.2→4.3, ...) como en el mockup.
|
||||||
|
- Estado de respuestas con clave compuesta `question_code:instance_id` (instancias) o
|
||||||
|
`question_code` con `instance_id='default'` (normales).
|
||||||
|
|
||||||
|
## 4. Tareas
|
||||||
|
|
||||||
|
### 4.1 Tipos del motor (`lib/types.ts` ampliado o nuevo)
|
||||||
|
Definir/ampliar:
|
||||||
|
- `ConditionalRule`: operadores y acciones completos del vocabulario v3.
|
||||||
|
- `FormSchema`: la representación del formulario que el motor consume (secciones, preguntas,
|
||||||
|
reglas, instanciación) — derivada de las filas de `questions`.
|
||||||
|
- `WizardState`: respuestas (con instancias), instancia activa, pantalla actual.
|
||||||
|
- `Screen`: una pantalla resoluble (sección-intro | pregunta | pregunta-de-instancia | fin).
|
||||||
|
|
||||||
|
### 4.2 Evaluador de reglas
|
||||||
|
Reescribir la evaluación (reemplaza `lib/conditional.ts`):
|
||||||
|
- Implementar los 5 operadores y 2 acciones.
|
||||||
|
- `contains` / `eq_sole` operan sobre respuestas array (multiple_choice).
|
||||||
|
- Semántica OR documentada y correcta para el caso `r_hide_ning_sn`.
|
||||||
|
- Función pura: `(rule, answers) => boolean` y `(question, answers) => 'show'|'hide'`.
|
||||||
|
|
||||||
|
### 4.3 Resolución del grafo de pantallas
|
||||||
|
Función pura que dado el esquema + estado devuelve la lista ordenada de pantallas visibles:
|
||||||
|
- Expande instancias (4.2/4.3 por cada familiar activo declarado en 4.1).
|
||||||
|
- Aplica visibilidad (oculta secciones/preguntas según reglas).
|
||||||
|
- Incluye las pantallas de sección.
|
||||||
|
- Equivale conceptualmente al `buildVisible()` del mockup, pero como módulo puro.
|
||||||
|
|
||||||
|
### 4.4 Navegación
|
||||||
|
Funciones puras `next(state, schema)` y `back(state, schema)` que devuelven el nuevo
|
||||||
|
estado (pantalla actual actualizada), resolviendo saltos. Identificar la pantalla actual
|
||||||
|
por ID estable, no por índice (lección del mockup: el índice se desincroniza cuando
|
||||||
|
cambian las instancias).
|
||||||
|
|
||||||
|
### 4.5 Carga del esquema
|
||||||
|
Actualizar la query (`app/page.tsx`) para traer las 3 columnas nuevas
|
||||||
|
(`hint`, `instance_generator`, `instance_of`). Transformar las filas de `questions`
|
||||||
|
en el `FormSchema` que consume el motor.
|
||||||
|
|
||||||
|
### 4.6 Tests del motor (Node, sin navegador)
|
||||||
|
Tests puros que verifiquen:
|
||||||
|
- Recorrido completo (todos los vínculos) genera las pantallas esperadas.
|
||||||
|
- "Solo niño sin discapacidad" (eq_sole) → recorrido liviano correcto (5.3, 8.4, 9.1, 9.4).
|
||||||
|
- "Ninguna de las anteriores" (contains) → salta a sección 10.
|
||||||
|
- 3.1='No' oculta 3.2-3.5.
|
||||||
|
- 3 familiares → 6 pantallas de instancia en orden por familiar.
|
||||||
|
- Navegación next/back coherente cuando cambian las instancias.
|
||||||
|
|
||||||
|
## 5. Entregables (DoD)
|
||||||
|
- [ ] Motor puro en `lib/` sin dependencias de React/DOM.
|
||||||
|
- [ ] Los 5 operadores y 2 acciones implementados y testeados.
|
||||||
|
- [ ] Resolución de grafo con instancias y secciones-pantalla.
|
||||||
|
- [ ] Navegación por ID estable, no por índice.
|
||||||
|
- [ ] Query actualizada con las 3 columnas nuevas.
|
||||||
|
- [ ] Tests Node que cubren los recorridos del punto 4.6, todos en verde.
|
||||||
|
- [ ] NO se toca el componente todavía (es 4D) — el motor se entrega standalone + tests.
|
||||||
|
|
||||||
|
## 6. Qué reportar
|
||||||
|
```
|
||||||
|
Verificado:
|
||||||
|
- Motor en [archivo], puro (sin React/DOM) ✓
|
||||||
|
- Operadores implementados: eq, eq_any, not_in, contains, eq_sole ✓
|
||||||
|
- Acciones: show, hide ✓ — semántica de combinación: [descripción]
|
||||||
|
- Tests: N/N en verde
|
||||||
|
- recorrido completo ✓
|
||||||
|
- solo niño (eq_sole) → 5.3/8.4/9.1/9.4 ✓
|
||||||
|
- ninguna (contains) → salta S10 ✓
|
||||||
|
- 3.1=No oculta 3.2-3.5 ✓
|
||||||
|
- 3 familiares → 6 pantallas en orden ✓
|
||||||
|
- next/back coherente ✓
|
||||||
|
|
||||||
|
Asumido:
|
||||||
|
- [supuestos de diseño del motor]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Qué NO hacer
|
||||||
|
- ❌ No poner lógica de flujo en un componente React (el motor es puro, lib/).
|
||||||
|
- ❌ No tocar el componente de formulario todavía (es 4D).
|
||||||
|
- ❌ No implementar validación de seguridad acá (es 4G, server-side).
|
||||||
|
- ❌ No usar índices numéricos para la pantalla actual — usar ID estable.
|
||||||
|
- ❌ No tocar v2.1.0-stable ni el seed.
|
||||||
|
|
||||||
|
## 8. Versionado
|
||||||
|
Commit sugerido:
|
||||||
|
```
|
||||||
|
feat(engine): motor de resolución de flujo declarativo [4C]
|
||||||
|
|
||||||
|
Módulo puro que interpreta el esquema v3 y resuelve pantallas.
|
||||||
|
5 operadores (eq, eq_any, not_in, contains, eq_sole), acciones show/hide.
|
||||||
|
Instancias de vínculo y secciones-pantalla. Navegación por ID estable.
|
||||||
|
Tests Node cubren los 3 recorridos. Reemplaza lib/conditional.ts de v2.
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user