Merge pull request 'fix engram rtk' (#42) from pre-dev into dev
All checks were successful
DEPLOY_MULTI_BRACH/pipeline/head This commit looks good

Reviewed-on: #42
This commit was merged in pull request #42.
This commit is contained in:
2026-04-16 16:25:26 +00:00
1030 changed files with 947923 additions and 3 deletions

View File

@@ -16,7 +16,15 @@
"Bash(mv core:*)", "Bash(mv core:*)",
"Bash(mv apps/backend_admin app/backend_admin)", "Bash(mv apps/backend_admin app/backend_admin)",
"Bash(mv apps/common app/common)", "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:*)"
] ]
} }
} }

View File

@@ -58,6 +58,7 @@ INSTALLED_APPS = [
# Tus Apps (Asegúrate de que el path sea correcto) # Tus Apps (Asegúrate de que el path sea correcto)
'general', 'general',
'promociones', 'promociones',
'automatizados',
'backend_admin', 'backend_admin',
'common', 'common',
] ]

View File

@@ -2,8 +2,9 @@ from django.urls import path, include
from backend_admin import views as admin_views from backend_admin import views as admin_views
urlpatterns = [ urlpatterns = [
path('general/', include('general.urls')),
path('admin/', include('backend_admin.urls')), 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'), path('api/token/', admin_views.api_token, name='token_obtain_pair'),
] ]

View File

View 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,
}

View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class AutomatizadosConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'automatizados'

View 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
}
}
]

View File

View 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}]'

View 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
View 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)

View File

@@ -91,6 +91,7 @@ class LogService:
) )
return nuevo_log.pk return nuevo_log.pk
else: else:
# --- ACTUALIZACIÓN: enriquece el log con datos del procesamiento --- # --- ACTUALIZACIÓN: enriquece el log con datos del procesamiento ---
datos_a_actualizar = { datos_a_actualizar = {

12
frontend/index.html Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

21
frontend/node_modules/@reduxjs/toolkit/LICENSE generated vendored Normal file
View 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
View File

@@ -0,0 +1,110 @@
# Redux Toolkit
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/reduxjs/redux-toolkit/tests.yml?style=flat-square)
[![npm version](https://img.shields.io/npm/v/@reduxjs/toolkit.svg?style=flat-square)](https://www.npmjs.com/package/@reduxjs/toolkit)
[![npm downloads](https://img.shields.io/npm/dm/@reduxjs/toolkit.svg?style=flat-square&label=RTK+downloads)](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.

View 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')
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

File diff suppressed because it is too large Load Diff

2662
frontend/node_modules/@reduxjs/toolkit/dist/index.d.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

View 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')
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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')
}

View 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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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 };

View 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 };

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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

File diff suppressed because one or more lines are too long

View 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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View 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')
}

View 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

View 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"]}

View 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

View 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"]}

View 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 };

View 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 };

View File

@@ -0,0 +1,2 @@
export*from"@reduxjs/toolkit";import{createDynamicMiddleware as p}from"@reduxjs/toolkit";import{createDispatchHook as d,ReactReduxContext as c,useDispatch as s}from"react-redux";var h=()=>{let t=p(),a=(i=c)=>{let o=i===c?s:d(i);function e(...r){return t.addMiddleware(...r),o}return e.withTypes=()=>e,e},n=a();return{...t,createDispatchWithMiddlewareHookFactory:a,createDispatchWithMiddlewareHook:n}};export{h as createDynamicMiddleware};
//# sourceMappingURL=redux-toolkit-react.browser.mjs.map

View 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":"AAGA,WAAc,mBCFd,OAAS,2BAA2BA,MAAW,mBAG/C,OAAS,sBAAAC,EAAoB,qBAAAC,EAAmB,eAAeC,MAA0B,cAYlF,IAAMC,EAA0B,IAAgJ,CACrL,IAAMC,EAAWL,EAAyB,EACpCM,EAA0C,CAEhDC,EAA2FL,IAAsB,CAC/G,IAAMM,EAAcD,IAAYL,EAAoBC,EAAqBF,EAAmBM,CAAO,EACnG,SAASE,KAAgGC,EAA0B,CACjI,OAAAL,EAAS,cAAc,GAAGK,CAAW,EAC9BF,CACT,CACA,OAAAC,EAAiC,UAAY,IAAMA,EAC5CA,CACT,EACMA,EAAmCH,EAAwC,EACjF,MAAO,CACL,GAAGD,EACH,wCAAAC,EACA,iCAAAG,CACF,CACF","names":["cDM","createDispatchHook","ReactReduxContext","useDefaultDispatch","createDynamicMiddleware","instance","createDispatchWithMiddlewareHookFactory","context","useDispatch","createDispatchWithMiddlewareHook","middlewares"]}

View File

@@ -0,0 +1,47 @@
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));
// src/react/index.ts
export * from "@reduxjs/toolkit";
// src/dynamicMiddleware/react/index.ts
import { createDynamicMiddleware as cDM } from "@reduxjs/toolkit";
import { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from "react-redux";
var createDynamicMiddleware = () => {
const instance = cDM();
const createDispatchWithMiddlewareHookFactory = (context = ReactReduxContext) => {
const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);
function createDispatchWithMiddlewareHook2(...middlewares) {
instance.addMiddleware(...middlewares);
return useDispatch;
}
createDispatchWithMiddlewareHook2.withTypes = () => createDispatchWithMiddlewareHook2;
return createDispatchWithMiddlewareHook2;
};
const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();
return __spreadProps(__spreadValues({}, instance), {
createDispatchWithMiddlewareHookFactory,
createDispatchWithMiddlewareHook
});
};
export {
createDynamicMiddleware
};
//# sourceMappingURL=redux-toolkit-react.legacy-esm.js.map

View 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":";;;;;;;;;;;;;;;;;;;;;AAGA,cAAc;;;ACFd,SAAS,2BAA2B,WAAW;AAG/C,SAAS,oBAAoB,mBAAmB,eAAe,0BAA0B;AAYlF,IAAM,0BAA0B,MAAgJ;AACrL,QAAM,WAAW,IAAyB;AAC1C,QAAM,0CAA0C,CAEhD,UAA2F,sBAAsB;AAC/G,UAAM,cAAc,YAAY,oBAAoB,qBAAqB,mBAAmB,OAAO;AACnG,aAASA,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,iCACF,WADE;AAAA,IAEL;AAAA,IACA;AAAA,EACF;AACF;","names":["createDispatchWithMiddlewareHook"]}

View File

@@ -0,0 +1,28 @@
// src/react/index.ts
export * from "@reduxjs/toolkit";
// src/dynamicMiddleware/react/index.ts
import { createDynamicMiddleware as cDM } from "@reduxjs/toolkit";
import { createDispatchHook, ReactReduxContext, useDispatch as useDefaultDispatch } from "react-redux";
var createDynamicMiddleware = () => {
const instance = cDM();
const createDispatchWithMiddlewareHookFactory = (context = ReactReduxContext) => {
const useDispatch = context === ReactReduxContext ? useDefaultDispatch : createDispatchHook(context);
function createDispatchWithMiddlewareHook2(...middlewares) {
instance.addMiddleware(...middlewares);
return useDispatch;
}
createDispatchWithMiddlewareHook2.withTypes = () => createDispatchWithMiddlewareHook2;
return createDispatchWithMiddlewareHook2;
};
const createDispatchWithMiddlewareHook = createDispatchWithMiddlewareHookFactory();
return {
...instance,
createDispatchWithMiddlewareHookFactory,
createDispatchWithMiddlewareHook
};
};
export {
createDynamicMiddleware
};
//# sourceMappingURL=redux-toolkit-react.modern.mjs.map

View 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":";AAGA,cAAc;;;ACFd,SAAS,2BAA2B,WAAW;AAG/C,SAAS,oBAAoB,mBAAmB,eAAe,0BAA0B;AAYlF,IAAM,0BAA0B,MAAgJ;AACrL,QAAM,WAAW,IAAyB;AAC1C,QAAM,0CAA0C,CAEhD,UAA2F,sBAAsB;AAC/G,UAAM,cAAc,YAAY,oBAAoB,qBAAqB,mBAAmB,OAAO;AACnG,aAASA,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":["createDispatchWithMiddlewareHook"]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
// inlined from https://github.com/EskiMojo14/uncheckedindexed
// relies on remaining as a TS file, not .d.ts
type IfMaybeUndefined<T, True, False> = [undefined] extends [T] ? True : False
const testAccess = ({} as Record<string, 0>)['a']
export type IfUncheckedIndexedAccess<True, False> = IfMaybeUndefined<
typeof testAccess,
True,
False
>
export type UncheckedIndexedAccess<T> = IfUncheckedIndexedAccess<
T | undefined,
T
>

286
frontend/node_modules/@reduxjs/toolkit/package.json generated vendored Normal file
View File

@@ -0,0 +1,286 @@
{
"name": "@reduxjs/toolkit",
"version": "2.11.2",
"description": "The official, opinionated, batteries-included toolset for efficient Redux development",
"author": "Mark Erikson <mark@isquaredsoftware.com>",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/reduxjs/redux-toolkit.git"
},
"keywords": [
"redux",
"react",
"starter",
"toolkit",
"reducer",
"slice",
"immer",
"immutable",
"redux-toolkit"
],
"publishConfig": {
"access": "public"
},
"module": "dist/redux-toolkit.legacy-esm.js",
"main": "dist/cjs/index.js",
"types": "dist/index.d.ts",
"react-native": "dist/redux-toolkit.legacy-esm.js",
"unpkg": "dist/redux-toolkit.browser.mjs",
"exports": {
"./package.json": "./package.json",
".": {
"module-sync": {
"types": "./dist/index.d.mts",
"default": "./dist/redux-toolkit.modern.mjs"
},
"module": {
"types": "./dist/index.d.mts",
"default": "./dist/redux-toolkit.modern.mjs"
},
"react-native": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/redux-toolkit.modern.mjs"
},
"default": {
"types": "./dist/index.d.ts",
"default": "./dist/cjs/index.js"
}
},
"browser": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/redux-toolkit.browser.mjs"
},
"default": {
"types": "./dist/index.d.ts",
"default": "./dist/cjs/index.js"
}
},
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/redux-toolkit.modern.mjs"
},
"default": {
"types": "./dist/index.d.ts",
"default": "./dist/cjs/index.js"
}
},
"./react": {
"module-sync": {
"types": "./dist/react/index.d.mts",
"default": "./dist/react/redux-toolkit-react.modern.mjs"
},
"module": {
"types": "./dist/react/index.d.mts",
"default": "./dist/react/redux-toolkit-react.modern.mjs"
},
"react-native": {
"import": {
"types": "./dist/react/index.d.mts",
"default": "./dist/react/redux-toolkit-react.modern.mjs"
},
"default": {
"types": "./dist/react/index.d.ts",
"default": "./dist/react/cjs/index.js"
}
},
"browser": {
"import": {
"types": "./dist/react/index.d.mts",
"default": "./dist/react/redux-toolkit-react.browser.mjs"
},
"default": {
"types": "./dist/react/index.d.ts",
"default": "./dist/react/cjs/index.js"
}
},
"import": {
"types": "./dist/react/index.d.mts",
"default": "./dist/react/redux-toolkit-react.modern.mjs"
},
"default": {
"types": "./dist/react/index.d.ts",
"default": "./dist/react/cjs/index.js"
}
},
"./query": {
"module-sync": {
"types": "./dist/query/index.d.mts",
"default": "./dist/query/rtk-query.modern.mjs"
},
"module": {
"types": "./dist/query/index.d.mts",
"default": "./dist/query/rtk-query.modern.mjs"
},
"react-native": {
"import": {
"types": "./dist/query/index.d.mts",
"default": "./dist/query/rtk-query.modern.mjs"
},
"default": {
"types": "./dist/query/index.d.ts",
"default": "./dist/query/cjs/index.js"
}
},
"browser": {
"import": {
"types": "./dist/query/index.d.mts",
"default": "./dist/query/rtk-query.browser.mjs"
},
"default": {
"types": "./dist/query/index.d.ts",
"default": "./dist/query/cjs/index.js"
}
},
"import": {
"types": "./dist/query/index.d.mts",
"default": "./dist/query/rtk-query.modern.mjs"
},
"default": {
"types": "./dist/query/index.d.ts",
"default": "./dist/query/cjs/index.js"
}
},
"./query/react": {
"module-sync": {
"types": "./dist/query/react/index.d.mts",
"default": "./dist/query/react/rtk-query-react.modern.mjs"
},
"module": {
"types": "./dist/query/react/index.d.mts",
"default": "./dist/query/react/rtk-query-react.modern.mjs"
},
"react-native": {
"import": {
"types": "./dist/query/react/index.d.mts",
"default": "./dist/query/react/rtk-query-react.modern.mjs"
},
"default": {
"types": "./dist/query/react/index.d.ts",
"default": "./dist/query/react/cjs/index.js"
}
},
"browser": {
"import": {
"types": "./dist/query/react/index.d.mts",
"default": "./dist/query/react/rtk-query-react.browser.mjs"
},
"default": {
"types": "./dist/query/react/index.d.ts",
"default": "./dist/query/react/cjs/index.js"
}
},
"import": {
"types": "./dist/query/react/index.d.mts",
"default": "./dist/query/react/rtk-query-react.modern.mjs"
},
"default": {
"types": "./dist/query/react/index.d.ts",
"default": "./dist/query/react/cjs/index.js"
}
}
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.13.5",
"@babel/core": "^7.24.8",
"@babel/helper-module-imports": "^7.24.7",
"@microsoft/api-extractor": "^7.13.2",
"@phryneas/ts-version": "^1.0.2",
"@size-limit/file": "^11.0.1",
"@size-limit/webpack": "^11.0.1",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.0.1",
"@testing-library/react-render-stream": "^1.0.3",
"@testing-library/user-event": "^14.5.2",
"@types/babel__core": "^7.20.5",
"@types/babel__helper-module-imports": "^7.18.3",
"@types/json-stringify-safe": "^5.0.0",
"@types/nanoid": "^2.1.0",
"@types/node": "^20.11.0",
"@types/query-string": "^6.3.0",
"@types/react": "^19.0.1",
"@types/react-dom": "^19.0.1",
"@types/yargs": "^16.0.1",
"@typescript-eslint/eslint-plugin": "^6",
"@typescript-eslint/parser": "^6",
"axios": "^0.19.2",
"esbuild": "^0.25.1",
"esbuild-extra": "^0.4.0",
"eslint": "^7.25.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-flowtype": "^5.7.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "^4.2.0",
"fs-extra": "^9.1.0",
"invariant": "^2.2.4",
"jsdom": "^25.0.1",
"json-stringify-safe": "^5.0.1",
"msw": "^2.1.4",
"node-fetch": "^3.3.2",
"prettier": "^3.2.5",
"query-string": "^7.0.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"rimraf": "^3.0.2",
"size-limit": "^11.0.1",
"tslib": "^1.10.0",
"tsup": "^8.4.0",
"tsx": "^4.19.0",
"typescript": "^5.8.2",
"valibot": "^1.0.0",
"vite-tsconfig-paths": "^4.3.1",
"vitest": "^4",
"yargs": "^15.3.1"
},
"scripts": {
"clean": "rimraf dist",
"run-build": "tsup --config=$INIT_CWD/tsup.config.mts",
"build": "yarn clean && yarn run-build && tsx scripts/fixUniqueSymbolExports.mts",
"build-only": "yarn clean && yarn run-build",
"format": "prettier --write \"(src|examples)/**/*.{ts,tsx}\" \"**/*.md\"",
"format:check": "prettier --list-different \"(src|examples)/**/*.{ts,tsx}\" \"docs/*/**.md\"",
"lint": "eslint src examples",
"test": "vitest --typecheck --run ",
"test:watch": "vitest --watch",
"type-tests": "yarn tsc -p tsconfig.test.json --noEmit",
"prepack": "yarn build",
"size": "size-limit"
},
"files": [
"dist/",
"src/",
"query",
"react"
],
"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
}
},
"sideEffects": false,
"bugs": {
"url": "https://github.com/reduxjs/redux-toolkit/issues"
},
"homepage": "https://redux-toolkit.js.org"
}

View File

@@ -0,0 +1,13 @@
{
"name": "@reduxjs/toolkit-query",
"version": "1.0.0",
"description": "",
"type": "module",
"module": "../dist/query/rtk-query.legacy-esm.js",
"main": "../dist/query/cjs/index.js",
"types": "./../dist/query/index.d.ts",
"react-native": "./../dist/query/rtk-query.legacy-esm.js",
"author": "Mark Erikson <mark@isquaredsoftware.com>",
"license": "MIT",
"sideEffects": false
}

View File

@@ -0,0 +1,13 @@
{
"name": "@reduxjs/toolkit-query-react",
"version": "1.0.0",
"description": "",
"type": "module",
"module": "../../dist/query/react/rtk-query-react.legacy-esm.js",
"main": "../../dist/query/react/cjs/index.js",
"types": "./../../dist/query/react/index.d.ts",
"react-native": "./../../dist/query/react/rtk-query-react.legacy-esm.js",
"author": "Mark Erikson <mark@isquaredsoftware.com>",
"license": "MIT",
"sideEffects": false
}

View File

@@ -0,0 +1,13 @@
{
"name": "@reduxjs/toolkit-react",
"version": "1.0.0",
"description": "",
"type": "module",
"module": "../dist/react/redux-toolkit-react.legacy-esm.js",
"main": "./../dist/react/redux-toolkit-react.modern.mjs",
"types": "./../dist/react/index.d.ts",
"react-native": "./../dist/react/redux-toolkit-react.modern.mjs",
"author": "Mark Erikson <mark@isquaredsoftware.com>",
"license": "MIT",
"sideEffects": false
}

View File

@@ -0,0 +1,34 @@
import type { Middleware } from 'redux'
import { isActionCreator as isRTKAction } from './createAction'
export interface ActionCreatorInvariantMiddlewareOptions {
/**
* The function to identify whether a value is an action creator.
* The default checks for a function with a static type property and match method.
*/
isActionCreator?: (action: unknown) => action is Function & { type?: unknown }
}
export function getMessage(type?: unknown) {
const splitType = type ? `${type}`.split('/') : []
const actionName = splitType[splitType.length - 1] || 'actionCreator'
return `Detected an action creator with type "${
type || 'unknown'
}" being dispatched.
Make sure you're calling the action creator before dispatching, i.e. \`dispatch(${actionName}())\` instead of \`dispatch(${actionName})\`. This is necessary even if the action has no payload.`
}
export function createActionCreatorInvariantMiddleware(
options: ActionCreatorInvariantMiddlewareOptions = {},
): Middleware {
if (process.env.NODE_ENV === 'production') {
return () => (next) => (action) => next(action)
}
const { isActionCreator = isRTKAction } = options
return () => (next) => (action) => {
if (isActionCreator(action)) {
console.warn(getMessage(action.type))
}
return next(action)
}
}

View File

@@ -0,0 +1,128 @@
import type { StoreEnhancer } from 'redux'
export const SHOULD_AUTOBATCH = 'RTK_autoBatch'
export const prepareAutoBatched =
<T>() =>
(payload: T): { payload: T; meta: unknown } => ({
payload,
meta: { [SHOULD_AUTOBATCH]: true },
})
const createQueueWithTimer = (timeout: number) => {
return (notify: () => void) => {
setTimeout(notify, timeout)
}
}
export type AutoBatchOptions =
| { type: 'tick' }
| { type: 'timer'; timeout: number }
| { type: 'raf' }
| { type: 'callback'; queueNotification: (notify: () => void) => void }
/**
* A Redux store enhancer that watches for "low-priority" actions, and delays
* notifying subscribers until either the queued callback executes or the
* next "standard-priority" action is dispatched.
*
* This allows dispatching multiple "low-priority" actions in a row with only
* a single subscriber notification to the UI after the sequence of actions
* is finished, thus improving UI re-render performance.
*
* Watches for actions with the `action.meta[SHOULD_AUTOBATCH]` attribute.
* This can be added to `action.meta` manually, or by using the
* `prepareAutoBatched` helper.
*
* By default, it will queue a notification for the end of the event loop tick.
* However, you can pass several other options to configure the behavior:
* - `{type: 'tick'}`: queues using `queueMicrotask`
* - `{type: 'timer', timeout: number}`: queues using `setTimeout`
* - `{type: 'raf'}`: queues using `requestAnimationFrame` (default)
* - `{type: 'callback', queueNotification: (notify: () => void) => void}`: lets you provide your own callback
*
*
*/
export const autoBatchEnhancer =
(options: AutoBatchOptions = { type: 'raf' }): StoreEnhancer =>
(next) =>
(...args) => {
const store = next(...args)
let notifying = true
let shouldNotifyAtEndOfTick = false
let notificationQueued = false
const listeners = new Set<() => void>()
const queueCallback =
options.type === 'tick'
? queueMicrotask
: options.type === 'raf'
? // requestAnimationFrame won't exist in SSR environments. Fall back to a vague approximation just to keep from erroring.
typeof window !== 'undefined' && window.requestAnimationFrame
? window.requestAnimationFrame
: createQueueWithTimer(10)
: options.type === 'callback'
? options.queueNotification
: createQueueWithTimer(options.timeout)
const notifyListeners = () => {
// We're running at the end of the event loop tick.
// Run the real listener callbacks to actually update the UI.
notificationQueued = false
if (shouldNotifyAtEndOfTick) {
shouldNotifyAtEndOfTick = false
listeners.forEach((l) => l())
}
}
return Object.assign({}, store, {
// Override the base `store.subscribe` method to keep original listeners
// from running if we're delaying notifications
subscribe(listener: () => void) {
// Each wrapped listener will only call the real listener if
// the `notifying` flag is currently active when it's called.
// This lets the base store work as normal, while the actual UI
// update becomes controlled by this enhancer.
const wrappedListener: typeof listener = () => notifying && listener()
const unsubscribe = store.subscribe(wrappedListener)
listeners.add(listener)
return () => {
unsubscribe()
listeners.delete(listener)
}
},
// Override the base `store.dispatch` method so that we can check actions
// for the `shouldAutoBatch` flag and determine if batching is active
dispatch(action: any) {
try {
// If the action does _not_ have the `shouldAutoBatch` flag,
// we resume/continue normal notify-after-each-dispatch behavior
notifying = !action?.meta?.[SHOULD_AUTOBATCH]
// If a `notifyListeners` microtask was queued, you can't cancel it.
// Instead, we set a flag so that it's a no-op when it does run
shouldNotifyAtEndOfTick = !notifying
if (shouldNotifyAtEndOfTick) {
// We've seen at least 1 action with `SHOULD_AUTOBATCH`. Try to queue
// a microtask to notify listeners at the end of the event loop tick.
// Make sure we only enqueue this _once_ per tick.
if (!notificationQueued) {
notificationQueued = true
queueCallback(notifyListeners)
}
}
// Go ahead and process the action as usual, including reducers.
// If normal notification behavior is enabled, the store will notify
// all of its own listeners, and the wrapper callbacks above will
// see `notifying` is true and pass on to the real listener callbacks.
// If we're "batching" behavior, then the wrapped callbacks will
// bail out, causing the base store notification behavior to be no-ops.
return store.dispatch(action)
} finally {
// Assume we're back to normal behavior after each action
notifying = true
}
},
})
}

View File

@@ -0,0 +1,487 @@
import type {
PreloadedStateShapeFromReducersMapObject,
Reducer,
StateFromReducersMapObject,
UnknownAction,
} from 'redux'
import { combineReducers } from 'redux'
import { nanoid } from './nanoid'
import type {
Id,
NonUndefined,
Tail,
UnionToIntersection,
WithOptionalProp,
} from './tsHelpers'
import { getOrInsertComputed } from './utils'
type SliceLike<ReducerPath extends string, State, PreloadedState = State> = {
reducerPath: ReducerPath
reducer: Reducer<State, any, PreloadedState>
}
type AnySliceLike = SliceLike<string, any>
type SliceLikeReducerPath<A extends AnySliceLike> =
A extends SliceLike<infer ReducerPath, any> ? ReducerPath : never
type SliceLikeState<A extends AnySliceLike> =
A extends SliceLike<any, infer State, any> ? State : never
type SliceLikePreloadedState<A extends AnySliceLike> =
A extends SliceLike<any, any, infer PreloadedState> ? PreloadedState : never
export type WithSlice<A extends AnySliceLike> = {
[Path in SliceLikeReducerPath<A>]: SliceLikeState<A>
}
export type WithSlicePreloadedState<A extends AnySliceLike> = {
[Path in SliceLikeReducerPath<A>]: SliceLikePreloadedState<A>
}
type ReducerMap = Record<string, Reducer>
type ExistingSliceLike<DeclaredState, PreloadedState> = {
[ReducerPath in keyof DeclaredState]: SliceLike<
ReducerPath & string,
NonUndefined<DeclaredState[ReducerPath]>,
NonUndefined<PreloadedState[ReducerPath & keyof PreloadedState]>
>
}[keyof DeclaredState]
export type InjectConfig = {
/**
* Allow replacing reducer with a different reference. Normally, an error will be thrown if a different reducer instance to the one already injected is used.
*/
overrideExisting?: boolean
}
/**
* A reducer that allows for slices/reducers to be injected after initialisation.
*/
export interface CombinedSliceReducer<
InitialState,
DeclaredState extends InitialState = InitialState,
PreloadedState extends Partial<
Record<keyof PreloadedState, any>
> = Partial<DeclaredState>,
> extends Reducer<DeclaredState, UnknownAction, PreloadedState> {
/**
* Provide a type for slices that will be injected lazily.
*
* One way to do this would be with interface merging:
* ```ts
*
* export interface LazyLoadedSlices {}
*
* export const rootReducer = combineSlices(stringSlice).withLazyLoadedSlices<LazyLoadedSlices>();
*
* // elsewhere
*
* declare module './reducer' {
* export interface LazyLoadedSlices extends WithSlice<typeof booleanSlice> {}
* }
*
* const withBoolean = rootReducer.inject(booleanSlice);
*
* // elsewhere again
*
* declare module './reducer' {
* export interface LazyLoadedSlices {
* customName: CustomState
* }
* }
*
* const withCustom = rootReducer.inject({ reducerPath: "customName", reducer: customSlice.reducer })
* ```
*/
withLazyLoadedSlices<Lazy = {}, LazyPreloaded = Lazy>(): CombinedSliceReducer<
InitialState,
Id<DeclaredState & Partial<Lazy>>,
Id<PreloadedState & Partial<LazyPreloaded>>
>
/**
* Inject a slice.
*
* Accepts an individual slice, RTKQ API instance, or a "slice-like" { reducerPath, reducer } object.
*
* ```ts
* rootReducer.inject(booleanSlice)
* rootReducer.inject(baseApi)
* rootReducer.inject({ reducerPath: 'boolean' as const, reducer: newReducer }, { overrideExisting: true })
* ```
*
*/
inject<Sl extends Id<ExistingSliceLike<DeclaredState, PreloadedState>>>(
slice: Sl,
config?: InjectConfig,
): CombinedSliceReducer<
InitialState,
Id<DeclaredState & WithSlice<Sl>>,
Id<PreloadedState & Partial<WithSlicePreloadedState<Sl>>>
>
/**
* Inject a slice.
*
* Accepts an individual slice, RTKQ API instance, or a "slice-like" { reducerPath, reducer } object.
*
* ```ts
* rootReducer.inject(booleanSlice)
* rootReducer.inject(baseApi)
* rootReducer.inject({ reducerPath: 'boolean' as const, reducer: newReducer }, { overrideExisting: true })
* ```
*
*/
inject<ReducerPath extends string, State, PreloadedState = State>(
slice: SliceLike<
ReducerPath,
State & (ReducerPath extends keyof DeclaredState ? never : State),
PreloadedState &
(ReducerPath extends keyof PreloadedState ? never : PreloadedState)
>,
config?: InjectConfig,
): CombinedSliceReducer<
InitialState,
Id<DeclaredState & WithSlice<SliceLike<ReducerPath, State>>>,
Id<
PreloadedState &
WithSlicePreloadedState<SliceLike<ReducerPath, State, PreloadedState>>
>
>
/**
* Create a selector that guarantees that the slices injected will have a defined value when selector is run.
*
* ```ts
* const selectBooleanWithoutInjection = (state: RootState) => state.boolean;
* // ^? boolean | undefined
*
* const selectBoolean = rootReducer.inject(booleanSlice).selector((state) => {
* // if action hasn't been dispatched since slice was injected, this would usually be undefined
* // however selector() uses a Proxy around the first parameter to ensure that it evaluates to the initial state instead, if undefined
* return state.boolean;
* // ^? boolean
* })
* ```
*
* If the reducer is nested inside the root state, a selectState callback can be passed to retrieve the reducer's state.
*
* ```ts
*
* export interface LazyLoadedSlices {};
*
* export const innerReducer = combineSlices(stringSlice).withLazyLoadedSlices<LazyLoadedSlices>();
*
* export const rootReducer = combineSlices({ inner: innerReducer });
*
* export type RootState = ReturnType<typeof rootReducer>;
*
* // elsewhere
*
* declare module "./reducer.ts" {
* export interface LazyLoadedSlices extends WithSlice<typeof booleanSlice> {}
* }
*
* const withBool = innerReducer.inject(booleanSlice);
*
* const selectBoolean = withBool.selector(
* (state) => state.boolean,
* (rootState: RootState) => state.inner
* );
* // now expects to be passed RootState instead of innerReducer state
*
* ```
*
* Value passed to selectorFn will be a Proxy - use selector.original(proxy) to get original state value (useful for debugging)
*
* ```ts
* const injectedReducer = rootReducer.inject(booleanSlice);
* const selectBoolean = injectedReducer.selector((state) => {
* console.log(injectedReducer.selector.original(state).boolean) // possibly undefined
* return state.boolean
* })
* ```
*/
selector: {
/**
* Create a selector that guarantees that the slices injected will have a defined value when selector is run.
*
* ```ts
* const selectBooleanWithoutInjection = (state: RootState) => state.boolean;
* // ^? boolean | undefined
*
* const selectBoolean = rootReducer.inject(booleanSlice).selector((state) => {
* // if action hasn't been dispatched since slice was injected, this would usually be undefined
* // however selector() uses a Proxy around the first parameter to ensure that it evaluates to the initial state instead, if undefined
* return state.boolean;
* // ^? boolean
* })
* ```
*
* Value passed to selectorFn will be a Proxy - use selector.original(proxy) to get original state value (useful for debugging)
*
* ```ts
* const injectedReducer = rootReducer.inject(booleanSlice);
* const selectBoolean = injectedReducer.selector((state) => {
* console.log(injectedReducer.selector.original(state).boolean) // undefined
* return state.boolean
* })
* ```
*/
<Selector extends (state: DeclaredState, ...args: any[]) => unknown>(
selectorFn: Selector,
): (
state: WithOptionalProp<
Parameters<Selector>[0],
Exclude<keyof DeclaredState, keyof InitialState>
>,
...args: Tail<Parameters<Selector>>
) => ReturnType<Selector>
/**
* Create a selector that guarantees that the slices injected will have a defined value when selector is run.
*
* ```ts
* const selectBooleanWithoutInjection = (state: RootState) => state.boolean;
* // ^? boolean | undefined
*
* const selectBoolean = rootReducer.inject(booleanSlice).selector((state) => {
* // if action hasn't been dispatched since slice was injected, this would usually be undefined
* // however selector() uses a Proxy around the first parameter to ensure that it evaluates to the initial state instead, if undefined
* return state.boolean;
* // ^? boolean
* })
* ```
*
* If the reducer is nested inside the root state, a selectState callback can be passed to retrieve the reducer's state.
*
* ```ts
*
* interface LazyLoadedSlices {};
*
* const innerReducer = combineSlices(stringSlice).withLazyLoadedSlices<LazyLoadedSlices>();
*
* const rootReducer = combineSlices({ inner: innerReducer });
*
* type RootState = ReturnType<typeof rootReducer>;
*
* // elsewhere
*
* declare module "./reducer.ts" {
* interface LazyLoadedSlices extends WithSlice<typeof booleanSlice> {}
* }
*
* const withBool = innerReducer.inject(booleanSlice);
*
* const selectBoolean = withBool.selector(
* (state) => state.boolean,
* (rootState: RootState) => state.inner
* );
* // now expects to be passed RootState instead of innerReducer state
*
* ```
*
* Value passed to selectorFn will be a Proxy - use selector.original(proxy) to get original state value (useful for debugging)
*
* ```ts
* const injectedReducer = rootReducer.inject(booleanSlice);
* const selectBoolean = injectedReducer.selector((state) => {
* console.log(injectedReducer.selector.original(state).boolean) // possibly undefined
* return state.boolean
* })
* ```
*/
<
Selector extends (state: DeclaredState, ...args: any[]) => unknown,
RootState,
>(
selectorFn: Selector,
selectState: (
rootState: RootState,
...args: Tail<Parameters<Selector>>
) => WithOptionalProp<
Parameters<Selector>[0],
Exclude<keyof DeclaredState, keyof InitialState>
>,
): (
state: RootState,
...args: Tail<Parameters<Selector>>
) => ReturnType<Selector>
/**
* Returns the unproxied state. Useful for debugging.
* @param state state Proxy, that ensures injected reducers have value
* @returns original, unproxied state
* @throws if value passed is not a state Proxy
*/
original: (state: DeclaredState) => InitialState & Partial<DeclaredState>
}
}
type InitialState<Slices extends Array<AnySliceLike | ReducerMap>> =
UnionToIntersection<
Slices[number] extends infer Slice
? Slice extends AnySliceLike
? WithSlice<Slice>
: StateFromReducersMapObject<Slice>
: never
>
type InitialPreloadedState<Slices extends Array<AnySliceLike | ReducerMap>> =
UnionToIntersection<
Slices[number] extends infer Slice
? Slice extends AnySliceLike
? WithSlicePreloadedState<Slice>
: PreloadedStateShapeFromReducersMapObject<Slice>
: never
>
const isSliceLike = (
maybeSliceLike: AnySliceLike | ReducerMap,
): maybeSliceLike is AnySliceLike =>
'reducerPath' in maybeSliceLike &&
typeof maybeSliceLike.reducerPath === 'string'
const getReducers = (slices: Array<AnySliceLike | ReducerMap>) =>
slices.flatMap<[string, Reducer]>((sliceOrMap) =>
isSliceLike(sliceOrMap)
? [[sliceOrMap.reducerPath, sliceOrMap.reducer]]
: Object.entries(sliceOrMap),
)
const ORIGINAL_STATE = Symbol.for('rtk-state-proxy-original')
const isStateProxy = (value: any) => !!value && !!value[ORIGINAL_STATE]
const stateProxyMap = new WeakMap<object, object>()
const createStateProxy = <State extends object>(
state: State,
reducerMap: Partial<Record<PropertyKey, Reducer>>,
initialStateCache: Record<PropertyKey, unknown>,
) =>
getOrInsertComputed(
stateProxyMap,
state,
() =>
new Proxy(state, {
get: (target, prop, receiver) => {
if (prop === ORIGINAL_STATE) return target
const result = Reflect.get(target, prop, receiver)
if (typeof result === 'undefined') {
const cached = initialStateCache[prop]
if (typeof cached !== 'undefined') return cached
const reducer = reducerMap[prop]
if (reducer) {
// ensure action type is random, to prevent reducer treating it differently
const reducerResult = reducer(undefined, { type: nanoid() })
if (typeof reducerResult === 'undefined') {
throw new Error(
`The slice reducer for key "${prop.toString()}" returned undefined when called for selector(). ` +
`If the state passed to the reducer is undefined, you must ` +
`explicitly return the initial state. The initial state may ` +
`not be undefined. If you don't want to set a value for this reducer, ` +
`you can use null instead of undefined.`,
)
}
initialStateCache[prop] = reducerResult
return reducerResult
}
}
return result
},
}),
) as State
const original = (state: any) => {
if (!isStateProxy(state)) {
throw new Error('original must be used on state Proxy')
}
return state[ORIGINAL_STATE]
}
const emptyObject = {}
const noopReducer: Reducer<Record<string, any>> = (state = emptyObject) => state
export function combineSlices<Slices extends Array<AnySliceLike | ReducerMap>>(
...slices: Slices
): CombinedSliceReducer<
Id<InitialState<Slices>>,
Id<InitialState<Slices>>,
Partial<Id<InitialPreloadedState<Slices>>>
> {
const reducerMap = Object.fromEntries(getReducers(slices))
const getReducer = () =>
Object.keys(reducerMap).length ? combineReducers(reducerMap) : noopReducer
let reducer = getReducer()
function combinedReducer(
state: Record<string, unknown>,
action: UnknownAction,
) {
return reducer(state, action)
}
combinedReducer.withLazyLoadedSlices = () => combinedReducer
const initialStateCache: Record<PropertyKey, unknown> = {}
const inject = (
slice: AnySliceLike,
config: InjectConfig = {},
): typeof combinedReducer => {
const { reducerPath, reducer: reducerToInject } = slice
const currentReducer = reducerMap[reducerPath]
if (
!config.overrideExisting &&
currentReducer &&
currentReducer !== reducerToInject
) {
if (
typeof process !== 'undefined' &&
process.env.NODE_ENV === 'development'
) {
console.error(
`called \`inject\` to override already-existing reducer ${reducerPath} without specifying \`overrideExisting: true\``,
)
}
return combinedReducer
}
if (config.overrideExisting && currentReducer !== reducerToInject) {
delete initialStateCache[reducerPath]
}
reducerMap[reducerPath] = reducerToInject
reducer = getReducer()
return combinedReducer
}
const selector = Object.assign(
function makeSelector<State extends object, RootState, Args extends any[]>(
selectorFn: (state: State, ...args: Args) => any,
selectState?: (rootState: RootState, ...args: Args) => State,
) {
return function selector(state: State, ...args: Args) {
return selectorFn(
createStateProxy(
selectState ? selectState(state as any, ...args) : state,
reducerMap,
initialStateCache,
),
...args,
)
}
},
{ original },
)
return Object.assign(combinedReducer, { inject, selector }) as any
}

View File

@@ -0,0 +1,248 @@
import type {
Reducer,
ReducersMapObject,
Middleware,
Action,
StoreEnhancer,
Store,
UnknownAction,
} from 'redux'
import {
applyMiddleware,
createStore,
compose,
combineReducers,
isPlainObject,
} from './reduxImports'
import type { DevToolsEnhancerOptions as DevToolsOptions } from './devtoolsExtension'
import { composeWithDevTools } from './devtoolsExtension'
import type {
ThunkMiddlewareFor,
GetDefaultMiddleware,
} from './getDefaultMiddleware'
import { buildGetDefaultMiddleware } from './getDefaultMiddleware'
import type {
ExtractDispatchExtensions,
ExtractStoreExtensions,
ExtractStateExtensions,
UnknownIfNonSpecific,
} from './tsHelpers'
import type { Tuple } from './utils'
import type { GetDefaultEnhancers } from './getDefaultEnhancers'
import { buildGetDefaultEnhancers } from './getDefaultEnhancers'
/**
* Options for `configureStore()`.
*
* @public
*/
export interface ConfigureStoreOptions<
S = any,
A extends Action = UnknownAction,
M extends Tuple<Middlewares<S>> = Tuple<Middlewares<S>>,
E extends Tuple<Enhancers> = Tuple<Enhancers>,
P = S,
> {
/**
* A single reducer function that will be used as the root reducer, or an
* object of slice reducers that will be passed to `combineReducers()`.
*/
reducer: Reducer<S, A, P> | ReducersMapObject<S, A, P>
/**
* An array of Redux middleware to install, or a callback receiving `getDefaultMiddleware` and returning a Tuple of middleware.
* If not supplied, defaults to the set of middleware returned by `getDefaultMiddleware()`.
*
* @example `middleware: (gDM) => gDM().concat(logger, apiMiddleware, yourCustomMiddleware)`
* @see https://redux-toolkit.js.org/api/getDefaultMiddleware#intended-usage
*/
middleware?: (getDefaultMiddleware: GetDefaultMiddleware<S>) => M
/**
* Whether to enable Redux DevTools integration. Defaults to `true`.
*
* Additional configuration can be done by passing Redux DevTools options
*/
devTools?: boolean | DevToolsOptions
/**
* Whether to check for duplicate middleware instances. Defaults to `true`.
*/
duplicateMiddlewareCheck?: boolean
/**
* The initial state, same as Redux's createStore.
* You may optionally specify it to hydrate the state
* from the server in universal apps, or to restore a previously serialized
* user session. If you use `combineReducers()` to produce the root reducer
* function (either directly or indirectly by passing an object as `reducer`),
* this must be an object with the same shape as the reducer map keys.
*/
// we infer here, and instead complain if the reducer doesn't match
preloadedState?: P
/**
* The store enhancers to apply. See Redux's `createStore()`.
* All enhancers will be included before the DevTools Extension enhancer.
* If you need to customize the order of enhancers, supply a callback
* function that will receive a `getDefaultEnhancers` function that returns a Tuple,
* and should return a Tuple of enhancers (such as `getDefaultEnhancers().concat(offline)`).
* If you only need to add middleware, you can use the `middleware` parameter instead.
*/
enhancers?: (getDefaultEnhancers: GetDefaultEnhancers<M>) => E
}
export type Middlewares<S> = ReadonlyArray<Middleware<{}, S>>
type Enhancers = ReadonlyArray<StoreEnhancer>
/**
* A Redux store returned by `configureStore()`. Supports dispatching
* side-effectful _thunks_ in addition to plain actions.
*
* @public
*/
export type EnhancedStore<
S = any,
A extends Action = UnknownAction,
E extends Enhancers = Enhancers,
> = ExtractStoreExtensions<E> &
Store<S, A, UnknownIfNonSpecific<ExtractStateExtensions<E>>>
/**
* A friendly abstraction over the standard Redux `createStore()` function.
*
* @param options The store configuration.
* @returns A configured Redux store.
*
* @public
*/
export function configureStore<
S = any,
A extends Action = UnknownAction,
M extends Tuple<Middlewares<S>> = Tuple<[ThunkMiddlewareFor<S>]>,
E extends Tuple<Enhancers> = Tuple<
[StoreEnhancer<{ dispatch: ExtractDispatchExtensions<M> }>, StoreEnhancer]
>,
P = S,
>(options: ConfigureStoreOptions<S, A, M, E, P>): EnhancedStore<S, A, E> {
const getDefaultMiddleware = buildGetDefaultMiddleware<S>()
const {
reducer = undefined,
middleware,
devTools = true,
duplicateMiddlewareCheck = true,
preloadedState = undefined,
enhancers = undefined,
} = options || {}
let rootReducer: Reducer<S, A, P>
if (typeof reducer === 'function') {
rootReducer = reducer
} else if (isPlainObject(reducer)) {
rootReducer = combineReducers(reducer) as unknown as Reducer<S, A, P>
} else {
throw new Error(
'`reducer` is a required argument, and must be a function or an object of functions that can be passed to combineReducers',
)
}
if (
process.env.NODE_ENV !== 'production' &&
middleware &&
typeof middleware !== 'function'
) {
throw new Error('`middleware` field must be a callback')
}
let finalMiddleware: Tuple<Middlewares<S>>
if (typeof middleware === 'function') {
finalMiddleware = middleware(getDefaultMiddleware)
if (
process.env.NODE_ENV !== 'production' &&
!Array.isArray(finalMiddleware)
) {
throw new Error(
'when using a middleware builder function, an array of middleware must be returned',
)
}
} else {
finalMiddleware = getDefaultMiddleware()
}
if (
process.env.NODE_ENV !== 'production' &&
finalMiddleware.some((item: any) => typeof item !== 'function')
) {
throw new Error(
'each middleware provided to configureStore must be a function',
)
}
if (process.env.NODE_ENV !== 'production' && duplicateMiddlewareCheck) {
let middlewareReferences = new Set<Middleware<any, S>>()
finalMiddleware.forEach((middleware) => {
if (middlewareReferences.has(middleware)) {
throw new Error(
'Duplicate middleware references found when creating the store. Ensure that each middleware is only included once.',
)
}
middlewareReferences.add(middleware)
})
}
let finalCompose = compose
if (devTools) {
finalCompose = composeWithDevTools({
// Enable capture of stack traces for dispatched Redux actions
trace: process.env.NODE_ENV !== 'production',
...(typeof devTools === 'object' && devTools),
})
}
const middlewareEnhancer = applyMiddleware(...finalMiddleware)
const getDefaultEnhancers = buildGetDefaultEnhancers<M>(middlewareEnhancer)
if (
process.env.NODE_ENV !== 'production' &&
enhancers &&
typeof enhancers !== 'function'
) {
throw new Error('`enhancers` field must be a callback')
}
let storeEnhancers =
typeof enhancers === 'function'
? enhancers(getDefaultEnhancers)
: getDefaultEnhancers()
if (process.env.NODE_ENV !== 'production' && !Array.isArray(storeEnhancers)) {
throw new Error('`enhancers` callback must return an array')
}
if (
process.env.NODE_ENV !== 'production' &&
storeEnhancers.some((item: any) => typeof item !== 'function')
) {
throw new Error(
'each enhancer provided to configureStore must be a function',
)
}
if (
process.env.NODE_ENV !== 'production' &&
finalMiddleware.length &&
!storeEnhancers.includes(middlewareEnhancer)
) {
console.error(
'middlewares were provided, but middleware enhancer was not included in final enhancers - make sure to call `getDefaultEnhancers`',
)
}
const composedEnhancer: StoreEnhancer<any> = finalCompose(...storeEnhancers)
return createStore(rootReducer, preloadedState as P, composedEnhancer)
}

View File

@@ -0,0 +1,324 @@
import { isAction } from './reduxImports'
import type {
IsUnknownOrNonInferrable,
IfMaybeUndefined,
IfVoid,
IsAny,
} from './tsHelpers'
import { hasMatchFunction } from './tsHelpers'
/**
* An action with a string type and an associated payload. This is the
* type of action returned by `createAction()` action creators.
*
* @template P The type of the action's payload.
* @template T the type used for the action type.
* @template M The type of the action's meta (optional)
* @template E The type of the action's error (optional)
*
* @public
*/
export type PayloadAction<
P = void,
T extends string = string,
M = never,
E = never,
> = {
payload: P
type: T
} & ([M] extends [never]
? {}
: {
meta: M
}) &
([E] extends [never]
? {}
: {
error: E
})
/**
* A "prepare" method to be used as the second parameter of `createAction`.
* Takes any number of arguments and returns a Flux Standard Action without
* type (will be added later) that *must* contain a payload (might be undefined).
*
* @public
*/
export type PrepareAction<P> =
| ((...args: any[]) => { payload: P })
| ((...args: any[]) => { payload: P; meta: any })
| ((...args: any[]) => { payload: P; error: any })
| ((...args: any[]) => { payload: P; meta: any; error: any })
/**
* Internal version of `ActionCreatorWithPreparedPayload`. Not to be used externally.
*
* @internal
*/
export type _ActionCreatorWithPreparedPayload<
PA extends PrepareAction<any> | void,
T extends string = string,
> =
PA extends PrepareAction<infer P>
? ActionCreatorWithPreparedPayload<
Parameters<PA>,
P,
T,
ReturnType<PA> extends {
error: infer E
}
? E
: never,
ReturnType<PA> extends {
meta: infer M
}
? M
: never
>
: void
/**
* Basic type for all action creators.
*
* @inheritdoc {redux#ActionCreator}
*/
export type BaseActionCreator<P, T extends string, M = never, E = never> = {
type: T
match: (action: unknown) => action is PayloadAction<P, T, M, E>
}
/**
* An action creator that takes multiple arguments that are passed
* to a `PrepareAction` method to create the final Action.
* @typeParam Args arguments for the action creator function
* @typeParam P `payload` type
* @typeParam T `type` name
* @typeParam E optional `error` type
* @typeParam M optional `meta` type
*
* @inheritdoc {redux#ActionCreator}
*
* @public
*/
export interface ActionCreatorWithPreparedPayload<
Args extends unknown[],
P,
T extends string = string,
E = never,
M = never,
> extends BaseActionCreator<P, T, M, E> {
/**
* Calling this {@link redux#ActionCreator} with `Args` will return
* an Action with a payload of type `P` and (depending on the `PrepareAction`
* method used) a `meta`- and `error` property of types `M` and `E` respectively.
*/
(...args: Args): PayloadAction<P, T, M, E>
}
/**
* An action creator of type `T` that takes an optional payload of type `P`.
*
* @inheritdoc {redux#ActionCreator}
*
* @public
*/
export interface ActionCreatorWithOptionalPayload<P, T extends string = string>
extends BaseActionCreator<P, T> {
/**
* Calling this {@link redux#ActionCreator} with an argument will
* return a {@link PayloadAction} of type `T` with a payload of `P`.
* Calling it without an argument will return a PayloadAction with a payload of `undefined`.
*/
(payload?: P): PayloadAction<P, T>
}
/**
* An action creator of type `T` that takes no payload.
*
* @inheritdoc {redux#ActionCreator}
*
* @public
*/
export interface ActionCreatorWithoutPayload<T extends string = string>
extends BaseActionCreator<undefined, T> {
/**
* Calling this {@link redux#ActionCreator} will
* return a {@link PayloadAction} of type `T` with a payload of `undefined`
*/
(noArgument: void): PayloadAction<undefined, T>
}
/**
* An action creator of type `T` that requires a payload of type P.
*
* @inheritdoc {redux#ActionCreator}
*
* @public
*/
export interface ActionCreatorWithPayload<P, T extends string = string>
extends BaseActionCreator<P, T> {
/**
* Calling this {@link redux#ActionCreator} with an argument will
* return a {@link PayloadAction} of type `T` with a payload of `P`
*/
(payload: P): PayloadAction<P, T>
}
/**
* An action creator of type `T` whose `payload` type could not be inferred. Accepts everything as `payload`.
*
* @inheritdoc {redux#ActionCreator}
*
* @public
*/
export interface ActionCreatorWithNonInferrablePayload<
T extends string = string,
> extends BaseActionCreator<unknown, T> {
/**
* Calling this {@link redux#ActionCreator} with an argument will
* return a {@link PayloadAction} of type `T` with a payload
* of exactly the type of the argument.
*/
<PT extends unknown>(payload: PT): PayloadAction<PT, T>
}
/**
* An action creator that produces actions with a `payload` attribute.
*
* @typeParam P the `payload` type
* @typeParam T the `type` of the resulting action
* @typeParam PA if the resulting action is preprocessed by a `prepare` method, the signature of said method.
*
* @public
*/
export type PayloadActionCreator<
P = void,
T extends string = string,
PA extends PrepareAction<P> | void = void,
> = IfPrepareActionMethodProvided<
PA,
_ActionCreatorWithPreparedPayload<PA, T>,
// else
IsAny<
P,
ActionCreatorWithPayload<any, T>,
IsUnknownOrNonInferrable<
P,
ActionCreatorWithNonInferrablePayload<T>,
// else
IfVoid<
P,
ActionCreatorWithoutPayload<T>,
// else
IfMaybeUndefined<
P,
ActionCreatorWithOptionalPayload<P, T>,
// else
ActionCreatorWithPayload<P, T>
>
>
>
>
>
/**
* A utility function to create an action creator for the given action type
* string. The action creator accepts a single argument, which will be included
* in the action object as a field called payload. The action creator function
* will also have its toString() overridden so that it returns the action type.
*
* @param type The action type to use for created actions.
* @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }.
* If this is given, the resulting action creator will pass its arguments to this method to calculate payload & meta.
*
* @public
*/
export function createAction<P = void, T extends string = string>(
type: T,
): PayloadActionCreator<P, T>
/**
* A utility function to create an action creator for the given action type
* string. The action creator accepts a single argument, which will be included
* in the action object as a field called payload. The action creator function
* will also have its toString() overridden so that it returns the action type.
*
* @param type The action type to use for created actions.
* @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }.
* If this is given, the resulting action creator will pass its arguments to this method to calculate payload & meta.
*
* @public
*/
export function createAction<
PA extends PrepareAction<any>,
T extends string = string,
>(
type: T,
prepareAction: PA,
): PayloadActionCreator<ReturnType<PA>['payload'], T, PA>
export function createAction(type: string, prepareAction?: Function): any {
function actionCreator(...args: any[]) {
if (prepareAction) {
let prepared = prepareAction(...args)
if (!prepared) {
throw new Error('prepareAction did not return an object')
}
return {
type,
payload: prepared.payload,
...('meta' in prepared && { meta: prepared.meta }),
...('error' in prepared && { error: prepared.error }),
}
}
return { type, payload: args[0] }
}
actionCreator.toString = () => `${type}`
actionCreator.type = type
actionCreator.match = (action: unknown): action is PayloadAction =>
isAction(action) && action.type === type
return actionCreator
}
/**
* Returns true if value is an RTK-like action creator, with a static type property and match method.
*/
export function isActionCreator(
action: unknown,
): action is BaseActionCreator<unknown, string> & Function {
return (
typeof action === 'function' &&
'type' in action &&
// hasMatchFunction only wants Matchers but I don't see the point in rewriting it
hasMatchFunction(action as any)
)
}
/**
* Returns true if value is an action with a string type and valid Flux Standard Action keys.
*/
export function isFSA(action: unknown): action is {
type: string
payload?: unknown
error?: unknown
meta?: unknown
} {
return isAction(action) && Object.keys(action).every(isValidKey)
}
function isValidKey(key: string) {
return ['type', 'payload', 'error', 'meta'].indexOf(key) > -1
}
// helper types for more readable typings
type IfPrepareActionMethodProvided<
PA extends PrepareAction<any> | void,
True,
False,
> = PA extends (...args: any[]) => any ? True : False

View File

@@ -0,0 +1,791 @@
import type { Dispatch, UnknownAction } from 'redux'
import type { ThunkDispatch } from 'redux-thunk'
import type { ActionCreatorWithPreparedPayload } from './createAction'
import { createAction } from './createAction'
import { isAnyOf } from './matchers'
import { nanoid } from './nanoid'
import type {
FallbackIfUnknown,
Id,
IsAny,
IsUnknown,
SafePromise,
} from './tsHelpers'
export type BaseThunkAPI<
S,
E,
D extends Dispatch = Dispatch,
RejectedValue = unknown,
RejectedMeta = unknown,
FulfilledMeta = unknown,
> = {
dispatch: D
getState: () => S
extra: E
requestId: string
signal: AbortSignal
abort: (reason?: string) => void
rejectWithValue: IsUnknown<
RejectedMeta,
(value: RejectedValue) => RejectWithValue<RejectedValue, RejectedMeta>,
(
value: RejectedValue,
meta: RejectedMeta,
) => RejectWithValue<RejectedValue, RejectedMeta>
>
fulfillWithValue: IsUnknown<
FulfilledMeta,
<FulfilledValue>(value: FulfilledValue) => FulfilledValue,
<FulfilledValue>(
value: FulfilledValue,
meta: FulfilledMeta,
) => FulfillWithMeta<FulfilledValue, FulfilledMeta>
>
}
/**
* @public
*/
export interface SerializedError {
name?: string
message?: string
stack?: string
code?: string
}
const commonProperties: Array<keyof SerializedError> = [
'name',
'message',
'stack',
'code',
]
class RejectWithValue<Payload, RejectedMeta> {
/*
type-only property to distinguish between RejectWithValue and FulfillWithMeta
does not exist at runtime
*/
private readonly _type!: 'RejectWithValue'
constructor(
public readonly payload: Payload,
public readonly meta: RejectedMeta,
) {}
}
class FulfillWithMeta<Payload, FulfilledMeta> {
/*
type-only property to distinguish between RejectWithValue and FulfillWithMeta
does not exist at runtime
*/
private readonly _type!: 'FulfillWithMeta'
constructor(
public readonly payload: Payload,
public readonly meta: FulfilledMeta,
) {}
}
/**
* Serializes an error into a plain object.
* Reworked from https://github.com/sindresorhus/serialize-error
*
* @public
*/
export const miniSerializeError = (value: any): SerializedError => {
if (typeof value === 'object' && value !== null) {
const simpleError: SerializedError = {}
for (const property of commonProperties) {
if (typeof value[property] === 'string') {
simpleError[property] = value[property]
}
}
return simpleError
}
return { message: String(value) }
}
export type AsyncThunkConfig = {
state?: unknown
dispatch?: ThunkDispatch<unknown, unknown, UnknownAction>
extra?: unknown
rejectValue?: unknown
serializedErrorType?: unknown
pendingMeta?: unknown
fulfilledMeta?: unknown
rejectedMeta?: unknown
}
export type GetState<ThunkApiConfig> = ThunkApiConfig extends {
state: infer State
}
? State
: unknown
type GetExtra<ThunkApiConfig> = ThunkApiConfig extends { extra: infer Extra }
? Extra
: unknown
type GetDispatch<ThunkApiConfig> = ThunkApiConfig extends {
dispatch: infer Dispatch
}
? FallbackIfUnknown<
Dispatch,
ThunkDispatch<
GetState<ThunkApiConfig>,
GetExtra<ThunkApiConfig>,
UnknownAction
>
>
: ThunkDispatch<
GetState<ThunkApiConfig>,
GetExtra<ThunkApiConfig>,
UnknownAction
>
export type GetThunkAPI<ThunkApiConfig> = BaseThunkAPI<
GetState<ThunkApiConfig>,
GetExtra<ThunkApiConfig>,
GetDispatch<ThunkApiConfig>,
GetRejectValue<ThunkApiConfig>,
GetRejectedMeta<ThunkApiConfig>,
GetFulfilledMeta<ThunkApiConfig>
>
type GetRejectValue<ThunkApiConfig> = ThunkApiConfig extends {
rejectValue: infer RejectValue
}
? RejectValue
: unknown
type GetPendingMeta<ThunkApiConfig> = ThunkApiConfig extends {
pendingMeta: infer PendingMeta
}
? PendingMeta
: unknown
type GetFulfilledMeta<ThunkApiConfig> = ThunkApiConfig extends {
fulfilledMeta: infer FulfilledMeta
}
? FulfilledMeta
: unknown
type GetRejectedMeta<ThunkApiConfig> = ThunkApiConfig extends {
rejectedMeta: infer RejectedMeta
}
? RejectedMeta
: unknown
type GetSerializedErrorType<ThunkApiConfig> = ThunkApiConfig extends {
serializedErrorType: infer GetSerializedErrorType
}
? GetSerializedErrorType
: SerializedError
type MaybePromise<T> = T | Promise<T> | (T extends any ? Promise<T> : never)
/**
* A type describing the return value of the `payloadCreator` argument to `createAsyncThunk`.
* Might be useful for wrapping `createAsyncThunk` in custom abstractions.
*
* @public
*/
export type AsyncThunkPayloadCreatorReturnValue<
Returned,
ThunkApiConfig extends AsyncThunkConfig,
> = MaybePromise<
| IsUnknown<
GetFulfilledMeta<ThunkApiConfig>,
Returned,
FulfillWithMeta<Returned, GetFulfilledMeta<ThunkApiConfig>>
>
| RejectWithValue<
GetRejectValue<ThunkApiConfig>,
GetRejectedMeta<ThunkApiConfig>
>
>
/**
* A type describing the `payloadCreator` argument to `createAsyncThunk`.
* Might be useful for wrapping `createAsyncThunk` in custom abstractions.
*
* @public
*/
export type AsyncThunkPayloadCreator<
Returned,
ThunkArg = void,
ThunkApiConfig extends AsyncThunkConfig = {},
> = (
arg: ThunkArg,
thunkAPI: GetThunkAPI<ThunkApiConfig>,
) => AsyncThunkPayloadCreatorReturnValue<Returned, ThunkApiConfig>
/**
* A ThunkAction created by `createAsyncThunk`.
* Dispatching it returns a Promise for either a
* fulfilled or rejected action.
* Also, the returned value contains an `abort()` method
* that allows the asyncAction to be cancelled from the outside.
*
* @public
*/
export type AsyncThunkAction<
Returned,
ThunkArg,
ThunkApiConfig extends AsyncThunkConfig,
> = (
dispatch: NonNullable<GetDispatch<ThunkApiConfig>>,
getState: () => GetState<ThunkApiConfig>,
extra: GetExtra<ThunkApiConfig>,
) => SafePromise<
| ReturnType<AsyncThunkFulfilledActionCreator<Returned, ThunkArg>>
| ReturnType<AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>>
> & {
abort: (reason?: string) => void
requestId: string
arg: ThunkArg
unwrap: () => Promise<Returned>
}
/**
* Config provided when calling the async thunk action creator.
*/
export interface AsyncThunkDispatchConfig {
/**
* An external `AbortSignal` that will be tracked by the internal `AbortSignal`.
*/
signal?: AbortSignal
}
type AsyncThunkActionCreator<
Returned,
ThunkArg,
ThunkApiConfig extends AsyncThunkConfig,
> = IsAny<
ThunkArg,
// any handling
(
arg: ThunkArg,
config?: AsyncThunkDispatchConfig,
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>,
// unknown handling
unknown extends ThunkArg
? (
arg: ThunkArg,
config?: AsyncThunkDispatchConfig,
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig> // argument not specified or specified as void or undefined
: [ThunkArg] extends [void] | [undefined]
? (
arg?: undefined,
config?: AsyncThunkDispatchConfig,
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig> // argument contains void
: [void] extends [ThunkArg] // make optional
? (
arg?: ThunkArg,
config?: AsyncThunkDispatchConfig,
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig> // argument contains undefined
: [undefined] extends [ThunkArg]
? WithStrictNullChecks<
// with strict nullChecks: make optional
(
arg?: ThunkArg,
config?: AsyncThunkDispatchConfig,
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>,
// without strict null checks this will match everything, so don't make it optional
(
arg: ThunkArg,
config?: AsyncThunkDispatchConfig,
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>
> // default case: normal argument
: (
arg: ThunkArg,
config?: AsyncThunkDispatchConfig,
) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>
>
/**
* Options object for `createAsyncThunk`.
*
* @public
*/
export type AsyncThunkOptions<
ThunkArg = void,
ThunkApiConfig extends AsyncThunkConfig = {},
> = {
/**
* A method to control whether the asyncThunk should be executed. Has access to the
* `arg`, `api.getState()` and `api.extra` arguments.
*
* @returns `false` if it should be skipped
*/
condition?(
arg: ThunkArg,
api: Pick<GetThunkAPI<ThunkApiConfig>, 'getState' | 'extra'>,
): MaybePromise<boolean | undefined>
/**
* If `condition` returns `false`, the asyncThunk will be skipped.
* This option allows you to control whether a `rejected` action with `meta.condition == false`
* will be dispatched or not.
*
* @default `false`
*/
dispatchConditionRejection?: boolean
serializeError?: (x: unknown) => GetSerializedErrorType<ThunkApiConfig>
/**
* A function to use when generating the `requestId` for the request sequence.
*
* @default `nanoid`
*/
idGenerator?: (arg: ThunkArg) => string
} & IsUnknown<
GetPendingMeta<ThunkApiConfig>,
{
/**
* A method to generate additional properties to be added to `meta` of the pending action.
*
* Using this optional overload will not modify the types correctly, this overload is only in place to support JavaScript users.
* Please use the `ThunkApiConfig` parameter `pendingMeta` to get access to a correctly typed overload
*/
getPendingMeta?(
base: {
arg: ThunkArg
requestId: string
},
api: Pick<GetThunkAPI<ThunkApiConfig>, 'getState' | 'extra'>,
): GetPendingMeta<ThunkApiConfig>
},
{
/**
* A method to generate additional properties to be added to `meta` of the pending action.
*/
getPendingMeta(
base: {
arg: ThunkArg
requestId: string
},
api: Pick<GetThunkAPI<ThunkApiConfig>, 'getState' | 'extra'>,
): GetPendingMeta<ThunkApiConfig>
}
>
export type AsyncThunkPendingActionCreator<
ThunkArg,
ThunkApiConfig = {},
> = ActionCreatorWithPreparedPayload<
[string, ThunkArg, GetPendingMeta<ThunkApiConfig>?],
undefined,
string,
never,
{
arg: ThunkArg
requestId: string
requestStatus: 'pending'
} & GetPendingMeta<ThunkApiConfig>
>
export type AsyncThunkRejectedActionCreator<
ThunkArg,
ThunkApiConfig = {},
> = ActionCreatorWithPreparedPayload<
[
Error | null,
string,
ThunkArg,
GetRejectValue<ThunkApiConfig>?,
GetRejectedMeta<ThunkApiConfig>?,
],
GetRejectValue<ThunkApiConfig> | undefined,
string,
GetSerializedErrorType<ThunkApiConfig>,
{
arg: ThunkArg
requestId: string
requestStatus: 'rejected'
aborted: boolean
condition: boolean
} & (
| ({ rejectedWithValue: false } & {
[K in keyof GetRejectedMeta<ThunkApiConfig>]?: undefined
})
| ({ rejectedWithValue: true } & GetRejectedMeta<ThunkApiConfig>)
)
>
export type AsyncThunkFulfilledActionCreator<
Returned,
ThunkArg,
ThunkApiConfig = {},
> = ActionCreatorWithPreparedPayload<
[Returned, string, ThunkArg, GetFulfilledMeta<ThunkApiConfig>?],
Returned,
string,
never,
{
arg: ThunkArg
requestId: string
requestStatus: 'fulfilled'
} & GetFulfilledMeta<ThunkApiConfig>
>
/**
* A type describing the return value of `createAsyncThunk`.
* Might be useful for wrapping `createAsyncThunk` in custom abstractions.
*
* @public
*/
export type AsyncThunk<
Returned,
ThunkArg,
ThunkApiConfig extends AsyncThunkConfig,
> = AsyncThunkActionCreator<Returned, ThunkArg, ThunkApiConfig> & {
pending: AsyncThunkPendingActionCreator<ThunkArg, ThunkApiConfig>
rejected: AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>
fulfilled: AsyncThunkFulfilledActionCreator<
Returned,
ThunkArg,
ThunkApiConfig
>
// matchSettled?
settled: (
action: any,
) => action is ReturnType<
| AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>
| AsyncThunkFulfilledActionCreator<Returned, ThunkArg, ThunkApiConfig>
>
typePrefix: string
}
export type OverrideThunkApiConfigs<OldConfig, NewConfig> = Id<
NewConfig & Omit<OldConfig, keyof NewConfig>
>
export type CreateAsyncThunkFunction<
CurriedThunkApiConfig extends AsyncThunkConfig,
> = {
/**
*
* @param typePrefix
* @param payloadCreator
* @param options
*
* @public
*/
// separate signature without `AsyncThunkConfig` for better inference
<Returned, ThunkArg = void>(
typePrefix: string,
payloadCreator: AsyncThunkPayloadCreator<
Returned,
ThunkArg,
CurriedThunkApiConfig
>,
options?: AsyncThunkOptions<ThunkArg, CurriedThunkApiConfig>,
): AsyncThunk<Returned, ThunkArg, CurriedThunkApiConfig>
/**
*
* @param typePrefix
* @param payloadCreator
* @param options
*
* @public
*/
<Returned, ThunkArg, ThunkApiConfig extends AsyncThunkConfig>(
typePrefix: string,
payloadCreator: AsyncThunkPayloadCreator<
Returned,
ThunkArg,
OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
>,
options?: AsyncThunkOptions<
ThunkArg,
OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
>,
): AsyncThunk<
Returned,
ThunkArg,
OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
>
}
type CreateAsyncThunk<CurriedThunkApiConfig extends AsyncThunkConfig> =
CreateAsyncThunkFunction<CurriedThunkApiConfig> & {
withTypes<ThunkApiConfig extends AsyncThunkConfig>(): CreateAsyncThunk<
OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
>
}
const externalAbortMessage = 'External signal was aborted'
export const createAsyncThunk = /* @__PURE__ */ (() => {
function createAsyncThunk<
Returned,
ThunkArg,
ThunkApiConfig extends AsyncThunkConfig,
>(
typePrefix: string,
payloadCreator: AsyncThunkPayloadCreator<
Returned,
ThunkArg,
ThunkApiConfig
>,
options?: AsyncThunkOptions<ThunkArg, ThunkApiConfig>,
): AsyncThunk<Returned, ThunkArg, ThunkApiConfig> {
type RejectedValue = GetRejectValue<ThunkApiConfig>
type PendingMeta = GetPendingMeta<ThunkApiConfig>
type FulfilledMeta = GetFulfilledMeta<ThunkApiConfig>
type RejectedMeta = GetRejectedMeta<ThunkApiConfig>
const fulfilled: AsyncThunkFulfilledActionCreator<
Returned,
ThunkArg,
ThunkApiConfig
> = createAction(
typePrefix + '/fulfilled',
(
payload: Returned,
requestId: string,
arg: ThunkArg,
meta?: FulfilledMeta,
) => ({
payload,
meta: {
...((meta as any) || {}),
arg,
requestId,
requestStatus: 'fulfilled' as const,
},
}),
)
const pending: AsyncThunkPendingActionCreator<ThunkArg, ThunkApiConfig> =
createAction(
typePrefix + '/pending',
(requestId: string, arg: ThunkArg, meta?: PendingMeta) => ({
payload: undefined,
meta: {
...((meta as any) || {}),
arg,
requestId,
requestStatus: 'pending' as const,
},
}),
)
const rejected: AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig> =
createAction(
typePrefix + '/rejected',
(
error: Error | null,
requestId: string,
arg: ThunkArg,
payload?: RejectedValue,
meta?: RejectedMeta,
) => ({
payload,
error: ((options && options.serializeError) || miniSerializeError)(
error || 'Rejected',
) as GetSerializedErrorType<ThunkApiConfig>,
meta: {
...((meta as any) || {}),
arg,
requestId,
rejectedWithValue: !!payload,
requestStatus: 'rejected' as const,
aborted: error?.name === 'AbortError',
condition: error?.name === 'ConditionError',
},
}),
)
function actionCreator(
arg: ThunkArg,
{ signal }: AsyncThunkDispatchConfig = {},
): AsyncThunkAction<Returned, ThunkArg, Required<ThunkApiConfig>> {
return (dispatch, getState, extra) => {
const requestId = options?.idGenerator
? options.idGenerator(arg)
: nanoid()
const abortController = new AbortController()
let abortHandler: (() => void) | undefined
let abortReason: string | undefined
function abort(reason?: string) {
abortReason = reason
abortController.abort()
}
if (signal) {
if (signal.aborted) {
abort(externalAbortMessage)
} else {
signal.addEventListener(
'abort',
() => abort(externalAbortMessage),
{ once: true },
)
}
}
const promise = (async function () {
let finalAction: ReturnType<typeof fulfilled | typeof rejected>
try {
let conditionResult = options?.condition?.(arg, { getState, extra })
if (isThenable(conditionResult)) {
conditionResult = await conditionResult
}
if (conditionResult === false || abortController.signal.aborted) {
// eslint-disable-next-line no-throw-literal
throw {
name: 'ConditionError',
message: 'Aborted due to condition callback returning false.',
}
}
const abortedPromise = new Promise<never>((_, reject) => {
abortHandler = () => {
reject({
name: 'AbortError',
message: abortReason || 'Aborted',
})
}
abortController.signal.addEventListener('abort', abortHandler, {
once: true,
})
})
dispatch(
pending(
requestId,
arg,
options?.getPendingMeta?.(
{ requestId, arg },
{ getState, extra },
),
) as any,
)
finalAction = await Promise.race([
abortedPromise,
Promise.resolve(
payloadCreator(arg, {
dispatch,
getState,
extra,
requestId,
signal: abortController.signal,
abort,
rejectWithValue: ((
value: RejectedValue,
meta?: RejectedMeta,
) => {
return new RejectWithValue(value, meta)
}) as any,
fulfillWithValue: ((value: unknown, meta?: FulfilledMeta) => {
return new FulfillWithMeta(value, meta)
}) as any,
}),
).then((result) => {
if (result instanceof RejectWithValue) {
throw result
}
if (result instanceof FulfillWithMeta) {
return fulfilled(result.payload, requestId, arg, result.meta)
}
return fulfilled(result as any, requestId, arg)
}),
])
} catch (err) {
finalAction =
err instanceof RejectWithValue
? rejected(null, requestId, arg, err.payload, err.meta)
: rejected(err as any, requestId, arg)
} finally {
if (abortHandler) {
abortController.signal.removeEventListener('abort', abortHandler)
}
}
// We dispatch the result action _after_ the catch, to avoid having any errors
// here get swallowed by the try/catch block,
// per https://twitter.com/dan_abramov/status/770914221638942720
// and https://github.com/reduxjs/redux-toolkit/blob/e85eb17b39a2118d859f7b7746e0f3fee523e089/docs/tutorials/advanced-tutorial.md#async-error-handling-logic-in-thunks
const skipDispatch =
options &&
!options.dispatchConditionRejection &&
rejected.match(finalAction) &&
(finalAction as any).meta.condition
if (!skipDispatch) {
dispatch(finalAction as any)
}
return finalAction
})()
return Object.assign(promise as SafePromise<any>, {
abort,
requestId,
arg,
unwrap() {
return promise.then<any>(unwrapResult)
},
})
}
}
return Object.assign(
actionCreator as AsyncThunkActionCreator<
Returned,
ThunkArg,
ThunkApiConfig
>,
{
pending,
rejected,
fulfilled,
settled: isAnyOf(rejected, fulfilled),
typePrefix,
},
)
}
createAsyncThunk.withTypes = () => createAsyncThunk
return createAsyncThunk as CreateAsyncThunk<AsyncThunkConfig>
})()
interface UnwrappableAction {
payload: any
meta?: any
error?: any
}
type UnwrappedActionPayload<T extends UnwrappableAction> = Exclude<
T,
{ error: any }
>['payload']
/**
* @public
*/
export function unwrapResult<R extends UnwrappableAction>(
action: R,
): UnwrappedActionPayload<R> {
if (action.meta && action.meta.rejectedWithValue) {
throw action.payload
}
if (action.error) {
throw action.error
}
return action.payload
}
type WithStrictNullChecks<True, False> = undefined extends boolean
? False
: True
function isThenable(value: any): value is PromiseLike<any> {
return (
value !== null &&
typeof value === 'object' &&
typeof value.then === 'function'
)
}

View File

@@ -0,0 +1,30 @@
import { current, isDraft } from './immerImports'
import { createSelectorCreator, weakMapMemoize } from './reselectImports'
export const createDraftSafeSelectorCreator: typeof createSelectorCreator = (
...args: unknown[]
) => {
const createSelector = (createSelectorCreator as any)(...args)
const createDraftSafeSelector = Object.assign(
(...args: unknown[]) => {
const selector = createSelector(...args)
const wrappedSelector = (value: unknown, ...rest: unknown[]) =>
selector(isDraft(value) ? current(value) : value, ...rest)
Object.assign(wrappedSelector, selector)
return wrappedSelector as any
},
{ withTypes: () => createDraftSafeSelector },
)
return createDraftSafeSelector
}
/**
* "Draft-Safe" version of `reselect`'s `createSelector`:
* If an `immer`-drafted object is passed into the resulting selector's first argument,
* the selector will act on the current draft value, instead of returning a cached value
* that might be possibly outdated if the draft has been modified since.
* @public
*/
export const createDraftSafeSelector =
/* @__PURE__ */
createDraftSafeSelectorCreator(weakMapMemoize)

View File

@@ -0,0 +1,226 @@
import type { Draft } from 'immer'
import {
createNextState,
isDraft,
isDraftable,
setUseStrictIteration,
} from './immerImports'
import type { Action, Reducer, UnknownAction } from 'redux'
import type { ActionReducerMapBuilder } from './mapBuilders'
import { executeReducerBuilderCallback } from './mapBuilders'
import type { NoInfer, TypeGuard } from './tsHelpers'
import { freezeDraftable } from './utils'
/**
* Defines a mapping from action types to corresponding action object shapes.
*
* @deprecated This should not be used manually - it is only used for internal
* inference purposes and should not have any further value.
* It might be removed in the future.
* @public
*/
export type Actions<T extends keyof any = string> = Record<T, Action>
export type ActionMatcherDescription<S, A extends Action> = {
matcher: TypeGuard<A>
reducer: CaseReducer<S, NoInfer<A>>
}
export type ReadonlyActionMatcherDescriptionCollection<S> = ReadonlyArray<
ActionMatcherDescription<S, any>
>
export type ActionMatcherDescriptionCollection<S> = Array<
ActionMatcherDescription<S, any>
>
/**
* A *case reducer* is a reducer function for a specific action type. Case
* reducers can be composed to full reducers using `createReducer()`.
*
* Unlike a normal Redux reducer, a case reducer is never called with an
* `undefined` state to determine the initial state. Instead, the initial
* state is explicitly specified as an argument to `createReducer()`.
*
* In addition, a case reducer can choose to mutate the passed-in `state`
* value directly instead of returning a new state. This does not actually
* cause the store state to be mutated directly; instead, thanks to
* [immer](https://github.com/mweststrate/immer), the mutations are
* translated to copy operations that result in a new state.
*
* @public
*/
export type CaseReducer<S = any, A extends Action = UnknownAction> = (
state: Draft<S>,
action: A,
) => NoInfer<S> | void | Draft<NoInfer<S>>
/**
* A mapping from action types to case reducers for `createReducer()`.
*
* @deprecated This should not be used manually - it is only used
* for internal inference purposes and using it manually
* would lead to type erasure.
* It might be removed in the future.
* @public
*/
export type CaseReducers<S, AS extends Actions> = {
[T in keyof AS]: AS[T] extends Action ? CaseReducer<S, AS[T]> : void
}
export type NotFunction<T> = T extends Function ? never : T
function isStateFunction<S>(x: unknown): x is () => S {
return typeof x === 'function'
}
export type ReducerWithInitialState<S extends NotFunction<any>> = Reducer<S> & {
getInitialState: () => S
}
/**
* A utility function that allows defining a reducer as a mapping from action
* type to *case reducer* functions that handle these action types. The
* reducer's initial state is passed as the first argument.
*
* @remarks
* The body of every case reducer is implicitly wrapped with a call to
* `produce()` from the [immer](https://github.com/mweststrate/immer) library.
* This means that rather than returning a new state object, you can also
* mutate the passed-in state object directly; these mutations will then be
* automatically and efficiently translated into copies, giving you both
* convenience and immutability.
*
* @overloadSummary
* This function accepts a callback that receives a `builder` object as its argument.
* That builder provides `addCase`, `addMatcher` and `addDefaultCase` functions that may be
* called to define what actions this reducer will handle.
*
* @param initialState - `State | (() => State)`: The initial state that should be used when the reducer is called the first time. This may also be a "lazy initializer" function, which should return an initial state value when called. This will be used whenever the reducer is called with `undefined` as its state value, and is primarily useful for cases like reading initial state from `localStorage`.
* @param builderCallback - `(builder: Builder) => void` A callback that receives a *builder* object to define
* case reducers via calls to `builder.addCase(actionCreatorOrType, reducer)`.
* @example
```ts
import {
createAction,
createReducer,
UnknownAction,
PayloadAction,
} from "@reduxjs/toolkit";
const increment = createAction<number>("increment");
const decrement = createAction<number>("decrement");
function isActionWithNumberPayload(
action: UnknownAction
): action is PayloadAction<number> {
return typeof action.payload === "number";
}
const reducer = createReducer(
{
counter: 0,
sumOfNumberPayloads: 0,
unhandledActions: 0,
},
(builder) => {
builder
.addCase(increment, (state, action) => {
// action is inferred correctly here
state.counter += action.payload;
})
// You can chain calls, or have separate `builder.addCase()` lines each time
.addCase(decrement, (state, action) => {
state.counter -= action.payload;
})
// You can apply a "matcher function" to incoming actions
.addMatcher(isActionWithNumberPayload, (state, action) => {})
// and provide a default case if no other handlers matched
.addDefaultCase((state, action) => {});
}
);
```
* @public
*/
export function createReducer<S extends NotFunction<any>>(
initialState: S | (() => S),
mapOrBuilderCallback: (builder: ActionReducerMapBuilder<S>) => void,
): ReducerWithInitialState<S> {
if (process.env.NODE_ENV !== 'production') {
if (typeof mapOrBuilderCallback === 'object') {
throw new Error(
"The object notation for `createReducer` has been removed. Please use the 'builder callback' notation instead: https://redux-toolkit.js.org/api/createReducer",
)
}
}
let [actionsMap, finalActionMatchers, finalDefaultCaseReducer] =
executeReducerBuilderCallback(mapOrBuilderCallback)
// Ensure the initial state gets frozen either way (if draftable)
let getInitialState: () => S
if (isStateFunction(initialState)) {
getInitialState = () => freezeDraftable(initialState())
} else {
const frozenInitialState = freezeDraftable(initialState)
getInitialState = () => frozenInitialState
}
function reducer(state = getInitialState(), action: any): S {
let caseReducers = [
actionsMap[action.type],
...finalActionMatchers
.filter(({ matcher }) => matcher(action))
.map(({ reducer }) => reducer),
]
if (caseReducers.filter((cr) => !!cr).length === 0) {
caseReducers = [finalDefaultCaseReducer]
}
return caseReducers.reduce((previousState, caseReducer): S => {
if (caseReducer) {
if (isDraft(previousState)) {
// If it's already a draft, we must already be inside a `createNextState` call,
// likely because this is being wrapped in `createReducer`, `createSlice`, or nested
// inside an existing draft. It's safe to just pass the draft to the mutator.
const draft = previousState as Draft<S> // We can assume this is already a draft
const result = caseReducer(draft, action)
if (result === undefined) {
return previousState
}
return result as S
} else if (!isDraftable(previousState)) {
// If state is not draftable (ex: a primitive, such as 0), we want to directly
// return the caseReducer func and not wrap it with produce.
const result = caseReducer(previousState as any, action)
if (result === undefined) {
if (previousState === null) {
return previousState
}
throw Error(
'A case reducer on a non-draftable value must not return undefined',
)
}
return result as S
} else {
// @ts-ignore createNextState() produces an Immutable<Draft<S>> rather
// than an Immutable<S>, and TypeScript cannot find out how to reconcile
// these two types.
return createNextState(previousState, (draft: Draft<S>) => {
return caseReducer(draft, action)
})
}
}
return previousState
}, state)
}
reducer.getInitialState = getInitialState
return reducer as ReducerWithInitialState<S>
}

Some files were not shown because too many files have changed in this diff Show More