Compare commits
51 Commits
d444021a00
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99de5f06b5 | ||
|
|
fbc5f0f6c4 | ||
|
|
a17f00bad2 | ||
|
|
41fc2a0aa0 | ||
|
|
001bf13d26 | ||
|
|
47f23a73e1 | ||
|
|
04c37f669c | ||
|
|
92a00ec75f | ||
| b91f5d09e5 | |||
| aee34d797d | |||
|
|
0fc5392bd2 | ||
| 1e1348bc1a | |||
| f68029edc1 | |||
|
|
384f47df5e | ||
|
|
a8dbb62b09 | ||
|
|
2684e251f7 | ||
|
|
94faedecae | ||
| 3f95e92318 | |||
| aed8661331 | |||
|
|
e908125d31 | ||
|
|
03663aacb4 | ||
|
|
0c18ffc2f9 | ||
| 77b722d739 | |||
| 3c7d47782b | |||
|
|
156b5ad77d | ||
|
|
5d2a6469aa | ||
|
|
2f6564d9a6 | ||
| e2ae400889 | |||
| e597a05f08 | |||
|
|
4425141cb3 | ||
|
|
29db0eb0a2 | ||
|
|
91fc6900eb | ||
| 0a73b91e12 | |||
| 508f3f028d | |||
| bc82249a29 | |||
| f3514d399e | |||
| 0ac0a859b9 | |||
| 7a9a1686fa | |||
| 5a7209badb | |||
| 32e3184b59 | |||
| 083375c5f0 | |||
| 6f84db00cd | |||
| b60ecccad4 | |||
| c4e8675fe8 | |||
| 04fb83447f | |||
| bdda074fa1 | |||
| 64afc3aedb | |||
| 156e1aa27c | |||
| 16b7f956b3 | |||
| 34faf2157e | |||
| 2a6723aedf |
@@ -16,7 +16,15 @@
|
||||
"Bash(mv core:*)",
|
||||
"Bash(mv apps/backend_admin app/backend_admin)",
|
||||
"Bash(mv apps/common app/common)",
|
||||
"Bash(mv apps/promociones app/promociones)"
|
||||
"Bash(mv apps/promociones app/promociones)",
|
||||
"WebSearch",
|
||||
"Bash(npm install:*)",
|
||||
"Bash(engram init:*)",
|
||||
"Bash(dir:*)",
|
||||
"Bash(engram --help:*)",
|
||||
"Bash(engram remember:*)",
|
||||
"Bash(engram stats:*)",
|
||||
"Bash(engram recall:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -9,6 +9,12 @@ deployments/docker-compose.yml
|
||||
# Archivos de datos de la DB local
|
||||
postgres_data/
|
||||
local_postgres_data/
|
||||
|
||||
# Carpeta de datos (BD SQLite y similares), pero se mantiene la carpeta
|
||||
data/*
|
||||
!data/.gitkeep
|
||||
app/data/*
|
||||
!app/data/.gitkeep
|
||||
*.pyc
|
||||
# Bloquear todos los .env en cualquier carpeta
|
||||
.env
|
||||
|
||||
110
CLAUDE.md
Normal file
110
CLAUDE.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Convenciones del Ecosistema V-Encore Lab
|
||||
|
||||
## Ecosistema de microservicios
|
||||
|
||||
| Repo | Rol | Puerto |
|
||||
|------|-----|--------|
|
||||
| `django-core-base` | Hub orquestador principal | 8000 |
|
||||
| `api_backoffice` | Consulta y gestión de BD | 8001 |
|
||||
| `api_comunicaciones` | Emails, notificaciones, webhooks | 8002 |
|
||||
| `api_documentacion` | Generación y gestión de documentos | 8003 |
|
||||
| `web_interno` | Panel de gestión (React + Ant Design) | 3000 |
|
||||
|
||||
## Stack Django
|
||||
|
||||
- Django 5.0 + DRF + SimpleJWT
|
||||
- Apps bajo `app/`. Prefijo `/api/` en todas las URLs salvo `admin/`.
|
||||
- Patrón 3 capas: **URL → View → Action**
|
||||
- SQL con `connection.cursor()` y placeholders (`%s`). Nunca concatenar strings.
|
||||
|
||||
## Patrón de vistas — 4 bloques obligatorios
|
||||
|
||||
```python
|
||||
from general.utilidades.acciones import LogService
|
||||
|
||||
class MiVista(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
path = '/mi-app/mi-endpoint/'
|
||||
|
||||
# Bloque 1 — Inicio Log
|
||||
log_id = LogService.gestionar_log(self, request, path=path)
|
||||
|
||||
try:
|
||||
# Bloque 2 — Data Cleaning
|
||||
data = request.data
|
||||
LogService.gestionar_log(self, request, log_id=log_id,
|
||||
path=path, body_request=data, status_code=100)
|
||||
params = {'campo': data.get('campo')}
|
||||
except Exception as error:
|
||||
response = {'error': str(error)}
|
||||
LogService.gestionar_log(self, request, log_id=log_id,
|
||||
path=path, body_response=response, status_code=400)
|
||||
return JsonResponse(response, status=400)
|
||||
|
||||
try:
|
||||
# Bloque 3 — Action Call
|
||||
resultado = mi_accion(params)
|
||||
# Bloque 4 — Cierre Log
|
||||
LogService.gestionar_log(self, request, log_id=log_id,
|
||||
path=path, body_response=resultado, status_code=200)
|
||||
return JsonResponse(resultado, status=200)
|
||||
except Exception as error:
|
||||
response = {'error': str(error)}
|
||||
LogService.gestionar_log(self, request, log_id=log_id,
|
||||
path=path, body_response=response, status_code=500)
|
||||
return JsonResponse(response, status=500)
|
||||
```
|
||||
|
||||
## LogService — reglas
|
||||
|
||||
- Siempre llamar como `LogService.gestionar_log(self, request, ...)` — pasar `self` de la vista.
|
||||
- Primera llamada (sin `log_id`): crea el registro, devuelve el `log_id`.
|
||||
- Llamadas siguientes: actualizar con `log_id=log_id`.
|
||||
- `body_request` y `body_response` se serializan con `DjangoJSONEncoder` — soporta `datetime.date`, `Decimal`, etc.
|
||||
- `status_code` como entero. Usar `is not None` para comprobar (0 es válido).
|
||||
|
||||
## Base de datos
|
||||
|
||||
- `DB_HOST` definido → PostgreSQL
|
||||
- `DB_HOST` no definido → SQLite en `app/data/db.sqlite3`
|
||||
- Migraciones siempre desde `app/`: `cd app && python manage.py migrate`
|
||||
- SQL INSERT con psycopg2: usar `INSERT ... RETURNING id` + `cursor.fetchone()`. **Nunca `cursor.lastrowid`**.
|
||||
- Booleans en psycopg2: pasar `True`/`False`, no `1`/`0`.
|
||||
|
||||
## Flujo de ramas
|
||||
|
||||
```
|
||||
pre-dev → dev → master
|
||||
```
|
||||
|
||||
- `pre-dev`: desarrollo activo — aquí entran todos los cambios
|
||||
- `dev`: validación previa a producción
|
||||
- `master`: producción estable
|
||||
- Merges siempre con `--no-ff`
|
||||
- **NUNCA** propagar en sentido inverso (master → dev o dev → pre-dev)
|
||||
- Secuencia correcta:
|
||||
```bash
|
||||
git checkout pre-dev && git merge <mi-cambio> --no-ff
|
||||
git checkout dev && git merge pre-dev --no-ff && git push origin dev
|
||||
git checkout master && git merge dev --no-ff && git push origin master
|
||||
```
|
||||
|
||||
## Estructura de app Django
|
||||
|
||||
```
|
||||
app/
|
||||
├── api_config/ # settings.py, urls.py, wsgi.py
|
||||
├── general/ # LogService, utils — NO tiene modelos propios
|
||||
├── backend_admin/ # Modelo Log (audit_logs), admin panel
|
||||
├── common/ # Modelos y utilidades compartidas entre apps
|
||||
├── <feature_app>/ # Una app por dominio de negocio
|
||||
├── data/ # SQLite (gitignored, solo .gitkeep versionado)
|
||||
└── manage.py
|
||||
```
|
||||
|
||||
## Fixtures
|
||||
|
||||
- `loaddata` ignora `auto_now_add=True` — incluir fechas explícitas en el JSON o falla con NOT NULL en PostgreSQL.
|
||||
329
README.md
329
README.md
@@ -1,73 +1,312 @@
|
||||
# django-core-base
|
||||
# django-core-base · API Hub Orquestador
|
||||
|
||||
// V-Encore Lab: Sistema Automatizado v1.0.4
|
||||
> V-Encore Lab — Microservicio principal. Actúa como orquestador y punto de entrada central del ecosistema SaaS.
|
||||
> Puerto por defecto: **8000**
|
||||
|
||||
## 🚀 Inicio Rápido (Desarrollo Local)
|
||||
---
|
||||
|
||||
## Tabla de contenidos
|
||||
|
||||
1. [Requisitos previos](#requisitos-previos)
|
||||
2. [Inicio rápido — Desarrollo local](#inicio-rápido--desarrollo-local)
|
||||
3. [Variables de entorno](#variables-de-entorno)
|
||||
4. [Base de datos](#base-de-datos)
|
||||
5. [Docker — Producción](#docker--producción)
|
||||
6. [Estructura del proyecto](#estructura-del-proyecto)
|
||||
7. [Endpoints principales](#endpoints-principales)
|
||||
8. [Patrón LogService](#patrón-logservice)
|
||||
9. [Flujo de ramas](#flujo-de-ramas)
|
||||
10. [Mantenimiento](#mantenimiento)
|
||||
|
||||
---
|
||||
|
||||
## Requisitos previos
|
||||
|
||||
| Herramienta | Versión mínima |
|
||||
|-------------|---------------|
|
||||
| Python | 3.11 |
|
||||
| pip | 23+ |
|
||||
| Docker | 24+ |
|
||||
| Docker Compose | v2 |
|
||||
| Git | 2.40+ |
|
||||
|
||||
---
|
||||
|
||||
## Inicio rápido — Desarrollo local
|
||||
|
||||
### 1. Clonar y Configurar
|
||||
```bash
|
||||
# 1. Clonar
|
||||
git clone https://git.v-encore-lab.com/Proyecto-SaaS/django-core-base.git
|
||||
cd django-core-base
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### 2. Instalar Dependencias
|
||||
```bash
|
||||
# 2. Entorno virtual
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate # Linux/Mac
|
||||
.venv\Scripts\activate # Windows
|
||||
|
||||
# 3. Dependencias
|
||||
pip install -r deployments/requirements.txt
|
||||
```
|
||||
|
||||
### 3. Migraciones de Base de Datos
|
||||
```bash
|
||||
# Crear y aplicar migraciones para todos los modelos
|
||||
python manage.py makemigrations
|
||||
# 4. Variables de entorno
|
||||
cp .env.example .env
|
||||
# Editar .env según el entorno (ver sección Variables de entorno)
|
||||
|
||||
# 5. Migraciones (SQLite en local)
|
||||
cd app
|
||||
python manage.py migrate
|
||||
|
||||
# Opcional: Crear superusuario
|
||||
# 6. Superusuario (primera vez)
|
||||
python manage.py createsuperuser
|
||||
|
||||
# 7. Servidor de desarrollo
|
||||
python manage.py runserver 0.0.0.0:8000
|
||||
```
|
||||
|
||||
Accesos:
|
||||
- API: http://localhost:8000/api/
|
||||
- Admin: http://localhost:8000/admin/
|
||||
|
||||
---
|
||||
|
||||
## Variables de entorno
|
||||
|
||||
Copia `.env.example` a `.env` y ajusta los valores:
|
||||
|
||||
| Variable | Descripción | Ejemplo / Default |
|
||||
|----------------|--------------------------------------------------|----------------------------|
|
||||
| `SECRET_KEY` | Clave secreta Django | `django-insecure-...` |
|
||||
| `DEBUG` | Modo debug | `True` (dev) / `False` (prod) |
|
||||
| `ALLOWED_HOSTS`| Hosts permitidos (separados por coma) | `localhost,127.0.0.1` |
|
||||
| `DB_HOST` | Host PostgreSQL. **Si no se define → SQLite** | `localhost` / vacío |
|
||||
| `DB_PORT` | Puerto PostgreSQL | `5432` |
|
||||
| `DB_NAME` | Nombre de la base de datos | `vencorelab` |
|
||||
| `DB_USER` | Usuario PostgreSQL | `postgres` |
|
||||
| `DB_PASSWORD` | Contraseña PostgreSQL | `postgres` |
|
||||
|
||||
---
|
||||
|
||||
## Base de datos
|
||||
|
||||
### Desarrollo local — SQLite
|
||||
|
||||
Si `DB_HOST` **no** está definido en `.env`, Django usa automáticamente SQLite:
|
||||
|
||||
```
|
||||
app/data/db.sqlite3
|
||||
```
|
||||
|
||||
```bash
|
||||
cd app
|
||||
python manage.py migrate # crea app/data/db.sqlite3
|
||||
python manage.py createsuperuser
|
||||
```
|
||||
|
||||
### 4. Correr el Servidor
|
||||
```bash
|
||||
python manage.py runserver
|
||||
La carpeta `app/data/` está en `.gitignore` (solo se versiona `.gitkeep`).
|
||||
|
||||
### Producción — PostgreSQL
|
||||
|
||||
Define `DB_HOST` en `.env` para activar el driver PostgreSQL:
|
||||
|
||||
```env
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_NAME=vencorelab
|
||||
DB_USER=postgres
|
||||
DB_PASSWORD=supersecret
|
||||
```
|
||||
|
||||
Abrir http://localhost:8000
|
||||
|
||||
## 🐳 Docker (Producción/Desarrollo)
|
||||
|
||||
```bash
|
||||
docker-compose up --build
|
||||
cd app
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
Acceder a:
|
||||
- App: http://localhost:8000
|
||||
- Admin: http://localhost:8000/admin/
|
||||
- DB: localhost:5432 (Postgres)
|
||||
|
||||
## 📋 Comandos Django Comunes
|
||||
### Comandos útiles de migración
|
||||
|
||||
```bash
|
||||
# Verificar configuración
|
||||
python manage.py check
|
||||
cd app
|
||||
|
||||
# Recopilar static files
|
||||
python manage.py collectstatic --noinput
|
||||
# Ver migraciones pendientes
|
||||
python manage.py showmigrations
|
||||
|
||||
# Test
|
||||
python manage.py test
|
||||
# Crear migraciones de una app
|
||||
python manage.py makemigrations <app_name>
|
||||
|
||||
# Aplicar todas las migraciones
|
||||
python manage.py migrate
|
||||
|
||||
# Revertir migraciones de una app al estado inicial
|
||||
python manage.py migrate <app_name> zero
|
||||
```
|
||||
|
||||
## 🔧 Estructura del Proyecto
|
||||
---
|
||||
|
||||
```
|
||||
├── apps/ # Aplicaciones Django
|
||||
│ ├── backend_admin/
|
||||
│ ├── common/
|
||||
│ └── promociones/
|
||||
├── core/ # Configuración principal
|
||||
├── deployments/ # Docker, requirements prod
|
||||
└── manage.py
|
||||
## Docker — Producción
|
||||
|
||||
```bash
|
||||
# Construir e iniciar
|
||||
docker-compose up --build -d
|
||||
|
||||
# Ver logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Parar
|
||||
docker-compose down
|
||||
|
||||
# Parar y eliminar volúmenes (¡cuidado en producción!)
|
||||
docker-compose down -v
|
||||
```
|
||||
|
||||
## .env Variables
|
||||
Ver `.env.example` para configuración.
|
||||
El contenedor expone el puerto **8000**.
|
||||
|
||||
Para producción con PostgreSQL, asegúrate de que `.env` tenga `DB_HOST` apuntando al host correcto (puede ser el nombre del servicio en la red Docker).
|
||||
|
||||
---
|
||||
|
||||
## Estructura del proyecto
|
||||
|
||||
```
|
||||
django-core-base/
|
||||
├── app/
|
||||
│ ├── api_config/ # Configuración Django (settings, urls, wsgi)
|
||||
│ ├── general/ # App transversal
|
||||
│ │ └── utilidades/
|
||||
│ │ ├── acciones.py # LogService — auditoría centralizada
|
||||
│ │ └── utils.py # Utilidades HTTP (get_client_ip, etc.)
|
||||
│ ├── backend_admin/ # App admin: modelo Log, endpoints de gestión
|
||||
│ ├── common/ # Modelos y utilidades compartidas
|
||||
│ ├── promociones/ # App de ejemplo
|
||||
│ ├── automatizados/ # Endpoints para Jenkins/automatizaciones
|
||||
│ ├── data/ # Directorio de la BD SQLite (gitignored)
|
||||
│ │ └── .gitkeep
|
||||
│ └── manage.py
|
||||
├── deployments/
|
||||
│ ├── requirements.txt
|
||||
│ └── Dockerfile
|
||||
├── docker-compose.yml
|
||||
├── .env.example
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Endpoints principales
|
||||
|
||||
| Método | Ruta | Descripción | Auth |
|
||||
|--------|-------------------------------|-----------------------------------|--------------|
|
||||
| POST | `/api/token/` | Obtener JWT (login) | No |
|
||||
| POST | `/api/token/refresh/` | Renovar access token | No |
|
||||
| GET | `/admin/` | Panel de administración Django | Session |
|
||||
| POST | `/api/promociones/obtener/` | Consultar promociones | JWT Bearer |
|
||||
| GET | `/api/general/health/` | Health check | No |
|
||||
|
||||
Autenticación: `Authorization: Bearer <access_token>`
|
||||
|
||||
---
|
||||
|
||||
## Patrón LogService
|
||||
|
||||
Todas las vistas deben usar `LogService` para auditoría:
|
||||
|
||||
```python
|
||||
from general.utilidades.acciones import LogService
|
||||
|
||||
class MiVista(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
path = '/mi-app/mi-endpoint/'
|
||||
|
||||
# Bloque 1 — Inicio log
|
||||
log_id = LogService.gestionar_log(self, request, path=path)
|
||||
|
||||
try:
|
||||
# Bloque 2 — Limpieza de datos
|
||||
data = request.data
|
||||
LogService.gestionar_log(self, request, log_id=log_id,
|
||||
path=path, body_request=data, status_code=100)
|
||||
params = {'campo': data.get('campo')}
|
||||
except Exception as error:
|
||||
response = {'error': str(error)}
|
||||
LogService.gestionar_log(self, request, log_id=log_id,
|
||||
path=path, body_response=response, status_code=400)
|
||||
return JsonResponse(response, status=400)
|
||||
|
||||
try:
|
||||
# Bloque 3 — Acción
|
||||
resultado = mi_accion(params)
|
||||
LogService.gestionar_log(self, request, log_id=log_id,
|
||||
path=path, body_response=resultado, status_code=200)
|
||||
return JsonResponse(resultado, status=200)
|
||||
except Exception as error:
|
||||
response = {'error': str(error)}
|
||||
LogService.gestionar_log(self, request, log_id=log_id,
|
||||
path=path, body_response=response, status_code=500)
|
||||
return JsonResponse(response, status=500)
|
||||
```
|
||||
|
||||
`LogService` registra automáticamente en la tabla `audit_logs` el usuario, IP, path, request/response y status code.
|
||||
|
||||
---
|
||||
|
||||
## Flujo de ramas
|
||||
|
||||
```
|
||||
pre-dev → dev → master
|
||||
```
|
||||
|
||||
- `pre-dev`: desarrollo activo, integración de features
|
||||
- `dev`: validación previa a producción
|
||||
- `master`: rama de producción estable
|
||||
|
||||
```bash
|
||||
# Crear feature
|
||||
git checkout pre-dev
|
||||
git checkout -b feature/mi-feature
|
||||
|
||||
# Mergear a pre-dev
|
||||
git checkout pre-dev
|
||||
git merge feature/mi-feature --no-ff
|
||||
|
||||
# Promover a dev
|
||||
git checkout dev
|
||||
git merge pre-dev --no-ff
|
||||
|
||||
# Promover a master
|
||||
git checkout master
|
||||
git merge dev --no-ff
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mantenimiento
|
||||
|
||||
```bash
|
||||
# Limpiar sesiones expiradas
|
||||
cd app && python manage.py clearsessions
|
||||
|
||||
# Ver estado de la BD
|
||||
cd app && python manage.py dbshell
|
||||
|
||||
# Backup SQLite (desarrollo)
|
||||
cp app/data/db.sqlite3 app/data/db.sqlite3.bak
|
||||
|
||||
# Backup PostgreSQL (producción)
|
||||
pg_dump -U postgres vencorelab > backup_$(date +%Y%m%d).sql
|
||||
|
||||
# Actualizar dependencias
|
||||
pip list --outdated
|
||||
pip install -U <paquete>
|
||||
pip freeze > deployments/requirements.txt
|
||||
|
||||
# Reiniciar contenedor Docker
|
||||
docker-compose restart web
|
||||
|
||||
# Ver logs del contenedor
|
||||
docker-compose logs -f web --tail=100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
> **V-Encore Lab** — Sistema Automatizado v1.0
|
||||
> Repositorio: `Proyecto-SaaS/django-core-base`
|
||||
|
||||
@@ -56,7 +56,9 @@ INSTALLED_APPS = [
|
||||
'corsheaders',
|
||||
|
||||
# Tus Apps (Asegúrate de que el path sea correcto)
|
||||
'general',
|
||||
'promociones',
|
||||
'automatizados',
|
||||
'backend_admin',
|
||||
'common',
|
||||
]
|
||||
@@ -93,17 +95,26 @@ TEMPLATES = [
|
||||
WSGI_APPLICATION = 'api_config.wsgi.application'
|
||||
|
||||
# 3. DATABASE
|
||||
# Extraemos con fallback por si el .env falla
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': os.getenv('DB_NAME', 'postgres'),
|
||||
'USER': os.getenv('DB_USER', 'postgres'),
|
||||
'PASSWORD': os.getenv('DB_PASSWORD', ''),
|
||||
'HOST': os.getenv('DB_HOST', 'localhost'),
|
||||
'PORT': os.getenv('DB_PORT', '5432'),
|
||||
# En producción (cuando DB_HOST está definido) usa PostgreSQL.
|
||||
# En local/desarrollo sin configuración, cae a SQLite en data/
|
||||
if os.getenv('DB_HOST'):
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': os.getenv('DB_NAME', 'postgres'),
|
||||
'USER': os.getenv('DB_USER', 'postgres'),
|
||||
'PASSWORD': os.getenv('DB_PASSWORD', ''),
|
||||
'HOST': os.getenv('DB_HOST'),
|
||||
'PORT': os.getenv('DB_PORT', '5432'),
|
||||
}
|
||||
}
|
||||
else:
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'data' / 'db.sqlite3',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Internationalization
|
||||
LANGUAGE_CODE = 'es-es'
|
||||
|
||||
@@ -3,6 +3,8 @@ from backend_admin import views as admin_views
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', include('backend_admin.urls')),
|
||||
path('promociones/', include('promociones.urls')),
|
||||
path('api/general/', include('general.urls')),
|
||||
path('api/promociones/', include('promociones.urls')),
|
||||
path('api/automatizados/', include('automatizados.urls')),
|
||||
path('api/token/', admin_views.api_token, name='token_obtain_pair'),
|
||||
]
|
||||
0
app/automatizados/__init__.py
Normal file
0
app/automatizados/__init__.py
Normal file
220
app/automatizados/acciones.py
Normal file
220
app/automatizados/acciones.py
Normal file
@@ -0,0 +1,220 @@
|
||||
import json
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
from datetime import datetime
|
||||
|
||||
from django.db import connection
|
||||
from django.utils import timezone
|
||||
from common.utils import clean_sql_string, clean_sql_int
|
||||
|
||||
|
||||
# =========================================================
|
||||
# Helper HTTP (stdlib) — evita dependencia extra en requirements
|
||||
# =========================================================
|
||||
def _http_get_json(url, timeout=8):
|
||||
"""GET a un servicio externo que responde JSON. Usa stdlib para no añadir deps."""
|
||||
req = urllib.request.Request(url, headers={'User-Agent': 'django-core-base/1.0'})
|
||||
with urllib.request.urlopen(req, timeout=timeout) as response:
|
||||
raw = response.read().decode('utf-8')
|
||||
try:
|
||||
return json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
return {'raw': raw}
|
||||
|
||||
|
||||
def _http_get_text(url, timeout=8):
|
||||
"""GET a un servicio externo que responde texto plano."""
|
||||
req = urllib.request.Request(url, headers={'User-Agent': 'django-core-base/1.0'})
|
||||
with urllib.request.urlopen(req, timeout=timeout) as response:
|
||||
return response.read().decode('utf-8').strip()
|
||||
|
||||
|
||||
# =========================================================
|
||||
# ACCIÓN 1 — Base de datos (INSERT histórico de ejecución)
|
||||
# set_parameterized
|
||||
# =========================================================
|
||||
def setEjecucion(params):
|
||||
"""
|
||||
Inserta una fila en automatizacion_ejecuciones registrando una ejecución.
|
||||
params esperados: nombre, descripcion, estado, origen, resultado, error
|
||||
"""
|
||||
query = """
|
||||
INSERT INTO automatizacion_ejecuciones
|
||||
(nombre, descripcion, estado, origen, resultado, error, fecha_inicio, fecha_fin, activo)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING id
|
||||
"""
|
||||
|
||||
ahora = timezone.now()
|
||||
resultado_json = json.dumps(params.get('resultado')) if params.get('resultado') is not None else None
|
||||
|
||||
parameter_dict = [
|
||||
clean_sql_string(params.get('nombre')),
|
||||
clean_sql_string(params.get('descripcion')),
|
||||
clean_sql_string(params.get('estado') or 'ok'),
|
||||
clean_sql_string(params.get('origen') or 'manual'),
|
||||
resultado_json,
|
||||
clean_sql_string(params.get('error')) if params.get('error') else None,
|
||||
ahora,
|
||||
ahora,
|
||||
bool(params.get('activo', True)),
|
||||
]
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(query, parameter_dict)
|
||||
row = cursor.fetchone()
|
||||
nuevo_id = row[0] if row else None
|
||||
|
||||
return {'id': nuevo_id, 'fecha': ahora.isoformat()}
|
||||
|
||||
|
||||
# =========================================================
|
||||
# ACCIÓN 2 — Servicio externo: Cat Fact API
|
||||
# https://catfact.ninja/fact (gratis, sin auth)
|
||||
# =========================================================
|
||||
def getCatFact():
|
||||
url = 'https://catfact.ninja/fact'
|
||||
data = _http_get_json(url)
|
||||
return {
|
||||
'servicio': 'catfact.ninja',
|
||||
'url': url,
|
||||
'fact': data.get('fact'),
|
||||
'length': data.get('length'),
|
||||
}
|
||||
|
||||
|
||||
# =========================================================
|
||||
# ACCIÓN 3 — Servicio externo: GitHub Zen
|
||||
# https://api.github.com/zen (gratis, sin auth)
|
||||
# =========================================================
|
||||
def getGithubZen():
|
||||
url = 'https://api.github.com/zen'
|
||||
texto = _http_get_text(url)
|
||||
return {
|
||||
'servicio': 'api.github.com/zen',
|
||||
'url': url,
|
||||
'zen': texto,
|
||||
}
|
||||
|
||||
|
||||
# =========================================================
|
||||
# Orquestador — ejecuta las 3 acciones en secuencia
|
||||
# =========================================================
|
||||
def ejecutarAutomatizaciones(params):
|
||||
"""
|
||||
Ejecuta las 3 acciones automatizadas:
|
||||
1) Llamada a servicio externo: catfact.ninja
|
||||
2) Llamada a servicio externo: api.github.com/zen
|
||||
3) Persistencia en BD: inserta la ejecución en automatizacion_ejecuciones
|
||||
"""
|
||||
resultados = {'acciones': []}
|
||||
errores = []
|
||||
|
||||
# Acción 2 — catfact
|
||||
try:
|
||||
resultados['acciones'].append({'step': 1, 'ok': True, 'data': getCatFact()})
|
||||
except Exception as err:
|
||||
errores.append(f'catfact: {err}')
|
||||
resultados['acciones'].append({'step': 1, 'ok': False, 'error': str(err)})
|
||||
|
||||
# Acción 3 — github zen
|
||||
try:
|
||||
resultados['acciones'].append({'step': 2, 'ok': True, 'data': getGithubZen()})
|
||||
except Exception as err:
|
||||
errores.append(f'github_zen: {err}')
|
||||
resultados['acciones'].append({'step': 2, 'ok': False, 'error': str(err)})
|
||||
|
||||
# Acción 1 — persistir en BD
|
||||
estado_final = 'ok' if not errores else 'error'
|
||||
nombre = clean_sql_string(params.get('nombre')) or f'Ejecucion {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}'
|
||||
origen = clean_sql_string(params.get('origen')) or 'manual'
|
||||
|
||||
registro = setEjecucion({
|
||||
'nombre': nombre,
|
||||
'descripcion': params.get('descripcion') or 'Ejecución orquestada por /api/automatizados/ejecutar/',
|
||||
'estado': estado_final,
|
||||
'origen': origen,
|
||||
'resultado': resultados,
|
||||
'error': '; '.join(errores) if errores else None,
|
||||
'activo': True,
|
||||
})
|
||||
|
||||
resultados['acciones'].append({'step': 3, 'ok': True, 'data': registro})
|
||||
|
||||
return {
|
||||
'ejecucion_id': registro.get('id'),
|
||||
'estado': estado_final,
|
||||
'total_acciones': len(resultados['acciones']),
|
||||
'resultados': resultados,
|
||||
'errores': errores,
|
||||
}
|
||||
|
||||
|
||||
# =========================================================
|
||||
# Lectura — historial (get_parameterized)
|
||||
# =========================================================
|
||||
def getHistorial(params):
|
||||
"""
|
||||
Devuelve el histórico de ejecuciones. Permite filtrar por estado y limit.
|
||||
"""
|
||||
query = """
|
||||
SELECT id, nombre, descripcion, estado, origen, resultado, error,
|
||||
fecha_inicio, fecha_fin, activo
|
||||
FROM automatizacion_ejecuciones
|
||||
WHERE (%s = '' OR estado = %s)
|
||||
ORDER BY fecha_inicio DESC
|
||||
LIMIT %s
|
||||
"""
|
||||
|
||||
estado = clean_sql_string(params.get('estado')) if params.get('estado') else ''
|
||||
limite = clean_sql_int(params.get('limit')) or 20
|
||||
|
||||
parameter_dict = [estado, estado, limite]
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(query, parameter_dict)
|
||||
columns = [col[0] for col in cursor.description]
|
||||
rows = [dict(zip(columns, row)) for row in cursor.fetchall()]
|
||||
|
||||
# Normalizamos el campo resultado (JSON serializado en SQLite)
|
||||
for row in rows:
|
||||
if isinstance(row.get('resultado'), str):
|
||||
try:
|
||||
row['resultado'] = json.loads(row['resultado'])
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
return {'total': len(rows), 'data': rows}
|
||||
|
||||
|
||||
# =========================================================
|
||||
# Estado del módulo
|
||||
# =========================================================
|
||||
def getEstado():
|
||||
"""
|
||||
Devuelve el estado general del módulo de automatizaciones:
|
||||
cuántas ejecuciones hay, última ejecución, endpoints disponibles.
|
||||
"""
|
||||
query = """
|
||||
SELECT COUNT(*) AS total,
|
||||
SUM(CASE WHEN estado = 'ok' THEN 1 ELSE 0 END) AS ok,
|
||||
SUM(CASE WHEN estado = 'error' THEN 1 ELSE 0 END) AS errores,
|
||||
MAX(fecha_inicio) AS ultima_ejecucion
|
||||
FROM automatizacion_ejecuciones
|
||||
"""
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(query)
|
||||
columns = [col[0] for col in cursor.description]
|
||||
row = cursor.fetchone()
|
||||
resumen = dict(zip(columns, row)) if row else {}
|
||||
|
||||
return {
|
||||
'status': 'ok',
|
||||
'modulo': 'automatizados',
|
||||
'endpoints': [
|
||||
'POST /api/automatizados/ejecutar/',
|
||||
'POST /api/automatizados/historial/',
|
||||
'POST /api/automatizados/estado/',
|
||||
],
|
||||
'resumen': resumen,
|
||||
}
|
||||
6
app/automatizados/apps.py
Normal file
6
app/automatizados/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AutomatizadosConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'automatizados'
|
||||
47
app/automatizados/fixtures/semillas.json
Normal file
47
app/automatizados/fixtures/semillas.json
Normal file
@@ -0,0 +1,47 @@
|
||||
[
|
||||
{
|
||||
"model": "automatizados.automatizacionejecucion",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"nombre": "Ejecución inicial de prueba",
|
||||
"descripcion": "Seed de ejemplo para poblar la tabla de ejecuciones automatizadas",
|
||||
"estado": "ok",
|
||||
"origen": "seed",
|
||||
"resultado": {"acciones": 0, "detalle": "fixture de arranque"},
|
||||
"error": null,
|
||||
"fecha_inicio": "2026-04-16T10:00:00Z",
|
||||
"fecha_fin": "2026-04-16T10:00:05Z",
|
||||
"activo": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "automatizados.automatizacionejecucion",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"nombre": "Chequeo nocturno",
|
||||
"descripcion": "Ejemplo de ejecución recurrente programada",
|
||||
"estado": "ok",
|
||||
"origen": "jenkins",
|
||||
"resultado": {"acciones": 3, "detalle": "todas las llamadas OK"},
|
||||
"error": null,
|
||||
"fecha_inicio": "2026-04-16T03:00:00Z",
|
||||
"fecha_fin": "2026-04-16T03:00:12Z",
|
||||
"activo": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "automatizados.automatizacionejecucion",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"nombre": "Ejecución con error simulado",
|
||||
"descripcion": "Registro de referencia para estado=error",
|
||||
"estado": "error",
|
||||
"origen": "manual",
|
||||
"resultado": null,
|
||||
"error": "timeout al llamar servicio externo",
|
||||
"fecha_inicio": "2026-04-15T18:30:00Z",
|
||||
"fecha_fin": "2026-04-15T18:30:08Z",
|
||||
"activo": false
|
||||
}
|
||||
}
|
||||
]
|
||||
0
app/automatizados/migrations/__init__.py
Normal file
0
app/automatizados/migrations/__init__.py
Normal file
25
app/automatizados/models.py
Normal file
25
app/automatizados/models.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class AutomatizacionEjecucion(models.Model):
|
||||
"""
|
||||
Registro histórico de ejecuciones automatizadas.
|
||||
Cada vez que el endpoint `ejecutar/` corre, se guarda una fila con el
|
||||
resultado consolidado de las acciones ejecutadas.
|
||||
"""
|
||||
nombre = models.CharField(max_length=255)
|
||||
descripcion = models.TextField(null=True, blank=True)
|
||||
estado = models.CharField(max_length=50, default='pendiente') # pendiente | ok | error
|
||||
origen = models.CharField(max_length=100, default='manual') # manual | jenkins | cron
|
||||
resultado = models.JSONField(null=True, blank=True)
|
||||
error = models.TextField(null=True, blank=True)
|
||||
fecha_inicio = models.DateTimeField(auto_now_add=True)
|
||||
fecha_fin = models.DateTimeField(null=True, blank=True)
|
||||
activo = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'automatizacion_ejecuciones'
|
||||
ordering = ['-fecha_inicio']
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.nombre} [{self.estado}]'
|
||||
8
app/automatizados/urls.py
Normal file
8
app/automatizados/urls.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.urls import path
|
||||
from .views import AutomatizadosEjecutar, AutomatizadosHistorial, AutomatizadosEstado
|
||||
|
||||
urlpatterns = [
|
||||
path('ejecutar/', AutomatizadosEjecutar.as_view(), name='automatizados_ejecutar'),
|
||||
path('historial/', AutomatizadosHistorial.as_view(), name='automatizados_historial'),
|
||||
path('estado/', AutomatizadosEstado.as_view(), name='automatizados_estado'),
|
||||
]
|
||||
132
app/automatizados/views.py
Normal file
132
app/automatizados/views.py
Normal file
@@ -0,0 +1,132 @@
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||||
from django.http import JsonResponse
|
||||
|
||||
from general.utilidades.acciones import LogService
|
||||
from .acciones import ejecutarAutomatizaciones, getHistorial, getEstado
|
||||
|
||||
|
||||
class AutomatizadosEjecutar(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
path = '/automatizados/ejecutar/'
|
||||
|
||||
# --- BLOQUE 1: Inicio Log ---
|
||||
log_id = LogService.gestionar_log(self, request, path=path)
|
||||
|
||||
try:
|
||||
# --- BLOQUE 2: Data Cleaning ---
|
||||
data = request.data
|
||||
status = 100
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_request=data, status_code=status)
|
||||
|
||||
params = {
|
||||
'nombre': data.get('nombre'),
|
||||
'descripcion': data.get('descripcion'),
|
||||
'origen': data.get('origen') or 'manual',
|
||||
}
|
||||
|
||||
except Exception as error:
|
||||
response = {'body': {'data': [], 'error': str(error)}, 'mensaje': str(error)}
|
||||
status = 400
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, status=status, safe=False)
|
||||
|
||||
try:
|
||||
# --- BLOQUE 3: Action Call ---
|
||||
resultado = ejecutarAutomatizaciones(params)
|
||||
response = resultado
|
||||
status = 200
|
||||
# --- BLOQUE 4: Cierre Log ---
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, safe=False, status=status)
|
||||
|
||||
except Exception as error:
|
||||
response = {'body': {'data': [], 'error': str(error)}, 'error': str(error)}
|
||||
status = 500
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, status=status, safe=False)
|
||||
|
||||
|
||||
class AutomatizadosHistorial(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
path = '/automatizados/historial/'
|
||||
|
||||
# --- BLOQUE 1: Inicio Log ---
|
||||
log_id = LogService.gestionar_log(self, request, path=path)
|
||||
|
||||
try:
|
||||
# --- BLOQUE 2: Data Cleaning ---
|
||||
data = request.data
|
||||
status = 100
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_request=data, status_code=status)
|
||||
|
||||
params = {
|
||||
'estado': data.get('estado'),
|
||||
'limit': data.get('limit') or 20,
|
||||
}
|
||||
|
||||
except Exception as error:
|
||||
response = {'body': {'data': [], 'error': str(error)}, 'mensaje': str(error)}
|
||||
status = 400
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, status=status, safe=False)
|
||||
|
||||
try:
|
||||
# --- BLOQUE 3: Action Call ---
|
||||
resultado = getHistorial(params)
|
||||
response = resultado
|
||||
status = 200
|
||||
# --- BLOQUE 4: Cierre Log ---
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, safe=False, status=status)
|
||||
|
||||
except Exception as error:
|
||||
response = {'body': {'data': [], 'error': str(error)}, 'error': str(error)}
|
||||
status = 500
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, status=status, safe=False)
|
||||
|
||||
|
||||
class AutomatizadosEstado(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
path = '/automatizados/estado/'
|
||||
|
||||
# --- BLOQUE 1: Inicio Log ---
|
||||
log_id = LogService.gestionar_log(self, request, path=path)
|
||||
|
||||
try:
|
||||
# --- BLOQUE 2: Data Cleaning ---
|
||||
data = request.data
|
||||
status = 100
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_request=data, status_code=status)
|
||||
|
||||
except Exception as error:
|
||||
response = {'body': {'data': [], 'error': str(error)}, 'mensaje': str(error)}
|
||||
status = 400
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, status=status, safe=False)
|
||||
|
||||
try:
|
||||
# --- BLOQUE 3: Action Call ---
|
||||
resultado = getEstado()
|
||||
response = resultado
|
||||
status = 200
|
||||
# --- BLOQUE 4: Cierre Log ---
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, safe=False, status=status)
|
||||
|
||||
except Exception as error:
|
||||
response = {'body': {'data': [], 'error': str(error)}, 'error': str(error)}
|
||||
status = 500
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, status=status, safe=False)
|
||||
@@ -18,7 +18,7 @@ class Admin:
|
||||
|
||||
# 1. Autenticación
|
||||
user = authenticate(username=username, password=password)
|
||||
|
||||
|
||||
if user is not None:
|
||||
# 2. Generación de JWT (Access & Refresh)
|
||||
refresh = RefreshToken.for_user(user)
|
||||
|
||||
0
app/data/.gitkeep
Normal file
0
app/data/.gitkeep
Normal file
0
app/general/__init__.py
Normal file
0
app/general/__init__.py
Normal file
1
app/general/admin.py
Normal file
1
app/general/admin.py
Normal file
@@ -0,0 +1 @@
|
||||
from django.contrib import admin
|
||||
6
app/general/apps.py
Normal file
6
app/general/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class GeneralConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'general'
|
||||
21
app/general/exception.py
Normal file
21
app/general/exception.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from rest_framework.views import exception_handler
|
||||
from rest_framework.response import Response
|
||||
|
||||
|
||||
def custom_exception_handler(exc, context):
|
||||
"""
|
||||
Handler global de excepciones para DRF.
|
||||
Añadir en settings.py:
|
||||
REST_FRAMEWORK = {
|
||||
'EXCEPTION_HANDLER': 'general.exception.custom_exception_handler',
|
||||
}
|
||||
"""
|
||||
response = exception_handler(exc, context)
|
||||
|
||||
if response is not None:
|
||||
response.data = {
|
||||
'body': {'data': [], 'error': response.data},
|
||||
'mensaje': str(exc),
|
||||
}
|
||||
|
||||
return response
|
||||
0
app/general/migrations/__init__.py
Normal file
0
app/general/migrations/__init__.py
Normal file
5
app/general/models.py
Normal file
5
app/general/models.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.db import models
|
||||
|
||||
# La app general no define modelos propios.
|
||||
# El modelo Log vive en backend_admin.models y se accede desde
|
||||
# general.utilidades.acciones.LogService.
|
||||
24
app/general/request.py
Normal file
24
app/general/request.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import json
|
||||
from django.http import JsonResponse
|
||||
|
||||
|
||||
def parse_body(request):
|
||||
"""
|
||||
Parsea el body de la request como JSON.
|
||||
Lanza ValueError si el body está vacío o no es JSON válido.
|
||||
"""
|
||||
raw = request.body
|
||||
if not raw:
|
||||
raise ValueError('El body de la petición está vacío.')
|
||||
return json.loads(raw)
|
||||
|
||||
|
||||
def build_error_response(message, status=400, data=None):
|
||||
"""Construye una respuesta de error en el formato estándar del proyecto."""
|
||||
body = {'data': data if data is not None else [], 'error': message}
|
||||
return JsonResponse({'body': body, 'mensaje': message}, status=status, safe=False)
|
||||
|
||||
|
||||
def build_success_response(data, status=200):
|
||||
"""Construye una respuesta de éxito en el formato estándar del proyecto."""
|
||||
return JsonResponse(data, status=status, safe=False)
|
||||
6
app/general/serializers.py
Normal file
6
app/general/serializers.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class EmptySerializer(serializers.Serializer):
|
||||
"""Serializer base vacío para endpoints sin body estructurado."""
|
||||
pass
|
||||
7
app/general/tests.py
Normal file
7
app/general/tests.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
class LogServiceTest(TestCase):
|
||||
def test_placeholder(self):
|
||||
"""Placeholder: añadir tests de LogService aquí."""
|
||||
pass
|
||||
6
app/general/urls.py
Normal file
6
app/general/urls.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.urls import path
|
||||
from .views import status_view
|
||||
|
||||
urlpatterns = [
|
||||
path('status/', status_view, name='general_status'),
|
||||
]
|
||||
0
app/general/utilidades/__init__.py
Normal file
0
app/general/utilidades/__init__.py
Normal file
114
app/general/utilidades/acciones.py
Normal file
114
app/general/utilidades/acciones.py
Normal file
@@ -0,0 +1,114 @@
|
||||
import json
|
||||
import logging
|
||||
from django.utils import timezone
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from . import utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _json_safe(value):
|
||||
"""
|
||||
Convierte cualquier valor a un tipo seguro para JSONField.
|
||||
Usa DjangoJSONEncoder para manejar date, datetime, Decimal, UUID, etc.
|
||||
"""
|
||||
if value is None or value == '':
|
||||
return value
|
||||
try:
|
||||
return json.loads(json.dumps(value, cls=DjangoJSONEncoder))
|
||||
except Exception:
|
||||
return str(value)
|
||||
|
||||
|
||||
class LogService:
|
||||
"""
|
||||
Servicio centralizado de gestión de logs.
|
||||
Única fuente de inserción en la tabla audit_logs.
|
||||
|
||||
Uso en vistas:
|
||||
log_id = LogService.gestionar_log(self, request, path='/mi/path/')
|
||||
LogService.gestionar_log(self, request, log_id=log_id, body_request=data, status_code=200)
|
||||
|
||||
Si la BD no está disponible, el log falla silenciosamente para no
|
||||
interrumpir la petición del usuario.
|
||||
"""
|
||||
|
||||
def gestionar_log(
|
||||
self,
|
||||
request,
|
||||
log_id=None,
|
||||
path=None,
|
||||
user=None,
|
||||
body_request=None,
|
||||
body_response=None,
|
||||
status_code=None,
|
||||
):
|
||||
try:
|
||||
return LogService._ejecutar_log(
|
||||
self, request, log_id, path, user, body_request, body_response, status_code
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning('LogService.gestionar_log falló (log omitido): %s', str(e))
|
||||
return log_id # Devuelve el log_id existente o None si era creación
|
||||
|
||||
@staticmethod
|
||||
def _ejecutar_log(caller, request, log_id, path, user, body_request, body_response, status_code):
|
||||
# Importación diferida para evitar problemas de arranque si la BD no está lista
|
||||
from backend_admin.models import Log
|
||||
|
||||
# Determinar la app llamante a partir del módulo de la vista
|
||||
modulo = caller.__class__.__module__
|
||||
app_nombre = modulo.split('.')[0]
|
||||
|
||||
tag_header = request.headers.get('tag')
|
||||
|
||||
if tag_header:
|
||||
usuario_final = tag_header
|
||||
elif app_nombre:
|
||||
apps_automatizadas = ['automatizados']
|
||||
if app_nombre.lower() in apps_automatizadas:
|
||||
usuario_final = 'Jenkins'
|
||||
else:
|
||||
usuario_final = app_nombre
|
||||
else:
|
||||
usuario_final = user if user else 'orquestador'
|
||||
|
||||
if log_id is None:
|
||||
# --- CREACIÓN: primer registro del ciclo de vida de la petición ---
|
||||
path_final = path if path else request.path
|
||||
|
||||
nuevo_log = Log.objects.create(
|
||||
user_id=0,
|
||||
user=usuario_final,
|
||||
app_id=0,
|
||||
remote_address=utils.get_client_ip(request),
|
||||
request='',
|
||||
response='',
|
||||
status_code=status_code if status_code else '0',
|
||||
path=path_final,
|
||||
method=request.method,
|
||||
createdAt=timezone.now(),
|
||||
)
|
||||
return nuevo_log.pk
|
||||
|
||||
|
||||
else:
|
||||
# --- ACTUALIZACIÓN: enriquece el log con datos del procesamiento ---
|
||||
datos_a_actualizar = {
|
||||
'updatedAt': timezone.now(),
|
||||
}
|
||||
|
||||
if user:
|
||||
datos_a_actualizar['user'] = user
|
||||
if path:
|
||||
datos_a_actualizar['path'] = path
|
||||
if body_request is not None:
|
||||
# _json_safe convierte dates, Decimals, etc. a tipos JSON válidos
|
||||
datos_a_actualizar['request'] = _json_safe(body_request)
|
||||
if body_response is not None:
|
||||
datos_a_actualizar['response'] = _json_safe(body_response)
|
||||
if status_code is not None:
|
||||
datos_a_actualizar['status_code'] = str(status_code)
|
||||
|
||||
Log.objects.filter(pk=log_id).update(**datos_a_actualizar)
|
||||
return log_id
|
||||
33
app/general/utilidades/custom_errors.py
Normal file
33
app/general/utilidades/custom_errors.py
Normal file
@@ -0,0 +1,33 @@
|
||||
class ValidationError(Exception):
|
||||
"""Error de validación de datos de entrada."""
|
||||
def __init__(self, message, field=None):
|
||||
self.message = message
|
||||
self.field = field
|
||||
super().__init__(message)
|
||||
|
||||
def to_response(self):
|
||||
detail = {'error': self.message}
|
||||
if self.field:
|
||||
detail['field'] = self.field
|
||||
return {'body': {'data': [], **detail}, 'mensaje': self.message}
|
||||
|
||||
|
||||
class ExternalServiceError(Exception):
|
||||
"""Error en la comunicación con un servicio externo."""
|
||||
def __init__(self, message, service=None):
|
||||
self.message = message
|
||||
self.service = service
|
||||
super().__init__(message)
|
||||
|
||||
def to_response(self):
|
||||
return {'body': {'data': [], 'error': self.message}, 'mensaje': self.message}
|
||||
|
||||
|
||||
class NotFoundError(Exception):
|
||||
"""Recurso no encontrado."""
|
||||
def __init__(self, message='Recurso no encontrado'):
|
||||
self.message = message
|
||||
super().__init__(message)
|
||||
|
||||
def to_response(self):
|
||||
return {'body': {'data': [], 'error': self.message}, 'mensaje': self.message}
|
||||
6
app/general/utilidades/utils.py
Normal file
6
app/general/utilidades/utils.py
Normal file
@@ -0,0 +1,6 @@
|
||||
def get_client_ip(request):
|
||||
"""Obtiene la IP real del cliente, considerando proxies."""
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if x_forwarded_for:
|
||||
return x_forwarded_for.split(',')[0].strip()
|
||||
return request.META.get('REMOTE_ADDR')
|
||||
0
app/general/validaciones/__init__.py
Normal file
0
app/general/validaciones/__init__.py
Normal file
5
app/general/views.py
Normal file
5
app/general/views.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.http import JsonResponse
|
||||
|
||||
|
||||
def status_view(request):
|
||||
return JsonResponse({'status': 'ok', 'service': 'general'})
|
||||
@@ -2,45 +2,45 @@ from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||||
from django.http import JsonResponse
|
||||
from backend_admin.models import Log
|
||||
|
||||
from general.utilidades.acciones import LogService
|
||||
from .acciones import getData
|
||||
from django.utils import timezone # Esta es la forma correcta
|
||||
|
||||
|
||||
class PromocionObtener(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
# --- BLOQUE 1: LOG INITIATION ---
|
||||
log_entry = Log.objects.create(
|
||||
user=request.user.username,
|
||||
path='promociones/obtener/',
|
||||
method='POST',
|
||||
status_code='0'
|
||||
)
|
||||
path = '/promociones/obtener/'
|
||||
|
||||
print('llega a despues de log entry')
|
||||
# --- LOG: inicio de la petición ---
|
||||
log_id = LogService.gestionar_log(self, request, path=path)
|
||||
|
||||
try:
|
||||
# --- BLOQUE 2: DATA CLEANING ---
|
||||
# --- BLOQUE 2: limpieza y validación del body ---
|
||||
data = request.data
|
||||
log_entry.request = data
|
||||
log_entry.save()
|
||||
status = 100
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_request=data, status_code=status)
|
||||
|
||||
params = {'id': data.get('id'), 'activo': data.get('activo')}
|
||||
|
||||
# --- BLOQUE 3: ACTION CALL ---
|
||||
# Aquí ya recibimos las fechas como strings gracias al paso 1
|
||||
except Exception as error:
|
||||
response = {'body': {'data': [], 'error': str(error)}, 'mensaje': str(error)}
|
||||
status = 400
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, status=status, safe=False)
|
||||
|
||||
try:
|
||||
# --- BLOQUE 3: llamada a la acción ---
|
||||
resultado = getData(params)
|
||||
response = resultado
|
||||
status = 200
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, safe=False, status=status)
|
||||
|
||||
# --- BLOQUE 4: LOG CLOSURE & RESPONSE ---
|
||||
log_entry.response = {"count": len(resultado)} # No guardes todo el JSON si es muy grande
|
||||
log_entry.status_code = '200'
|
||||
log_entry.save()
|
||||
|
||||
return JsonResponse(resultado, safe=False, status=200)
|
||||
|
||||
except Exception as e:
|
||||
log_entry.status_code = '500'
|
||||
log_entry.response = {'error': str(e)}
|
||||
log_entry.save()
|
||||
return JsonResponse({'error': str(e)}, status=500)
|
||||
except Exception as error:
|
||||
response = {'body': {'data': [], 'error': str(error)}, 'error': str(error)}
|
||||
status = 500
|
||||
LogService.gestionar_log(self, request, log_id=log_id, path=path, body_response=response, status_code=status)
|
||||
return JsonResponse(response, status=status, safe=False)
|
||||
|
||||
0
data/.gitkeep
Normal file
0
data/.gitkeep
Normal file
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
@@ -1,45 +1,41 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
gitea-db:
|
||||
image: postgres:15
|
||||
# Usará el nombre de tu .env (django_db_local)
|
||||
container_name: ${DB_CONTAINER_NAME:-django_db_dev}
|
||||
restart: always
|
||||
db:
|
||||
image: postgres:15-alpine
|
||||
container_name: ${DB_CONTAINER_NAME:-django_core_db}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: ${DB_NAME:-gitea}
|
||||
POSTGRES_USER: ${DB_USER:-gitea}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-gitea}
|
||||
POSTGRES_DB: ${DB_NAME:-django_core_db}
|
||||
POSTGRES_USER: ${DB_USER:-postgres}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
# --- ESTO ES LO QUE FALTA ---
|
||||
ports:
|
||||
- "${DATABASE_EXPOSE_PORT:-5432}:5432"
|
||||
# ----------------------------
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-gitea} -d ${DB_NAME:-gitea}"]
|
||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-django_core_db}"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
|
||||
web:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deployments/Dockerfile
|
||||
container_name: ${APP_CONTAINER_NAME:-django_app_dev}
|
||||
restart: always
|
||||
container_name: ${APP_CONTAINER_NAME:-django_core_app}
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- DEBUG=${DEBUG_MODE:-1}
|
||||
# IMPORTANTE: Este nombre debe coincidir con el nombre del servicio arriba (gitea-db)
|
||||
- DB_HOST=gitea-db
|
||||
- DB_HOST=db
|
||||
- DB_PORT=5432
|
||||
ports:
|
||||
- "${PORT:-8000}:8000"
|
||||
depends_on:
|
||||
gitea-db:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
postgres_data:
|
||||
|
||||
@@ -3,16 +3,39 @@
|
||||
# Salir inmediatamente si un comando falla
|
||||
set -e
|
||||
|
||||
# --- Esperar a PostgreSQL si estamos en modo BD remota ---
|
||||
if [ -n "$DB_HOST" ]; then
|
||||
echo "--> Esperando a PostgreSQL en $DB_HOST:${DB_PORT:-5432}..."
|
||||
until python -c "
|
||||
import sys, psycopg2, os
|
||||
try:
|
||||
psycopg2.connect(
|
||||
host=os.environ['DB_HOST'],
|
||||
port=os.environ.get('DB_PORT', 5432),
|
||||
user=os.environ['DB_USER'],
|
||||
password=os.environ['DB_PASSWORD'],
|
||||
dbname=os.environ['DB_NAME']
|
||||
)
|
||||
sys.exit(0)
|
||||
except Exception:
|
||||
sys.exit(1)
|
||||
" 2>/dev/null; do
|
||||
echo " PostgreSQL no disponible, reintentando en 2s..."
|
||||
sleep 2
|
||||
done
|
||||
echo "--> PostgreSQL listo."
|
||||
fi
|
||||
|
||||
echo "--> Ejecutando migraciones..."
|
||||
# Esto asegura que si hay cambios en models.py, se generen y apliquen las tablas
|
||||
python manage.py makemigrations --noinput
|
||||
python manage.py migrate --noinput
|
||||
|
||||
echo "--> Cargando datos de prueba..."
|
||||
# Este comando busca archivos JSON en las carpetas 'fixtures' de tus apps
|
||||
# Usamos || true para que si el archivo no existe o ya están cargados, el contenedor no se detenga
|
||||
python manage.py loaddata semillas || echo "Aviso: No se pudieron cargar las semillas (fichero no encontrado o error de formato)."
|
||||
echo "--> Cargando semillas (si existen)..."
|
||||
python manage.py loaddata semillas 2>/dev/null || echo " Sin semillas, continuando."
|
||||
|
||||
echo "--> Arrancando el servidor Django..."
|
||||
# Usamos exec para que Django sea el proceso principal (PID 1) y reciba señales de Docker
|
||||
exec python manage.py runserver 0.0.0.0:8000
|
||||
echo "--> Arrancando servidor con Gunicorn..."
|
||||
exec gunicorn api_config.wsgi:application \
|
||||
--bind 0.0.0.0:8000 \
|
||||
--workers 2 \
|
||||
--timeout 120 \
|
||||
--access-logfile - \
|
||||
--error-logfile -
|
||||
|
||||
12
frontend/index.html
Normal file
12
frontend/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Django Core Base</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
16
frontend/node_modules/.bin/nanoid
generated
vendored
Normal file
16
frontend/node_modules/.bin/nanoid
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../nanoid/bin/nanoid.cjs" "$@"
|
||||
else
|
||||
exec node "$basedir/../nanoid/bin/nanoid.cjs" "$@"
|
||||
fi
|
||||
17
frontend/node_modules/.bin/nanoid.cmd
generated
vendored
Normal file
17
frontend/node_modules/.bin/nanoid.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\nanoid\bin\nanoid.cjs" %*
|
||||
28
frontend/node_modules/.bin/nanoid.ps1
generated
vendored
Normal file
28
frontend/node_modules/.bin/nanoid.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
frontend/node_modules/.bin/rolldown
generated
vendored
Normal file
16
frontend/node_modules/.bin/rolldown
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../rolldown/bin/cli.mjs" "$@"
|
||||
else
|
||||
exec node "$basedir/../rolldown/bin/cli.mjs" "$@"
|
||||
fi
|
||||
17
frontend/node_modules/.bin/rolldown.cmd
generated
vendored
Normal file
17
frontend/node_modules/.bin/rolldown.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\rolldown\bin\cli.mjs" %*
|
||||
28
frontend/node_modules/.bin/rolldown.ps1
generated
vendored
Normal file
28
frontend/node_modules/.bin/rolldown.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../rolldown/bin/cli.mjs" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../rolldown/bin/cli.mjs" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../rolldown/bin/cli.mjs" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../rolldown/bin/cli.mjs" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
frontend/node_modules/.bin/tsc
generated
vendored
Normal file
16
frontend/node_modules/.bin/tsc
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
||||
else
|
||||
exec node "$basedir/../typescript/bin/tsc" "$@"
|
||||
fi
|
||||
17
frontend/node_modules/.bin/tsc.cmd
generated
vendored
Normal file
17
frontend/node_modules/.bin/tsc.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\typescript\bin\tsc" %*
|
||||
28
frontend/node_modules/.bin/tsc.ps1
generated
vendored
Normal file
28
frontend/node_modules/.bin/tsc.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../typescript/bin/tsc" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../typescript/bin/tsc" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../typescript/bin/tsc" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../typescript/bin/tsc" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
frontend/node_modules/.bin/tsserver
generated
vendored
Normal file
16
frontend/node_modules/.bin/tsserver
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
||||
else
|
||||
exec node "$basedir/../typescript/bin/tsserver" "$@"
|
||||
fi
|
||||
17
frontend/node_modules/.bin/tsserver.cmd
generated
vendored
Normal file
17
frontend/node_modules/.bin/tsserver.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\typescript\bin\tsserver" %*
|
||||
28
frontend/node_modules/.bin/tsserver.ps1
generated
vendored
Normal file
28
frontend/node_modules/.bin/tsserver.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../typescript/bin/tsserver" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../typescript/bin/tsserver" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../typescript/bin/tsserver" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../typescript/bin/tsserver" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
frontend/node_modules/.bin/vite
generated
vendored
Normal file
16
frontend/node_modules/.bin/vite
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../vite/bin/vite.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../vite/bin/vite.js" "$@"
|
||||
fi
|
||||
17
frontend/node_modules/.bin/vite.cmd
generated
vendored
Normal file
17
frontend/node_modules/.bin/vite.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\vite\bin\vite.js" %*
|
||||
28
frontend/node_modules/.bin/vite.ps1
generated
vendored
Normal file
28
frontend/node_modules/.bin/vite.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../vite/bin/vite.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../vite/bin/vite.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../vite/bin/vite.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../vite/bin/vite.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
536
frontend/node_modules/.package-lock.json
generated
vendored
Normal file
536
frontend/node_modules/.package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,536 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/@oxc-project/types": {
|
||||
"version": "0.124.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz",
|
||||
"integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/Boshen"
|
||||
}
|
||||
},
|
||||
"node_modules/@reduxjs/toolkit": {
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz",
|
||||
"integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@standard-schema/utils": "^0.3.0",
|
||||
"immer": "^11.0.0",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"reselect": "^5.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
|
||||
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-rc.7",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz",
|
||||
"integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@standard-schema/spec": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
||||
"integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@standard-schema/utils": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
|
||||
"integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
||||
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
|
||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
|
||||
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz",
|
||||
"integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rolldown/pluginutils": "1.0.0-rc.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@rolldown/plugin-babel": "^0.1.7 || ^0.2.0",
|
||||
"babel-plugin-react-compiler": "^1.0.0",
|
||||
"vite": "^8.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@rolldown/plugin-babel": {
|
||||
"optional": true
|
||||
},
|
||||
"babel-plugin-react-compiler": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "11.1.4",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz",
|
||||
"integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||
"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"lightningcss-android-arm64": "1.32.0",
|
||||
"lightningcss-darwin-arm64": "1.32.0",
|
||||
"lightningcss-darwin-x64": "1.32.0",
|
||||
"lightningcss-freebsd-x64": "1.32.0",
|
||||
"lightningcss-linux-arm-gnueabihf": "1.32.0",
|
||||
"lightningcss-linux-arm64-gnu": "1.32.0",
|
||||
"lightningcss-linux-arm64-musl": "1.32.0",
|
||||
"lightningcss-linux-x64-gnu": "1.32.0",
|
||||
"lightningcss-linux-x64-musl": "1.32.0",
|
||||
"lightningcss-win32-arm64-msvc": "1.32.0",
|
||||
"lightningcss-win32-x64-msvc": "1.32.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-x64-msvc": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
|
||||
"integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.10",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
|
||||
"integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.2.5",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz",
|
||||
"integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.2.5",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz",
|
||||
"integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.2.5"
|
||||
}
|
||||
},
|
||||
"node_modules/react-redux": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
||||
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/use-sync-external-store": "^0.0.6",
|
||||
"use-sync-external-store": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.2.25 || ^19",
|
||||
"react": "^18.0 || ^19",
|
||||
"redux": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/redux-thunk": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
|
||||
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"redux": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/reselect": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
|
||||
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oxc-project/types": "=0.124.0",
|
||||
"@rolldown/pluginutils": "1.0.0-rc.15"
|
||||
},
|
||||
"bin": {
|
||||
"rolldown": "bin/cli.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rolldown/binding-android-arm64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-darwin-x64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.15",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.15",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15"
|
||||
}
|
||||
},
|
||||
"node_modules/rolldown/node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.16",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
|
||||
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.5.0",
|
||||
"picomatch": "^4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz",
|
||||
"integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
||||
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "8.0.8",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz",
|
||||
"integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lightningcss": "^1.32.0",
|
||||
"picomatch": "^4.0.4",
|
||||
"postcss": "^8.5.8",
|
||||
"rolldown": "1.0.0-rc.15",
|
||||
"tinyglobby": "^0.2.15"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^20.19.0 || >=22.12.0",
|
||||
"@vitejs/devtools": "^0.1.0",
|
||||
"esbuild": "^0.27.0 || ^0.28.0",
|
||||
"jiti": ">=1.21.0",
|
||||
"less": "^4.0.0",
|
||||
"sass": "^1.70.0",
|
||||
"sass-embedded": "^1.70.0",
|
||||
"stylus": ">=0.54.8",
|
||||
"sugarss": "^5.0.0",
|
||||
"terser": "^5.16.0",
|
||||
"tsx": "^4.8.1",
|
||||
"yaml": "^2.4.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitejs/devtools": {
|
||||
"optional": true
|
||||
},
|
||||
"esbuild": {
|
||||
"optional": true
|
||||
},
|
||||
"jiti": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"sass-embedded": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
},
|
||||
"tsx": {
|
||||
"optional": true
|
||||
},
|
||||
"yaml": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
frontend/node_modules/@oxc-project/types/LICENSE
generated
vendored
Normal file
22
frontend/node_modules/@oxc-project/types/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024-present VoidZero Inc. & Contributors
|
||||
Copyright (c) 2023 Boshen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
3
frontend/node_modules/@oxc-project/types/README.md
generated
vendored
Normal file
3
frontend/node_modules/@oxc-project/types/README.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Oxc Types
|
||||
|
||||
Typescript definitions for Oxc AST nodes.
|
||||
26
frontend/node_modules/@oxc-project/types/package.json
generated
vendored
Normal file
26
frontend/node_modules/@oxc-project/types/package.json
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@oxc-project/types",
|
||||
"version": "0.124.0",
|
||||
"description": "Types for Oxc AST nodes",
|
||||
"keywords": [
|
||||
"AST",
|
||||
"Parser"
|
||||
],
|
||||
"homepage": "https://oxc.rs",
|
||||
"bugs": "https://github.com/oxc-project/oxc/issues",
|
||||
"license": "MIT",
|
||||
"author": "Boshen and oxc contributors",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/oxc-project/oxc.git",
|
||||
"directory": "npm/oxc-types"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/Boshen"
|
||||
},
|
||||
"files": [
|
||||
"types.d.ts"
|
||||
],
|
||||
"type": "module",
|
||||
"types": "types.d.ts"
|
||||
}
|
||||
1912
frontend/node_modules/@oxc-project/types/types.d.ts
generated
vendored
Normal file
1912
frontend/node_modules/@oxc-project/types/types.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
21
frontend/node_modules/@reduxjs/toolkit/LICENSE
generated
vendored
Normal file
21
frontend/node_modules/@reduxjs/toolkit/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Mark Erikson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
110
frontend/node_modules/@reduxjs/toolkit/README.md
generated
vendored
Normal file
110
frontend/node_modules/@reduxjs/toolkit/README.md
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
# Redux Toolkit
|
||||
|
||||

|
||||
[](https://www.npmjs.com/package/@reduxjs/toolkit)
|
||||
[](https://www.npmjs.com/package/@reduxjs/toolkit)
|
||||
|
||||
**The official, opinionated, batteries-included toolset for efficient Redux development**
|
||||
|
||||
## Installation
|
||||
|
||||
### Create a React Redux App
|
||||
|
||||
The recommended way to start new apps with React and Redux Toolkit is by using [our official Redux Toolkit + TS template for Vite](https://github.com/reduxjs/redux-templates), or by creating a new Next.js project using [Next's `with-redux` template](https://github.com/vercel/next.js/tree/canary/examples/with-redux).
|
||||
|
||||
Both of these already have Redux Toolkit and React-Redux configured appropriately for that build tool, and come with a small example app that demonstrates how to use several of Redux Toolkit's features.
|
||||
|
||||
```bash
|
||||
# Vite with our Redux+TS template
|
||||
# (using the `degit` tool to clone and extract the template)
|
||||
npx degit reduxjs/redux-templates/packages/vite-template-redux my-app
|
||||
|
||||
# Next.js using the `with-redux` template
|
||||
npx create-next-app --example with-redux my-app
|
||||
```
|
||||
|
||||
We do not currently have official React Native templates, but recommend these templates for standard React Native and for Expo:
|
||||
|
||||
- https://github.com/rahsheen/react-native-template-redux-typescript
|
||||
- https://github.com/rahsheen/expo-template-redux-typescript
|
||||
|
||||
### An Existing App
|
||||
|
||||
Redux Toolkit is available as a package on NPM for use with a module bundler or in a Node application:
|
||||
|
||||
```bash
|
||||
# NPM
|
||||
npm install @reduxjs/toolkit
|
||||
|
||||
# Yarn
|
||||
yarn add @reduxjs/toolkit
|
||||
```
|
||||
|
||||
The package includes a precompiled ESM build that can be used as a [`<script type="module">` tag](https://unpkg.com/@reduxjs/toolkit/dist/redux-toolkit.browser.mjs) directly in the browser.
|
||||
|
||||
## Documentation
|
||||
|
||||
The Redux Toolkit docs are available at **https://redux-toolkit.js.org**, including API references and usage guides for all of the APIs included in Redux Toolkit.
|
||||
|
||||
The Redux core docs at https://redux.js.org includes the full Redux tutorials, as well usage guides on general Redux patterns.
|
||||
|
||||
## Purpose
|
||||
|
||||
The **Redux Toolkit** package is intended to be the standard way to write Redux logic. It was originally created to help address three common concerns about Redux:
|
||||
|
||||
- "Configuring a Redux store is too complicated"
|
||||
- "I have to add a lot of packages to get Redux to do anything useful"
|
||||
- "Redux requires too much boilerplate code"
|
||||
|
||||
We can't solve every use case, but in the spirit of [`create-react-app`](https://github.com/facebook/create-react-app), we can try to provide some tools that abstract over the setup process and handle the most common use cases, as well as include some useful utilities that will let the user simplify their application code.
|
||||
|
||||
Because of that, this package is deliberately limited in scope. It does _not_ address concepts like "reusable encapsulated Redux modules", folder or file structures, managing entity relationships in the store, and so on.
|
||||
|
||||
Redux Toolkit also includes a powerful data fetching and caching capability that we've dubbed "RTK Query". It's included in the package as a separate set of entry points. It's optional, but can eliminate the need to hand-write data fetching logic yourself.
|
||||
|
||||
## What's Included
|
||||
|
||||
Redux Toolkit includes these APIs:
|
||||
|
||||
- `configureStore()`: wraps `createStore` to provide simplified configuration options and good defaults. It can automatically combine your slice reducers, add whatever Redux middleware you supply, includes `redux-thunk` by default, and enables use of the Redux DevTools Extension.
|
||||
- `createReducer()`: lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses the [`immer` library](https://github.com/mweststrate/immer) to let you write simpler immutable updates with normal mutative code, like `state.todos[3].completed = true`.
|
||||
- `createAction()`: generates an action creator function for the given action type string. The function itself has `toString()` defined, so that it can be used in place of the type constant.
|
||||
- `createSlice()`: combines `createReducer()` + `createAction()`. Accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.
|
||||
- `combineSlices()`: combines multiple slices into a single reducer, and allows "lazy loading" of slices after initialisation.
|
||||
- `createListenerMiddleware()`: lets you define "listener" entries that contain an "effect" callback with additional logic, and a way to specify when that callback should run based on dispatched actions or state changes. A lightweight alternative to Redux async middleware like sagas and observables.
|
||||
- `createAsyncThunk()`: accepts an action type string and a function that returns a promise, and generates a thunk that dispatches `pending/resolved/rejected` action types based on that promise
|
||||
- `createEntityAdapter()`: generates a set of reusable reducers and selectors to manage normalized data in the store
|
||||
- The `createSelector()` utility from the [Reselect](https://github.com/reduxjs/reselect) library, re-exported for ease of use.
|
||||
|
||||
For details, see [the Redux Toolkit API Reference section in the docs](https://redux-toolkit.js.org/api/configureStore).
|
||||
|
||||
## RTK Query
|
||||
|
||||
**RTK Query** is provided as an optional addon within the `@reduxjs/toolkit` package. It is purpose-built to solve the use case of data fetching and caching, supplying a compact, but powerful toolset to define an API interface layer for your app. It is intended to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.
|
||||
|
||||
RTK Query is built on top of the Redux Toolkit core for its implementation, using [Redux](https://redux.js.org/) internally for its architecture. Although knowledge of Redux and RTK are not required to use RTK Query, you should explore all of the additional global store management capabilities they provide, as well as installing the [Redux DevTools browser extension](https://github.com/reduxjs/redux-devtools), which works flawlessly with RTK Query to traverse and replay a timeline of your request & cache behavior.
|
||||
|
||||
RTK Query is included within the installation of the core Redux Toolkit package. It is available via either of the two entry points below:
|
||||
|
||||
```ts no-transpile
|
||||
import { createApi } from '@reduxjs/toolkit/query'
|
||||
|
||||
/* React-specific entry point that automatically generates
|
||||
hooks corresponding to the defined endpoints */
|
||||
import { createApi } from '@reduxjs/toolkit/query/react'
|
||||
```
|
||||
|
||||
### What's included
|
||||
|
||||
RTK Query includes these APIs:
|
||||
|
||||
- `createApi()`: The core of RTK Query's functionality. It allows you to define a set of endpoints describe how to retrieve data from a series of endpoints, including configuration of how to fetch and transform that data. In most cases, you should use this once per app, with "one API slice per base URL" as a rule of thumb.
|
||||
- `fetchBaseQuery()`: A small wrapper around fetch that aims to simplify requests. Intended as the recommended baseQuery to be used in createApi for the majority of users.
|
||||
- `<ApiProvider />`: Can be used as a Provider if you do not already have a Redux store.
|
||||
- `setupListeners()`: A utility used to enable refetchOnMount and refetchOnReconnect behaviors.
|
||||
|
||||
See the [**RTK Query Overview**](https://redux-toolkit.js.org/rtk-query/overview) page for more details on what RTK Query is, what problems it solves, and how to use it.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please refer to our [contributing guide](/CONTRIBUTING.md) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to Redux Toolkit.
|
||||
6
frontend/node_modules/@reduxjs/toolkit/dist/cjs/index.js
generated
vendored
Normal file
6
frontend/node_modules/@reduxjs/toolkit/dist/cjs/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict'
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./redux-toolkit.production.min.cjs')
|
||||
} else {
|
||||
module.exports = require('./redux-toolkit.development.cjs')
|
||||
}
|
||||
2387
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.development.cjs
generated
vendored
Normal file
2387
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.development.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.development.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.development.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
3
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.production.min.cjs
generated
vendored
Normal file
3
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.production.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.production.min.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.production.min.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2662
frontend/node_modules/@reduxjs/toolkit/dist/index.d.mts
generated
vendored
Normal file
2662
frontend/node_modules/@reduxjs/toolkit/dist/index.d.mts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2662
frontend/node_modules/@reduxjs/toolkit/dist/index.d.ts
generated
vendored
Normal file
2662
frontend/node_modules/@reduxjs/toolkit/dist/index.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/index.js
generated
vendored
Normal file
6
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict'
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./rtk-query.production.min.cjs')
|
||||
} else {
|
||||
module.exports = require('./rtk-query.development.cjs')
|
||||
}
|
||||
3087
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.development.cjs
generated
vendored
Normal file
3087
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.development.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.development.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.development.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.production.min.cjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.production.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.production.min.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/cjs/rtk-query.production.min.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2954
frontend/node_modules/@reduxjs/toolkit/dist/query/index.d.mts
generated
vendored
Normal file
2954
frontend/node_modules/@reduxjs/toolkit/dist/query/index.d.mts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2954
frontend/node_modules/@reduxjs/toolkit/dist/query/index.d.ts
generated
vendored
Normal file
2954
frontend/node_modules/@reduxjs/toolkit/dist/query/index.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/index.js
generated
vendored
Normal file
6
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict'
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./rtk-query-react.production.min.cjs')
|
||||
} else {
|
||||
module.exports = require('./rtk-query-react.development.cjs')
|
||||
}
|
||||
748
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.development.cjs
generated
vendored
Normal file
748
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.development.cjs
generated
vendored
Normal file
@@ -0,0 +1,748 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/query/react/index.ts
|
||||
var react_exports = {};
|
||||
__export(react_exports, {
|
||||
ApiProvider: () => ApiProvider,
|
||||
UNINITIALIZED_VALUE: () => UNINITIALIZED_VALUE,
|
||||
createApi: () => createApi,
|
||||
reactHooksModule: () => reactHooksModule,
|
||||
reactHooksModuleName: () => reactHooksModuleName
|
||||
});
|
||||
module.exports = __toCommonJS(react_exports);
|
||||
|
||||
// src/query/react/rtkqImports.ts
|
||||
var import_query = require("@reduxjs/toolkit/query");
|
||||
|
||||
// src/query/react/module.ts
|
||||
var import_toolkit2 = require("@reduxjs/toolkit");
|
||||
var import_react_redux2 = require("react-redux");
|
||||
var import_reselect = require("reselect");
|
||||
|
||||
// src/query/utils/capitalize.ts
|
||||
function capitalize(str) {
|
||||
return str.replace(str[0], str[0].toUpperCase());
|
||||
}
|
||||
|
||||
// src/query/utils/countObjectKeys.ts
|
||||
function countObjectKeys(obj) {
|
||||
let count = 0;
|
||||
for (const _key in obj) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// src/query/endpointDefinitions.ts
|
||||
var ENDPOINT_QUERY = "query" /* query */;
|
||||
var ENDPOINT_MUTATION = "mutation" /* mutation */;
|
||||
var ENDPOINT_INFINITEQUERY = "infinitequery" /* infinitequery */;
|
||||
function isQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_QUERY;
|
||||
}
|
||||
function isMutationDefinition(e) {
|
||||
return e.type === ENDPOINT_MUTATION;
|
||||
}
|
||||
function isInfiniteQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_INFINITEQUERY;
|
||||
}
|
||||
|
||||
// src/query/tsHelpers.ts
|
||||
function safeAssign(target, ...args) {
|
||||
return Object.assign(target, ...args);
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
var import_toolkit = require("@reduxjs/toolkit");
|
||||
|
||||
// src/query/react/reactImports.ts
|
||||
var import_react = require("react");
|
||||
|
||||
// src/query/react/reactReduxImports.ts
|
||||
var import_react_redux = require("react-redux");
|
||||
|
||||
// src/query/react/constants.ts
|
||||
var UNINITIALIZED_VALUE = Symbol();
|
||||
|
||||
// src/query/react/useSerializedStableValue.ts
|
||||
function useStableQueryArgs(queryArgs) {
|
||||
const cache = (0, import_react.useRef)(queryArgs);
|
||||
const copy = (0, import_react.useMemo)(() => (0, import_query.copyWithStructuralSharing)(cache.current, queryArgs), [queryArgs]);
|
||||
(0, import_react.useEffect)(() => {
|
||||
if (cache.current !== copy) {
|
||||
cache.current = copy;
|
||||
}
|
||||
}, [copy]);
|
||||
return copy;
|
||||
}
|
||||
|
||||
// src/query/react/useShallowStableValue.ts
|
||||
function useShallowStableValue(value) {
|
||||
const cache = (0, import_react.useRef)(value);
|
||||
(0, import_react.useEffect)(() => {
|
||||
if (!(0, import_react_redux.shallowEqual)(cache.current, value)) {
|
||||
cache.current = value;
|
||||
}
|
||||
}, [value]);
|
||||
return (0, import_react_redux.shallowEqual)(cache.current, value) ? cache.current : value;
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
var canUseDOM = () => !!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined");
|
||||
var isDOM = /* @__PURE__ */ canUseDOM();
|
||||
var isRunningInReactNative = () => typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
||||
var isReactNative = /* @__PURE__ */ isRunningInReactNative();
|
||||
var getUseIsomorphicLayoutEffect = () => isDOM || isReactNative ? import_react.useLayoutEffect : import_react.useEffect;
|
||||
var useIsomorphicLayoutEffect = /* @__PURE__ */ getUseIsomorphicLayoutEffect();
|
||||
var noPendingQueryStateSelector = (selected) => {
|
||||
if (selected.isUninitialized) {
|
||||
return {
|
||||
...selected,
|
||||
isUninitialized: false,
|
||||
isFetching: true,
|
||||
isLoading: selected.data !== void 0 ? false : true,
|
||||
// This is the one place where we still have to use `QueryStatus` as an enum,
|
||||
// since it's the only reference in the React package and not in the core.
|
||||
status: import_query.QueryStatus.pending
|
||||
};
|
||||
}
|
||||
return selected;
|
||||
};
|
||||
function pick(obj, ...keys) {
|
||||
const ret = {};
|
||||
keys.forEach((key) => {
|
||||
ret[key] = obj[key];
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
var COMMON_HOOK_DEBUG_FIELDS = ["data", "status", "isLoading", "isSuccess", "isError", "error"];
|
||||
function buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks: {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
useStore
|
||||
},
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
}) {
|
||||
const usePossiblyImmediateEffect = unstable__sideEffectsInRender ? (cb) => cb() : import_react.useEffect;
|
||||
const unsubscribePromiseRef = (ref) => ref.current?.unsubscribe?.();
|
||||
const endpointDefinitions = context.endpointDefinitions;
|
||||
return {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
};
|
||||
function queryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if (lastResult?.endpointName && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== import_query.skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult?.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || hasData && (isFetching && !lastResult?.isError || currentState.isUninitialized);
|
||||
return {
|
||||
...currentState,
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
};
|
||||
}
|
||||
function infiniteQueryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if (lastResult?.endpointName && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== import_query.skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult?.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || isFetching && hasData;
|
||||
return {
|
||||
...currentState,
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
};
|
||||
}
|
||||
function usePrefetch(endpointName, defaultOptions) {
|
||||
const dispatch = useDispatch();
|
||||
const stableDefaultOptions = useShallowStableValue(defaultOptions);
|
||||
return (0, import_react.useCallback)((arg, options) => dispatch(api.util.prefetch(endpointName, arg, {
|
||||
...stableDefaultOptions,
|
||||
...options
|
||||
})), [endpointName, dispatch, stableDefaultOptions]);
|
||||
}
|
||||
function useQuerySubscriptionCommonImpl(endpointName, arg, {
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
refetchOnMountOrArgChange,
|
||||
skip = false,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false,
|
||||
...rest
|
||||
} = {}) {
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const subscriptionSelectorsRef = (0, import_react.useRef)(void 0);
|
||||
if (!subscriptionSelectorsRef.current) {
|
||||
const returnedValue = dispatch(api.internalActions.internal_getRTKQSubscriptions());
|
||||
if (true) {
|
||||
if (typeof returnedValue !== "object" || typeof returnedValue?.type === "string") {
|
||||
throw new Error(false ? _formatProdErrorMessage(37) : `Warning: Middleware for RTK-Query API at reducerPath "${api.reducerPath}" has not been added to the store.
|
||||
You must add the middleware for RTK-Query to function correctly!`);
|
||||
}
|
||||
}
|
||||
subscriptionSelectorsRef.current = returnedValue;
|
||||
}
|
||||
const stableArg = useStableQueryArgs(skip ? import_query.skipToken : arg);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
const initialPageParam = rest.initialPageParam;
|
||||
const stableInitialPageParam = useShallowStableValue(initialPageParam);
|
||||
const refetchCachedPages = rest.refetchCachedPages;
|
||||
const stableRefetchCachedPages = useShallowStableValue(refetchCachedPages);
|
||||
const promiseRef = (0, import_react.useRef)(void 0);
|
||||
let {
|
||||
queryCacheKey,
|
||||
requestId
|
||||
} = promiseRef.current || {};
|
||||
let currentRenderHasSubscription = false;
|
||||
if (queryCacheKey && requestId) {
|
||||
currentRenderHasSubscription = subscriptionSelectorsRef.current.isRequestSubscribed(queryCacheKey, requestId);
|
||||
}
|
||||
const subscriptionRemoved = !currentRenderHasSubscription && promiseRef.current !== void 0;
|
||||
usePossiblyImmediateEffect(() => {
|
||||
if (subscriptionRemoved) {
|
||||
promiseRef.current = void 0;
|
||||
}
|
||||
}, [subscriptionRemoved]);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
const lastPromise = promiseRef.current;
|
||||
if (typeof process !== "undefined" && false) {
|
||||
console.log(subscriptionRemoved);
|
||||
}
|
||||
if (stableArg === import_query.skipToken) {
|
||||
lastPromise?.unsubscribe();
|
||||
promiseRef.current = void 0;
|
||||
return;
|
||||
}
|
||||
const lastSubscriptionOptions = promiseRef.current?.subscriptionOptions;
|
||||
if (!lastPromise || lastPromise.arg !== stableArg) {
|
||||
lastPromise?.unsubscribe();
|
||||
const promise = dispatch(initiate(stableArg, {
|
||||
subscriptionOptions: stableSubscriptionOptions,
|
||||
forceRefetch: refetchOnMountOrArgChange,
|
||||
...isInfiniteQueryDefinition(endpointDefinitions[endpointName]) ? {
|
||||
initialPageParam: stableInitialPageParam,
|
||||
refetchCachedPages: stableRefetchCachedPages
|
||||
} : {}
|
||||
}));
|
||||
promiseRef.current = promise;
|
||||
} else if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
lastPromise.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [dispatch, initiate, refetchOnMountOrArgChange, stableArg, stableSubscriptionOptions, subscriptionRemoved, stableInitialPageParam, stableRefetchCachedPages, endpointName]);
|
||||
return [promiseRef, dispatch, initiate, stableSubscriptionOptions];
|
||||
}
|
||||
function buildUseQueryState(endpointName, preSelector) {
|
||||
const useQueryState = (arg, {
|
||||
skip = false,
|
||||
selectFromResult
|
||||
} = {}) => {
|
||||
const {
|
||||
select
|
||||
} = api.endpoints[endpointName];
|
||||
const stableArg = useStableQueryArgs(skip ? import_query.skipToken : arg);
|
||||
const lastValue = (0, import_react.useRef)(void 0);
|
||||
const selectDefaultResult = (0, import_react.useMemo)(() => (
|
||||
// Normally ts-ignores are bad and should be avoided, but we're
|
||||
// already casting this selector to be `Selector<any>` anyway,
|
||||
// so the inconsistencies don't matter here
|
||||
// @ts-ignore
|
||||
createSelector([
|
||||
// @ts-ignore
|
||||
select(stableArg),
|
||||
(_, lastResult) => lastResult,
|
||||
(_) => stableArg
|
||||
], preSelector, {
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: import_react_redux.shallowEqual
|
||||
}
|
||||
})
|
||||
), [select, stableArg]);
|
||||
const querySelector = (0, import_react.useMemo)(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult, {
|
||||
devModeChecks: {
|
||||
identityFunctionCheck: "never"
|
||||
}
|
||||
}) : selectDefaultResult, [selectDefaultResult, selectFromResult]);
|
||||
const currentState = useSelector((state) => querySelector(state, lastValue.current), import_react_redux.shallowEqual);
|
||||
const store = useStore();
|
||||
const newLastValue = selectDefaultResult(store.getState(), lastValue.current);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
lastValue.current = newLastValue;
|
||||
}, [newLastValue]);
|
||||
return currentState;
|
||||
};
|
||||
return useQueryState;
|
||||
}
|
||||
function usePromiseRefUnsubscribeOnUnmount(promiseRef) {
|
||||
(0, import_react.useEffect)(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = void 0;
|
||||
};
|
||||
}, [promiseRef]);
|
||||
}
|
||||
function refetchOrErrorIfUnmounted(promiseRef) {
|
||||
if (!promiseRef.current) throw new Error(false ? _formatProdErrorMessage2(38) : "Cannot refetch a query that has not been started yet.");
|
||||
return promiseRef.current.refetch();
|
||||
}
|
||||
function buildQueryHooks(endpointName) {
|
||||
const useQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
return (0, import_react.useMemo)(() => ({
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch: () => refetchOrErrorIfUnmounted(promiseRef)
|
||||
}), [promiseRef]);
|
||||
};
|
||||
const useLazyQuerySubscription = ({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false
|
||||
} = {}) => {
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const [arg, setArg] = (0, import_react.useState)(UNINITIALIZED_VALUE);
|
||||
const promiseRef = (0, import_react.useRef)(void 0);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
usePossiblyImmediateEffect(() => {
|
||||
const lastSubscriptionOptions = promiseRef.current?.subscriptionOptions;
|
||||
if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
promiseRef.current?.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [stableSubscriptionOptions]);
|
||||
const subscriptionOptionsRef = (0, import_react.useRef)(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const trigger = (0, import_react.useCallback)(function(arg2, preferCacheValue = false) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
forceRefetch: !preferCacheValue
|
||||
}));
|
||||
setArg(arg2);
|
||||
});
|
||||
return promise;
|
||||
}, [dispatch, initiate]);
|
||||
const reset = (0, import_react.useCallback)(() => {
|
||||
if (promiseRef.current?.queryCacheKey) {
|
||||
dispatch(api.internalActions.removeQueryResult({
|
||||
queryCacheKey: promiseRef.current?.queryCacheKey
|
||||
}));
|
||||
}
|
||||
}, [dispatch]);
|
||||
(0, import_react.useEffect)(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
};
|
||||
}, []);
|
||||
(0, import_react.useEffect)(() => {
|
||||
if (arg !== UNINITIALIZED_VALUE && !promiseRef.current) {
|
||||
trigger(arg, true);
|
||||
}
|
||||
}, [arg, trigger]);
|
||||
return (0, import_react.useMemo)(() => [trigger, arg, {
|
||||
reset
|
||||
}], [trigger, arg, reset]);
|
||||
};
|
||||
const useQueryState = buildUseQueryState(endpointName, queryStatePreSelector);
|
||||
return {
|
||||
useQueryState,
|
||||
useQuerySubscription,
|
||||
useLazyQuerySubscription,
|
||||
useLazyQuery(options) {
|
||||
const [trigger, arg, {
|
||||
reset
|
||||
}] = useLazyQuerySubscription(options);
|
||||
const queryStateResults = useQueryState(arg, {
|
||||
...options,
|
||||
skip: arg === UNINITIALIZED_VALUE
|
||||
});
|
||||
const info = (0, import_react.useMemo)(() => ({
|
||||
lastArg: arg
|
||||
}), [arg]);
|
||||
return (0, import_react.useMemo)(() => [trigger, {
|
||||
...queryStateResults,
|
||||
reset
|
||||
}, info], [trigger, queryStateResults, reset, info]);
|
||||
},
|
||||
useQuery(arg, options) {
|
||||
const querySubscriptionResults = useQuerySubscription(arg, options);
|
||||
const queryStateResults = useQueryState(arg, {
|
||||
selectFromResult: arg === import_query.skipToken || options?.skip ? void 0 : noPendingQueryStateSelector,
|
||||
...options
|
||||
});
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS);
|
||||
(0, import_react.useDebugValue)(debugValue);
|
||||
return (0, import_react.useMemo)(() => ({
|
||||
...queryStateResults,
|
||||
...querySubscriptionResults
|
||||
}), [queryStateResults, querySubscriptionResults]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildInfiniteQueryHooks(endpointName) {
|
||||
const useInfiniteQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef, dispatch, initiate, stableSubscriptionOptions] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
const subscriptionOptionsRef = (0, import_react.useRef)(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const hookRefetchCachedPages = options.refetchCachedPages;
|
||||
const stableHookRefetchCachedPages = useShallowStableValue(hookRefetchCachedPages);
|
||||
const trigger = (0, import_react.useCallback)(function(arg2, direction) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
direction
|
||||
}));
|
||||
});
|
||||
return promise;
|
||||
}, [promiseRef, dispatch, initiate]);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
const stableArg = useStableQueryArgs(options.skip ? import_query.skipToken : arg);
|
||||
const refetch = (0, import_react.useCallback)((options2) => {
|
||||
if (!promiseRef.current) throw new Error(false ? _formatProdErrorMessage3(38) : "Cannot refetch a query that has not been started yet.");
|
||||
const mergedOptions = {
|
||||
refetchCachedPages: options2?.refetchCachedPages ?? stableHookRefetchCachedPages
|
||||
};
|
||||
return promiseRef.current.refetch(mergedOptions);
|
||||
}, [promiseRef, stableHookRefetchCachedPages]);
|
||||
return (0, import_react.useMemo)(() => {
|
||||
const fetchNextPage = () => {
|
||||
return trigger(stableArg, "forward");
|
||||
};
|
||||
const fetchPreviousPage = () => {
|
||||
return trigger(stableArg, "backward");
|
||||
};
|
||||
return {
|
||||
trigger,
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
};
|
||||
}, [refetch, trigger, stableArg]);
|
||||
};
|
||||
const useInfiniteQueryState = buildUseQueryState(endpointName, infiniteQueryStatePreSelector);
|
||||
return {
|
||||
useInfiniteQueryState,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQuery(arg, options) {
|
||||
const {
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
} = useInfiniteQuerySubscription(arg, options);
|
||||
const queryStateResults = useInfiniteQueryState(arg, {
|
||||
selectFromResult: arg === import_query.skipToken || options?.skip ? void 0 : noPendingQueryStateSelector,
|
||||
...options
|
||||
});
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS, "hasNextPage", "hasPreviousPage");
|
||||
(0, import_react.useDebugValue)(debugValue);
|
||||
return (0, import_react.useMemo)(() => ({
|
||||
...queryStateResults,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage,
|
||||
refetch
|
||||
}), [queryStateResults, fetchNextPage, fetchPreviousPage, refetch]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildMutationHook(name) {
|
||||
return ({
|
||||
selectFromResult,
|
||||
fixedCacheKey
|
||||
} = {}) => {
|
||||
const {
|
||||
select,
|
||||
initiate
|
||||
} = api.endpoints[name];
|
||||
const dispatch = useDispatch();
|
||||
const [promise, setPromise] = (0, import_react.useState)();
|
||||
(0, import_react.useEffect)(() => () => {
|
||||
if (!promise?.arg.fixedCacheKey) {
|
||||
promise?.reset();
|
||||
}
|
||||
}, [promise]);
|
||||
const triggerMutation = (0, import_react.useCallback)(function(arg) {
|
||||
const promise2 = dispatch(initiate(arg, {
|
||||
fixedCacheKey
|
||||
}));
|
||||
setPromise(promise2);
|
||||
return promise2;
|
||||
}, [dispatch, initiate, fixedCacheKey]);
|
||||
const {
|
||||
requestId
|
||||
} = promise || {};
|
||||
const selectDefaultResult = (0, import_react.useMemo)(() => select({
|
||||
fixedCacheKey,
|
||||
requestId: promise?.requestId
|
||||
}), [fixedCacheKey, promise, select]);
|
||||
const mutationSelector = (0, import_react.useMemo)(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult) : selectDefaultResult, [selectFromResult, selectDefaultResult]);
|
||||
const currentState = useSelector(mutationSelector, import_react_redux.shallowEqual);
|
||||
const originalArgs = fixedCacheKey == null ? promise?.arg.originalArgs : void 0;
|
||||
const reset = (0, import_react.useCallback)(() => {
|
||||
batch(() => {
|
||||
if (promise) {
|
||||
setPromise(void 0);
|
||||
}
|
||||
if (fixedCacheKey) {
|
||||
dispatch(api.internalActions.removeMutationResult({
|
||||
requestId,
|
||||
fixedCacheKey
|
||||
}));
|
||||
}
|
||||
});
|
||||
}, [dispatch, fixedCacheKey, promise, requestId]);
|
||||
const debugValue = pick(currentState, ...COMMON_HOOK_DEBUG_FIELDS, "endpointName");
|
||||
(0, import_react.useDebugValue)(debugValue);
|
||||
const finalState = (0, import_react.useMemo)(() => ({
|
||||
...currentState,
|
||||
originalArgs,
|
||||
reset
|
||||
}), [currentState, originalArgs, reset]);
|
||||
return (0, import_react.useMemo)(() => [triggerMutation, finalState], [triggerMutation, finalState]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// src/query/react/module.ts
|
||||
var reactHooksModuleName = /* @__PURE__ */ Symbol();
|
||||
var reactHooksModule = ({
|
||||
batch = import_react_redux2.batch,
|
||||
hooks = {
|
||||
useDispatch: import_react_redux2.useDispatch,
|
||||
useSelector: import_react_redux2.useSelector,
|
||||
useStore: import_react_redux2.useStore
|
||||
},
|
||||
createSelector = import_reselect.createSelector,
|
||||
unstable__sideEffectsInRender = false,
|
||||
...rest
|
||||
} = {}) => {
|
||||
if (true) {
|
||||
const hookNames = ["useDispatch", "useSelector", "useStore"];
|
||||
let warned = false;
|
||||
for (const hookName of hookNames) {
|
||||
if (countObjectKeys(rest) > 0) {
|
||||
if (rest[hookName]) {
|
||||
if (!warned) {
|
||||
console.warn("As of RTK 2.0, the hooks now need to be specified as one object, provided under a `hooks` key:\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`");
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
hooks[hookName] = rest[hookName];
|
||||
}
|
||||
if (typeof hooks[hookName] !== "function") {
|
||||
throw new Error(false ? _formatProdErrorMessage4(36) : `When using custom hooks for context, all ${hookNames.length} hooks need to be provided: ${hookNames.join(", ")}.
|
||||
Hook ${hookName} was either not provided or not a function.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: reactHooksModuleName,
|
||||
init(api, {
|
||||
serializeQueryArgs
|
||||
}, context) {
|
||||
const anyApi = api;
|
||||
const {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
} = buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks,
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
});
|
||||
safeAssign(anyApi, {
|
||||
usePrefetch
|
||||
});
|
||||
safeAssign(context, {
|
||||
batch
|
||||
});
|
||||
return {
|
||||
injectEndpoint(endpointName, definition) {
|
||||
if (isQueryDefinition(definition)) {
|
||||
const {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
} = buildQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Query`] = useQuery;
|
||||
api[`useLazy${capitalize(endpointName)}Query`] = useLazyQuery;
|
||||
}
|
||||
if (isMutationDefinition(definition)) {
|
||||
const useMutation = buildMutationHook(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useMutation
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Mutation`] = useMutation;
|
||||
} else if (isInfiniteQueryDefinition(definition)) {
|
||||
const {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
} = buildInfiniteQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
});
|
||||
api[`use${capitalize(endpointName)}InfiniteQuery`] = useInfiniteQuery;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/query/react/index.ts
|
||||
__reExport(react_exports, require("@reduxjs/toolkit/query"), module.exports);
|
||||
|
||||
// src/query/react/ApiProvider.tsx
|
||||
var import_toolkit3 = require("@reduxjs/toolkit");
|
||||
var React = __toESM(require("react"));
|
||||
function ApiProvider(props) {
|
||||
const context = props.context || import_react_redux.ReactReduxContext;
|
||||
const existingContext = (0, import_react.useContext)(context);
|
||||
if (existingContext) {
|
||||
throw new Error(false ? _formatProdErrorMessage5(35) : "Existing Redux context detected. If you already have a store set up, please use the traditional Redux setup.");
|
||||
}
|
||||
const [store] = React.useState(() => (0, import_toolkit3.configureStore)({
|
||||
reducer: {
|
||||
[props.api.reducerPath]: props.api.reducer
|
||||
},
|
||||
middleware: (gDM) => gDM().concat(props.api.middleware)
|
||||
}));
|
||||
(0, import_react.useEffect)(() => props.setupListeners === false ? void 0 : (0, import_query.setupListeners)(store.dispatch, props.setupListeners), [props.setupListeners, store.dispatch]);
|
||||
return /* @__PURE__ */ React.createElement(import_react_redux.Provider, { store, context }, props.children);
|
||||
}
|
||||
|
||||
// src/query/react/index.ts
|
||||
var createApi = /* @__PURE__ */ (0, import_query.buildCreateApi)((0, import_query.coreModule)(), reactHooksModule());
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
ApiProvider,
|
||||
UNINITIALIZED_VALUE,
|
||||
createApi,
|
||||
reactHooksModule,
|
||||
reactHooksModuleName,
|
||||
...require("@reduxjs/toolkit/query")
|
||||
});
|
||||
//# sourceMappingURL=rtk-query-react.development.cjs.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.development.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.development.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.production.min.cjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.production.min.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.production.min.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/cjs/rtk-query-react.production.min.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
980
frontend/node_modules/@reduxjs/toolkit/dist/query/react/index.d.mts
generated
vendored
Normal file
980
frontend/node_modules/@reduxjs/toolkit/dist/query/react/index.d.mts
generated
vendored
Normal file
@@ -0,0 +1,980 @@
|
||||
import * as _reduxjs_toolkit_query from '@reduxjs/toolkit/query';
|
||||
import { QueryDefinition, TSHelpersId, TSHelpersOverride, QuerySubState, ResultTypeFrom, QueryStatus, QueryArgFrom, SkipToken, SubscriptionOptions, TSHelpersNoInfer, QueryActionCreatorResult, MutationDefinition, MutationResultSelectorResult, MutationActionCreatorResult, InfiniteQueryDefinition, InfiniteQuerySubState, PageParamFrom, InfiniteQueryArgFrom, InfiniteQueryActionCreatorResult, BaseQueryFn, EndpointDefinitions, DefinitionType, QueryKeys, PrefetchOptions, Module, Api, setupListeners } from '@reduxjs/toolkit/query';
|
||||
export * from '@reduxjs/toolkit/query';
|
||||
import * as react_redux from 'react-redux';
|
||||
import { ReactReduxContextValue } from 'react-redux';
|
||||
import { CreateSelectorFunction } from 'reselect';
|
||||
import * as React from 'react';
|
||||
import { Context } from 'react';
|
||||
|
||||
type InfiniteData<DataType, PageParam> = {
|
||||
pages: Array<DataType>;
|
||||
pageParams: Array<PageParam>;
|
||||
};
|
||||
type InfiniteQueryDirection = 'forward' | 'backward';
|
||||
|
||||
export declare const UNINITIALIZED_VALUE: unique symbol;
|
||||
type UninitializedValue = typeof UNINITIALIZED_VALUE;
|
||||
|
||||
type QueryHooks<Definition extends QueryDefinition<any, any, any, any, any>> = {
|
||||
useQuery: UseQuery<Definition>;
|
||||
useLazyQuery: UseLazyQuery<Definition>;
|
||||
useQuerySubscription: UseQuerySubscription<Definition>;
|
||||
useLazyQuerySubscription: UseLazyQuerySubscription<Definition>;
|
||||
useQueryState: UseQueryState<Definition>;
|
||||
};
|
||||
type InfiniteQueryHooks<Definition extends InfiniteQueryDefinition<any, any, any, any, any>> = {
|
||||
useInfiniteQuery: UseInfiniteQuery<Definition>;
|
||||
useInfiniteQuerySubscription: UseInfiniteQuerySubscription<Definition>;
|
||||
useInfiniteQueryState: UseInfiniteQueryState<Definition>;
|
||||
};
|
||||
type MutationHooks<Definition extends MutationDefinition<any, any, any, any, any>> = {
|
||||
useMutation: UseMutation<Definition>;
|
||||
};
|
||||
/**
|
||||
* A React hook that automatically triggers fetches of data from an endpoint, 'subscribes' the component to the cached data, and reads the request status and cached data from the Redux store. The component will re-render as the loading status changes and the data becomes available.
|
||||
*
|
||||
* The query arg is used as a cache key. Changing the query arg will tell the hook to re-fetch the data if it does not exist in the cache already, and the hook will return the data for that query arg once it's available.
|
||||
*
|
||||
* This hook combines the functionality of both [`useQueryState`](#usequerystate) and [`useQuerySubscription`](#usequerysubscription) together, and is intended to be used in the majority of situations.
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Automatically triggers requests to retrieve data based on the hook argument and whether cached data exists by default
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
*/
|
||||
type UseQuery<D extends QueryDefinition<any, any, any, any>> = <R extends Record<string, any> = UseQueryStateDefaultResult<D>>(arg: QueryArgFrom<D> | SkipToken, options?: UseQuerySubscriptionOptions & UseQueryStateOptions<D, R>) => UseQueryHookResult<D, R>;
|
||||
type TypedUseQuery<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseQuery<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
type UseQueryHookResult<D extends QueryDefinition<any, any, any, any>, R = UseQueryStateDefaultResult<D>> = UseQueryStateResult<D, R> & UseQuerySubscriptionResult<D>;
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useQuery` hook in userland code.
|
||||
*/
|
||||
type TypedUseQueryHookResult<ResultType, QueryArg, BaseQuery extends BaseQueryFn, R = UseQueryStateDefaultResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>> = TypedUseQueryStateResult<ResultType, QueryArg, BaseQuery, R> & TypedUseQuerySubscriptionResult<ResultType, QueryArg, BaseQuery>;
|
||||
type UseQuerySubscriptionOptions = SubscriptionOptions & {
|
||||
/**
|
||||
* Prevents a query from automatically running.
|
||||
*
|
||||
* @remarks
|
||||
* When `skip` is true (or `skipToken` is passed in as `arg`):
|
||||
*
|
||||
* - **If the query has cached data:**
|
||||
* * The cached data **will not be used** on the initial load, and will ignore updates from any identical query until the `skip` condition is removed
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * If `skip: false` is set after the initial load, the cached result will be used
|
||||
* - **If the query does not have cached data:**
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * The query will not exist in the state when viewed with the dev tools
|
||||
* * The query will not automatically fetch on mount
|
||||
* * The query will not automatically run when additional components with the same query are added that do run
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* // codeblock-meta no-transpile title="Skip example"
|
||||
* const Pokemon = ({ name, skip }: { name: string; skip: boolean }) => {
|
||||
* const { data, error, status } = useGetPokemonByNameQuery(name, {
|
||||
* skip,
|
||||
* });
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* {name} - {status}
|
||||
* </div>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
skip?: boolean;
|
||||
/**
|
||||
* Defaults to `false`. This setting allows you to control whether if a cached result is already available, RTK Query will only serve a cached result, or if it should `refetch` when set to `true` or if an adequate amount of time has passed since the last successful query result.
|
||||
* - `false` - Will not cause a query to be performed _unless_ it does not exist yet.
|
||||
* - `true` - Will always refetch when a new subscriber to a query is added. Behaves the same as calling the `refetch` callback or passing `forceRefetch: true` in the action creator.
|
||||
* - `number` - **Value is in seconds**. If a number is provided and there is an existing query in the cache, it will compare the current time vs the last fulfilled timestamp, and only refetch if enough time has elapsed.
|
||||
*
|
||||
* If you specify this option alongside `skip: true`, this **will not be evaluated** until `skip` is false.
|
||||
*/
|
||||
refetchOnMountOrArgChange?: boolean | number;
|
||||
};
|
||||
/**
|
||||
* A React hook that automatically triggers fetches of data from an endpoint, and 'subscribes' the component to the cached data.
|
||||
*
|
||||
* The query arg is used as a cache key. Changing the query arg will tell the hook to re-fetch the data if it does not exist in the cache already.
|
||||
*
|
||||
* Note that this hook does not return a request status or cached data. For that use-case, see [`useQuery`](#usequery) or [`useQueryState`](#usequerystate).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Automatically triggers requests to retrieve data based on the hook argument and whether cached data exists by default
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met
|
||||
*/
|
||||
type UseQuerySubscription<D extends QueryDefinition<any, any, any, any>> = (arg: QueryArgFrom<D> | SkipToken, options?: UseQuerySubscriptionOptions) => UseQuerySubscriptionResult<D>;
|
||||
type TypedUseQuerySubscription<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseQuerySubscription<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
type UseQuerySubscriptionResult<D extends QueryDefinition<any, any, any, any>> = Pick<QueryActionCreatorResult<D>, 'refetch'>;
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useQuerySubscription` hook in userland code.
|
||||
*/
|
||||
type TypedUseQuerySubscriptionResult<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseQuerySubscriptionResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
type UseLazyQueryLastPromiseInfo<D extends QueryDefinition<any, any, any, any>> = {
|
||||
lastArg: QueryArgFrom<D>;
|
||||
};
|
||||
/**
|
||||
* A React hook similar to [`useQuery`](#usequery), but with manual control over when the data fetching occurs.
|
||||
*
|
||||
* This hook includes the functionality of [`useLazyQuerySubscription`](#uselazyquerysubscription).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Manual control over firing a request to retrieve data
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met and the fetch has been manually called at least once
|
||||
*
|
||||
* #### Note
|
||||
*
|
||||
* When the trigger function returned from a LazyQuery is called, it always initiates a new request to the server even if there is cached data. Set `preferCacheValue`(the second argument to the function) as `true` if you want it to immediately return a cached value if one exists.
|
||||
*/
|
||||
type UseLazyQuery<D extends QueryDefinition<any, any, any, any>> = <R extends Record<string, any> = UseQueryStateDefaultResult<D>>(options?: SubscriptionOptions & Omit<UseQueryStateOptions<D, R>, 'skip'>) => [
|
||||
LazyQueryTrigger<D>,
|
||||
UseLazyQueryStateResult<D, R>,
|
||||
UseLazyQueryLastPromiseInfo<D>
|
||||
];
|
||||
type TypedUseLazyQuery<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseLazyQuery<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
type UseLazyQueryStateResult<D extends QueryDefinition<any, any, any, any>, R = UseQueryStateDefaultResult<D>> = UseQueryStateResult<D, R> & {
|
||||
/**
|
||||
* Resets the hook state to its initial `uninitialized` state.
|
||||
* This will also remove the last result from the cache.
|
||||
*/
|
||||
reset: () => void;
|
||||
};
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useLazyQuery` hook in userland code.
|
||||
*/
|
||||
type TypedUseLazyQueryStateResult<ResultType, QueryArg, BaseQuery extends BaseQueryFn, R = UseQueryStateDefaultResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>> = UseLazyQueryStateResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>, R>;
|
||||
type LazyQueryTrigger<D extends QueryDefinition<any, any, any, any>> = {
|
||||
/**
|
||||
* Triggers a lazy query.
|
||||
*
|
||||
* By default, this will start a new request even if there is already a value in the cache.
|
||||
* If you want to use the cache value and only start a request if there is no cache value, set the second argument to `true`.
|
||||
*
|
||||
* @remarks
|
||||
* If you need to access the error or success payload immediately after a lazy query, you can chain .unwrap().
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Using .unwrap with async await"
|
||||
* try {
|
||||
* const payload = await getUserById(1).unwrap();
|
||||
* console.log('fulfilled', payload)
|
||||
* } catch (error) {
|
||||
* console.error('rejected', error);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
(arg: QueryArgFrom<D>, preferCacheValue?: boolean): QueryActionCreatorResult<D>;
|
||||
};
|
||||
type TypedLazyQueryTrigger<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = LazyQueryTrigger<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* A React hook similar to [`useQuerySubscription`](#usequerysubscription), but with manual control over when the data fetching occurs.
|
||||
*
|
||||
* Note that this hook does not return a request status or cached data. For that use-case, see [`useLazyQuery`](#uselazyquery).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Manual control over firing a request to retrieve data
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met and the fetch has been manually called at least once
|
||||
*/
|
||||
type UseLazyQuerySubscription<D extends QueryDefinition<any, any, any, any>> = (options?: SubscriptionOptions) => readonly [
|
||||
LazyQueryTrigger<D>,
|
||||
QueryArgFrom<D> | UninitializedValue,
|
||||
{
|
||||
reset: () => void;
|
||||
}
|
||||
];
|
||||
type TypedUseLazyQuerySubscription<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseLazyQuerySubscription<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
type QueryStateSelector<R extends Record<string, any>, D extends QueryDefinition<any, any, any, any>> = (state: UseQueryStateDefaultResult<D>) => R;
|
||||
/**
|
||||
* Provides a way to define a strongly-typed version of
|
||||
* {@linkcode QueryStateSelector} for use with a specific query.
|
||||
* This is useful for scenarios where you want to create a "pre-typed"
|
||||
* {@linkcode UseQueryStateOptions.selectFromResult | selectFromResult}
|
||||
* function.
|
||||
*
|
||||
* @example
|
||||
* <caption>#### __Create a strongly-typed `selectFromResult` selector function__</caption>
|
||||
*
|
||||
* ```tsx
|
||||
* import type { TypedQueryStateSelector } from '@reduxjs/toolkit/query/react'
|
||||
* import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
*
|
||||
* type Post = {
|
||||
* id: number
|
||||
* title: string
|
||||
* }
|
||||
*
|
||||
* type PostsApiResponse = {
|
||||
* posts: Post[]
|
||||
* total: number
|
||||
* skip: number
|
||||
* limit: number
|
||||
* }
|
||||
*
|
||||
* type QueryArgument = number | undefined
|
||||
*
|
||||
* type BaseQueryFunction = ReturnType<typeof fetchBaseQuery>
|
||||
*
|
||||
* type SelectedResult = Pick<PostsApiResponse, 'posts'>
|
||||
*
|
||||
* const postsApiSlice = createApi({
|
||||
* baseQuery: fetchBaseQuery({ baseUrl: 'https://dummyjson.com/posts' }),
|
||||
* reducerPath: 'postsApi',
|
||||
* tagTypes: ['Posts'],
|
||||
* endpoints: (build) => ({
|
||||
* getPosts: build.query<PostsApiResponse, QueryArgument>({
|
||||
* query: (limit = 5) => `?limit=${limit}&select=title`,
|
||||
* }),
|
||||
* }),
|
||||
* })
|
||||
*
|
||||
* const { useGetPostsQuery } = postsApiSlice
|
||||
*
|
||||
* function PostById({ id }: { id: number }) {
|
||||
* const { post } = useGetPostsQuery(undefined, {
|
||||
* selectFromResult: (state) => ({
|
||||
* post: state.data?.posts.find((post) => post.id === id),
|
||||
* }),
|
||||
* })
|
||||
*
|
||||
* return <li>{post?.title}</li>
|
||||
* }
|
||||
*
|
||||
* const EMPTY_ARRAY: Post[] = []
|
||||
*
|
||||
* const typedSelectFromResult: TypedQueryStateSelector<
|
||||
* PostsApiResponse,
|
||||
* QueryArgument,
|
||||
* BaseQueryFunction,
|
||||
* SelectedResult
|
||||
* > = (state) => ({ posts: state.data?.posts ?? EMPTY_ARRAY })
|
||||
*
|
||||
* function PostsList() {
|
||||
* const { posts } = useGetPostsQuery(undefined, {
|
||||
* selectFromResult: typedSelectFromResult,
|
||||
* })
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* <ul>
|
||||
* {posts.map((post) => (
|
||||
* <PostById key={post.id} id={post.id} />
|
||||
* ))}
|
||||
* </ul>
|
||||
* </div>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @template ResultType - The type of the result `data` returned by the query.
|
||||
* @template QueryArgumentType - The type of the argument passed into the query.
|
||||
* @template BaseQueryFunctionType - The type of the base query function being used.
|
||||
* @template SelectedResultType - The type of the selected result returned by the __`selectFromResult`__ function.
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @public
|
||||
*/
|
||||
type TypedQueryStateSelector<ResultType, QueryArgumentType, BaseQueryFunctionType extends BaseQueryFn, SelectedResultType extends Record<string, any> = UseQueryStateDefaultResult<QueryDefinition<QueryArgumentType, BaseQueryFunctionType, string, ResultType, string>>> = QueryStateSelector<SelectedResultType, QueryDefinition<QueryArgumentType, BaseQueryFunctionType, string, ResultType, string>>;
|
||||
/**
|
||||
* A React hook that reads the request status and cached data from the Redux store. The component will re-render as the loading status changes and the data becomes available.
|
||||
*
|
||||
* Note that this hook does not trigger fetching new data. For that use-case, see [`useQuery`](#usequery) or [`useQuerySubscription`](#usequerysubscription).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
*/
|
||||
type UseQueryState<D extends QueryDefinition<any, any, any, any>> = <R extends Record<string, any> = UseQueryStateDefaultResult<D>>(arg: QueryArgFrom<D> | SkipToken, options?: UseQueryStateOptions<D, R>) => UseQueryStateResult<D, R>;
|
||||
type TypedUseQueryState<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseQueryState<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
type UseQueryStateOptions<D extends QueryDefinition<any, any, any, any>, R extends Record<string, any>> = {
|
||||
/**
|
||||
* Prevents a query from automatically running.
|
||||
*
|
||||
* @remarks
|
||||
* When skip is true:
|
||||
*
|
||||
* - **If the query has cached data:**
|
||||
* * The cached data **will not be used** on the initial load, and will ignore updates from any identical query until the `skip` condition is removed
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * If `skip: false` is set after skipping the initial load, the cached result will be used
|
||||
* - **If the query does not have cached data:**
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * The query will not exist in the state when viewed with the dev tools
|
||||
* * The query will not automatically fetch on mount
|
||||
* * The query will not automatically run when additional components with the same query are added that do run
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Skip example"
|
||||
* const Pokemon = ({ name, skip }: { name: string; skip: boolean }) => {
|
||||
* const { data, error, status } = useGetPokemonByNameQuery(name, {
|
||||
* skip,
|
||||
* });
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* {name} - {status}
|
||||
* </div>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
skip?: boolean;
|
||||
/**
|
||||
* `selectFromResult` allows you to get a specific segment from a query result in a performant manner.
|
||||
* When using this feature, the component will not rerender unless the underlying data of the selected item has changed.
|
||||
* If the selected item is one element in a larger collection, it will disregard changes to elements in the same collection.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Using selectFromResult to extract a single result"
|
||||
* function PostsList() {
|
||||
* const { data: posts } = api.useGetPostsQuery();
|
||||
*
|
||||
* return (
|
||||
* <ul>
|
||||
* {posts?.data?.map((post) => (
|
||||
* <PostById key={post.id} id={post.id} />
|
||||
* ))}
|
||||
* </ul>
|
||||
* );
|
||||
* }
|
||||
*
|
||||
* function PostById({ id }: { id: number }) {
|
||||
* // Will select the post with the given id, and will only rerender if the given posts data changes
|
||||
* const { post } = api.useGetPostsQuery(undefined, {
|
||||
* selectFromResult: ({ data }) => ({ post: data?.find((post) => post.id === id) }),
|
||||
* });
|
||||
*
|
||||
* return <li>{post?.name}</li>;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
selectFromResult?: QueryStateSelector<R, D>;
|
||||
};
|
||||
/**
|
||||
* Provides a way to define a "pre-typed" version of
|
||||
* {@linkcode UseQueryStateOptions} with specific options for a given query.
|
||||
* This is particularly useful for setting default query behaviors such as
|
||||
* refetching strategies, which can be overridden as needed.
|
||||
*
|
||||
* @example
|
||||
* <caption>#### __Create a `useQuery` hook with default options__</caption>
|
||||
*
|
||||
* ```ts
|
||||
* import type {
|
||||
* SubscriptionOptions,
|
||||
* TypedUseQueryStateOptions,
|
||||
* } from '@reduxjs/toolkit/query/react'
|
||||
* import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
*
|
||||
* type Post = {
|
||||
* id: number
|
||||
* name: string
|
||||
* }
|
||||
*
|
||||
* const api = createApi({
|
||||
* baseQuery: fetchBaseQuery({ baseUrl: '/' }),
|
||||
* tagTypes: ['Post'],
|
||||
* endpoints: (build) => ({
|
||||
* getPosts: build.query<Post[], void>({
|
||||
* query: () => 'posts',
|
||||
* }),
|
||||
* }),
|
||||
* })
|
||||
*
|
||||
* const { useGetPostsQuery } = api
|
||||
*
|
||||
* export const useGetPostsQueryWithDefaults = <
|
||||
* SelectedResult extends Record<string, any>,
|
||||
* >(
|
||||
* overrideOptions: TypedUseQueryStateOptions<
|
||||
* Post[],
|
||||
* void,
|
||||
* ReturnType<typeof fetchBaseQuery>,
|
||||
* SelectedResult
|
||||
* > &
|
||||
* SubscriptionOptions,
|
||||
* ) =>
|
||||
* useGetPostsQuery(undefined, {
|
||||
* // Insert default options here
|
||||
*
|
||||
* refetchOnMountOrArgChange: true,
|
||||
* refetchOnFocus: true,
|
||||
* ...overrideOptions,
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @template ResultType - The type of the result `data` returned by the query.
|
||||
* @template QueryArg - The type of the argument passed into the query.
|
||||
* @template BaseQuery - The type of the base query function being used.
|
||||
* @template SelectedResult - The type of the selected result returned by the __`selectFromResult`__ function.
|
||||
*
|
||||
* @since 2.2.8
|
||||
* @public
|
||||
*/
|
||||
type TypedUseQueryStateOptions<ResultType, QueryArg, BaseQuery extends BaseQueryFn, SelectedResult extends Record<string, any> = UseQueryStateDefaultResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>> = UseQueryStateOptions<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>, SelectedResult>;
|
||||
type UseQueryStateResult<_ extends QueryDefinition<any, any, any, any>, R> = TSHelpersNoInfer<R>;
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useQueryState` hook in userland code.
|
||||
*/
|
||||
type TypedUseQueryStateResult<ResultType, QueryArg, BaseQuery extends BaseQueryFn, R = UseQueryStateDefaultResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>> = TSHelpersNoInfer<R>;
|
||||
type UseQueryStateBaseResult<D extends QueryDefinition<any, any, any, any>> = QuerySubState<D> & {
|
||||
/**
|
||||
* Where `data` tries to hold data as much as possible, also re-using
|
||||
* data from the last arguments passed into the hook, this property
|
||||
* will always contain the received data from the query, for the current query arguments.
|
||||
*/
|
||||
currentData?: ResultTypeFrom<D>;
|
||||
/**
|
||||
* Query has not started yet.
|
||||
*/
|
||||
isUninitialized: false;
|
||||
/**
|
||||
* Query is currently loading for the first time. No data yet.
|
||||
*/
|
||||
isLoading: false;
|
||||
/**
|
||||
* Query is currently fetching, but might have data from an earlier request.
|
||||
*/
|
||||
isFetching: false;
|
||||
/**
|
||||
* Query has data from a successful load.
|
||||
*/
|
||||
isSuccess: false;
|
||||
/**
|
||||
* Query is currently in "error" state.
|
||||
*/
|
||||
isError: false;
|
||||
};
|
||||
type UseQueryStateUninitialized<D extends QueryDefinition<any, any, any, any>> = TSHelpersOverride<Extract<UseQueryStateBaseResult<D>, {
|
||||
status: QueryStatus.uninitialized;
|
||||
}>, {
|
||||
isUninitialized: true;
|
||||
}>;
|
||||
type UseQueryStateLoading<D extends QueryDefinition<any, any, any, any>> = TSHelpersOverride<UseQueryStateBaseResult<D>, {
|
||||
isLoading: true;
|
||||
isFetching: boolean;
|
||||
data: undefined;
|
||||
}>;
|
||||
type UseQueryStateSuccessFetching<D extends QueryDefinition<any, any, any, any>> = TSHelpersOverride<UseQueryStateBaseResult<D>, {
|
||||
isSuccess: true;
|
||||
isFetching: true;
|
||||
error: undefined;
|
||||
} & {
|
||||
data: ResultTypeFrom<D>;
|
||||
} & Required<Pick<UseQueryStateBaseResult<D>, 'fulfilledTimeStamp'>>>;
|
||||
type UseQueryStateSuccessNotFetching<D extends QueryDefinition<any, any, any, any>> = TSHelpersOverride<UseQueryStateBaseResult<D>, {
|
||||
isSuccess: true;
|
||||
isFetching: false;
|
||||
error: undefined;
|
||||
} & {
|
||||
data: ResultTypeFrom<D>;
|
||||
currentData: ResultTypeFrom<D>;
|
||||
} & Required<Pick<UseQueryStateBaseResult<D>, 'fulfilledTimeStamp'>>>;
|
||||
type UseQueryStateError<D extends QueryDefinition<any, any, any, any>> = TSHelpersOverride<UseQueryStateBaseResult<D>, {
|
||||
isError: true;
|
||||
} & Required<Pick<UseQueryStateBaseResult<D>, 'error'>>>;
|
||||
type UseQueryStateDefaultResult<D extends QueryDefinition<any, any, any, any>> = TSHelpersId<UseQueryStateUninitialized<D> | UseQueryStateLoading<D> | UseQueryStateSuccessFetching<D> | UseQueryStateSuccessNotFetching<D> | UseQueryStateError<D>> & {
|
||||
/**
|
||||
* @deprecated Included for completeness, but discouraged.
|
||||
* Please use the `isLoading`, `isFetching`, `isSuccess`, `isError`
|
||||
* and `isUninitialized` flags instead
|
||||
*/
|
||||
status: QueryStatus;
|
||||
};
|
||||
type LazyInfiniteQueryTrigger<D extends InfiniteQueryDefinition<any, any, any, any, any>> = {
|
||||
/**
|
||||
* Triggers a lazy query.
|
||||
*
|
||||
* By default, this will start a new request even if there is already a value in the cache.
|
||||
* If you want to use the cache value and only start a request if there is no cache value, set the second argument to `true`.
|
||||
*
|
||||
* @remarks
|
||||
* If you need to access the error or success payload immediately after a lazy query, you can chain .unwrap().
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Using .unwrap with async await"
|
||||
* try {
|
||||
* const payload = await getUserById(1).unwrap();
|
||||
* console.log('fulfilled', payload)
|
||||
* } catch (error) {
|
||||
* console.error('rejected', error);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
(arg: QueryArgFrom<D>, direction: InfiniteQueryDirection): InfiniteQueryActionCreatorResult<D>;
|
||||
};
|
||||
type TypedLazyInfiniteQueryTrigger<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn> = LazyInfiniteQueryTrigger<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
type UseInfiniteQuerySubscriptionOptions<D extends InfiniteQueryDefinition<any, any, any, any, any>> = SubscriptionOptions & {
|
||||
/**
|
||||
* Prevents a query from automatically running.
|
||||
*
|
||||
* @remarks
|
||||
* When `skip` is true (or `skipToken` is passed in as `arg`):
|
||||
*
|
||||
* - **If the query has cached data:**
|
||||
* * The cached data **will not be used** on the initial load, and will ignore updates from any identical query until the `skip` condition is removed
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * If `skip: false` is set after the initial load, the cached result will be used
|
||||
* - **If the query does not have cached data:**
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * The query will not exist in the state when viewed with the dev tools
|
||||
* * The query will not automatically fetch on mount
|
||||
* * The query will not automatically run when additional components with the same query are added that do run
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* // codeblock-meta no-transpile title="Skip example"
|
||||
* const Pokemon = ({ name, skip }: { name: string; skip: boolean }) => {
|
||||
* const { data, error, status } = useGetPokemonByNameQuery(name, {
|
||||
* skip,
|
||||
* });
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* {name} - {status}
|
||||
* </div>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
skip?: boolean;
|
||||
/**
|
||||
* Defaults to `false`. This setting allows you to control whether if a cached result is already available, RTK Query will only serve a cached result, or if it should `refetch` when set to `true` or if an adequate amount of time has passed since the last successful query result.
|
||||
* - `false` - Will not cause a query to be performed _unless_ it does not exist yet.
|
||||
* - `true` - Will always refetch when a new subscriber to a query is added. Behaves the same as calling the `refetch` callback or passing `forceRefetch: true` in the action creator.
|
||||
* - `number` - **Value is in seconds**. If a number is provided and there is an existing query in the cache, it will compare the current time vs the last fulfilled timestamp, and only refetch if enough time has elapsed.
|
||||
*
|
||||
* If you specify this option alongside `skip: true`, this **will not be evaluated** until `skip` is false.
|
||||
*/
|
||||
refetchOnMountOrArgChange?: boolean | number;
|
||||
initialPageParam?: PageParamFrom<D>;
|
||||
/**
|
||||
* Defaults to `true`. When this is `true` and an infinite query endpoint is refetched
|
||||
* (due to tag invalidation, polling, arg change configuration, or manual refetching),
|
||||
* RTK Query will try to sequentially refetch all pages currently in the cache.
|
||||
* When `false` only the first page will be refetched.
|
||||
*
|
||||
* This option applies to all automatic refetches for this subscription (polling, tag invalidation, etc.).
|
||||
* It can be overridden on a per-call basis using the `refetch()` method.
|
||||
*/
|
||||
refetchCachedPages?: boolean;
|
||||
};
|
||||
type TypedUseInfiniteQuerySubscription<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn> = UseInfiniteQuerySubscription<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
type UseInfiniteQuerySubscriptionResult<D extends InfiniteQueryDefinition<any, any, any, any, any>> = {
|
||||
refetch: (options?: Pick<UseInfiniteQuerySubscriptionOptions<D>, 'refetchCachedPages'>) => InfiniteQueryActionCreatorResult<D>;
|
||||
trigger: LazyInfiniteQueryTrigger<D>;
|
||||
fetchNextPage: () => InfiniteQueryActionCreatorResult<D>;
|
||||
fetchPreviousPage: () => InfiniteQueryActionCreatorResult<D>;
|
||||
};
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useQuerySubscription` hook in userland code.
|
||||
*/
|
||||
type TypedUseInfiniteQuerySubscriptionResult<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn> = UseInfiniteQuerySubscriptionResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
type InfiniteQueryStateSelector<R extends Record<string, any>, D extends InfiniteQueryDefinition<any, any, any, any, any>> = (state: UseInfiniteQueryStateDefaultResult<D>) => R;
|
||||
type TypedInfiniteQueryStateSelector<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn, SelectedResult extends Record<string, any> = UseInfiniteQueryStateDefaultResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>> = InfiniteQueryStateSelector<SelectedResult, InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* A React hook that automatically triggers fetches of data from an endpoint, 'subscribes' the component to the cached data, and reads the request status and cached data from the Redux store. The component will re-render as the loading status changes and the data becomes available. Additionally, it will cache multiple "pages" worth of responses within a single cache entry, and allows fetching more pages forwards and backwards from the current cached pages.
|
||||
*
|
||||
* The query arg is used as a cache key. Changing the query arg will tell the hook to re-fetch the data if it does not exist in the cache already, and the hook will return the data for that query arg once it's available.
|
||||
*
|
||||
* The `data` field will be a `{pages: Data[], pageParams: PageParam[]}` structure containing all fetched page responses and the corresponding page param values for each page. You may use this to render individual pages, combine all pages into a single infinite list, or other display logic as needed.
|
||||
*
|
||||
* This hook combines the functionality of both [`useInfiniteQueryState`](#useinfinitequerystate) and [`useInfiniteQuerySubscription`](#useinfinitequerysubscription) together, and is intended to be used in the majority of situations.
|
||||
*
|
||||
* As with normal query hooks, `skipToken` is a valid argument that will skip the query from executing.
|
||||
*
|
||||
* By default, the initial request will use the `initialPageParam` value that was defined on the infinite query endpoint. If you want to start from a different value, you can pass `initialPageParam` as part of the hook options to override that initial request value.
|
||||
*
|
||||
* Use the returned `fetchNextPage` and `fetchPreviousPage` methods on the hook result object to trigger fetches forwards and backwards. These will always calculate the next or previous page param based on the current cached pages and the provided `getNext/PreviousPageParam` callbacks defined in the endpoint.
|
||||
*
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Automatically triggers requests to retrieve data based on the hook argument and whether cached data exists by default
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Caches multiple pages worth of responses, and provides methods to trigger more page fetches forwards and backwards
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
*/
|
||||
type UseInfiniteQuery<D extends InfiniteQueryDefinition<any, any, any, any, any>> = <R extends Record<string, any> = UseInfiniteQueryStateDefaultResult<D>>(arg: InfiniteQueryArgFrom<D> | SkipToken, options?: UseInfiniteQuerySubscriptionOptions<D> & UseInfiniteQueryStateOptions<D, R>) => UseInfiniteQueryHookResult<D, R> & Pick<UseInfiniteQuerySubscriptionResult<D>, 'fetchNextPage' | 'fetchPreviousPage'>;
|
||||
type TypedUseInfiniteQuery<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn> = UseInfiniteQuery<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* A React hook that reads the request status and cached data from the Redux store. The component will re-render as the loading status changes and the data becomes available.
|
||||
*
|
||||
* Note that this hook does not trigger fetching new data. For that use-case, see [`useInfiniteQuery`](#useinfinitequery) or [`useInfiniteQuerySubscription`](#useinfinitequerysubscription).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
*/
|
||||
type UseInfiniteQueryState<D extends InfiniteQueryDefinition<any, any, any, any, any>> = <R extends Record<string, any> = UseInfiniteQueryStateDefaultResult<D>>(arg: InfiniteQueryArgFrom<D> | SkipToken, options?: UseInfiniteQueryStateOptions<D, R>) => UseInfiniteQueryStateResult<D, R>;
|
||||
type TypedUseInfiniteQueryState<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn> = UseInfiniteQueryState<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* A React hook that automatically triggers fetches of data from an endpoint, and 'subscribes' the component to the cached data. Additionally, it will cache multiple "pages" worth of responses within a single cache entry, and allows fetching more pages forwards and backwards from the current cached pages.
|
||||
*
|
||||
* The query arg is used as a cache key. Changing the query arg will tell the hook to re-fetch the data if it does not exist in the cache already.
|
||||
*
|
||||
* Note that this hook does not return a request status or cached data. For that use-case, see [`useInfiniteQuery`](#useinfinitequery) or [`useInfiniteQueryState`](#useinfinitequerystate).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Automatically triggers requests to retrieve data based on the hook argument and whether cached data exists by default
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Caches multiple pages worth of responses, and provides methods to trigger more page fetches forwards and backwards
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met
|
||||
*/
|
||||
type UseInfiniteQuerySubscription<D extends InfiniteQueryDefinition<any, any, any, any, any>> = (arg: InfiniteQueryArgFrom<D> | SkipToken, options?: UseInfiniteQuerySubscriptionOptions<D>) => UseInfiniteQuerySubscriptionResult<D>;
|
||||
type UseInfiniteQueryHookResult<D extends InfiniteQueryDefinition<any, any, any, any, any>, R = UseInfiniteQueryStateDefaultResult<D>> = UseInfiniteQueryStateResult<D, R> & Pick<UseInfiniteQuerySubscriptionResult<D>, 'refetch' | 'fetchNextPage' | 'fetchPreviousPage'>;
|
||||
type TypedUseInfiniteQueryHookResult<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn, R extends Record<string, any> = UseInfiniteQueryStateDefaultResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>> = UseInfiniteQueryHookResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>, R>;
|
||||
type UseInfiniteQueryStateOptions<D extends InfiniteQueryDefinition<any, any, any, any, any>, R extends Record<string, any>> = {
|
||||
/**
|
||||
* Prevents a query from automatically running.
|
||||
*
|
||||
* @remarks
|
||||
* When skip is true:
|
||||
*
|
||||
* - **If the query has cached data:**
|
||||
* * The cached data **will not be used** on the initial load, and will ignore updates from any identical query until the `skip` condition is removed
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * If `skip: false` is set after skipping the initial load, the cached result will be used
|
||||
* - **If the query does not have cached data:**
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * The query will not exist in the state when viewed with the dev tools
|
||||
* * The query will not automatically fetch on mount
|
||||
* * The query will not automatically run when additional components with the same query are added that do run
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Skip example"
|
||||
* const Pokemon = ({ name, skip }: { name: string; skip: boolean }) => {
|
||||
* const { data, error, status } = useGetPokemonByNameQuery(name, {
|
||||
* skip,
|
||||
* });
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* {name} - {status}
|
||||
* </div>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
skip?: boolean;
|
||||
/**
|
||||
* `selectFromResult` allows you to get a specific segment from a query result in a performant manner.
|
||||
* When using this feature, the component will not rerender unless the underlying data of the selected item has changed.
|
||||
* If the selected item is one element in a larger collection, it will disregard changes to elements in the same collection.
|
||||
* Note that this should always return an object (not a primitive), as RTKQ adds fields to the return value.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Using selectFromResult to extract a single result"
|
||||
* function PostsList() {
|
||||
* const { data: posts } = api.useGetPostsQuery();
|
||||
*
|
||||
* return (
|
||||
* <ul>
|
||||
* {posts?.data?.map((post) => (
|
||||
* <PostById key={post.id} id={post.id} />
|
||||
* ))}
|
||||
* </ul>
|
||||
* );
|
||||
* }
|
||||
*
|
||||
* function PostById({ id }: { id: number }) {
|
||||
* // Will select the post with the given id, and will only rerender if the given posts data changes
|
||||
* const { post } = api.useGetPostsQuery(undefined, {
|
||||
* selectFromResult: ({ data }) => ({ post: data?.find((post) => post.id === id) }),
|
||||
* });
|
||||
*
|
||||
* return <li>{post?.name}</li>;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
selectFromResult?: InfiniteQueryStateSelector<R, D>;
|
||||
};
|
||||
type TypedUseInfiniteQueryStateOptions<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn, SelectedResult extends Record<string, any> = UseInfiniteQueryStateDefaultResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>> = UseInfiniteQueryStateOptions<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>, SelectedResult>;
|
||||
type UseInfiniteQueryStateResult<D extends InfiniteQueryDefinition<any, any, any, any, any>, R = UseInfiniteQueryStateDefaultResult<D>> = TSHelpersNoInfer<R>;
|
||||
type TypedUseInfiniteQueryStateResult<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn, R = UseInfiniteQueryStateDefaultResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>> = UseInfiniteQueryStateResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>, R>;
|
||||
type UseInfiniteQueryStateBaseResult<D extends InfiniteQueryDefinition<any, any, any, any, any>> = InfiniteQuerySubState<D> & {
|
||||
/**
|
||||
* Where `data` tries to hold data as much as possible, also re-using
|
||||
* data from the last arguments passed into the hook, this property
|
||||
* will always contain the received data from the query, for the current query arguments.
|
||||
*/
|
||||
currentData?: InfiniteData<ResultTypeFrom<D>, PageParamFrom<D>>;
|
||||
/**
|
||||
* Query has not started yet.
|
||||
*/
|
||||
isUninitialized: false;
|
||||
/**
|
||||
* Query is currently loading for the first time. No data yet.
|
||||
*/
|
||||
isLoading: false;
|
||||
/**
|
||||
* Query is currently fetching, but might have data from an earlier request.
|
||||
*/
|
||||
isFetching: false;
|
||||
/**
|
||||
* Query has data from a successful load.
|
||||
*/
|
||||
isSuccess: false;
|
||||
/**
|
||||
* Query is currently in "error" state.
|
||||
*/
|
||||
isError: false;
|
||||
hasNextPage: boolean;
|
||||
hasPreviousPage: boolean;
|
||||
isFetchingNextPage: boolean;
|
||||
isFetchingPreviousPage: boolean;
|
||||
};
|
||||
type UseInfiniteQueryStateDefaultResult<D extends InfiniteQueryDefinition<any, any, any, any, any>> = TSHelpersId<TSHelpersOverride<Extract<UseInfiniteQueryStateBaseResult<D>, {
|
||||
status: QueryStatus.uninitialized;
|
||||
}>, {
|
||||
isUninitialized: true;
|
||||
}> | TSHelpersOverride<UseInfiniteQueryStateBaseResult<D>, {
|
||||
isLoading: true;
|
||||
isFetching: boolean;
|
||||
data: undefined;
|
||||
} | ({
|
||||
isSuccess: true;
|
||||
isFetching: true;
|
||||
error: undefined;
|
||||
} & Required<Pick<UseInfiniteQueryStateBaseResult<D>, 'data' | 'fulfilledTimeStamp'>>) | ({
|
||||
isSuccess: true;
|
||||
isFetching: false;
|
||||
error: undefined;
|
||||
} & Required<Pick<UseInfiniteQueryStateBaseResult<D>, 'data' | 'fulfilledTimeStamp' | 'currentData'>>) | ({
|
||||
isError: true;
|
||||
} & Required<Pick<UseInfiniteQueryStateBaseResult<D>, 'error'>>)>> & {
|
||||
/**
|
||||
* @deprecated Included for completeness, but discouraged.
|
||||
* Please use the `isLoading`, `isFetching`, `isSuccess`, `isError`
|
||||
* and `isUninitialized` flags instead
|
||||
*/
|
||||
status: QueryStatus;
|
||||
};
|
||||
type MutationStateSelector<R extends Record<string, any>, D extends MutationDefinition<any, any, any, any>> = (state: MutationResultSelectorResult<D>) => R;
|
||||
type UseMutationStateOptions<D extends MutationDefinition<any, any, any, any>, R extends Record<string, any>> = {
|
||||
selectFromResult?: MutationStateSelector<R, D>;
|
||||
fixedCacheKey?: string;
|
||||
};
|
||||
type UseMutationStateResult<D extends MutationDefinition<any, any, any, any>, R> = TSHelpersNoInfer<R> & {
|
||||
originalArgs?: QueryArgFrom<D>;
|
||||
/**
|
||||
* Resets the hook state to its initial `uninitialized` state.
|
||||
* This will also remove the last result from the cache.
|
||||
*/
|
||||
reset: () => void;
|
||||
};
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useMutation` hook in userland code.
|
||||
*/
|
||||
type TypedUseMutationResult<ResultType, QueryArg, BaseQuery extends BaseQueryFn, R = MutationResultSelectorResult<MutationDefinition<QueryArg, BaseQuery, string, ResultType, string>>> = UseMutationStateResult<MutationDefinition<QueryArg, BaseQuery, string, ResultType, string>, R>;
|
||||
/**
|
||||
* A React hook that lets you trigger an update request for a given endpoint, and subscribes the component to read the request status from the Redux store. The component will re-render as the loading status changes.
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Manual control over firing a request to alter data on the server or possibly invalidate the cache
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
*/
|
||||
type UseMutation<D extends MutationDefinition<any, any, any, any>> = <R extends Record<string, any> = MutationResultSelectorResult<D>>(options?: UseMutationStateOptions<D, R>) => readonly [MutationTrigger<D>, UseMutationStateResult<D, R>];
|
||||
type TypedUseMutation<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseMutation<MutationDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
type MutationTrigger<D extends MutationDefinition<any, any, any, any>> = {
|
||||
/**
|
||||
* Triggers the mutation and returns a Promise.
|
||||
* @remarks
|
||||
* If you need to access the error or success payload immediately after a mutation, you can chain .unwrap().
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Using .unwrap with async await"
|
||||
* try {
|
||||
* const payload = await addPost({ id: 1, name: 'Example' }).unwrap();
|
||||
* console.log('fulfilled', payload)
|
||||
* } catch (error) {
|
||||
* console.error('rejected', error);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
(arg: QueryArgFrom<D>): MutationActionCreatorResult<D>;
|
||||
};
|
||||
type TypedMutationTrigger<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = MutationTrigger<MutationDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
|
||||
type QueryHookNames<Definitions extends EndpointDefinitions> = {
|
||||
[K in keyof Definitions as Definitions[K] extends {
|
||||
type: DefinitionType.query;
|
||||
} ? `use${Capitalize<K & string>}Query` : never]: UseQuery<Extract<Definitions[K], QueryDefinition<any, any, any, any>>>;
|
||||
};
|
||||
type LazyQueryHookNames<Definitions extends EndpointDefinitions> = {
|
||||
[K in keyof Definitions as Definitions[K] extends {
|
||||
type: DefinitionType.query;
|
||||
} ? `useLazy${Capitalize<K & string>}Query` : never]: UseLazyQuery<Extract<Definitions[K], QueryDefinition<any, any, any, any>>>;
|
||||
};
|
||||
type InfiniteQueryHookNames<Definitions extends EndpointDefinitions> = {
|
||||
[K in keyof Definitions as Definitions[K] extends {
|
||||
type: DefinitionType.infinitequery;
|
||||
} ? `use${Capitalize<K & string>}InfiniteQuery` : never]: UseInfiniteQuery<Extract<Definitions[K], InfiniteQueryDefinition<any, any, any, any, any>>>;
|
||||
};
|
||||
type MutationHookNames<Definitions extends EndpointDefinitions> = {
|
||||
[K in keyof Definitions as Definitions[K] extends {
|
||||
type: DefinitionType.mutation;
|
||||
} ? `use${Capitalize<K & string>}Mutation` : never]: UseMutation<Extract<Definitions[K], MutationDefinition<any, any, any, any>>>;
|
||||
};
|
||||
type HooksWithUniqueNames<Definitions extends EndpointDefinitions> = QueryHookNames<Definitions> & LazyQueryHookNames<Definitions> & InfiniteQueryHookNames<Definitions> & MutationHookNames<Definitions>;
|
||||
|
||||
export declare const reactHooksModuleName: unique symbol;
|
||||
type ReactHooksModule = typeof reactHooksModuleName;
|
||||
declare module '@reduxjs/toolkit/query' {
|
||||
interface ApiModules<BaseQuery extends BaseQueryFn, Definitions extends EndpointDefinitions, ReducerPath extends string, TagTypes extends string> {
|
||||
[reactHooksModuleName]: {
|
||||
/**
|
||||
* Endpoints based on the input endpoints provided to `createApi`, containing `select`, `hooks` and `action matchers`.
|
||||
*/
|
||||
endpoints: {
|
||||
[K in keyof Definitions]: Definitions[K] extends QueryDefinition<any, any, any, any, any> ? QueryHooks<Definitions[K]> : Definitions[K] extends MutationDefinition<any, any, any, any, any> ? MutationHooks<Definitions[K]> : Definitions[K] extends InfiniteQueryDefinition<any, any, any, any, any> ? InfiniteQueryHooks<Definitions[K]> : never;
|
||||
};
|
||||
/**
|
||||
* A hook that accepts a string endpoint name, and provides a callback that when called, pre-fetches the data for that endpoint.
|
||||
*/
|
||||
usePrefetch<EndpointName extends QueryKeys<Definitions>>(endpointName: EndpointName, options?: PrefetchOptions): (arg: QueryArgFrom<Definitions[EndpointName]>, options?: PrefetchOptions) => void;
|
||||
} & HooksWithUniqueNames<Definitions>;
|
||||
}
|
||||
}
|
||||
type RR = typeof react_redux;
|
||||
interface ReactHooksModuleOptions {
|
||||
/**
|
||||
* The hooks from React Redux to be used
|
||||
*/
|
||||
hooks?: {
|
||||
/**
|
||||
* The version of the `useDispatch` hook to be used
|
||||
*/
|
||||
useDispatch: RR['useDispatch'];
|
||||
/**
|
||||
* The version of the `useSelector` hook to be used
|
||||
*/
|
||||
useSelector: RR['useSelector'];
|
||||
/**
|
||||
* The version of the `useStore` hook to be used
|
||||
*/
|
||||
useStore: RR['useStore'];
|
||||
};
|
||||
/**
|
||||
* The version of the `batchedUpdates` function to be used
|
||||
*/
|
||||
batch?: RR['batch'];
|
||||
/**
|
||||
* Enables performing asynchronous tasks immediately within a render.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* import {
|
||||
* buildCreateApi,
|
||||
* coreModule,
|
||||
* reactHooksModule
|
||||
* } from '@reduxjs/toolkit/query/react'
|
||||
*
|
||||
* const createApi = buildCreateApi(
|
||||
* coreModule(),
|
||||
* reactHooksModule({ unstable__sideEffectsInRender: true })
|
||||
* )
|
||||
* ```
|
||||
*/
|
||||
unstable__sideEffectsInRender?: boolean;
|
||||
/**
|
||||
* A selector creator (usually from `reselect`, or matching the same signature)
|
||||
*/
|
||||
createSelector?: CreateSelectorFunction<any, any, any>;
|
||||
}
|
||||
/**
|
||||
* Creates a module that generates react hooks from endpoints, for use with `buildCreateApi`.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const MyContext = React.createContext<ReactReduxContextValue | null>(null);
|
||||
* const customCreateApi = buildCreateApi(
|
||||
* coreModule(),
|
||||
* reactHooksModule({
|
||||
* hooks: {
|
||||
* useDispatch: createDispatchHook(MyContext),
|
||||
* useSelector: createSelectorHook(MyContext),
|
||||
* useStore: createStoreHook(MyContext)
|
||||
* }
|
||||
* })
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @returns A module for use with `buildCreateApi`
|
||||
*/
|
||||
declare const reactHooksModule: ({ batch, hooks, createSelector, unstable__sideEffectsInRender, ...rest }?: ReactHooksModuleOptions) => Module<ReactHooksModule>;
|
||||
|
||||
/**
|
||||
* Can be used as a `Provider` if you **do not already have a Redux store**.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* // codeblock-meta no-transpile title="Basic usage - wrap your App with ApiProvider"
|
||||
* import * as React from 'react';
|
||||
* import { ApiProvider } from '@reduxjs/toolkit/query/react';
|
||||
* import { Pokemon } from './features/Pokemon';
|
||||
*
|
||||
* function App() {
|
||||
* return (
|
||||
* <ApiProvider api={api}>
|
||||
* <Pokemon />
|
||||
* </ApiProvider>
|
||||
* );
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @remarks
|
||||
* Using this together with an existing redux store, both will
|
||||
* conflict with each other - please use the traditional redux setup
|
||||
* in that case.
|
||||
*/
|
||||
declare function ApiProvider(props: {
|
||||
children: any;
|
||||
api: Api<any, {}, any, any>;
|
||||
setupListeners?: Parameters<typeof setupListeners>[1] | false;
|
||||
context?: Context<ReactReduxContextValue | null>;
|
||||
}): React.JSX.Element;
|
||||
|
||||
declare const createApi: _reduxjs_toolkit_query.CreateApi<typeof _reduxjs_toolkit_query.coreModuleName | typeof reactHooksModuleName>;
|
||||
|
||||
export { ApiProvider, type TypedInfiniteQueryStateSelector, type TypedLazyInfiniteQueryTrigger, type TypedLazyQueryTrigger, type TypedMutationTrigger, type TypedQueryStateSelector, type TypedUseInfiniteQuery, type TypedUseInfiniteQueryHookResult, type TypedUseInfiniteQueryState, type TypedUseInfiniteQueryStateOptions, type TypedUseInfiniteQueryStateResult, type TypedUseInfiniteQuerySubscription, type TypedUseInfiniteQuerySubscriptionResult, type TypedUseLazyQuery, type TypedUseLazyQueryStateResult, type TypedUseLazyQuerySubscription, type TypedUseMutation, type TypedUseMutationResult, type TypedUseQuery, type TypedUseQueryHookResult, type TypedUseQueryState, type TypedUseQueryStateOptions, type TypedUseQueryStateResult, type TypedUseQuerySubscription, type TypedUseQuerySubscriptionResult, createApi, reactHooksModule };
|
||||
980
frontend/node_modules/@reduxjs/toolkit/dist/query/react/index.d.ts
generated
vendored
Normal file
980
frontend/node_modules/@reduxjs/toolkit/dist/query/react/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,980 @@
|
||||
import * as _reduxjs_toolkit_query from '@reduxjs/toolkit/query';
|
||||
import { QueryDefinition, TSHelpersId, TSHelpersOverride, QuerySubState, ResultTypeFrom, QueryStatus, QueryArgFrom, SkipToken, SubscriptionOptions, TSHelpersNoInfer, QueryActionCreatorResult, MutationDefinition, MutationResultSelectorResult, MutationActionCreatorResult, InfiniteQueryDefinition, InfiniteQuerySubState, PageParamFrom, InfiniteQueryArgFrom, InfiniteQueryActionCreatorResult, BaseQueryFn, EndpointDefinitions, DefinitionType, QueryKeys, PrefetchOptions, Module, Api, setupListeners } from '@reduxjs/toolkit/query';
|
||||
export * from '@reduxjs/toolkit/query';
|
||||
import * as react_redux from 'react-redux';
|
||||
import { ReactReduxContextValue } from 'react-redux';
|
||||
import { CreateSelectorFunction } from 'reselect';
|
||||
import * as React from 'react';
|
||||
import { Context } from 'react';
|
||||
|
||||
type InfiniteData<DataType, PageParam> = {
|
||||
pages: Array<DataType>;
|
||||
pageParams: Array<PageParam>;
|
||||
};
|
||||
type InfiniteQueryDirection = 'forward' | 'backward';
|
||||
|
||||
export declare const UNINITIALIZED_VALUE: unique symbol;
|
||||
type UninitializedValue = typeof UNINITIALIZED_VALUE;
|
||||
|
||||
type QueryHooks<Definition extends QueryDefinition<any, any, any, any, any>> = {
|
||||
useQuery: UseQuery<Definition>;
|
||||
useLazyQuery: UseLazyQuery<Definition>;
|
||||
useQuerySubscription: UseQuerySubscription<Definition>;
|
||||
useLazyQuerySubscription: UseLazyQuerySubscription<Definition>;
|
||||
useQueryState: UseQueryState<Definition>;
|
||||
};
|
||||
type InfiniteQueryHooks<Definition extends InfiniteQueryDefinition<any, any, any, any, any>> = {
|
||||
useInfiniteQuery: UseInfiniteQuery<Definition>;
|
||||
useInfiniteQuerySubscription: UseInfiniteQuerySubscription<Definition>;
|
||||
useInfiniteQueryState: UseInfiniteQueryState<Definition>;
|
||||
};
|
||||
type MutationHooks<Definition extends MutationDefinition<any, any, any, any, any>> = {
|
||||
useMutation: UseMutation<Definition>;
|
||||
};
|
||||
/**
|
||||
* A React hook that automatically triggers fetches of data from an endpoint, 'subscribes' the component to the cached data, and reads the request status and cached data from the Redux store. The component will re-render as the loading status changes and the data becomes available.
|
||||
*
|
||||
* The query arg is used as a cache key. Changing the query arg will tell the hook to re-fetch the data if it does not exist in the cache already, and the hook will return the data for that query arg once it's available.
|
||||
*
|
||||
* This hook combines the functionality of both [`useQueryState`](#usequerystate) and [`useQuerySubscription`](#usequerysubscription) together, and is intended to be used in the majority of situations.
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Automatically triggers requests to retrieve data based on the hook argument and whether cached data exists by default
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
*/
|
||||
type UseQuery<D extends QueryDefinition<any, any, any, any>> = <R extends Record<string, any> = UseQueryStateDefaultResult<D>>(arg: QueryArgFrom<D> | SkipToken, options?: UseQuerySubscriptionOptions & UseQueryStateOptions<D, R>) => UseQueryHookResult<D, R>;
|
||||
type TypedUseQuery<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseQuery<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
type UseQueryHookResult<D extends QueryDefinition<any, any, any, any>, R = UseQueryStateDefaultResult<D>> = UseQueryStateResult<D, R> & UseQuerySubscriptionResult<D>;
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useQuery` hook in userland code.
|
||||
*/
|
||||
type TypedUseQueryHookResult<ResultType, QueryArg, BaseQuery extends BaseQueryFn, R = UseQueryStateDefaultResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>> = TypedUseQueryStateResult<ResultType, QueryArg, BaseQuery, R> & TypedUseQuerySubscriptionResult<ResultType, QueryArg, BaseQuery>;
|
||||
type UseQuerySubscriptionOptions = SubscriptionOptions & {
|
||||
/**
|
||||
* Prevents a query from automatically running.
|
||||
*
|
||||
* @remarks
|
||||
* When `skip` is true (or `skipToken` is passed in as `arg`):
|
||||
*
|
||||
* - **If the query has cached data:**
|
||||
* * The cached data **will not be used** on the initial load, and will ignore updates from any identical query until the `skip` condition is removed
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * If `skip: false` is set after the initial load, the cached result will be used
|
||||
* - **If the query does not have cached data:**
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * The query will not exist in the state when viewed with the dev tools
|
||||
* * The query will not automatically fetch on mount
|
||||
* * The query will not automatically run when additional components with the same query are added that do run
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* // codeblock-meta no-transpile title="Skip example"
|
||||
* const Pokemon = ({ name, skip }: { name: string; skip: boolean }) => {
|
||||
* const { data, error, status } = useGetPokemonByNameQuery(name, {
|
||||
* skip,
|
||||
* });
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* {name} - {status}
|
||||
* </div>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
skip?: boolean;
|
||||
/**
|
||||
* Defaults to `false`. This setting allows you to control whether if a cached result is already available, RTK Query will only serve a cached result, or if it should `refetch` when set to `true` or if an adequate amount of time has passed since the last successful query result.
|
||||
* - `false` - Will not cause a query to be performed _unless_ it does not exist yet.
|
||||
* - `true` - Will always refetch when a new subscriber to a query is added. Behaves the same as calling the `refetch` callback or passing `forceRefetch: true` in the action creator.
|
||||
* - `number` - **Value is in seconds**. If a number is provided and there is an existing query in the cache, it will compare the current time vs the last fulfilled timestamp, and only refetch if enough time has elapsed.
|
||||
*
|
||||
* If you specify this option alongside `skip: true`, this **will not be evaluated** until `skip` is false.
|
||||
*/
|
||||
refetchOnMountOrArgChange?: boolean | number;
|
||||
};
|
||||
/**
|
||||
* A React hook that automatically triggers fetches of data from an endpoint, and 'subscribes' the component to the cached data.
|
||||
*
|
||||
* The query arg is used as a cache key. Changing the query arg will tell the hook to re-fetch the data if it does not exist in the cache already.
|
||||
*
|
||||
* Note that this hook does not return a request status or cached data. For that use-case, see [`useQuery`](#usequery) or [`useQueryState`](#usequerystate).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Automatically triggers requests to retrieve data based on the hook argument and whether cached data exists by default
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met
|
||||
*/
|
||||
type UseQuerySubscription<D extends QueryDefinition<any, any, any, any>> = (arg: QueryArgFrom<D> | SkipToken, options?: UseQuerySubscriptionOptions) => UseQuerySubscriptionResult<D>;
|
||||
type TypedUseQuerySubscription<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseQuerySubscription<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
type UseQuerySubscriptionResult<D extends QueryDefinition<any, any, any, any>> = Pick<QueryActionCreatorResult<D>, 'refetch'>;
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useQuerySubscription` hook in userland code.
|
||||
*/
|
||||
type TypedUseQuerySubscriptionResult<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseQuerySubscriptionResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
type UseLazyQueryLastPromiseInfo<D extends QueryDefinition<any, any, any, any>> = {
|
||||
lastArg: QueryArgFrom<D>;
|
||||
};
|
||||
/**
|
||||
* A React hook similar to [`useQuery`](#usequery), but with manual control over when the data fetching occurs.
|
||||
*
|
||||
* This hook includes the functionality of [`useLazyQuerySubscription`](#uselazyquerysubscription).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Manual control over firing a request to retrieve data
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met and the fetch has been manually called at least once
|
||||
*
|
||||
* #### Note
|
||||
*
|
||||
* When the trigger function returned from a LazyQuery is called, it always initiates a new request to the server even if there is cached data. Set `preferCacheValue`(the second argument to the function) as `true` if you want it to immediately return a cached value if one exists.
|
||||
*/
|
||||
type UseLazyQuery<D extends QueryDefinition<any, any, any, any>> = <R extends Record<string, any> = UseQueryStateDefaultResult<D>>(options?: SubscriptionOptions & Omit<UseQueryStateOptions<D, R>, 'skip'>) => [
|
||||
LazyQueryTrigger<D>,
|
||||
UseLazyQueryStateResult<D, R>,
|
||||
UseLazyQueryLastPromiseInfo<D>
|
||||
];
|
||||
type TypedUseLazyQuery<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseLazyQuery<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
type UseLazyQueryStateResult<D extends QueryDefinition<any, any, any, any>, R = UseQueryStateDefaultResult<D>> = UseQueryStateResult<D, R> & {
|
||||
/**
|
||||
* Resets the hook state to its initial `uninitialized` state.
|
||||
* This will also remove the last result from the cache.
|
||||
*/
|
||||
reset: () => void;
|
||||
};
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useLazyQuery` hook in userland code.
|
||||
*/
|
||||
type TypedUseLazyQueryStateResult<ResultType, QueryArg, BaseQuery extends BaseQueryFn, R = UseQueryStateDefaultResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>> = UseLazyQueryStateResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>, R>;
|
||||
type LazyQueryTrigger<D extends QueryDefinition<any, any, any, any>> = {
|
||||
/**
|
||||
* Triggers a lazy query.
|
||||
*
|
||||
* By default, this will start a new request even if there is already a value in the cache.
|
||||
* If you want to use the cache value and only start a request if there is no cache value, set the second argument to `true`.
|
||||
*
|
||||
* @remarks
|
||||
* If you need to access the error or success payload immediately after a lazy query, you can chain .unwrap().
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Using .unwrap with async await"
|
||||
* try {
|
||||
* const payload = await getUserById(1).unwrap();
|
||||
* console.log('fulfilled', payload)
|
||||
* } catch (error) {
|
||||
* console.error('rejected', error);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
(arg: QueryArgFrom<D>, preferCacheValue?: boolean): QueryActionCreatorResult<D>;
|
||||
};
|
||||
type TypedLazyQueryTrigger<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = LazyQueryTrigger<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* A React hook similar to [`useQuerySubscription`](#usequerysubscription), but with manual control over when the data fetching occurs.
|
||||
*
|
||||
* Note that this hook does not return a request status or cached data. For that use-case, see [`useLazyQuery`](#uselazyquery).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Manual control over firing a request to retrieve data
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met and the fetch has been manually called at least once
|
||||
*/
|
||||
type UseLazyQuerySubscription<D extends QueryDefinition<any, any, any, any>> = (options?: SubscriptionOptions) => readonly [
|
||||
LazyQueryTrigger<D>,
|
||||
QueryArgFrom<D> | UninitializedValue,
|
||||
{
|
||||
reset: () => void;
|
||||
}
|
||||
];
|
||||
type TypedUseLazyQuerySubscription<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseLazyQuerySubscription<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
type QueryStateSelector<R extends Record<string, any>, D extends QueryDefinition<any, any, any, any>> = (state: UseQueryStateDefaultResult<D>) => R;
|
||||
/**
|
||||
* Provides a way to define a strongly-typed version of
|
||||
* {@linkcode QueryStateSelector} for use with a specific query.
|
||||
* This is useful for scenarios where you want to create a "pre-typed"
|
||||
* {@linkcode UseQueryStateOptions.selectFromResult | selectFromResult}
|
||||
* function.
|
||||
*
|
||||
* @example
|
||||
* <caption>#### __Create a strongly-typed `selectFromResult` selector function__</caption>
|
||||
*
|
||||
* ```tsx
|
||||
* import type { TypedQueryStateSelector } from '@reduxjs/toolkit/query/react'
|
||||
* import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
*
|
||||
* type Post = {
|
||||
* id: number
|
||||
* title: string
|
||||
* }
|
||||
*
|
||||
* type PostsApiResponse = {
|
||||
* posts: Post[]
|
||||
* total: number
|
||||
* skip: number
|
||||
* limit: number
|
||||
* }
|
||||
*
|
||||
* type QueryArgument = number | undefined
|
||||
*
|
||||
* type BaseQueryFunction = ReturnType<typeof fetchBaseQuery>
|
||||
*
|
||||
* type SelectedResult = Pick<PostsApiResponse, 'posts'>
|
||||
*
|
||||
* const postsApiSlice = createApi({
|
||||
* baseQuery: fetchBaseQuery({ baseUrl: 'https://dummyjson.com/posts' }),
|
||||
* reducerPath: 'postsApi',
|
||||
* tagTypes: ['Posts'],
|
||||
* endpoints: (build) => ({
|
||||
* getPosts: build.query<PostsApiResponse, QueryArgument>({
|
||||
* query: (limit = 5) => `?limit=${limit}&select=title`,
|
||||
* }),
|
||||
* }),
|
||||
* })
|
||||
*
|
||||
* const { useGetPostsQuery } = postsApiSlice
|
||||
*
|
||||
* function PostById({ id }: { id: number }) {
|
||||
* const { post } = useGetPostsQuery(undefined, {
|
||||
* selectFromResult: (state) => ({
|
||||
* post: state.data?.posts.find((post) => post.id === id),
|
||||
* }),
|
||||
* })
|
||||
*
|
||||
* return <li>{post?.title}</li>
|
||||
* }
|
||||
*
|
||||
* const EMPTY_ARRAY: Post[] = []
|
||||
*
|
||||
* const typedSelectFromResult: TypedQueryStateSelector<
|
||||
* PostsApiResponse,
|
||||
* QueryArgument,
|
||||
* BaseQueryFunction,
|
||||
* SelectedResult
|
||||
* > = (state) => ({ posts: state.data?.posts ?? EMPTY_ARRAY })
|
||||
*
|
||||
* function PostsList() {
|
||||
* const { posts } = useGetPostsQuery(undefined, {
|
||||
* selectFromResult: typedSelectFromResult,
|
||||
* })
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* <ul>
|
||||
* {posts.map((post) => (
|
||||
* <PostById key={post.id} id={post.id} />
|
||||
* ))}
|
||||
* </ul>
|
||||
* </div>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @template ResultType - The type of the result `data` returned by the query.
|
||||
* @template QueryArgumentType - The type of the argument passed into the query.
|
||||
* @template BaseQueryFunctionType - The type of the base query function being used.
|
||||
* @template SelectedResultType - The type of the selected result returned by the __`selectFromResult`__ function.
|
||||
*
|
||||
* @since 2.3.0
|
||||
* @public
|
||||
*/
|
||||
type TypedQueryStateSelector<ResultType, QueryArgumentType, BaseQueryFunctionType extends BaseQueryFn, SelectedResultType extends Record<string, any> = UseQueryStateDefaultResult<QueryDefinition<QueryArgumentType, BaseQueryFunctionType, string, ResultType, string>>> = QueryStateSelector<SelectedResultType, QueryDefinition<QueryArgumentType, BaseQueryFunctionType, string, ResultType, string>>;
|
||||
/**
|
||||
* A React hook that reads the request status and cached data from the Redux store. The component will re-render as the loading status changes and the data becomes available.
|
||||
*
|
||||
* Note that this hook does not trigger fetching new data. For that use-case, see [`useQuery`](#usequery) or [`useQuerySubscription`](#usequerysubscription).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
*/
|
||||
type UseQueryState<D extends QueryDefinition<any, any, any, any>> = <R extends Record<string, any> = UseQueryStateDefaultResult<D>>(arg: QueryArgFrom<D> | SkipToken, options?: UseQueryStateOptions<D, R>) => UseQueryStateResult<D, R>;
|
||||
type TypedUseQueryState<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseQueryState<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
type UseQueryStateOptions<D extends QueryDefinition<any, any, any, any>, R extends Record<string, any>> = {
|
||||
/**
|
||||
* Prevents a query from automatically running.
|
||||
*
|
||||
* @remarks
|
||||
* When skip is true:
|
||||
*
|
||||
* - **If the query has cached data:**
|
||||
* * The cached data **will not be used** on the initial load, and will ignore updates from any identical query until the `skip` condition is removed
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * If `skip: false` is set after skipping the initial load, the cached result will be used
|
||||
* - **If the query does not have cached data:**
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * The query will not exist in the state when viewed with the dev tools
|
||||
* * The query will not automatically fetch on mount
|
||||
* * The query will not automatically run when additional components with the same query are added that do run
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Skip example"
|
||||
* const Pokemon = ({ name, skip }: { name: string; skip: boolean }) => {
|
||||
* const { data, error, status } = useGetPokemonByNameQuery(name, {
|
||||
* skip,
|
||||
* });
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* {name} - {status}
|
||||
* </div>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
skip?: boolean;
|
||||
/**
|
||||
* `selectFromResult` allows you to get a specific segment from a query result in a performant manner.
|
||||
* When using this feature, the component will not rerender unless the underlying data of the selected item has changed.
|
||||
* If the selected item is one element in a larger collection, it will disregard changes to elements in the same collection.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Using selectFromResult to extract a single result"
|
||||
* function PostsList() {
|
||||
* const { data: posts } = api.useGetPostsQuery();
|
||||
*
|
||||
* return (
|
||||
* <ul>
|
||||
* {posts?.data?.map((post) => (
|
||||
* <PostById key={post.id} id={post.id} />
|
||||
* ))}
|
||||
* </ul>
|
||||
* );
|
||||
* }
|
||||
*
|
||||
* function PostById({ id }: { id: number }) {
|
||||
* // Will select the post with the given id, and will only rerender if the given posts data changes
|
||||
* const { post } = api.useGetPostsQuery(undefined, {
|
||||
* selectFromResult: ({ data }) => ({ post: data?.find((post) => post.id === id) }),
|
||||
* });
|
||||
*
|
||||
* return <li>{post?.name}</li>;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
selectFromResult?: QueryStateSelector<R, D>;
|
||||
};
|
||||
/**
|
||||
* Provides a way to define a "pre-typed" version of
|
||||
* {@linkcode UseQueryStateOptions} with specific options for a given query.
|
||||
* This is particularly useful for setting default query behaviors such as
|
||||
* refetching strategies, which can be overridden as needed.
|
||||
*
|
||||
* @example
|
||||
* <caption>#### __Create a `useQuery` hook with default options__</caption>
|
||||
*
|
||||
* ```ts
|
||||
* import type {
|
||||
* SubscriptionOptions,
|
||||
* TypedUseQueryStateOptions,
|
||||
* } from '@reduxjs/toolkit/query/react'
|
||||
* import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
*
|
||||
* type Post = {
|
||||
* id: number
|
||||
* name: string
|
||||
* }
|
||||
*
|
||||
* const api = createApi({
|
||||
* baseQuery: fetchBaseQuery({ baseUrl: '/' }),
|
||||
* tagTypes: ['Post'],
|
||||
* endpoints: (build) => ({
|
||||
* getPosts: build.query<Post[], void>({
|
||||
* query: () => 'posts',
|
||||
* }),
|
||||
* }),
|
||||
* })
|
||||
*
|
||||
* const { useGetPostsQuery } = api
|
||||
*
|
||||
* export const useGetPostsQueryWithDefaults = <
|
||||
* SelectedResult extends Record<string, any>,
|
||||
* >(
|
||||
* overrideOptions: TypedUseQueryStateOptions<
|
||||
* Post[],
|
||||
* void,
|
||||
* ReturnType<typeof fetchBaseQuery>,
|
||||
* SelectedResult
|
||||
* > &
|
||||
* SubscriptionOptions,
|
||||
* ) =>
|
||||
* useGetPostsQuery(undefined, {
|
||||
* // Insert default options here
|
||||
*
|
||||
* refetchOnMountOrArgChange: true,
|
||||
* refetchOnFocus: true,
|
||||
* ...overrideOptions,
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @template ResultType - The type of the result `data` returned by the query.
|
||||
* @template QueryArg - The type of the argument passed into the query.
|
||||
* @template BaseQuery - The type of the base query function being used.
|
||||
* @template SelectedResult - The type of the selected result returned by the __`selectFromResult`__ function.
|
||||
*
|
||||
* @since 2.2.8
|
||||
* @public
|
||||
*/
|
||||
type TypedUseQueryStateOptions<ResultType, QueryArg, BaseQuery extends BaseQueryFn, SelectedResult extends Record<string, any> = UseQueryStateDefaultResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>> = UseQueryStateOptions<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>, SelectedResult>;
|
||||
type UseQueryStateResult<_ extends QueryDefinition<any, any, any, any>, R> = TSHelpersNoInfer<R>;
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useQueryState` hook in userland code.
|
||||
*/
|
||||
type TypedUseQueryStateResult<ResultType, QueryArg, BaseQuery extends BaseQueryFn, R = UseQueryStateDefaultResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>> = TSHelpersNoInfer<R>;
|
||||
type UseQueryStateBaseResult<D extends QueryDefinition<any, any, any, any>> = QuerySubState<D> & {
|
||||
/**
|
||||
* Where `data` tries to hold data as much as possible, also re-using
|
||||
* data from the last arguments passed into the hook, this property
|
||||
* will always contain the received data from the query, for the current query arguments.
|
||||
*/
|
||||
currentData?: ResultTypeFrom<D>;
|
||||
/**
|
||||
* Query has not started yet.
|
||||
*/
|
||||
isUninitialized: false;
|
||||
/**
|
||||
* Query is currently loading for the first time. No data yet.
|
||||
*/
|
||||
isLoading: false;
|
||||
/**
|
||||
* Query is currently fetching, but might have data from an earlier request.
|
||||
*/
|
||||
isFetching: false;
|
||||
/**
|
||||
* Query has data from a successful load.
|
||||
*/
|
||||
isSuccess: false;
|
||||
/**
|
||||
* Query is currently in "error" state.
|
||||
*/
|
||||
isError: false;
|
||||
};
|
||||
type UseQueryStateUninitialized<D extends QueryDefinition<any, any, any, any>> = TSHelpersOverride<Extract<UseQueryStateBaseResult<D>, {
|
||||
status: QueryStatus.uninitialized;
|
||||
}>, {
|
||||
isUninitialized: true;
|
||||
}>;
|
||||
type UseQueryStateLoading<D extends QueryDefinition<any, any, any, any>> = TSHelpersOverride<UseQueryStateBaseResult<D>, {
|
||||
isLoading: true;
|
||||
isFetching: boolean;
|
||||
data: undefined;
|
||||
}>;
|
||||
type UseQueryStateSuccessFetching<D extends QueryDefinition<any, any, any, any>> = TSHelpersOverride<UseQueryStateBaseResult<D>, {
|
||||
isSuccess: true;
|
||||
isFetching: true;
|
||||
error: undefined;
|
||||
} & {
|
||||
data: ResultTypeFrom<D>;
|
||||
} & Required<Pick<UseQueryStateBaseResult<D>, 'fulfilledTimeStamp'>>>;
|
||||
type UseQueryStateSuccessNotFetching<D extends QueryDefinition<any, any, any, any>> = TSHelpersOverride<UseQueryStateBaseResult<D>, {
|
||||
isSuccess: true;
|
||||
isFetching: false;
|
||||
error: undefined;
|
||||
} & {
|
||||
data: ResultTypeFrom<D>;
|
||||
currentData: ResultTypeFrom<D>;
|
||||
} & Required<Pick<UseQueryStateBaseResult<D>, 'fulfilledTimeStamp'>>>;
|
||||
type UseQueryStateError<D extends QueryDefinition<any, any, any, any>> = TSHelpersOverride<UseQueryStateBaseResult<D>, {
|
||||
isError: true;
|
||||
} & Required<Pick<UseQueryStateBaseResult<D>, 'error'>>>;
|
||||
type UseQueryStateDefaultResult<D extends QueryDefinition<any, any, any, any>> = TSHelpersId<UseQueryStateUninitialized<D> | UseQueryStateLoading<D> | UseQueryStateSuccessFetching<D> | UseQueryStateSuccessNotFetching<D> | UseQueryStateError<D>> & {
|
||||
/**
|
||||
* @deprecated Included for completeness, but discouraged.
|
||||
* Please use the `isLoading`, `isFetching`, `isSuccess`, `isError`
|
||||
* and `isUninitialized` flags instead
|
||||
*/
|
||||
status: QueryStatus;
|
||||
};
|
||||
type LazyInfiniteQueryTrigger<D extends InfiniteQueryDefinition<any, any, any, any, any>> = {
|
||||
/**
|
||||
* Triggers a lazy query.
|
||||
*
|
||||
* By default, this will start a new request even if there is already a value in the cache.
|
||||
* If you want to use the cache value and only start a request if there is no cache value, set the second argument to `true`.
|
||||
*
|
||||
* @remarks
|
||||
* If you need to access the error or success payload immediately after a lazy query, you can chain .unwrap().
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Using .unwrap with async await"
|
||||
* try {
|
||||
* const payload = await getUserById(1).unwrap();
|
||||
* console.log('fulfilled', payload)
|
||||
* } catch (error) {
|
||||
* console.error('rejected', error);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
(arg: QueryArgFrom<D>, direction: InfiniteQueryDirection): InfiniteQueryActionCreatorResult<D>;
|
||||
};
|
||||
type TypedLazyInfiniteQueryTrigger<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn> = LazyInfiniteQueryTrigger<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
type UseInfiniteQuerySubscriptionOptions<D extends InfiniteQueryDefinition<any, any, any, any, any>> = SubscriptionOptions & {
|
||||
/**
|
||||
* Prevents a query from automatically running.
|
||||
*
|
||||
* @remarks
|
||||
* When `skip` is true (or `skipToken` is passed in as `arg`):
|
||||
*
|
||||
* - **If the query has cached data:**
|
||||
* * The cached data **will not be used** on the initial load, and will ignore updates from any identical query until the `skip` condition is removed
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * If `skip: false` is set after the initial load, the cached result will be used
|
||||
* - **If the query does not have cached data:**
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * The query will not exist in the state when viewed with the dev tools
|
||||
* * The query will not automatically fetch on mount
|
||||
* * The query will not automatically run when additional components with the same query are added that do run
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* // codeblock-meta no-transpile title="Skip example"
|
||||
* const Pokemon = ({ name, skip }: { name: string; skip: boolean }) => {
|
||||
* const { data, error, status } = useGetPokemonByNameQuery(name, {
|
||||
* skip,
|
||||
* });
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* {name} - {status}
|
||||
* </div>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
skip?: boolean;
|
||||
/**
|
||||
* Defaults to `false`. This setting allows you to control whether if a cached result is already available, RTK Query will only serve a cached result, or if it should `refetch` when set to `true` or if an adequate amount of time has passed since the last successful query result.
|
||||
* - `false` - Will not cause a query to be performed _unless_ it does not exist yet.
|
||||
* - `true` - Will always refetch when a new subscriber to a query is added. Behaves the same as calling the `refetch` callback or passing `forceRefetch: true` in the action creator.
|
||||
* - `number` - **Value is in seconds**. If a number is provided and there is an existing query in the cache, it will compare the current time vs the last fulfilled timestamp, and only refetch if enough time has elapsed.
|
||||
*
|
||||
* If you specify this option alongside `skip: true`, this **will not be evaluated** until `skip` is false.
|
||||
*/
|
||||
refetchOnMountOrArgChange?: boolean | number;
|
||||
initialPageParam?: PageParamFrom<D>;
|
||||
/**
|
||||
* Defaults to `true`. When this is `true` and an infinite query endpoint is refetched
|
||||
* (due to tag invalidation, polling, arg change configuration, or manual refetching),
|
||||
* RTK Query will try to sequentially refetch all pages currently in the cache.
|
||||
* When `false` only the first page will be refetched.
|
||||
*
|
||||
* This option applies to all automatic refetches for this subscription (polling, tag invalidation, etc.).
|
||||
* It can be overridden on a per-call basis using the `refetch()` method.
|
||||
*/
|
||||
refetchCachedPages?: boolean;
|
||||
};
|
||||
type TypedUseInfiniteQuerySubscription<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn> = UseInfiniteQuerySubscription<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
type UseInfiniteQuerySubscriptionResult<D extends InfiniteQueryDefinition<any, any, any, any, any>> = {
|
||||
refetch: (options?: Pick<UseInfiniteQuerySubscriptionOptions<D>, 'refetchCachedPages'>) => InfiniteQueryActionCreatorResult<D>;
|
||||
trigger: LazyInfiniteQueryTrigger<D>;
|
||||
fetchNextPage: () => InfiniteQueryActionCreatorResult<D>;
|
||||
fetchPreviousPage: () => InfiniteQueryActionCreatorResult<D>;
|
||||
};
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useQuerySubscription` hook in userland code.
|
||||
*/
|
||||
type TypedUseInfiniteQuerySubscriptionResult<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn> = UseInfiniteQuerySubscriptionResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
type InfiniteQueryStateSelector<R extends Record<string, any>, D extends InfiniteQueryDefinition<any, any, any, any, any>> = (state: UseInfiniteQueryStateDefaultResult<D>) => R;
|
||||
type TypedInfiniteQueryStateSelector<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn, SelectedResult extends Record<string, any> = UseInfiniteQueryStateDefaultResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>> = InfiniteQueryStateSelector<SelectedResult, InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* A React hook that automatically triggers fetches of data from an endpoint, 'subscribes' the component to the cached data, and reads the request status and cached data from the Redux store. The component will re-render as the loading status changes and the data becomes available. Additionally, it will cache multiple "pages" worth of responses within a single cache entry, and allows fetching more pages forwards and backwards from the current cached pages.
|
||||
*
|
||||
* The query arg is used as a cache key. Changing the query arg will tell the hook to re-fetch the data if it does not exist in the cache already, and the hook will return the data for that query arg once it's available.
|
||||
*
|
||||
* The `data` field will be a `{pages: Data[], pageParams: PageParam[]}` structure containing all fetched page responses and the corresponding page param values for each page. You may use this to render individual pages, combine all pages into a single infinite list, or other display logic as needed.
|
||||
*
|
||||
* This hook combines the functionality of both [`useInfiniteQueryState`](#useinfinitequerystate) and [`useInfiniteQuerySubscription`](#useinfinitequerysubscription) together, and is intended to be used in the majority of situations.
|
||||
*
|
||||
* As with normal query hooks, `skipToken` is a valid argument that will skip the query from executing.
|
||||
*
|
||||
* By default, the initial request will use the `initialPageParam` value that was defined on the infinite query endpoint. If you want to start from a different value, you can pass `initialPageParam` as part of the hook options to override that initial request value.
|
||||
*
|
||||
* Use the returned `fetchNextPage` and `fetchPreviousPage` methods on the hook result object to trigger fetches forwards and backwards. These will always calculate the next or previous page param based on the current cached pages and the provided `getNext/PreviousPageParam` callbacks defined in the endpoint.
|
||||
*
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Automatically triggers requests to retrieve data based on the hook argument and whether cached data exists by default
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Caches multiple pages worth of responses, and provides methods to trigger more page fetches forwards and backwards
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
*/
|
||||
type UseInfiniteQuery<D extends InfiniteQueryDefinition<any, any, any, any, any>> = <R extends Record<string, any> = UseInfiniteQueryStateDefaultResult<D>>(arg: InfiniteQueryArgFrom<D> | SkipToken, options?: UseInfiniteQuerySubscriptionOptions<D> & UseInfiniteQueryStateOptions<D, R>) => UseInfiniteQueryHookResult<D, R> & Pick<UseInfiniteQuerySubscriptionResult<D>, 'fetchNextPage' | 'fetchPreviousPage'>;
|
||||
type TypedUseInfiniteQuery<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn> = UseInfiniteQuery<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* A React hook that reads the request status and cached data from the Redux store. The component will re-render as the loading status changes and the data becomes available.
|
||||
*
|
||||
* Note that this hook does not trigger fetching new data. For that use-case, see [`useInfiniteQuery`](#useinfinitequery) or [`useInfiniteQuerySubscription`](#useinfinitequerysubscription).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
*/
|
||||
type UseInfiniteQueryState<D extends InfiniteQueryDefinition<any, any, any, any, any>> = <R extends Record<string, any> = UseInfiniteQueryStateDefaultResult<D>>(arg: InfiniteQueryArgFrom<D> | SkipToken, options?: UseInfiniteQueryStateOptions<D, R>) => UseInfiniteQueryStateResult<D, R>;
|
||||
type TypedUseInfiniteQueryState<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn> = UseInfiniteQueryState<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>;
|
||||
/**
|
||||
* A React hook that automatically triggers fetches of data from an endpoint, and 'subscribes' the component to the cached data. Additionally, it will cache multiple "pages" worth of responses within a single cache entry, and allows fetching more pages forwards and backwards from the current cached pages.
|
||||
*
|
||||
* The query arg is used as a cache key. Changing the query arg will tell the hook to re-fetch the data if it does not exist in the cache already.
|
||||
*
|
||||
* Note that this hook does not return a request status or cached data. For that use-case, see [`useInfiniteQuery`](#useinfinitequery) or [`useInfiniteQueryState`](#useinfinitequerystate).
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Automatically triggers requests to retrieve data based on the hook argument and whether cached data exists by default
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Caches multiple pages worth of responses, and provides methods to trigger more page fetches forwards and backwards
|
||||
* - Accepts polling/re-fetching options to trigger automatic re-fetches when the corresponding criteria is met
|
||||
*/
|
||||
type UseInfiniteQuerySubscription<D extends InfiniteQueryDefinition<any, any, any, any, any>> = (arg: InfiniteQueryArgFrom<D> | SkipToken, options?: UseInfiniteQuerySubscriptionOptions<D>) => UseInfiniteQuerySubscriptionResult<D>;
|
||||
type UseInfiniteQueryHookResult<D extends InfiniteQueryDefinition<any, any, any, any, any>, R = UseInfiniteQueryStateDefaultResult<D>> = UseInfiniteQueryStateResult<D, R> & Pick<UseInfiniteQuerySubscriptionResult<D>, 'refetch' | 'fetchNextPage' | 'fetchPreviousPage'>;
|
||||
type TypedUseInfiniteQueryHookResult<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn, R extends Record<string, any> = UseInfiniteQueryStateDefaultResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>> = UseInfiniteQueryHookResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>, R>;
|
||||
type UseInfiniteQueryStateOptions<D extends InfiniteQueryDefinition<any, any, any, any, any>, R extends Record<string, any>> = {
|
||||
/**
|
||||
* Prevents a query from automatically running.
|
||||
*
|
||||
* @remarks
|
||||
* When skip is true:
|
||||
*
|
||||
* - **If the query has cached data:**
|
||||
* * The cached data **will not be used** on the initial load, and will ignore updates from any identical query until the `skip` condition is removed
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * If `skip: false` is set after skipping the initial load, the cached result will be used
|
||||
* - **If the query does not have cached data:**
|
||||
* * The query will have a status of `uninitialized`
|
||||
* * The query will not exist in the state when viewed with the dev tools
|
||||
* * The query will not automatically fetch on mount
|
||||
* * The query will not automatically run when additional components with the same query are added that do run
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Skip example"
|
||||
* const Pokemon = ({ name, skip }: { name: string; skip: boolean }) => {
|
||||
* const { data, error, status } = useGetPokemonByNameQuery(name, {
|
||||
* skip,
|
||||
* });
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* {name} - {status}
|
||||
* </div>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
skip?: boolean;
|
||||
/**
|
||||
* `selectFromResult` allows you to get a specific segment from a query result in a performant manner.
|
||||
* When using this feature, the component will not rerender unless the underlying data of the selected item has changed.
|
||||
* If the selected item is one element in a larger collection, it will disregard changes to elements in the same collection.
|
||||
* Note that this should always return an object (not a primitive), as RTKQ adds fields to the return value.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Using selectFromResult to extract a single result"
|
||||
* function PostsList() {
|
||||
* const { data: posts } = api.useGetPostsQuery();
|
||||
*
|
||||
* return (
|
||||
* <ul>
|
||||
* {posts?.data?.map((post) => (
|
||||
* <PostById key={post.id} id={post.id} />
|
||||
* ))}
|
||||
* </ul>
|
||||
* );
|
||||
* }
|
||||
*
|
||||
* function PostById({ id }: { id: number }) {
|
||||
* // Will select the post with the given id, and will only rerender if the given posts data changes
|
||||
* const { post } = api.useGetPostsQuery(undefined, {
|
||||
* selectFromResult: ({ data }) => ({ post: data?.find((post) => post.id === id) }),
|
||||
* });
|
||||
*
|
||||
* return <li>{post?.name}</li>;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
selectFromResult?: InfiniteQueryStateSelector<R, D>;
|
||||
};
|
||||
type TypedUseInfiniteQueryStateOptions<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn, SelectedResult extends Record<string, any> = UseInfiniteQueryStateDefaultResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>> = UseInfiniteQueryStateOptions<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>, SelectedResult>;
|
||||
type UseInfiniteQueryStateResult<D extends InfiniteQueryDefinition<any, any, any, any, any>, R = UseInfiniteQueryStateDefaultResult<D>> = TSHelpersNoInfer<R>;
|
||||
type TypedUseInfiniteQueryStateResult<ResultType, QueryArg, PageParam, BaseQuery extends BaseQueryFn, R = UseInfiniteQueryStateDefaultResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>>> = UseInfiniteQueryStateResult<InfiniteQueryDefinition<QueryArg, PageParam, BaseQuery, string, ResultType, string>, R>;
|
||||
type UseInfiniteQueryStateBaseResult<D extends InfiniteQueryDefinition<any, any, any, any, any>> = InfiniteQuerySubState<D> & {
|
||||
/**
|
||||
* Where `data` tries to hold data as much as possible, also re-using
|
||||
* data from the last arguments passed into the hook, this property
|
||||
* will always contain the received data from the query, for the current query arguments.
|
||||
*/
|
||||
currentData?: InfiniteData<ResultTypeFrom<D>, PageParamFrom<D>>;
|
||||
/**
|
||||
* Query has not started yet.
|
||||
*/
|
||||
isUninitialized: false;
|
||||
/**
|
||||
* Query is currently loading for the first time. No data yet.
|
||||
*/
|
||||
isLoading: false;
|
||||
/**
|
||||
* Query is currently fetching, but might have data from an earlier request.
|
||||
*/
|
||||
isFetching: false;
|
||||
/**
|
||||
* Query has data from a successful load.
|
||||
*/
|
||||
isSuccess: false;
|
||||
/**
|
||||
* Query is currently in "error" state.
|
||||
*/
|
||||
isError: false;
|
||||
hasNextPage: boolean;
|
||||
hasPreviousPage: boolean;
|
||||
isFetchingNextPage: boolean;
|
||||
isFetchingPreviousPage: boolean;
|
||||
};
|
||||
type UseInfiniteQueryStateDefaultResult<D extends InfiniteQueryDefinition<any, any, any, any, any>> = TSHelpersId<TSHelpersOverride<Extract<UseInfiniteQueryStateBaseResult<D>, {
|
||||
status: QueryStatus.uninitialized;
|
||||
}>, {
|
||||
isUninitialized: true;
|
||||
}> | TSHelpersOverride<UseInfiniteQueryStateBaseResult<D>, {
|
||||
isLoading: true;
|
||||
isFetching: boolean;
|
||||
data: undefined;
|
||||
} | ({
|
||||
isSuccess: true;
|
||||
isFetching: true;
|
||||
error: undefined;
|
||||
} & Required<Pick<UseInfiniteQueryStateBaseResult<D>, 'data' | 'fulfilledTimeStamp'>>) | ({
|
||||
isSuccess: true;
|
||||
isFetching: false;
|
||||
error: undefined;
|
||||
} & Required<Pick<UseInfiniteQueryStateBaseResult<D>, 'data' | 'fulfilledTimeStamp' | 'currentData'>>) | ({
|
||||
isError: true;
|
||||
} & Required<Pick<UseInfiniteQueryStateBaseResult<D>, 'error'>>)>> & {
|
||||
/**
|
||||
* @deprecated Included for completeness, but discouraged.
|
||||
* Please use the `isLoading`, `isFetching`, `isSuccess`, `isError`
|
||||
* and `isUninitialized` flags instead
|
||||
*/
|
||||
status: QueryStatus;
|
||||
};
|
||||
type MutationStateSelector<R extends Record<string, any>, D extends MutationDefinition<any, any, any, any>> = (state: MutationResultSelectorResult<D>) => R;
|
||||
type UseMutationStateOptions<D extends MutationDefinition<any, any, any, any>, R extends Record<string, any>> = {
|
||||
selectFromResult?: MutationStateSelector<R, D>;
|
||||
fixedCacheKey?: string;
|
||||
};
|
||||
type UseMutationStateResult<D extends MutationDefinition<any, any, any, any>, R> = TSHelpersNoInfer<R> & {
|
||||
originalArgs?: QueryArgFrom<D>;
|
||||
/**
|
||||
* Resets the hook state to its initial `uninitialized` state.
|
||||
* This will also remove the last result from the cache.
|
||||
*/
|
||||
reset: () => void;
|
||||
};
|
||||
/**
|
||||
* Helper type to manually type the result
|
||||
* of the `useMutation` hook in userland code.
|
||||
*/
|
||||
type TypedUseMutationResult<ResultType, QueryArg, BaseQuery extends BaseQueryFn, R = MutationResultSelectorResult<MutationDefinition<QueryArg, BaseQuery, string, ResultType, string>>> = UseMutationStateResult<MutationDefinition<QueryArg, BaseQuery, string, ResultType, string>, R>;
|
||||
/**
|
||||
* A React hook that lets you trigger an update request for a given endpoint, and subscribes the component to read the request status from the Redux store. The component will re-render as the loading status changes.
|
||||
*
|
||||
* #### Features
|
||||
*
|
||||
* - Manual control over firing a request to alter data on the server or possibly invalidate the cache
|
||||
* - 'Subscribes' the component to keep cached data in the store, and 'unsubscribes' when the component unmounts
|
||||
* - Returns the latest request status and cached data from the Redux store
|
||||
* - Re-renders as the request status changes and data becomes available
|
||||
*/
|
||||
type UseMutation<D extends MutationDefinition<any, any, any, any>> = <R extends Record<string, any> = MutationResultSelectorResult<D>>(options?: UseMutationStateOptions<D, R>) => readonly [MutationTrigger<D>, UseMutationStateResult<D, R>];
|
||||
type TypedUseMutation<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseMutation<MutationDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
type MutationTrigger<D extends MutationDefinition<any, any, any, any>> = {
|
||||
/**
|
||||
* Triggers the mutation and returns a Promise.
|
||||
* @remarks
|
||||
* If you need to access the error or success payload immediately after a mutation, you can chain .unwrap().
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // codeblock-meta title="Using .unwrap with async await"
|
||||
* try {
|
||||
* const payload = await addPost({ id: 1, name: 'Example' }).unwrap();
|
||||
* console.log('fulfilled', payload)
|
||||
* } catch (error) {
|
||||
* console.error('rejected', error);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
(arg: QueryArgFrom<D>): MutationActionCreatorResult<D>;
|
||||
};
|
||||
type TypedMutationTrigger<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = MutationTrigger<MutationDefinition<QueryArg, BaseQuery, string, ResultType, string>>;
|
||||
|
||||
type QueryHookNames<Definitions extends EndpointDefinitions> = {
|
||||
[K in keyof Definitions as Definitions[K] extends {
|
||||
type: DefinitionType.query;
|
||||
} ? `use${Capitalize<K & string>}Query` : never]: UseQuery<Extract<Definitions[K], QueryDefinition<any, any, any, any>>>;
|
||||
};
|
||||
type LazyQueryHookNames<Definitions extends EndpointDefinitions> = {
|
||||
[K in keyof Definitions as Definitions[K] extends {
|
||||
type: DefinitionType.query;
|
||||
} ? `useLazy${Capitalize<K & string>}Query` : never]: UseLazyQuery<Extract<Definitions[K], QueryDefinition<any, any, any, any>>>;
|
||||
};
|
||||
type InfiniteQueryHookNames<Definitions extends EndpointDefinitions> = {
|
||||
[K in keyof Definitions as Definitions[K] extends {
|
||||
type: DefinitionType.infinitequery;
|
||||
} ? `use${Capitalize<K & string>}InfiniteQuery` : never]: UseInfiniteQuery<Extract<Definitions[K], InfiniteQueryDefinition<any, any, any, any, any>>>;
|
||||
};
|
||||
type MutationHookNames<Definitions extends EndpointDefinitions> = {
|
||||
[K in keyof Definitions as Definitions[K] extends {
|
||||
type: DefinitionType.mutation;
|
||||
} ? `use${Capitalize<K & string>}Mutation` : never]: UseMutation<Extract<Definitions[K], MutationDefinition<any, any, any, any>>>;
|
||||
};
|
||||
type HooksWithUniqueNames<Definitions extends EndpointDefinitions> = QueryHookNames<Definitions> & LazyQueryHookNames<Definitions> & InfiniteQueryHookNames<Definitions> & MutationHookNames<Definitions>;
|
||||
|
||||
export declare const reactHooksModuleName: unique symbol;
|
||||
type ReactHooksModule = typeof reactHooksModuleName;
|
||||
declare module '@reduxjs/toolkit/query' {
|
||||
interface ApiModules<BaseQuery extends BaseQueryFn, Definitions extends EndpointDefinitions, ReducerPath extends string, TagTypes extends string> {
|
||||
[reactHooksModuleName]: {
|
||||
/**
|
||||
* Endpoints based on the input endpoints provided to `createApi`, containing `select`, `hooks` and `action matchers`.
|
||||
*/
|
||||
endpoints: {
|
||||
[K in keyof Definitions]: Definitions[K] extends QueryDefinition<any, any, any, any, any> ? QueryHooks<Definitions[K]> : Definitions[K] extends MutationDefinition<any, any, any, any, any> ? MutationHooks<Definitions[K]> : Definitions[K] extends InfiniteQueryDefinition<any, any, any, any, any> ? InfiniteQueryHooks<Definitions[K]> : never;
|
||||
};
|
||||
/**
|
||||
* A hook that accepts a string endpoint name, and provides a callback that when called, pre-fetches the data for that endpoint.
|
||||
*/
|
||||
usePrefetch<EndpointName extends QueryKeys<Definitions>>(endpointName: EndpointName, options?: PrefetchOptions): (arg: QueryArgFrom<Definitions[EndpointName]>, options?: PrefetchOptions) => void;
|
||||
} & HooksWithUniqueNames<Definitions>;
|
||||
}
|
||||
}
|
||||
type RR = typeof react_redux;
|
||||
interface ReactHooksModuleOptions {
|
||||
/**
|
||||
* The hooks from React Redux to be used
|
||||
*/
|
||||
hooks?: {
|
||||
/**
|
||||
* The version of the `useDispatch` hook to be used
|
||||
*/
|
||||
useDispatch: RR['useDispatch'];
|
||||
/**
|
||||
* The version of the `useSelector` hook to be used
|
||||
*/
|
||||
useSelector: RR['useSelector'];
|
||||
/**
|
||||
* The version of the `useStore` hook to be used
|
||||
*/
|
||||
useStore: RR['useStore'];
|
||||
};
|
||||
/**
|
||||
* The version of the `batchedUpdates` function to be used
|
||||
*/
|
||||
batch?: RR['batch'];
|
||||
/**
|
||||
* Enables performing asynchronous tasks immediately within a render.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* import {
|
||||
* buildCreateApi,
|
||||
* coreModule,
|
||||
* reactHooksModule
|
||||
* } from '@reduxjs/toolkit/query/react'
|
||||
*
|
||||
* const createApi = buildCreateApi(
|
||||
* coreModule(),
|
||||
* reactHooksModule({ unstable__sideEffectsInRender: true })
|
||||
* )
|
||||
* ```
|
||||
*/
|
||||
unstable__sideEffectsInRender?: boolean;
|
||||
/**
|
||||
* A selector creator (usually from `reselect`, or matching the same signature)
|
||||
*/
|
||||
createSelector?: CreateSelectorFunction<any, any, any>;
|
||||
}
|
||||
/**
|
||||
* Creates a module that generates react hooks from endpoints, for use with `buildCreateApi`.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const MyContext = React.createContext<ReactReduxContextValue | null>(null);
|
||||
* const customCreateApi = buildCreateApi(
|
||||
* coreModule(),
|
||||
* reactHooksModule({
|
||||
* hooks: {
|
||||
* useDispatch: createDispatchHook(MyContext),
|
||||
* useSelector: createSelectorHook(MyContext),
|
||||
* useStore: createStoreHook(MyContext)
|
||||
* }
|
||||
* })
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @returns A module for use with `buildCreateApi`
|
||||
*/
|
||||
declare const reactHooksModule: ({ batch, hooks, createSelector, unstable__sideEffectsInRender, ...rest }?: ReactHooksModuleOptions) => Module<ReactHooksModule>;
|
||||
|
||||
/**
|
||||
* Can be used as a `Provider` if you **do not already have a Redux store**.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* // codeblock-meta no-transpile title="Basic usage - wrap your App with ApiProvider"
|
||||
* import * as React from 'react';
|
||||
* import { ApiProvider } from '@reduxjs/toolkit/query/react';
|
||||
* import { Pokemon } from './features/Pokemon';
|
||||
*
|
||||
* function App() {
|
||||
* return (
|
||||
* <ApiProvider api={api}>
|
||||
* <Pokemon />
|
||||
* </ApiProvider>
|
||||
* );
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @remarks
|
||||
* Using this together with an existing redux store, both will
|
||||
* conflict with each other - please use the traditional redux setup
|
||||
* in that case.
|
||||
*/
|
||||
declare function ApiProvider(props: {
|
||||
children: any;
|
||||
api: Api<any, {}, any, any>;
|
||||
setupListeners?: Parameters<typeof setupListeners>[1] | false;
|
||||
context?: Context<ReactReduxContextValue | null>;
|
||||
}): React.JSX.Element;
|
||||
|
||||
declare const createApi: _reduxjs_toolkit_query.CreateApi<typeof _reduxjs_toolkit_query.coreModuleName | typeof reactHooksModuleName>;
|
||||
|
||||
export { ApiProvider, type TypedInfiniteQueryStateSelector, type TypedLazyInfiniteQueryTrigger, type TypedLazyQueryTrigger, type TypedMutationTrigger, type TypedQueryStateSelector, type TypedUseInfiniteQuery, type TypedUseInfiniteQueryHookResult, type TypedUseInfiniteQueryState, type TypedUseInfiniteQueryStateOptions, type TypedUseInfiniteQueryStateResult, type TypedUseInfiniteQuerySubscription, type TypedUseInfiniteQuerySubscriptionResult, type TypedUseLazyQuery, type TypedUseLazyQueryStateResult, type TypedUseLazyQuerySubscription, type TypedUseMutation, type TypedUseMutationResult, type TypedUseQuery, type TypedUseQueryHookResult, type TypedUseQueryState, type TypedUseQueryStateOptions, type TypedUseQueryStateResult, type TypedUseQuerySubscription, type TypedUseQuerySubscriptionResult, createApi, reactHooksModule };
|
||||
2
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.browser.mjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.browser.mjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.browser.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.browser.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
740
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.legacy-esm.js
generated
vendored
Normal file
740
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.legacy-esm.js
generated
vendored
Normal file
@@ -0,0 +1,740 @@
|
||||
var __defProp = Object.defineProperty;
|
||||
var __defProps = Object.defineProperties;
|
||||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
||||
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
||||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
||||
var __spreadValues = (a, b) => {
|
||||
for (var prop in b || (b = {}))
|
||||
if (__hasOwnProp.call(b, prop))
|
||||
__defNormalProp(a, prop, b[prop]);
|
||||
if (__getOwnPropSymbols)
|
||||
for (var prop of __getOwnPropSymbols(b)) {
|
||||
if (__propIsEnum.call(b, prop))
|
||||
__defNormalProp(a, prop, b[prop]);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
||||
var __objRest = (source, exclude) => {
|
||||
var target = {};
|
||||
for (var prop in source)
|
||||
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
||||
target[prop] = source[prop];
|
||||
if (source != null && __getOwnPropSymbols)
|
||||
for (var prop of __getOwnPropSymbols(source)) {
|
||||
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
||||
target[prop] = source[prop];
|
||||
}
|
||||
return target;
|
||||
};
|
||||
|
||||
// src/query/react/rtkqImports.ts
|
||||
import { buildCreateApi, coreModule, copyWithStructuralSharing, setupListeners, QueryStatus, skipToken } from "@reduxjs/toolkit/query";
|
||||
|
||||
// src/query/react/module.ts
|
||||
import { formatProdErrorMessage as _formatProdErrorMessage4 } from "@reduxjs/toolkit";
|
||||
import { batch as rrBatch, useDispatch as rrUseDispatch, useSelector as rrUseSelector, useStore as rrUseStore } from "react-redux";
|
||||
import { createSelector as _createSelector } from "reselect";
|
||||
|
||||
// src/query/utils/capitalize.ts
|
||||
function capitalize(str) {
|
||||
return str.replace(str[0], str[0].toUpperCase());
|
||||
}
|
||||
|
||||
// src/query/utils/countObjectKeys.ts
|
||||
function countObjectKeys(obj) {
|
||||
let count = 0;
|
||||
for (const _key in obj) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// src/query/endpointDefinitions.ts
|
||||
var ENDPOINT_QUERY = "query" /* query */;
|
||||
var ENDPOINT_MUTATION = "mutation" /* mutation */;
|
||||
var ENDPOINT_INFINITEQUERY = "infinitequery" /* infinitequery */;
|
||||
function isQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_QUERY;
|
||||
}
|
||||
function isMutationDefinition(e) {
|
||||
return e.type === ENDPOINT_MUTATION;
|
||||
}
|
||||
function isInfiniteQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_INFINITEQUERY;
|
||||
}
|
||||
|
||||
// src/query/tsHelpers.ts
|
||||
function safeAssign(target, ...args) {
|
||||
return Object.assign(target, ...args);
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
import { formatProdErrorMessage as _formatProdErrorMessage, formatProdErrorMessage as _formatProdErrorMessage2, formatProdErrorMessage as _formatProdErrorMessage3 } from "@reduxjs/toolkit";
|
||||
|
||||
// src/query/react/reactImports.ts
|
||||
import { useEffect, useRef, useMemo, useContext, useCallback, useDebugValue, useLayoutEffect, useState } from "react";
|
||||
|
||||
// src/query/react/reactReduxImports.ts
|
||||
import { shallowEqual, Provider, ReactReduxContext } from "react-redux";
|
||||
|
||||
// src/query/react/constants.ts
|
||||
var UNINITIALIZED_VALUE = Symbol();
|
||||
|
||||
// src/query/react/useSerializedStableValue.ts
|
||||
function useStableQueryArgs(queryArgs) {
|
||||
const cache = useRef(queryArgs);
|
||||
const copy = useMemo(() => copyWithStructuralSharing(cache.current, queryArgs), [queryArgs]);
|
||||
useEffect(() => {
|
||||
if (cache.current !== copy) {
|
||||
cache.current = copy;
|
||||
}
|
||||
}, [copy]);
|
||||
return copy;
|
||||
}
|
||||
|
||||
// src/query/react/useShallowStableValue.ts
|
||||
function useShallowStableValue(value) {
|
||||
const cache = useRef(value);
|
||||
useEffect(() => {
|
||||
if (!shallowEqual(cache.current, value)) {
|
||||
cache.current = value;
|
||||
}
|
||||
}, [value]);
|
||||
return shallowEqual(cache.current, value) ? cache.current : value;
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
var canUseDOM = () => !!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined");
|
||||
var isDOM = /* @__PURE__ */ canUseDOM();
|
||||
var isRunningInReactNative = () => typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
||||
var isReactNative = /* @__PURE__ */ isRunningInReactNative();
|
||||
var getUseIsomorphicLayoutEffect = () => isDOM || isReactNative ? useLayoutEffect : useEffect;
|
||||
var useIsomorphicLayoutEffect = /* @__PURE__ */ getUseIsomorphicLayoutEffect();
|
||||
var noPendingQueryStateSelector = (selected) => {
|
||||
if (selected.isUninitialized) {
|
||||
return __spreadProps(__spreadValues({}, selected), {
|
||||
isUninitialized: false,
|
||||
isFetching: true,
|
||||
isLoading: selected.data !== void 0 ? false : true,
|
||||
// This is the one place where we still have to use `QueryStatus` as an enum,
|
||||
// since it's the only reference in the React package and not in the core.
|
||||
status: QueryStatus.pending
|
||||
});
|
||||
}
|
||||
return selected;
|
||||
};
|
||||
function pick(obj, ...keys) {
|
||||
const ret = {};
|
||||
keys.forEach((key) => {
|
||||
ret[key] = obj[key];
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
var COMMON_HOOK_DEBUG_FIELDS = ["data", "status", "isLoading", "isSuccess", "isError", "error"];
|
||||
function buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks: {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
useStore
|
||||
},
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
}) {
|
||||
const usePossiblyImmediateEffect = unstable__sideEffectsInRender ? (cb) => cb() : useEffect;
|
||||
const unsubscribePromiseRef = (ref) => {
|
||||
var _a, _b;
|
||||
return (_b = (_a = ref.current) == null ? void 0 : _a.unsubscribe) == null ? void 0 : _b.call(_a);
|
||||
};
|
||||
const endpointDefinitions = context.endpointDefinitions;
|
||||
return {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
};
|
||||
function queryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if ((lastResult == null ? void 0 : lastResult.endpointName) && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult == null ? void 0 : lastResult.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || hasData && (isFetching && !(lastResult == null ? void 0 : lastResult.isError) || currentState.isUninitialized);
|
||||
return __spreadProps(__spreadValues({}, currentState), {
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
});
|
||||
}
|
||||
function infiniteQueryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if ((lastResult == null ? void 0 : lastResult.endpointName) && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult == null ? void 0 : lastResult.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || isFetching && hasData;
|
||||
return __spreadProps(__spreadValues({}, currentState), {
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
});
|
||||
}
|
||||
function usePrefetch(endpointName, defaultOptions) {
|
||||
const dispatch = useDispatch();
|
||||
const stableDefaultOptions = useShallowStableValue(defaultOptions);
|
||||
return useCallback((arg, options) => dispatch(api.util.prefetch(endpointName, arg, __spreadValues(__spreadValues({}, stableDefaultOptions), options))), [endpointName, dispatch, stableDefaultOptions]);
|
||||
}
|
||||
function useQuerySubscriptionCommonImpl(endpointName, arg, _a = {}) {
|
||||
var _b = _a, {
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
refetchOnMountOrArgChange,
|
||||
skip = false,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false
|
||||
} = _b, rest = __objRest(_b, [
|
||||
"refetchOnReconnect",
|
||||
"refetchOnFocus",
|
||||
"refetchOnMountOrArgChange",
|
||||
"skip",
|
||||
"pollingInterval",
|
||||
"skipPollingIfUnfocused"
|
||||
]);
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const subscriptionSelectorsRef = useRef(void 0);
|
||||
if (!subscriptionSelectorsRef.current) {
|
||||
const returnedValue = dispatch(api.internalActions.internal_getRTKQSubscriptions());
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (typeof returnedValue !== "object" || typeof (returnedValue == null ? void 0 : returnedValue.type) === "string") {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage(37) : `Warning: Middleware for RTK-Query API at reducerPath "${api.reducerPath}" has not been added to the store.
|
||||
You must add the middleware for RTK-Query to function correctly!`);
|
||||
}
|
||||
}
|
||||
subscriptionSelectorsRef.current = returnedValue;
|
||||
}
|
||||
const stableArg = useStableQueryArgs(skip ? skipToken : arg);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
const initialPageParam = rest.initialPageParam;
|
||||
const stableInitialPageParam = useShallowStableValue(initialPageParam);
|
||||
const refetchCachedPages = rest.refetchCachedPages;
|
||||
const stableRefetchCachedPages = useShallowStableValue(refetchCachedPages);
|
||||
const promiseRef = useRef(void 0);
|
||||
let {
|
||||
queryCacheKey,
|
||||
requestId
|
||||
} = promiseRef.current || {};
|
||||
let currentRenderHasSubscription = false;
|
||||
if (queryCacheKey && requestId) {
|
||||
currentRenderHasSubscription = subscriptionSelectorsRef.current.isRequestSubscribed(queryCacheKey, requestId);
|
||||
}
|
||||
const subscriptionRemoved = !currentRenderHasSubscription && promiseRef.current !== void 0;
|
||||
usePossiblyImmediateEffect(() => {
|
||||
if (subscriptionRemoved) {
|
||||
promiseRef.current = void 0;
|
||||
}
|
||||
}, [subscriptionRemoved]);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
var _a2;
|
||||
const lastPromise = promiseRef.current;
|
||||
if (typeof process !== "undefined" && process.env.NODE_ENV === "removeMeOnCompilation") {
|
||||
console.log(subscriptionRemoved);
|
||||
}
|
||||
if (stableArg === skipToken) {
|
||||
lastPromise == null ? void 0 : lastPromise.unsubscribe();
|
||||
promiseRef.current = void 0;
|
||||
return;
|
||||
}
|
||||
const lastSubscriptionOptions = (_a2 = promiseRef.current) == null ? void 0 : _a2.subscriptionOptions;
|
||||
if (!lastPromise || lastPromise.arg !== stableArg) {
|
||||
lastPromise == null ? void 0 : lastPromise.unsubscribe();
|
||||
const promise = dispatch(initiate(stableArg, __spreadValues({
|
||||
subscriptionOptions: stableSubscriptionOptions,
|
||||
forceRefetch: refetchOnMountOrArgChange
|
||||
}, isInfiniteQueryDefinition(endpointDefinitions[endpointName]) ? {
|
||||
initialPageParam: stableInitialPageParam,
|
||||
refetchCachedPages: stableRefetchCachedPages
|
||||
} : {})));
|
||||
promiseRef.current = promise;
|
||||
} else if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
lastPromise.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [dispatch, initiate, refetchOnMountOrArgChange, stableArg, stableSubscriptionOptions, subscriptionRemoved, stableInitialPageParam, stableRefetchCachedPages, endpointName]);
|
||||
return [promiseRef, dispatch, initiate, stableSubscriptionOptions];
|
||||
}
|
||||
function buildUseQueryState(endpointName, preSelector) {
|
||||
const useQueryState = (arg, {
|
||||
skip = false,
|
||||
selectFromResult
|
||||
} = {}) => {
|
||||
const {
|
||||
select
|
||||
} = api.endpoints[endpointName];
|
||||
const stableArg = useStableQueryArgs(skip ? skipToken : arg);
|
||||
const lastValue = useRef(void 0);
|
||||
const selectDefaultResult = useMemo(() => (
|
||||
// Normally ts-ignores are bad and should be avoided, but we're
|
||||
// already casting this selector to be `Selector<any>` anyway,
|
||||
// so the inconsistencies don't matter here
|
||||
// @ts-ignore
|
||||
createSelector([
|
||||
// @ts-ignore
|
||||
select(stableArg),
|
||||
(_, lastResult) => lastResult,
|
||||
(_) => stableArg
|
||||
], preSelector, {
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: shallowEqual
|
||||
}
|
||||
})
|
||||
), [select, stableArg]);
|
||||
const querySelector = useMemo(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult, {
|
||||
devModeChecks: {
|
||||
identityFunctionCheck: "never"
|
||||
}
|
||||
}) : selectDefaultResult, [selectDefaultResult, selectFromResult]);
|
||||
const currentState = useSelector((state) => querySelector(state, lastValue.current), shallowEqual);
|
||||
const store = useStore();
|
||||
const newLastValue = selectDefaultResult(store.getState(), lastValue.current);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
lastValue.current = newLastValue;
|
||||
}, [newLastValue]);
|
||||
return currentState;
|
||||
};
|
||||
return useQueryState;
|
||||
}
|
||||
function usePromiseRefUnsubscribeOnUnmount(promiseRef) {
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = void 0;
|
||||
};
|
||||
}, [promiseRef]);
|
||||
}
|
||||
function refetchOrErrorIfUnmounted(promiseRef) {
|
||||
if (!promiseRef.current) throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage2(38) : "Cannot refetch a query that has not been started yet.");
|
||||
return promiseRef.current.refetch();
|
||||
}
|
||||
function buildQueryHooks(endpointName) {
|
||||
const useQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
return useMemo(() => ({
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch: () => refetchOrErrorIfUnmounted(promiseRef)
|
||||
}), [promiseRef]);
|
||||
};
|
||||
const useLazyQuerySubscription = ({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false
|
||||
} = {}) => {
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const [arg, setArg] = useState(UNINITIALIZED_VALUE);
|
||||
const promiseRef = useRef(void 0);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
usePossiblyImmediateEffect(() => {
|
||||
var _a, _b;
|
||||
const lastSubscriptionOptions = (_a = promiseRef.current) == null ? void 0 : _a.subscriptionOptions;
|
||||
if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
(_b = promiseRef.current) == null ? void 0 : _b.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [stableSubscriptionOptions]);
|
||||
const subscriptionOptionsRef = useRef(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const trigger = useCallback(function(arg2, preferCacheValue = false) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
forceRefetch: !preferCacheValue
|
||||
}));
|
||||
setArg(arg2);
|
||||
});
|
||||
return promise;
|
||||
}, [dispatch, initiate]);
|
||||
const reset = useCallback(() => {
|
||||
var _a, _b;
|
||||
if ((_a = promiseRef.current) == null ? void 0 : _a.queryCacheKey) {
|
||||
dispatch(api.internalActions.removeQueryResult({
|
||||
queryCacheKey: (_b = promiseRef.current) == null ? void 0 : _b.queryCacheKey
|
||||
}));
|
||||
}
|
||||
}, [dispatch]);
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (arg !== UNINITIALIZED_VALUE && !promiseRef.current) {
|
||||
trigger(arg, true);
|
||||
}
|
||||
}, [arg, trigger]);
|
||||
return useMemo(() => [trigger, arg, {
|
||||
reset
|
||||
}], [trigger, arg, reset]);
|
||||
};
|
||||
const useQueryState = buildUseQueryState(endpointName, queryStatePreSelector);
|
||||
return {
|
||||
useQueryState,
|
||||
useQuerySubscription,
|
||||
useLazyQuerySubscription,
|
||||
useLazyQuery(options) {
|
||||
const [trigger, arg, {
|
||||
reset
|
||||
}] = useLazyQuerySubscription(options);
|
||||
const queryStateResults = useQueryState(arg, __spreadProps(__spreadValues({}, options), {
|
||||
skip: arg === UNINITIALIZED_VALUE
|
||||
}));
|
||||
const info = useMemo(() => ({
|
||||
lastArg: arg
|
||||
}), [arg]);
|
||||
return useMemo(() => [trigger, __spreadProps(__spreadValues({}, queryStateResults), {
|
||||
reset
|
||||
}), info], [trigger, queryStateResults, reset, info]);
|
||||
},
|
||||
useQuery(arg, options) {
|
||||
const querySubscriptionResults = useQuerySubscription(arg, options);
|
||||
const queryStateResults = useQueryState(arg, __spreadValues({
|
||||
selectFromResult: arg === skipToken || (options == null ? void 0 : options.skip) ? void 0 : noPendingQueryStateSelector
|
||||
}, options));
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS);
|
||||
useDebugValue(debugValue);
|
||||
return useMemo(() => __spreadValues(__spreadValues({}, queryStateResults), querySubscriptionResults), [queryStateResults, querySubscriptionResults]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildInfiniteQueryHooks(endpointName) {
|
||||
const useInfiniteQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef, dispatch, initiate, stableSubscriptionOptions] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
const subscriptionOptionsRef = useRef(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const hookRefetchCachedPages = options.refetchCachedPages;
|
||||
const stableHookRefetchCachedPages = useShallowStableValue(hookRefetchCachedPages);
|
||||
const trigger = useCallback(function(arg2, direction) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
direction
|
||||
}));
|
||||
});
|
||||
return promise;
|
||||
}, [promiseRef, dispatch, initiate]);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
const stableArg = useStableQueryArgs(options.skip ? skipToken : arg);
|
||||
const refetch = useCallback((options2) => {
|
||||
var _a;
|
||||
if (!promiseRef.current) throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage3(38) : "Cannot refetch a query that has not been started yet.");
|
||||
const mergedOptions = {
|
||||
refetchCachedPages: (_a = options2 == null ? void 0 : options2.refetchCachedPages) != null ? _a : stableHookRefetchCachedPages
|
||||
};
|
||||
return promiseRef.current.refetch(mergedOptions);
|
||||
}, [promiseRef, stableHookRefetchCachedPages]);
|
||||
return useMemo(() => {
|
||||
const fetchNextPage = () => {
|
||||
return trigger(stableArg, "forward");
|
||||
};
|
||||
const fetchPreviousPage = () => {
|
||||
return trigger(stableArg, "backward");
|
||||
};
|
||||
return {
|
||||
trigger,
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
};
|
||||
}, [refetch, trigger, stableArg]);
|
||||
};
|
||||
const useInfiniteQueryState = buildUseQueryState(endpointName, infiniteQueryStatePreSelector);
|
||||
return {
|
||||
useInfiniteQueryState,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQuery(arg, options) {
|
||||
const {
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
} = useInfiniteQuerySubscription(arg, options);
|
||||
const queryStateResults = useInfiniteQueryState(arg, __spreadValues({
|
||||
selectFromResult: arg === skipToken || (options == null ? void 0 : options.skip) ? void 0 : noPendingQueryStateSelector
|
||||
}, options));
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS, "hasNextPage", "hasPreviousPage");
|
||||
useDebugValue(debugValue);
|
||||
return useMemo(() => __spreadProps(__spreadValues({}, queryStateResults), {
|
||||
fetchNextPage,
|
||||
fetchPreviousPage,
|
||||
refetch
|
||||
}), [queryStateResults, fetchNextPage, fetchPreviousPage, refetch]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildMutationHook(name) {
|
||||
return ({
|
||||
selectFromResult,
|
||||
fixedCacheKey
|
||||
} = {}) => {
|
||||
const {
|
||||
select,
|
||||
initiate
|
||||
} = api.endpoints[name];
|
||||
const dispatch = useDispatch();
|
||||
const [promise, setPromise] = useState();
|
||||
useEffect(() => () => {
|
||||
if (!(promise == null ? void 0 : promise.arg.fixedCacheKey)) {
|
||||
promise == null ? void 0 : promise.reset();
|
||||
}
|
||||
}, [promise]);
|
||||
const triggerMutation = useCallback(function(arg) {
|
||||
const promise2 = dispatch(initiate(arg, {
|
||||
fixedCacheKey
|
||||
}));
|
||||
setPromise(promise2);
|
||||
return promise2;
|
||||
}, [dispatch, initiate, fixedCacheKey]);
|
||||
const {
|
||||
requestId
|
||||
} = promise || {};
|
||||
const selectDefaultResult = useMemo(() => select({
|
||||
fixedCacheKey,
|
||||
requestId: promise == null ? void 0 : promise.requestId
|
||||
}), [fixedCacheKey, promise, select]);
|
||||
const mutationSelector = useMemo(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult) : selectDefaultResult, [selectFromResult, selectDefaultResult]);
|
||||
const currentState = useSelector(mutationSelector, shallowEqual);
|
||||
const originalArgs = fixedCacheKey == null ? promise == null ? void 0 : promise.arg.originalArgs : void 0;
|
||||
const reset = useCallback(() => {
|
||||
batch(() => {
|
||||
if (promise) {
|
||||
setPromise(void 0);
|
||||
}
|
||||
if (fixedCacheKey) {
|
||||
dispatch(api.internalActions.removeMutationResult({
|
||||
requestId,
|
||||
fixedCacheKey
|
||||
}));
|
||||
}
|
||||
});
|
||||
}, [dispatch, fixedCacheKey, promise, requestId]);
|
||||
const debugValue = pick(currentState, ...COMMON_HOOK_DEBUG_FIELDS, "endpointName");
|
||||
useDebugValue(debugValue);
|
||||
const finalState = useMemo(() => __spreadProps(__spreadValues({}, currentState), {
|
||||
originalArgs,
|
||||
reset
|
||||
}), [currentState, originalArgs, reset]);
|
||||
return useMemo(() => [triggerMutation, finalState], [triggerMutation, finalState]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// src/query/react/module.ts
|
||||
var reactHooksModuleName = /* @__PURE__ */ Symbol();
|
||||
var reactHooksModule = (_a = {}) => {
|
||||
var _b = _a, {
|
||||
batch = rrBatch,
|
||||
hooks = {
|
||||
useDispatch: rrUseDispatch,
|
||||
useSelector: rrUseSelector,
|
||||
useStore: rrUseStore
|
||||
},
|
||||
createSelector = _createSelector,
|
||||
unstable__sideEffectsInRender = false
|
||||
} = _b, rest = __objRest(_b, [
|
||||
"batch",
|
||||
"hooks",
|
||||
"createSelector",
|
||||
"unstable__sideEffectsInRender"
|
||||
]);
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
const hookNames = ["useDispatch", "useSelector", "useStore"];
|
||||
let warned = false;
|
||||
for (const hookName of hookNames) {
|
||||
if (countObjectKeys(rest) > 0) {
|
||||
if (rest[hookName]) {
|
||||
if (!warned) {
|
||||
console.warn("As of RTK 2.0, the hooks now need to be specified as one object, provided under a `hooks` key:\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`");
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
hooks[hookName] = rest[hookName];
|
||||
}
|
||||
if (typeof hooks[hookName] !== "function") {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage4(36) : `When using custom hooks for context, all ${hookNames.length} hooks need to be provided: ${hookNames.join(", ")}.
|
||||
Hook ${hookName} was either not provided or not a function.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: reactHooksModuleName,
|
||||
init(api, {
|
||||
serializeQueryArgs
|
||||
}, context) {
|
||||
const anyApi = api;
|
||||
const {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
} = buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks,
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
});
|
||||
safeAssign(anyApi, {
|
||||
usePrefetch
|
||||
});
|
||||
safeAssign(context, {
|
||||
batch
|
||||
});
|
||||
return {
|
||||
injectEndpoint(endpointName, definition) {
|
||||
if (isQueryDefinition(definition)) {
|
||||
const {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
} = buildQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Query`] = useQuery;
|
||||
api[`useLazy${capitalize(endpointName)}Query`] = useLazyQuery;
|
||||
}
|
||||
if (isMutationDefinition(definition)) {
|
||||
const useMutation = buildMutationHook(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useMutation
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Mutation`] = useMutation;
|
||||
} else if (isInfiniteQueryDefinition(definition)) {
|
||||
const {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
} = buildInfiniteQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
});
|
||||
api[`use${capitalize(endpointName)}InfiniteQuery`] = useInfiniteQuery;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/query/react/index.ts
|
||||
export * from "@reduxjs/toolkit/query";
|
||||
|
||||
// src/query/react/ApiProvider.tsx
|
||||
import { configureStore, formatProdErrorMessage as _formatProdErrorMessage5 } from "@reduxjs/toolkit";
|
||||
import * as React from "react";
|
||||
function ApiProvider(props) {
|
||||
const context = props.context || ReactReduxContext;
|
||||
const existingContext = useContext(context);
|
||||
if (existingContext) {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage5(35) : "Existing Redux context detected. If you already have a store set up, please use the traditional Redux setup.");
|
||||
}
|
||||
const [store] = React.useState(() => configureStore({
|
||||
reducer: {
|
||||
[props.api.reducerPath]: props.api.reducer
|
||||
},
|
||||
middleware: (gDM) => gDM().concat(props.api.middleware)
|
||||
}));
|
||||
useEffect(() => props.setupListeners === false ? void 0 : setupListeners(store.dispatch, props.setupListeners), [props.setupListeners, store.dispatch]);
|
||||
return /* @__PURE__ */ React.createElement(Provider, { store, context }, props.children);
|
||||
}
|
||||
|
||||
// src/query/react/index.ts
|
||||
var createApi = /* @__PURE__ */ buildCreateApi(coreModule(), reactHooksModule());
|
||||
export {
|
||||
ApiProvider,
|
||||
UNINITIALIZED_VALUE,
|
||||
createApi,
|
||||
reactHooksModule,
|
||||
reactHooksModuleName
|
||||
};
|
||||
//# sourceMappingURL=rtk-query-react.legacy-esm.js.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.legacy-esm.js.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.legacy-esm.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
705
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs
generated
vendored
Normal file
705
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs
generated
vendored
Normal file
@@ -0,0 +1,705 @@
|
||||
// src/query/react/rtkqImports.ts
|
||||
import { buildCreateApi, coreModule, copyWithStructuralSharing, setupListeners, QueryStatus, skipToken } from "@reduxjs/toolkit/query";
|
||||
|
||||
// src/query/react/module.ts
|
||||
import { formatProdErrorMessage as _formatProdErrorMessage4 } from "@reduxjs/toolkit";
|
||||
import { batch as rrBatch, useDispatch as rrUseDispatch, useSelector as rrUseSelector, useStore as rrUseStore } from "react-redux";
|
||||
import { createSelector as _createSelector } from "reselect";
|
||||
|
||||
// src/query/utils/capitalize.ts
|
||||
function capitalize(str) {
|
||||
return str.replace(str[0], str[0].toUpperCase());
|
||||
}
|
||||
|
||||
// src/query/utils/countObjectKeys.ts
|
||||
function countObjectKeys(obj) {
|
||||
let count = 0;
|
||||
for (const _key in obj) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// src/query/endpointDefinitions.ts
|
||||
var ENDPOINT_QUERY = "query" /* query */;
|
||||
var ENDPOINT_MUTATION = "mutation" /* mutation */;
|
||||
var ENDPOINT_INFINITEQUERY = "infinitequery" /* infinitequery */;
|
||||
function isQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_QUERY;
|
||||
}
|
||||
function isMutationDefinition(e) {
|
||||
return e.type === ENDPOINT_MUTATION;
|
||||
}
|
||||
function isInfiniteQueryDefinition(e) {
|
||||
return e.type === ENDPOINT_INFINITEQUERY;
|
||||
}
|
||||
|
||||
// src/query/tsHelpers.ts
|
||||
function safeAssign(target, ...args) {
|
||||
return Object.assign(target, ...args);
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
import { formatProdErrorMessage as _formatProdErrorMessage, formatProdErrorMessage as _formatProdErrorMessage2, formatProdErrorMessage as _formatProdErrorMessage3 } from "@reduxjs/toolkit";
|
||||
|
||||
// src/query/react/reactImports.ts
|
||||
import { useEffect, useRef, useMemo, useContext, useCallback, useDebugValue, useLayoutEffect, useState } from "react";
|
||||
|
||||
// src/query/react/reactReduxImports.ts
|
||||
import { shallowEqual, Provider, ReactReduxContext } from "react-redux";
|
||||
|
||||
// src/query/react/constants.ts
|
||||
var UNINITIALIZED_VALUE = Symbol();
|
||||
|
||||
// src/query/react/useSerializedStableValue.ts
|
||||
function useStableQueryArgs(queryArgs) {
|
||||
const cache = useRef(queryArgs);
|
||||
const copy = useMemo(() => copyWithStructuralSharing(cache.current, queryArgs), [queryArgs]);
|
||||
useEffect(() => {
|
||||
if (cache.current !== copy) {
|
||||
cache.current = copy;
|
||||
}
|
||||
}, [copy]);
|
||||
return copy;
|
||||
}
|
||||
|
||||
// src/query/react/useShallowStableValue.ts
|
||||
function useShallowStableValue(value) {
|
||||
const cache = useRef(value);
|
||||
useEffect(() => {
|
||||
if (!shallowEqual(cache.current, value)) {
|
||||
cache.current = value;
|
||||
}
|
||||
}, [value]);
|
||||
return shallowEqual(cache.current, value) ? cache.current : value;
|
||||
}
|
||||
|
||||
// src/query/react/buildHooks.ts
|
||||
var canUseDOM = () => !!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined");
|
||||
var isDOM = /* @__PURE__ */ canUseDOM();
|
||||
var isRunningInReactNative = () => typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
||||
var isReactNative = /* @__PURE__ */ isRunningInReactNative();
|
||||
var getUseIsomorphicLayoutEffect = () => isDOM || isReactNative ? useLayoutEffect : useEffect;
|
||||
var useIsomorphicLayoutEffect = /* @__PURE__ */ getUseIsomorphicLayoutEffect();
|
||||
var noPendingQueryStateSelector = (selected) => {
|
||||
if (selected.isUninitialized) {
|
||||
return {
|
||||
...selected,
|
||||
isUninitialized: false,
|
||||
isFetching: true,
|
||||
isLoading: selected.data !== void 0 ? false : true,
|
||||
// This is the one place where we still have to use `QueryStatus` as an enum,
|
||||
// since it's the only reference in the React package and not in the core.
|
||||
status: QueryStatus.pending
|
||||
};
|
||||
}
|
||||
return selected;
|
||||
};
|
||||
function pick(obj, ...keys) {
|
||||
const ret = {};
|
||||
keys.forEach((key) => {
|
||||
ret[key] = obj[key];
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
var COMMON_HOOK_DEBUG_FIELDS = ["data", "status", "isLoading", "isSuccess", "isError", "error"];
|
||||
function buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks: {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
useStore
|
||||
},
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
}) {
|
||||
const usePossiblyImmediateEffect = unstable__sideEffectsInRender ? (cb) => cb() : useEffect;
|
||||
const unsubscribePromiseRef = (ref) => ref.current?.unsubscribe?.();
|
||||
const endpointDefinitions = context.endpointDefinitions;
|
||||
return {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
};
|
||||
function queryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if (lastResult?.endpointName && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult?.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || hasData && (isFetching && !lastResult?.isError || currentState.isUninitialized);
|
||||
return {
|
||||
...currentState,
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
};
|
||||
}
|
||||
function infiniteQueryStatePreSelector(currentState, lastResult, queryArgs) {
|
||||
if (lastResult?.endpointName && currentState.isUninitialized) {
|
||||
const {
|
||||
endpointName
|
||||
} = lastResult;
|
||||
const endpointDefinition = endpointDefinitions[endpointName];
|
||||
if (queryArgs !== skipToken && serializeQueryArgs({
|
||||
queryArgs: lastResult.originalArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
}) === serializeQueryArgs({
|
||||
queryArgs,
|
||||
endpointDefinition,
|
||||
endpointName
|
||||
})) lastResult = void 0;
|
||||
}
|
||||
let data = currentState.isSuccess ? currentState.data : lastResult?.data;
|
||||
if (data === void 0) data = currentState.data;
|
||||
const hasData = data !== void 0;
|
||||
const isFetching = currentState.isLoading;
|
||||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching;
|
||||
const isSuccess = currentState.isSuccess || isFetching && hasData;
|
||||
return {
|
||||
...currentState,
|
||||
data,
|
||||
currentData: currentState.data,
|
||||
isFetching,
|
||||
isLoading,
|
||||
isSuccess
|
||||
};
|
||||
}
|
||||
function usePrefetch(endpointName, defaultOptions) {
|
||||
const dispatch = useDispatch();
|
||||
const stableDefaultOptions = useShallowStableValue(defaultOptions);
|
||||
return useCallback((arg, options) => dispatch(api.util.prefetch(endpointName, arg, {
|
||||
...stableDefaultOptions,
|
||||
...options
|
||||
})), [endpointName, dispatch, stableDefaultOptions]);
|
||||
}
|
||||
function useQuerySubscriptionCommonImpl(endpointName, arg, {
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
refetchOnMountOrArgChange,
|
||||
skip = false,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false,
|
||||
...rest
|
||||
} = {}) {
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const subscriptionSelectorsRef = useRef(void 0);
|
||||
if (!subscriptionSelectorsRef.current) {
|
||||
const returnedValue = dispatch(api.internalActions.internal_getRTKQSubscriptions());
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (typeof returnedValue !== "object" || typeof returnedValue?.type === "string") {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage(37) : `Warning: Middleware for RTK-Query API at reducerPath "${api.reducerPath}" has not been added to the store.
|
||||
You must add the middleware for RTK-Query to function correctly!`);
|
||||
}
|
||||
}
|
||||
subscriptionSelectorsRef.current = returnedValue;
|
||||
}
|
||||
const stableArg = useStableQueryArgs(skip ? skipToken : arg);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
const initialPageParam = rest.initialPageParam;
|
||||
const stableInitialPageParam = useShallowStableValue(initialPageParam);
|
||||
const refetchCachedPages = rest.refetchCachedPages;
|
||||
const stableRefetchCachedPages = useShallowStableValue(refetchCachedPages);
|
||||
const promiseRef = useRef(void 0);
|
||||
let {
|
||||
queryCacheKey,
|
||||
requestId
|
||||
} = promiseRef.current || {};
|
||||
let currentRenderHasSubscription = false;
|
||||
if (queryCacheKey && requestId) {
|
||||
currentRenderHasSubscription = subscriptionSelectorsRef.current.isRequestSubscribed(queryCacheKey, requestId);
|
||||
}
|
||||
const subscriptionRemoved = !currentRenderHasSubscription && promiseRef.current !== void 0;
|
||||
usePossiblyImmediateEffect(() => {
|
||||
if (subscriptionRemoved) {
|
||||
promiseRef.current = void 0;
|
||||
}
|
||||
}, [subscriptionRemoved]);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
const lastPromise = promiseRef.current;
|
||||
if (typeof process !== "undefined" && process.env.NODE_ENV === "removeMeOnCompilation") {
|
||||
console.log(subscriptionRemoved);
|
||||
}
|
||||
if (stableArg === skipToken) {
|
||||
lastPromise?.unsubscribe();
|
||||
promiseRef.current = void 0;
|
||||
return;
|
||||
}
|
||||
const lastSubscriptionOptions = promiseRef.current?.subscriptionOptions;
|
||||
if (!lastPromise || lastPromise.arg !== stableArg) {
|
||||
lastPromise?.unsubscribe();
|
||||
const promise = dispatch(initiate(stableArg, {
|
||||
subscriptionOptions: stableSubscriptionOptions,
|
||||
forceRefetch: refetchOnMountOrArgChange,
|
||||
...isInfiniteQueryDefinition(endpointDefinitions[endpointName]) ? {
|
||||
initialPageParam: stableInitialPageParam,
|
||||
refetchCachedPages: stableRefetchCachedPages
|
||||
} : {}
|
||||
}));
|
||||
promiseRef.current = promise;
|
||||
} else if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
lastPromise.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [dispatch, initiate, refetchOnMountOrArgChange, stableArg, stableSubscriptionOptions, subscriptionRemoved, stableInitialPageParam, stableRefetchCachedPages, endpointName]);
|
||||
return [promiseRef, dispatch, initiate, stableSubscriptionOptions];
|
||||
}
|
||||
function buildUseQueryState(endpointName, preSelector) {
|
||||
const useQueryState = (arg, {
|
||||
skip = false,
|
||||
selectFromResult
|
||||
} = {}) => {
|
||||
const {
|
||||
select
|
||||
} = api.endpoints[endpointName];
|
||||
const stableArg = useStableQueryArgs(skip ? skipToken : arg);
|
||||
const lastValue = useRef(void 0);
|
||||
const selectDefaultResult = useMemo(() => (
|
||||
// Normally ts-ignores are bad and should be avoided, but we're
|
||||
// already casting this selector to be `Selector<any>` anyway,
|
||||
// so the inconsistencies don't matter here
|
||||
// @ts-ignore
|
||||
createSelector([
|
||||
// @ts-ignore
|
||||
select(stableArg),
|
||||
(_, lastResult) => lastResult,
|
||||
(_) => stableArg
|
||||
], preSelector, {
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: shallowEqual
|
||||
}
|
||||
})
|
||||
), [select, stableArg]);
|
||||
const querySelector = useMemo(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult, {
|
||||
devModeChecks: {
|
||||
identityFunctionCheck: "never"
|
||||
}
|
||||
}) : selectDefaultResult, [selectDefaultResult, selectFromResult]);
|
||||
const currentState = useSelector((state) => querySelector(state, lastValue.current), shallowEqual);
|
||||
const store = useStore();
|
||||
const newLastValue = selectDefaultResult(store.getState(), lastValue.current);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
lastValue.current = newLastValue;
|
||||
}, [newLastValue]);
|
||||
return currentState;
|
||||
};
|
||||
return useQueryState;
|
||||
}
|
||||
function usePromiseRefUnsubscribeOnUnmount(promiseRef) {
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = void 0;
|
||||
};
|
||||
}, [promiseRef]);
|
||||
}
|
||||
function refetchOrErrorIfUnmounted(promiseRef) {
|
||||
if (!promiseRef.current) throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage2(38) : "Cannot refetch a query that has not been started yet.");
|
||||
return promiseRef.current.refetch();
|
||||
}
|
||||
function buildQueryHooks(endpointName) {
|
||||
const useQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
return useMemo(() => ({
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch: () => refetchOrErrorIfUnmounted(promiseRef)
|
||||
}), [promiseRef]);
|
||||
};
|
||||
const useLazyQuerySubscription = ({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval = 0,
|
||||
skipPollingIfUnfocused = false
|
||||
} = {}) => {
|
||||
const {
|
||||
initiate
|
||||
} = api.endpoints[endpointName];
|
||||
const dispatch = useDispatch();
|
||||
const [arg, setArg] = useState(UNINITIALIZED_VALUE);
|
||||
const promiseRef = useRef(void 0);
|
||||
const stableSubscriptionOptions = useShallowStableValue({
|
||||
refetchOnReconnect,
|
||||
refetchOnFocus,
|
||||
pollingInterval,
|
||||
skipPollingIfUnfocused
|
||||
});
|
||||
usePossiblyImmediateEffect(() => {
|
||||
const lastSubscriptionOptions = promiseRef.current?.subscriptionOptions;
|
||||
if (stableSubscriptionOptions !== lastSubscriptionOptions) {
|
||||
promiseRef.current?.updateSubscriptionOptions(stableSubscriptionOptions);
|
||||
}
|
||||
}, [stableSubscriptionOptions]);
|
||||
const subscriptionOptionsRef = useRef(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const trigger = useCallback(function(arg2, preferCacheValue = false) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
forceRefetch: !preferCacheValue
|
||||
}));
|
||||
setArg(arg2);
|
||||
});
|
||||
return promise;
|
||||
}, [dispatch, initiate]);
|
||||
const reset = useCallback(() => {
|
||||
if (promiseRef.current?.queryCacheKey) {
|
||||
dispatch(api.internalActions.removeQueryResult({
|
||||
queryCacheKey: promiseRef.current?.queryCacheKey
|
||||
}));
|
||||
}
|
||||
}, [dispatch]);
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (arg !== UNINITIALIZED_VALUE && !promiseRef.current) {
|
||||
trigger(arg, true);
|
||||
}
|
||||
}, [arg, trigger]);
|
||||
return useMemo(() => [trigger, arg, {
|
||||
reset
|
||||
}], [trigger, arg, reset]);
|
||||
};
|
||||
const useQueryState = buildUseQueryState(endpointName, queryStatePreSelector);
|
||||
return {
|
||||
useQueryState,
|
||||
useQuerySubscription,
|
||||
useLazyQuerySubscription,
|
||||
useLazyQuery(options) {
|
||||
const [trigger, arg, {
|
||||
reset
|
||||
}] = useLazyQuerySubscription(options);
|
||||
const queryStateResults = useQueryState(arg, {
|
||||
...options,
|
||||
skip: arg === UNINITIALIZED_VALUE
|
||||
});
|
||||
const info = useMemo(() => ({
|
||||
lastArg: arg
|
||||
}), [arg]);
|
||||
return useMemo(() => [trigger, {
|
||||
...queryStateResults,
|
||||
reset
|
||||
}, info], [trigger, queryStateResults, reset, info]);
|
||||
},
|
||||
useQuery(arg, options) {
|
||||
const querySubscriptionResults = useQuerySubscription(arg, options);
|
||||
const queryStateResults = useQueryState(arg, {
|
||||
selectFromResult: arg === skipToken || options?.skip ? void 0 : noPendingQueryStateSelector,
|
||||
...options
|
||||
});
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS);
|
||||
useDebugValue(debugValue);
|
||||
return useMemo(() => ({
|
||||
...queryStateResults,
|
||||
...querySubscriptionResults
|
||||
}), [queryStateResults, querySubscriptionResults]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildInfiniteQueryHooks(endpointName) {
|
||||
const useInfiniteQuerySubscription = (arg, options = {}) => {
|
||||
const [promiseRef, dispatch, initiate, stableSubscriptionOptions] = useQuerySubscriptionCommonImpl(endpointName, arg, options);
|
||||
const subscriptionOptionsRef = useRef(stableSubscriptionOptions);
|
||||
usePossiblyImmediateEffect(() => {
|
||||
subscriptionOptionsRef.current = stableSubscriptionOptions;
|
||||
}, [stableSubscriptionOptions]);
|
||||
const hookRefetchCachedPages = options.refetchCachedPages;
|
||||
const stableHookRefetchCachedPages = useShallowStableValue(hookRefetchCachedPages);
|
||||
const trigger = useCallback(function(arg2, direction) {
|
||||
let promise;
|
||||
batch(() => {
|
||||
unsubscribePromiseRef(promiseRef);
|
||||
promiseRef.current = promise = dispatch(initiate(arg2, {
|
||||
subscriptionOptions: subscriptionOptionsRef.current,
|
||||
direction
|
||||
}));
|
||||
});
|
||||
return promise;
|
||||
}, [promiseRef, dispatch, initiate]);
|
||||
usePromiseRefUnsubscribeOnUnmount(promiseRef);
|
||||
const stableArg = useStableQueryArgs(options.skip ? skipToken : arg);
|
||||
const refetch = useCallback((options2) => {
|
||||
if (!promiseRef.current) throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage3(38) : "Cannot refetch a query that has not been started yet.");
|
||||
const mergedOptions = {
|
||||
refetchCachedPages: options2?.refetchCachedPages ?? stableHookRefetchCachedPages
|
||||
};
|
||||
return promiseRef.current.refetch(mergedOptions);
|
||||
}, [promiseRef, stableHookRefetchCachedPages]);
|
||||
return useMemo(() => {
|
||||
const fetchNextPage = () => {
|
||||
return trigger(stableArg, "forward");
|
||||
};
|
||||
const fetchPreviousPage = () => {
|
||||
return trigger(stableArg, "backward");
|
||||
};
|
||||
return {
|
||||
trigger,
|
||||
/**
|
||||
* A method to manually refetch data for the query
|
||||
*/
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
};
|
||||
}, [refetch, trigger, stableArg]);
|
||||
};
|
||||
const useInfiniteQueryState = buildUseQueryState(endpointName, infiniteQueryStatePreSelector);
|
||||
return {
|
||||
useInfiniteQueryState,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQuery(arg, options) {
|
||||
const {
|
||||
refetch,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage
|
||||
} = useInfiniteQuerySubscription(arg, options);
|
||||
const queryStateResults = useInfiniteQueryState(arg, {
|
||||
selectFromResult: arg === skipToken || options?.skip ? void 0 : noPendingQueryStateSelector,
|
||||
...options
|
||||
});
|
||||
const debugValue = pick(queryStateResults, ...COMMON_HOOK_DEBUG_FIELDS, "hasNextPage", "hasPreviousPage");
|
||||
useDebugValue(debugValue);
|
||||
return useMemo(() => ({
|
||||
...queryStateResults,
|
||||
fetchNextPage,
|
||||
fetchPreviousPage,
|
||||
refetch
|
||||
}), [queryStateResults, fetchNextPage, fetchPreviousPage, refetch]);
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildMutationHook(name) {
|
||||
return ({
|
||||
selectFromResult,
|
||||
fixedCacheKey
|
||||
} = {}) => {
|
||||
const {
|
||||
select,
|
||||
initiate
|
||||
} = api.endpoints[name];
|
||||
const dispatch = useDispatch();
|
||||
const [promise, setPromise] = useState();
|
||||
useEffect(() => () => {
|
||||
if (!promise?.arg.fixedCacheKey) {
|
||||
promise?.reset();
|
||||
}
|
||||
}, [promise]);
|
||||
const triggerMutation = useCallback(function(arg) {
|
||||
const promise2 = dispatch(initiate(arg, {
|
||||
fixedCacheKey
|
||||
}));
|
||||
setPromise(promise2);
|
||||
return promise2;
|
||||
}, [dispatch, initiate, fixedCacheKey]);
|
||||
const {
|
||||
requestId
|
||||
} = promise || {};
|
||||
const selectDefaultResult = useMemo(() => select({
|
||||
fixedCacheKey,
|
||||
requestId: promise?.requestId
|
||||
}), [fixedCacheKey, promise, select]);
|
||||
const mutationSelector = useMemo(() => selectFromResult ? createSelector([selectDefaultResult], selectFromResult) : selectDefaultResult, [selectFromResult, selectDefaultResult]);
|
||||
const currentState = useSelector(mutationSelector, shallowEqual);
|
||||
const originalArgs = fixedCacheKey == null ? promise?.arg.originalArgs : void 0;
|
||||
const reset = useCallback(() => {
|
||||
batch(() => {
|
||||
if (promise) {
|
||||
setPromise(void 0);
|
||||
}
|
||||
if (fixedCacheKey) {
|
||||
dispatch(api.internalActions.removeMutationResult({
|
||||
requestId,
|
||||
fixedCacheKey
|
||||
}));
|
||||
}
|
||||
});
|
||||
}, [dispatch, fixedCacheKey, promise, requestId]);
|
||||
const debugValue = pick(currentState, ...COMMON_HOOK_DEBUG_FIELDS, "endpointName");
|
||||
useDebugValue(debugValue);
|
||||
const finalState = useMemo(() => ({
|
||||
...currentState,
|
||||
originalArgs,
|
||||
reset
|
||||
}), [currentState, originalArgs, reset]);
|
||||
return useMemo(() => [triggerMutation, finalState], [triggerMutation, finalState]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// src/query/react/module.ts
|
||||
var reactHooksModuleName = /* @__PURE__ */ Symbol();
|
||||
var reactHooksModule = ({
|
||||
batch = rrBatch,
|
||||
hooks = {
|
||||
useDispatch: rrUseDispatch,
|
||||
useSelector: rrUseSelector,
|
||||
useStore: rrUseStore
|
||||
},
|
||||
createSelector = _createSelector,
|
||||
unstable__sideEffectsInRender = false,
|
||||
...rest
|
||||
} = {}) => {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
const hookNames = ["useDispatch", "useSelector", "useStore"];
|
||||
let warned = false;
|
||||
for (const hookName of hookNames) {
|
||||
if (countObjectKeys(rest) > 0) {
|
||||
if (rest[hookName]) {
|
||||
if (!warned) {
|
||||
console.warn("As of RTK 2.0, the hooks now need to be specified as one object, provided under a `hooks` key:\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`");
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
hooks[hookName] = rest[hookName];
|
||||
}
|
||||
if (typeof hooks[hookName] !== "function") {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage4(36) : `When using custom hooks for context, all ${hookNames.length} hooks need to be provided: ${hookNames.join(", ")}.
|
||||
Hook ${hookName} was either not provided or not a function.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: reactHooksModuleName,
|
||||
init(api, {
|
||||
serializeQueryArgs
|
||||
}, context) {
|
||||
const anyApi = api;
|
||||
const {
|
||||
buildQueryHooks,
|
||||
buildInfiniteQueryHooks,
|
||||
buildMutationHook,
|
||||
usePrefetch
|
||||
} = buildHooks({
|
||||
api,
|
||||
moduleOptions: {
|
||||
batch,
|
||||
hooks,
|
||||
unstable__sideEffectsInRender,
|
||||
createSelector
|
||||
},
|
||||
serializeQueryArgs,
|
||||
context
|
||||
});
|
||||
safeAssign(anyApi, {
|
||||
usePrefetch
|
||||
});
|
||||
safeAssign(context, {
|
||||
batch
|
||||
});
|
||||
return {
|
||||
injectEndpoint(endpointName, definition) {
|
||||
if (isQueryDefinition(definition)) {
|
||||
const {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
} = buildQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useQuery,
|
||||
useLazyQuery,
|
||||
useLazyQuerySubscription,
|
||||
useQueryState,
|
||||
useQuerySubscription
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Query`] = useQuery;
|
||||
api[`useLazy${capitalize(endpointName)}Query`] = useLazyQuery;
|
||||
}
|
||||
if (isMutationDefinition(definition)) {
|
||||
const useMutation = buildMutationHook(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useMutation
|
||||
});
|
||||
api[`use${capitalize(endpointName)}Mutation`] = useMutation;
|
||||
} else if (isInfiniteQueryDefinition(definition)) {
|
||||
const {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
} = buildInfiniteQueryHooks(endpointName);
|
||||
safeAssign(anyApi.endpoints[endpointName], {
|
||||
useInfiniteQuery,
|
||||
useInfiniteQuerySubscription,
|
||||
useInfiniteQueryState
|
||||
});
|
||||
api[`use${capitalize(endpointName)}InfiniteQuery`] = useInfiniteQuery;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/query/react/index.ts
|
||||
export * from "@reduxjs/toolkit/query";
|
||||
|
||||
// src/query/react/ApiProvider.tsx
|
||||
import { configureStore, formatProdErrorMessage as _formatProdErrorMessage5 } from "@reduxjs/toolkit";
|
||||
import * as React from "react";
|
||||
function ApiProvider(props) {
|
||||
const context = props.context || ReactReduxContext;
|
||||
const existingContext = useContext(context);
|
||||
if (existingContext) {
|
||||
throw new Error(process.env.NODE_ENV === "production" ? _formatProdErrorMessage5(35) : "Existing Redux context detected. If you already have a store set up, please use the traditional Redux setup.");
|
||||
}
|
||||
const [store] = React.useState(() => configureStore({
|
||||
reducer: {
|
||||
[props.api.reducerPath]: props.api.reducer
|
||||
},
|
||||
middleware: (gDM) => gDM().concat(props.api.middleware)
|
||||
}));
|
||||
useEffect(() => props.setupListeners === false ? void 0 : setupListeners(store.dispatch, props.setupListeners), [props.setupListeners, store.dispatch]);
|
||||
return /* @__PURE__ */ React.createElement(Provider, { store, context }, props.children);
|
||||
}
|
||||
|
||||
// src/query/react/index.ts
|
||||
var createApi = /* @__PURE__ */ buildCreateApi(coreModule(), reactHooksModule());
|
||||
export {
|
||||
ApiProvider,
|
||||
UNINITIALIZED_VALUE,
|
||||
createApi,
|
||||
reactHooksModule,
|
||||
reactHooksModuleName
|
||||
};
|
||||
//# sourceMappingURL=rtk-query-react.modern.mjs.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.browser.mjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.browser.mjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.browser.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.browser.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
3116
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.legacy-esm.js
generated
vendored
Normal file
3116
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.legacy-esm.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.legacy-esm.js.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.legacy-esm.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
3047
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.mjs
generated
vendored
Normal file
3047
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.mjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/query/rtk-query.modern.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
6
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/index.js
generated
vendored
Normal file
6
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict'
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./redux-toolkit-react.production.min.cjs')
|
||||
} else {
|
||||
module.exports = require('./redux-toolkit-react.development.cjs')
|
||||
}
|
||||
55
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.development.cjs
generated
vendored
Normal file
55
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.development.cjs
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/react/index.ts
|
||||
var react_exports = {};
|
||||
__export(react_exports, {
|
||||
createDynamicMiddleware: () => createDynamicMiddleware
|
||||
});
|
||||
module.exports = __toCommonJS(react_exports);
|
||||
__reExport(react_exports, require("@reduxjs/toolkit"), module.exports);
|
||||
|
||||
// src/dynamicMiddleware/react/index.ts
|
||||
var import_toolkit = require("@reduxjs/toolkit");
|
||||
var import_react_redux = require("react-redux");
|
||||
var createDynamicMiddleware = () => {
|
||||
const instance = (0, import_toolkit.createDynamicMiddleware)();
|
||||
const createDispatchWithMiddlewareHookFactory = (context = import_react_redux.ReactReduxContext) => {
|
||||
const useDispatch = context === import_react_redux.ReactReduxContext ? import_react_redux.useDispatch : (0, import_react_redux.createDispatchHook)(context);
|
||||
function createDispatchWithMiddlewareHook2(...middlewares) {
|
||||
instance.addMiddleware(...middlewares);
|
||||
return useDispatch;
|
||||
}
|
||||
createDispatchWithMiddlewareHook2.withTypes = () => createDispatchWithMiddlewareHook2;
|
||||
return createDispatchWithMiddlewareHook2;
|
||||
};
|
||||
const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();
|
||||
return {
|
||||
...instance,
|
||||
createDispatchWithMiddlewareHookFactory,
|
||||
createDispatchWithMiddlewareHook
|
||||
};
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
createDynamicMiddleware,
|
||||
...require("@reduxjs/toolkit")
|
||||
});
|
||||
//# sourceMappingURL=redux-toolkit-react.development.cjs.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.development.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.development.cjs.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../../../src/react/index.ts","../../../src/dynamicMiddleware/react/index.ts"],"sourcesContent":["// This must remain here so that the `mangleErrors.cjs` build script\n// does not have to import this into each source file it rewrites.\nimport { formatProdErrorMessage } from '@reduxjs/toolkit';\nexport * from '@reduxjs/toolkit';\nexport { createDynamicMiddleware } from '../dynamicMiddleware/react';\nexport type { CreateDispatchWithMiddlewareHook } from '../dynamicMiddleware/react/index';","import type { DynamicMiddlewareInstance, GetDispatch, GetState, MiddlewareApiConfig, TSHelpersExtractDispatchExtensions } from '@reduxjs/toolkit';\nimport { createDynamicMiddleware as cDM } from '@reduxjs/toolkit';\nimport type { Context } from 'react';\nimport type { ReactReduxContextValue } from 'react-redux';\nimport { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from 'react-redux';\nimport type { Action, Dispatch, Middleware, UnknownAction } from 'redux';\nexport type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;\nexport type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {\n <Middlewares extends [Middleware<any, State, DispatchType>, ...Middleware<any, State, DispatchType>[]]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;\n withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;\n};\ntype ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;\ntype ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {\n createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;\n createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;\n};\nexport const createDynamicMiddleware = <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>(): ReactDynamicMiddlewareInstance<State, DispatchType> => {\n const instance = cDM<State, DispatchType>();\n const createDispatchWithMiddlewareHookFactory = (\n // @ts-ignore\n context: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null> = ReactReduxContext) => {\n const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);\n function createDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[]>(...middlewares: Middlewares) {\n instance.addMiddleware(...middlewares);\n return useDispatch;\n }\n createDispatchWithMiddlewareHook.withTypes = () => createDispatchWithMiddlewareHook;\n return createDispatchWithMiddlewareHook as CreateDispatchWithMiddlewareHook<State, DispatchType>;\n };\n const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();\n return {\n ...instance,\n createDispatchWithMiddlewareHookFactory,\n createDispatchWithMiddlewareHook\n };\n};"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,0BAAc,6BAHd;;;ACCA,qBAA+C;AAG/C,yBAAyF;AAYlF,IAAM,0BAA0B,MAAgJ;AACrL,QAAM,eAAW,eAAAA,yBAAyB;AAC1C,QAAM,0CAA0C,CAEhD,UAA2F,yCAAsB;AAC/G,UAAM,cAAc,YAAY,uCAAoB,mBAAAC,kBAAqB,uCAAmB,OAAO;AACnG,aAASC,qCAAgG,aAA0B;AACjI,eAAS,cAAc,GAAG,WAAW;AACrC,aAAO;AAAA,IACT;AACA,IAAAA,kCAAiC,YAAY,MAAMA;AACnD,WAAOA;AAAA,EACT;AACA,QAAM,mCAAmC,wCAAwC;AACjF,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AACF;","names":["cDM","useDefaultDispatch","createDispatchWithMiddlewareHook"]}
|
||||
2
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.production.min.cjs
generated
vendored
Normal file
2
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.production.min.cjs
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";var s=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var M=Object.prototype.hasOwnProperty;var x=(t,e)=>{for(var a in e)s(t,a,{get:e[a],enumerable:!0})},d=(t,e,a,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of y(e))!M.call(t,i)&&i!==a&&s(t,i,{get:()=>e[i],enumerable:!(n=w(e,i))||n.enumerable});return t},r=(t,e,a)=>(d(t,e,"default"),a&&d(a,e,"default"));var m=t=>d(s({},"__esModule",{value:!0}),t);var o={};x(o,{createDynamicMiddleware:()=>D});module.exports=m(o);r(o,require("@reduxjs/toolkit"),module.exports);var h=require("@reduxjs/toolkit"),c=require("react-redux"),D=()=>{let t=(0,h.createDynamicMiddleware)(),e=(n=c.ReactReduxContext)=>{let i=n===c.ReactReduxContext?c.useDispatch:(0,c.createDispatchHook)(n);function p(...l){return t.addMiddleware(...l),i}return p.withTypes=()=>p,p},a=e();return{...t,createDispatchWithMiddlewareHookFactory:e,createDispatchWithMiddlewareHook:a}};0&&(module.exports={createDynamicMiddleware,...require("@reduxjs/toolkit")});
|
||||
//# sourceMappingURL=redux-toolkit-react.production.min.cjs.map
|
||||
1
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.production.min.cjs.map
generated
vendored
Normal file
1
frontend/node_modules/@reduxjs/toolkit/dist/react/cjs/redux-toolkit-react.production.min.cjs.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../../../src/react/index.ts","../../../src/dynamicMiddleware/react/index.ts"],"sourcesContent":["// This must remain here so that the `mangleErrors.cjs` build script\n// does not have to import this into each source file it rewrites.\nimport { formatProdErrorMessage } from '@reduxjs/toolkit';\nexport * from '@reduxjs/toolkit';\nexport { createDynamicMiddleware } from '../dynamicMiddleware/react';\nexport type { CreateDispatchWithMiddlewareHook } from '../dynamicMiddleware/react/index';","import type { DynamicMiddlewareInstance, GetDispatch, GetState, MiddlewareApiConfig, TSHelpersExtractDispatchExtensions } from '@reduxjs/toolkit';\nimport { createDynamicMiddleware as cDM } from '@reduxjs/toolkit';\nimport type { Context } from 'react';\nimport type { ReactReduxContextValue } from 'react-redux';\nimport { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from 'react-redux';\nimport type { Action, Dispatch, Middleware, UnknownAction } from 'redux';\nexport type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;\nexport type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {\n <Middlewares extends [Middleware<any, State, DispatchType>, ...Middleware<any, State, DispatchType>[]]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;\n withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;\n};\ntype ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;\ntype ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {\n createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;\n createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;\n};\nexport const createDynamicMiddleware = <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>(): ReactDynamicMiddlewareInstance<State, DispatchType> => {\n const instance = cDM<State, DispatchType>();\n const createDispatchWithMiddlewareHookFactory = (\n // @ts-ignore\n context: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null> = ReactReduxContext) => {\n const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);\n function createDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[]>(...middlewares: Middlewares) {\n instance.addMiddleware(...middlewares);\n return useDispatch;\n }\n createDispatchWithMiddlewareHook.withTypes = () => createDispatchWithMiddlewareHook;\n return createDispatchWithMiddlewareHook as CreateDispatchWithMiddlewareHook<State, DispatchType>;\n };\n const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();\n return {\n ...instance,\n createDispatchWithMiddlewareHookFactory,\n createDispatchWithMiddlewareHook\n };\n};"],"mappings":"2dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,6BAAAE,IAAA,eAAAC,EAAAH,GAGAI,EAAAJ,EAAc,4BAHd,gBCCA,IAAAK,EAA+C,4BAG/CC,EAAyF,uBAY5EC,EAA0B,IAAgJ,CACrL,IAAMC,KAAW,EAAAC,yBAAyB,EACpCC,EAA0C,CAEhDC,EAA2F,sBAAsB,CAC/G,IAAMC,EAAcD,IAAY,oBAAoB,EAAAE,eAAqB,sBAAmBF,CAAO,EACnG,SAASG,KAAgGC,EAA0B,CACjI,OAAAP,EAAS,cAAc,GAAGO,CAAW,EAC9BH,CACT,CACA,OAAAE,EAAiC,UAAY,IAAMA,EAC5CA,CACT,EACMA,EAAmCJ,EAAwC,EACjF,MAAO,CACL,GAAGF,EACH,wCAAAE,EACA,iCAAAI,CACF,CACF","names":["react_exports","__export","createDynamicMiddleware","__toCommonJS","__reExport","import_toolkit","import_react_redux","createDynamicMiddleware","instance","cDM","createDispatchWithMiddlewareHookFactory","context","useDispatch","useDefaultDispatch","createDispatchWithMiddlewareHook","middlewares"]}
|
||||
22
frontend/node_modules/@reduxjs/toolkit/dist/react/index.d.mts
generated
vendored
Normal file
22
frontend/node_modules/@reduxjs/toolkit/dist/react/index.d.mts
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { DynamicMiddlewareInstance, TSHelpersExtractDispatchExtensions, MiddlewareApiConfig, GetState, GetDispatch } from '@reduxjs/toolkit';
|
||||
export * from '@reduxjs/toolkit';
|
||||
import { Context } from 'react';
|
||||
import { ReactReduxContextValue } from 'react-redux';
|
||||
import { Dispatch, UnknownAction, Action, Middleware } from 'redux';
|
||||
|
||||
type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;
|
||||
type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {
|
||||
<Middlewares extends [
|
||||
Middleware<any, State, DispatchType>,
|
||||
...Middleware<any, State, DispatchType>[]
|
||||
]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;
|
||||
withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;
|
||||
};
|
||||
type ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;
|
||||
type ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {
|
||||
createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;
|
||||
createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;
|
||||
};
|
||||
declare const createDynamicMiddleware: <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>() => ReactDynamicMiddlewareInstance<State, DispatchType>;
|
||||
|
||||
export { type CreateDispatchWithMiddlewareHook, createDynamicMiddleware };
|
||||
22
frontend/node_modules/@reduxjs/toolkit/dist/react/index.d.ts
generated
vendored
Normal file
22
frontend/node_modules/@reduxjs/toolkit/dist/react/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { DynamicMiddlewareInstance, TSHelpersExtractDispatchExtensions, MiddlewareApiConfig, GetState, GetDispatch } from '@reduxjs/toolkit';
|
||||
export * from '@reduxjs/toolkit';
|
||||
import { Context } from 'react';
|
||||
import { ReactReduxContextValue } from 'react-redux';
|
||||
import { Dispatch, UnknownAction, Action, Middleware } from 'redux';
|
||||
|
||||
type UseDispatchWithMiddlewareHook<Middlewares extends Middleware<any, State, DispatchType>[] = [], State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = () => TSHelpersExtractDispatchExtensions<Middlewares> & DispatchType;
|
||||
type CreateDispatchWithMiddlewareHook<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = {
|
||||
<Middlewares extends [
|
||||
Middleware<any, State, DispatchType>,
|
||||
...Middleware<any, State, DispatchType>[]
|
||||
]>(...middlewares: Middlewares): UseDispatchWithMiddlewareHook<Middlewares, State, DispatchType>;
|
||||
withTypes<MiddlewareConfig extends MiddlewareApiConfig>(): CreateDispatchWithMiddlewareHook<GetState<MiddlewareConfig>, GetDispatch<MiddlewareConfig>>;
|
||||
};
|
||||
type ActionFromDispatch<DispatchType extends Dispatch<Action>> = DispatchType extends Dispatch<infer Action> ? Action : never;
|
||||
type ReactDynamicMiddlewareInstance<State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> = DynamicMiddlewareInstance<State, DispatchType> & {
|
||||
createDispatchWithMiddlewareHookFactory: (context?: Context<ReactReduxContextValue<State, ActionFromDispatch<DispatchType>> | null>) => CreateDispatchWithMiddlewareHook<State, DispatchType>;
|
||||
createDispatchWithMiddlewareHook: CreateDispatchWithMiddlewareHook<State, DispatchType>;
|
||||
};
|
||||
declare const createDynamicMiddleware: <State = any, DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>>() => ReactDynamicMiddlewareInstance<State, DispatchType>;
|
||||
|
||||
export { type CreateDispatchWithMiddlewareHook, createDynamicMiddleware };
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user