mirror of
https://github.com/escalante29/WealthySmart.git
synced 2026-07-17 09:08:46 +02:00
OpenAPI type codegen with CI drift gate (plan 3.4, ARCH-16, FE-14)
Every dict-returning route the SPA consumes now declares a response model (auth, bulk, sync-status, notifications). api-types.gen.ts is generated from app.openapi() via openapi-typescript, and the 22 hand- written read interfaces in api.ts are now aliases onto the generated schemas — backend schema drift becomes a typecheck failure, and CI regenerates the file and fails the deploy if it's stale. The aliasing immediately caught two real drifts: RecurringItemType was missing SAVINGS, and raw_charges (untyped JSON column) is now explicitly shaped at the boundary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
10
.github/workflows/deploy.yml
vendored
10
.github/workflows/deploy.yml
vendored
@@ -18,11 +18,17 @@ jobs:
|
|||||||
/tmp/test-venv/bin/pip install --quiet -r requirements.txt -r requirements-dev.txt
|
/tmp/test-venv/bin/pip install --quiet -r requirements.txt -r requirements-dev.txt
|
||||||
/tmp/test-venv/bin/python -m pytest tests/ -q
|
/tmp/test-venv/bin/python -m pytest tests/ -q
|
||||||
|
|
||||||
- name: Frontend typecheck
|
- name: Frontend typecheck + API type drift gate
|
||||||
run: |
|
run: |
|
||||||
cd frontend
|
cd backend
|
||||||
|
DATABASE_URL='sqlite://' SECRET_KEY='ci-only-0123456789abcdef0123456789abcdef0123456789abcdef' \
|
||||||
|
ADMIN_USERNAME=ci ADMIN_PASSWORD=ci-not-admin OPENAI_API_KEY=dummy \
|
||||||
|
/tmp/test-venv/bin/python -c "import json; from app.main import app; json.dump(app.openapi(), open('../frontend/openapi.json','w'), indent=1, sort_keys=True)"
|
||||||
|
cd ../frontend
|
||||||
corepack enable
|
corepack enable
|
||||||
pnpm install --frozen-lockfile
|
pnpm install --frozen-lockfile
|
||||||
|
pnpm exec openapi-typescript openapi.json -o src/lib/api-types.gen.ts
|
||||||
|
git diff --exit-code src/lib/api-types.gen.ts
|
||||||
pnpm typecheck
|
pnpm typecheck
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@ tech_docs/
|
|||||||
# Claude Code local state
|
# Claude Code local state
|
||||||
.claude/
|
.claude/
|
||||||
.venv/
|
.venv/
|
||||||
|
frontend/openapi.json
|
||||||
|
|||||||
14
CLAUDE.md
14
CLAUDE.md
@@ -68,3 +68,17 @@ Four automated flows on old-vps feed data into WealthySmart:
|
|||||||
4. **Pension PDFs** (`e88c3UhBeo9WCbcy`) — Gmail trigger (daily midnight) → POST /pensions/upload
|
4. **Pension PDFs** (`e88c3UhBeo9WCbcy`) — Gmail trigger (daily midnight) → POST /pensions/upload
|
||||||
|
|
||||||
Flow export: `docs/WealthySmart_ BAC Pensions Statements parser.json`
|
Flow export: `docs/WealthySmart_ BAC Pensions Statements parser.json`
|
||||||
|
|
||||||
|
## API Type Generation
|
||||||
|
|
||||||
|
Frontend read types are generated from the backend OpenAPI spec. After changing
|
||||||
|
backend response models:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend && DATABASE_URL='sqlite://' SECRET_KEY=$(openssl rand -hex 32) \
|
||||||
|
ADMIN_USERNAME=x ADMIN_PASSWORD=x-x OPENAI_API_KEY=dummy \
|
||||||
|
.venv/bin/python -c "import json; from app.main import app; json.dump(app.openapi(), open('../frontend/openapi.json','w'), indent=1, sort_keys=True)"
|
||||||
|
cd ../frontend && pnpm gen:api # regenerates src/lib/api-types.gen.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
CI regenerates and fails the deploy if `api-types.gen.ts` is stale.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request
|
||||||
|
from pydantic import BaseModel
|
||||||
from fastapi.security import OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordRequestForm
|
||||||
|
|
||||||
from app.auth import (
|
from app.auth import (
|
||||||
@@ -11,7 +12,16 @@ from app.auth import (
|
|||||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||||
|
|
||||||
|
|
||||||
@router.post("/login")
|
class TokenResponse(BaseModel):
|
||||||
|
access_token: str
|
||||||
|
token_type: str
|
||||||
|
|
||||||
|
|
||||||
|
class MeResponse(BaseModel):
|
||||||
|
username: str
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/login", response_model=TokenResponse)
|
||||||
def login(request: Request, form_data: OAuth2PasswordRequestForm = Depends()):
|
def login(request: Request, form_data: OAuth2PasswordRequestForm = Depends()):
|
||||||
check_login_rate_limit(request)
|
check_login_rate_limit(request)
|
||||||
verify_admin_credentials(form_data.username, form_data.password)
|
verify_admin_credentials(form_data.username, form_data.password)
|
||||||
@@ -19,6 +29,6 @@ def login(request: Request, form_data: OAuth2PasswordRequestForm = Depends()):
|
|||||||
return {"access_token": token, "token_type": "bearer"}
|
return {"access_token": token, "token_type": "bearer"}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/me")
|
@router.get("/me", response_model=MeResponse)
|
||||||
def me(username: str = Depends(get_current_user_cookie_or_bearer)):
|
def me(username: str = Depends(get_current_user_cookie_or_bearer)):
|
||||||
return {"username": username}
|
return {"username": username}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from pywebpush import WebPushException, webpush
|
from pywebpush import WebPushException, webpush
|
||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select
|
||||||
@@ -15,14 +16,22 @@ logger = logging.getLogger(__name__)
|
|||||||
router = APIRouter(prefix="/notifications", tags=["notifications"])
|
router = APIRouter(prefix="/notifications", tags=["notifications"])
|
||||||
|
|
||||||
|
|
||||||
@router.get("/vapid-public-key")
|
class VapidPublicKeyResponse(BaseModel):
|
||||||
|
publicKey: str
|
||||||
|
|
||||||
|
|
||||||
|
class SubscriptionStatusResponse(BaseModel):
|
||||||
|
status: str
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/vapid-public-key", response_model=VapidPublicKeyResponse)
|
||||||
def get_vapid_public_key(_user: str = Depends(get_current_user)):
|
def get_vapid_public_key(_user: str = Depends(get_current_user)):
|
||||||
if not settings.VAPID_PUBLIC_KEY:
|
if not settings.VAPID_PUBLIC_KEY:
|
||||||
raise HTTPException(status_code=503, detail="Push notifications not configured")
|
raise HTTPException(status_code=503, detail="Push notifications not configured")
|
||||||
return {"publicKey": settings.VAPID_PUBLIC_KEY}
|
return {"publicKey": settings.VAPID_PUBLIC_KEY}
|
||||||
|
|
||||||
|
|
||||||
@router.post("/subscribe", status_code=201)
|
@router.post("/subscribe", status_code=201, response_model=SubscriptionStatusResponse)
|
||||||
def subscribe(
|
def subscribe(
|
||||||
data: PushSubscriptionCreate,
|
data: PushSubscriptionCreate,
|
||||||
session: Session = Depends(get_session),
|
session: Session = Depends(get_session),
|
||||||
@@ -48,7 +57,7 @@ def subscribe(
|
|||||||
return {"status": "subscribed"}
|
return {"status": "subscribed"}
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/unsubscribe")
|
@router.delete("/unsubscribe", response_model=SubscriptionStatusResponse)
|
||||||
def unsubscribe(
|
def unsubscribe(
|
||||||
data: PushSubscriptionCreate,
|
data: PushSubscriptionCreate,
|
||||||
session: Session = Depends(get_session),
|
session: Session = Depends(get_session),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
|
from pydantic import BaseModel
|
||||||
from sqlmodel import Session
|
from sqlmodel import Session
|
||||||
|
|
||||||
from app.auth import get_current_user
|
from app.auth import get_current_user
|
||||||
@@ -8,7 +9,22 @@ from app.services.sync_status import compute_sync_status
|
|||||||
router = APIRouter(prefix="/sync-status", tags=["sync-status"])
|
router = APIRouter(prefix="/sync-status", tags=["sync-status"])
|
||||||
|
|
||||||
|
|
||||||
@router.get("/")
|
class SyncSourceStatus(BaseModel):
|
||||||
|
key: str
|
||||||
|
label: str
|
||||||
|
description: str
|
||||||
|
last_received: str | None
|
||||||
|
age_days: float | None
|
||||||
|
warn_after_days: float
|
||||||
|
status: str # 'ok' | 'warning' | 'never'
|
||||||
|
|
||||||
|
|
||||||
|
class SyncStatusResponse(BaseModel):
|
||||||
|
sources: list[SyncSourceStatus]
|
||||||
|
warnings: int
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/", response_model=SyncStatusResponse)
|
||||||
def sync_status(
|
def sync_status(
|
||||||
session: Session = Depends(get_session),
|
session: Session = Depends(get_session),
|
||||||
_user: str = Depends(get_current_user),
|
_user: str = Depends(get_current_user),
|
||||||
|
|||||||
@@ -106,7 +106,11 @@ class BulkActionRequest(BaseModel):
|
|||||||
deferred: Optional[bool] = None # for set_deferred
|
deferred: Optional[bool] = None # for set_deferred
|
||||||
|
|
||||||
|
|
||||||
@router.post("/bulk")
|
class BulkActionResponse(BaseModel):
|
||||||
|
affected: int
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/bulk", response_model=BulkActionResponse)
|
||||||
def bulk_action(
|
def bulk_action(
|
||||||
req: BulkActionRequest,
|
req: BulkActionRequest,
|
||||||
session: Session = Depends(get_session),
|
session: Session = Depends(get_session),
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
"dev": "concurrently -k -n vite,ck -c cyan,magenta \"vite --host 0.0.0.0 --port 3000\" \"tsx watch server.ts\"",
|
"dev": "concurrently -k -n vite,ck -c cyan,magenta \"vite --host 0.0.0.0 --port 3000\" \"tsx watch server.ts\"",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "tsx server.ts",
|
"preview": "tsx server.ts",
|
||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit",
|
||||||
|
"gen:api": "openapi-typescript openapi.json -o src/lib/api-types.gen.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ag-ui/client": "0.0.52",
|
"@ag-ui/client": "0.0.52",
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"@vitejs/plugin-react-swc": "^3.9.0",
|
"@vitejs/plugin-react-swc": "^3.9.0",
|
||||||
|
"openapi-typescript": "^7.13.0",
|
||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"typescript": "^5",
|
"typescript": "^5",
|
||||||
"vite": "^6.3.5"
|
"vite": "^6.3.5"
|
||||||
|
|||||||
191
frontend/pnpm-lock.yaml
generated
191
frontend/pnpm-lock.yaml
generated
@@ -96,6 +96,9 @@ importers:
|
|||||||
'@vitejs/plugin-react-swc':
|
'@vitejs/plugin-react-swc':
|
||||||
specifier: ^3.9.0
|
specifier: ^3.9.0
|
||||||
version: 3.11.0(@swc/helpers@0.5.21)(vite@6.4.2(@types/node@20.19.39)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))
|
version: 3.11.0(@swc/helpers@0.5.21)(vite@6.4.2(@types/node@20.19.39)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))
|
||||||
|
openapi-typescript:
|
||||||
|
specifier: ^7.13.0
|
||||||
|
version: 7.13.0(typescript@5.9.3)
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^4
|
specifier: ^4
|
||||||
version: 4.2.4
|
version: 4.2.4
|
||||||
@@ -225,6 +228,14 @@ packages:
|
|||||||
'@antfu/install-pkg@1.1.0':
|
'@antfu/install-pkg@1.1.0':
|
||||||
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
|
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
|
||||||
|
|
||||||
|
'@babel/code-frame@7.29.7':
|
||||||
|
resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/helper-validator-identifier@7.29.7':
|
||||||
|
resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/runtime@7.29.2':
|
'@babel/runtime@7.29.2':
|
||||||
resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==}
|
resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@@ -1215,6 +1226,16 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1
|
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1
|
||||||
|
|
||||||
|
'@redocly/ajv@8.11.2':
|
||||||
|
resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==}
|
||||||
|
|
||||||
|
'@redocly/config@0.22.0':
|
||||||
|
resolution: {integrity: sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==}
|
||||||
|
|
||||||
|
'@redocly/openapi-core@1.34.15':
|
||||||
|
resolution: {integrity: sha512-HAwCnNyKcs5XGQqms+9t7OdAPM/5TDstmhF+0i7tdCFato2QKuYIlyWETwkXd8c5zbltr1oB+6y9NTeQLr2d6Q==}
|
||||||
|
engines: {node: '>=18.17.0', npm: '>=9.5.0'}
|
||||||
|
|
||||||
'@reduxjs/toolkit@2.11.2':
|
'@reduxjs/toolkit@2.11.2':
|
||||||
resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==}
|
resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1894,6 +1915,10 @@ packages:
|
|||||||
ajv@8.20.0:
|
ajv@8.20.0:
|
||||||
resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==}
|
resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==}
|
||||||
|
|
||||||
|
ansi-colors@4.1.3:
|
||||||
|
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
ansi-regex@5.0.1:
|
ansi-regex@5.0.1:
|
||||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -1906,6 +1931,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
|
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
argparse@2.0.1:
|
||||||
|
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||||
|
|
||||||
aria-hidden@1.2.6:
|
aria-hidden@1.2.6:
|
||||||
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
|
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -1923,6 +1951,9 @@ packages:
|
|||||||
bail@2.0.2:
|
bail@2.0.2:
|
||||||
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
|
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
|
||||||
|
|
||||||
|
balanced-match@1.0.2:
|
||||||
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
|
|
||||||
base64-js@1.5.1:
|
base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
|
|
||||||
@@ -1937,6 +1968,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==}
|
resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
brace-expansion@2.1.1:
|
||||||
|
resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==}
|
||||||
|
|
||||||
buffer-equal-constant-time@1.0.1:
|
buffer-equal-constant-time@1.0.1:
|
||||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
||||||
|
|
||||||
@@ -1966,6 +2000,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
change-case@5.4.4:
|
||||||
|
resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==}
|
||||||
|
|
||||||
character-entities-html4@2.1.0:
|
character-entities-html4@2.1.0:
|
||||||
resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
|
resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
|
||||||
|
|
||||||
@@ -2024,6 +2061,9 @@ packages:
|
|||||||
color-name@1.1.4:
|
color-name@1.1.4:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
|
|
||||||
|
colorette@1.4.0:
|
||||||
|
resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==}
|
||||||
|
|
||||||
colorette@2.0.20:
|
colorette@2.0.20:
|
||||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||||
|
|
||||||
@@ -2724,6 +2764,10 @@ packages:
|
|||||||
immer@11.1.4:
|
immer@11.1.4:
|
||||||
resolution: {integrity: sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==}
|
resolution: {integrity: sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==}
|
||||||
|
|
||||||
|
index-to-position@1.2.0:
|
||||||
|
resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
inherits@2.0.4:
|
inherits@2.0.4:
|
||||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
|
||||||
@@ -2808,12 +2852,20 @@ packages:
|
|||||||
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
js-levenshtein@1.1.6:
|
||||||
|
resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
js-tiktoken@1.0.21:
|
js-tiktoken@1.0.21:
|
||||||
resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==}
|
resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==}
|
||||||
|
|
||||||
js-tokens@4.0.0:
|
js-tokens@4.0.0:
|
||||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||||
|
|
||||||
|
js-yaml@4.1.1:
|
||||||
|
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
json-bigint@1.0.0:
|
json-bigint@1.0.0:
|
||||||
resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
|
resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
|
||||||
|
|
||||||
@@ -3305,6 +3357,10 @@ packages:
|
|||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
minimatch@5.1.9:
|
||||||
|
resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
minimist@1.2.8:
|
minimist@1.2.8:
|
||||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||||
|
|
||||||
@@ -3393,6 +3449,12 @@ packages:
|
|||||||
zod:
|
zod:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
openapi-typescript@7.13.0:
|
||||||
|
resolution: {integrity: sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
typescript: ^5.x
|
||||||
|
|
||||||
p-finally@1.0.0:
|
p-finally@1.0.0:
|
||||||
resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
|
resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -3426,6 +3488,10 @@ packages:
|
|||||||
parse-entities@4.0.2:
|
parse-entities@4.0.2:
|
||||||
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
|
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
|
||||||
|
|
||||||
|
parse-json@8.3.0:
|
||||||
|
resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
parse5@7.3.0:
|
parse5@7.3.0:
|
||||||
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
|
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
|
||||||
|
|
||||||
@@ -3483,6 +3549,10 @@ packages:
|
|||||||
pkg-types@1.3.1:
|
pkg-types@1.3.1:
|
||||||
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
|
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
|
||||||
|
|
||||||
|
pluralize@8.0.0:
|
||||||
|
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
points-on-curve@0.2.0:
|
points-on-curve@0.2.0:
|
||||||
resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==}
|
resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==}
|
||||||
|
|
||||||
@@ -3925,6 +3995,10 @@ packages:
|
|||||||
stylis@4.4.0:
|
stylis@4.4.0:
|
||||||
resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==}
|
resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==}
|
||||||
|
|
||||||
|
supports-color@10.2.2:
|
||||||
|
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
supports-color@7.2.0:
|
supports-color@7.2.0:
|
||||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -3992,6 +4066,10 @@ packages:
|
|||||||
tw-animate-css@1.4.0:
|
tw-animate-css@1.4.0:
|
||||||
resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==}
|
resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==}
|
||||||
|
|
||||||
|
type-fest@4.41.0:
|
||||||
|
resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
type-graphql@2.0.0-rc.1:
|
type-graphql@2.0.0-rc.1:
|
||||||
resolution: {integrity: sha512-HCu4j3jR0tZvAAoO7DMBT3MRmah0DFRe5APymm9lXUghXA0sbhiMf6SLRafRYfk0R0KiUQYRduuGP3ap1RnF1Q==}
|
resolution: {integrity: sha512-HCu4j3jR0tZvAAoO7DMBT3MRmah0DFRe5APymm9lXUghXA0sbhiMf6SLRafRYfk0R0KiUQYRduuGP3ap1RnF1Q==}
|
||||||
engines: {node: '>= 18.12.0'}
|
engines: {node: '>= 18.12.0'}
|
||||||
@@ -4077,6 +4155,9 @@ packages:
|
|||||||
untruncate-json@0.0.1:
|
untruncate-json@0.0.1:
|
||||||
resolution: {integrity: sha512-4W9enDK4X1y1s2S/Rz7ysw6kDuMS3VmRjMFg7GZrNO+98OSe+x5Lh7PKYoVjy3lW/1wmhs6HW0lusnQRHgMarA==}
|
resolution: {integrity: sha512-4W9enDK4X1y1s2S/Rz7ysw6kDuMS3VmRjMFg7GZrNO+98OSe+x5Lh7PKYoVjy3lW/1wmhs6HW0lusnQRHgMarA==}
|
||||||
|
|
||||||
|
uri-js-replace@1.0.1:
|
||||||
|
resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==}
|
||||||
|
|
||||||
urlpattern-polyfill@10.1.0:
|
urlpattern-polyfill@10.1.0:
|
||||||
resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==}
|
resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==}
|
||||||
|
|
||||||
@@ -4275,6 +4356,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
yaml-ast-parser@0.0.43:
|
||||||
|
resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==}
|
||||||
|
|
||||||
yargs-parser@21.1.1:
|
yargs-parser@21.1.1:
|
||||||
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
|
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -4464,6 +4548,14 @@ snapshots:
|
|||||||
package-manager-detector: 1.6.0
|
package-manager-detector: 1.6.0
|
||||||
tinyexec: 1.1.1
|
tinyexec: 1.1.1
|
||||||
|
|
||||||
|
'@babel/code-frame@7.29.7':
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-validator-identifier': 7.29.7
|
||||||
|
js-tokens: 4.0.0
|
||||||
|
picocolors: 1.1.1
|
||||||
|
|
||||||
|
'@babel/helper-validator-identifier@7.29.7': {}
|
||||||
|
|
||||||
'@babel/runtime@7.29.2': {}
|
'@babel/runtime@7.29.2': {}
|
||||||
|
|
||||||
'@base-ui/react@1.4.1(@types/react@19.2.14)(date-fns@4.1.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
|
'@base-ui/react@1.4.1(@types/react@19.2.14)(date-fns@4.1.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
|
||||||
@@ -5430,6 +5522,29 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
react: 19.2.5
|
react: 19.2.5
|
||||||
|
|
||||||
|
'@redocly/ajv@8.11.2':
|
||||||
|
dependencies:
|
||||||
|
fast-deep-equal: 3.1.3
|
||||||
|
json-schema-traverse: 1.0.0
|
||||||
|
require-from-string: 2.0.2
|
||||||
|
uri-js-replace: 1.0.1
|
||||||
|
|
||||||
|
'@redocly/config@0.22.0': {}
|
||||||
|
|
||||||
|
'@redocly/openapi-core@1.34.15(supports-color@10.2.2)':
|
||||||
|
dependencies:
|
||||||
|
'@redocly/ajv': 8.11.2
|
||||||
|
'@redocly/config': 0.22.0
|
||||||
|
colorette: 1.4.0
|
||||||
|
https-proxy-agent: 7.0.6(supports-color@10.2.2)
|
||||||
|
js-levenshtein: 1.1.6
|
||||||
|
js-yaml: 4.1.1
|
||||||
|
minimatch: 5.1.9
|
||||||
|
pluralize: 8.0.0
|
||||||
|
yaml-ast-parser: 0.0.43
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
'@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@19.2.14)(react@19.2.5)(redux@5.0.1))(react@19.2.5)':
|
'@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@19.2.14)(react@19.2.5)(redux@5.0.1))(react@19.2.5)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@standard-schema/spec': 1.1.0
|
'@standard-schema/spec': 1.1.0
|
||||||
@@ -6039,6 +6154,8 @@ snapshots:
|
|||||||
json-schema-traverse: 1.0.0
|
json-schema-traverse: 1.0.0
|
||||||
require-from-string: 2.0.2
|
require-from-string: 2.0.2
|
||||||
|
|
||||||
|
ansi-colors@4.1.3: {}
|
||||||
|
|
||||||
ansi-regex@5.0.1: {}
|
ansi-regex@5.0.1: {}
|
||||||
|
|
||||||
ansi-styles@4.3.0:
|
ansi-styles@4.3.0:
|
||||||
@@ -6047,6 +6164,8 @@ snapshots:
|
|||||||
|
|
||||||
ansi-styles@5.2.0: {}
|
ansi-styles@5.2.0: {}
|
||||||
|
|
||||||
|
argparse@2.0.1: {}
|
||||||
|
|
||||||
aria-hidden@1.2.6:
|
aria-hidden@1.2.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
@@ -6060,6 +6179,8 @@ snapshots:
|
|||||||
|
|
||||||
bail@2.0.2: {}
|
bail@2.0.2: {}
|
||||||
|
|
||||||
|
balanced-match@1.0.2: {}
|
||||||
|
|
||||||
base64-js@1.5.1: {}
|
base64-js@1.5.1: {}
|
||||||
|
|
||||||
bignumber.js@9.3.1: {}
|
bignumber.js@9.3.1: {}
|
||||||
@@ -6085,7 +6206,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
bytes: 3.1.2
|
bytes: 3.1.2
|
||||||
content-type: 1.0.5
|
content-type: 1.0.5
|
||||||
debug: 4.4.3
|
debug: 4.4.3(supports-color@10.2.2)
|
||||||
http-errors: 2.0.1
|
http-errors: 2.0.1
|
||||||
iconv-lite: 0.7.2
|
iconv-lite: 0.7.2
|
||||||
on-finished: 2.4.1
|
on-finished: 2.4.1
|
||||||
@@ -6095,6 +6216,10 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
brace-expansion@2.1.1:
|
||||||
|
dependencies:
|
||||||
|
balanced-match: 1.0.2
|
||||||
|
|
||||||
buffer-equal-constant-time@1.0.1: {}
|
buffer-equal-constant-time@1.0.1: {}
|
||||||
|
|
||||||
buffer@6.0.3:
|
buffer@6.0.3:
|
||||||
@@ -6123,6 +6248,8 @@ snapshots:
|
|||||||
ansi-styles: 4.3.0
|
ansi-styles: 4.3.0
|
||||||
supports-color: 7.2.0
|
supports-color: 7.2.0
|
||||||
|
|
||||||
|
change-case@5.4.4: {}
|
||||||
|
|
||||||
character-entities-html4@2.1.0: {}
|
character-entities-html4@2.1.0: {}
|
||||||
|
|
||||||
character-entities-legacy@1.1.4: {}
|
character-entities-legacy@1.1.4: {}
|
||||||
@@ -6178,6 +6305,8 @@ snapshots:
|
|||||||
|
|
||||||
color-name@1.1.4: {}
|
color-name@1.1.4: {}
|
||||||
|
|
||||||
|
colorette@1.4.0: {}
|
||||||
|
|
||||||
colorette@2.0.20: {}
|
colorette@2.0.20: {}
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
combined-stream@1.0.8:
|
||||||
@@ -6443,9 +6572,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.0.0
|
ms: 2.0.0
|
||||||
|
|
||||||
debug@4.4.3:
|
debug@4.4.3(supports-color@10.2.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
optionalDependencies:
|
||||||
|
supports-color: 10.2.2
|
||||||
|
|
||||||
decamelize@1.2.0: {}
|
decamelize@1.2.0: {}
|
||||||
|
|
||||||
@@ -6660,7 +6791,7 @@ snapshots:
|
|||||||
content-type: 1.0.5
|
content-type: 1.0.5
|
||||||
cookie: 0.7.2
|
cookie: 0.7.2
|
||||||
cookie-signature: 1.2.2
|
cookie-signature: 1.2.2
|
||||||
debug: 4.4.3
|
debug: 4.4.3(supports-color@10.2.2)
|
||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
@@ -6724,7 +6855,7 @@ snapshots:
|
|||||||
|
|
||||||
finalhandler@2.1.1:
|
finalhandler@2.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3
|
debug: 4.4.3(supports-color@10.2.2)
|
||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
on-finished: 2.4.1
|
on-finished: 2.4.1
|
||||||
@@ -6771,7 +6902,7 @@ snapshots:
|
|||||||
gaxios@7.1.4:
|
gaxios@7.1.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
extend: 3.0.2
|
extend: 3.0.2
|
||||||
https-proxy-agent: 7.0.6
|
https-proxy-agent: 7.0.6(supports-color@10.2.2)
|
||||||
node-fetch: 3.3.2
|
node-fetch: 3.3.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -7032,10 +7163,10 @@ snapshots:
|
|||||||
statuses: 2.0.2
|
statuses: 2.0.2
|
||||||
toidentifier: 1.0.1
|
toidentifier: 1.0.1
|
||||||
|
|
||||||
https-proxy-agent@7.0.6:
|
https-proxy-agent@7.0.6(supports-color@10.2.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 7.1.4
|
agent-base: 7.1.4
|
||||||
debug: 4.4.3
|
debug: 4.4.3(supports-color@10.2.2)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -7062,6 +7193,8 @@ snapshots:
|
|||||||
|
|
||||||
immer@11.1.4: {}
|
immer@11.1.4: {}
|
||||||
|
|
||||||
|
index-to-position@1.2.0: {}
|
||||||
|
|
||||||
inherits@2.0.4: {}
|
inherits@2.0.4: {}
|
||||||
|
|
||||||
inline-style-parser@0.1.1: {}
|
inline-style-parser@0.1.1: {}
|
||||||
@@ -7118,12 +7251,18 @@ snapshots:
|
|||||||
|
|
||||||
joycon@3.1.1: {}
|
joycon@3.1.1: {}
|
||||||
|
|
||||||
|
js-levenshtein@1.1.6: {}
|
||||||
|
|
||||||
js-tiktoken@1.0.21:
|
js-tiktoken@1.0.21:
|
||||||
dependencies:
|
dependencies:
|
||||||
base64-js: 1.5.1
|
base64-js: 1.5.1
|
||||||
|
|
||||||
js-tokens@4.0.0: {}
|
js-tokens@4.0.0: {}
|
||||||
|
|
||||||
|
js-yaml@4.1.1:
|
||||||
|
dependencies:
|
||||||
|
argparse: 2.0.1
|
||||||
|
|
||||||
json-bigint@1.0.0:
|
json-bigint@1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
bignumber.js: 9.3.1
|
bignumber.js: 9.3.1
|
||||||
@@ -7865,7 +8004,7 @@ snapshots:
|
|||||||
micromark@3.2.0:
|
micromark@3.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/debug': 4.1.13
|
'@types/debug': 4.1.13
|
||||||
debug: 4.4.3
|
debug: 4.4.3(supports-color@10.2.2)
|
||||||
decode-named-character-reference: 1.3.0
|
decode-named-character-reference: 1.3.0
|
||||||
micromark-core-commonmark: 1.1.0
|
micromark-core-commonmark: 1.1.0
|
||||||
micromark-factory-space: 1.1.0
|
micromark-factory-space: 1.1.0
|
||||||
@@ -7887,7 +8026,7 @@ snapshots:
|
|||||||
micromark@4.0.2:
|
micromark@4.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/debug': 4.1.13
|
'@types/debug': 4.1.13
|
||||||
debug: 4.4.3
|
debug: 4.4.3(supports-color@10.2.2)
|
||||||
decode-named-character-reference: 1.3.0
|
decode-named-character-reference: 1.3.0
|
||||||
devlop: 1.1.0
|
devlop: 1.1.0
|
||||||
micromark-core-commonmark: 2.0.3
|
micromark-core-commonmark: 2.0.3
|
||||||
@@ -7920,6 +8059,10 @@ snapshots:
|
|||||||
|
|
||||||
mime@1.6.0: {}
|
mime@1.6.0: {}
|
||||||
|
|
||||||
|
minimatch@5.1.9:
|
||||||
|
dependencies:
|
||||||
|
brace-expansion: 2.1.1
|
||||||
|
|
||||||
minimist@1.2.8: {}
|
minimist@1.2.8: {}
|
||||||
|
|
||||||
mlly@1.8.2:
|
mlly@1.8.2:
|
||||||
@@ -7993,6 +8136,16 @@ snapshots:
|
|||||||
- encoding
|
- encoding
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
openapi-typescript@7.13.0(typescript@5.9.3):
|
||||||
|
dependencies:
|
||||||
|
'@redocly/openapi-core': 1.34.15(supports-color@10.2.2)
|
||||||
|
ansi-colors: 4.1.3
|
||||||
|
change-case: 5.4.4
|
||||||
|
parse-json: 8.3.0
|
||||||
|
supports-color: 10.2.2
|
||||||
|
typescript: 5.9.3
|
||||||
|
yargs-parser: 21.1.1
|
||||||
|
|
||||||
p-finally@1.0.0: {}
|
p-finally@1.0.0: {}
|
||||||
|
|
||||||
p-queue@6.6.2:
|
p-queue@6.6.2:
|
||||||
@@ -8036,6 +8189,12 @@ snapshots:
|
|||||||
is-decimal: 2.0.1
|
is-decimal: 2.0.1
|
||||||
is-hexadecimal: 2.0.1
|
is-hexadecimal: 2.0.1
|
||||||
|
|
||||||
|
parse-json@8.3.0:
|
||||||
|
dependencies:
|
||||||
|
'@babel/code-frame': 7.29.7
|
||||||
|
index-to-position: 1.2.0
|
||||||
|
type-fest: 4.41.0
|
||||||
|
|
||||||
parse5@7.3.0:
|
parse5@7.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
entities: 6.0.1
|
entities: 6.0.1
|
||||||
@@ -8105,6 +8264,8 @@ snapshots:
|
|||||||
mlly: 1.8.2
|
mlly: 1.8.2
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
|
|
||||||
|
pluralize@8.0.0: {}
|
||||||
|
|
||||||
points-on-curve@0.2.0: {}
|
points-on-curve@0.2.0: {}
|
||||||
|
|
||||||
points-on-path@0.2.1:
|
points-on-path@0.2.1:
|
||||||
@@ -8520,7 +8681,7 @@ snapshots:
|
|||||||
|
|
||||||
router@2.2.0:
|
router@2.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3
|
debug: 4.4.3(supports-color@10.2.2)
|
||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
is-promise: 4.0.0
|
is-promise: 4.0.0
|
||||||
parseurl: 1.3.3
|
parseurl: 1.3.3
|
||||||
@@ -8574,7 +8735,7 @@ snapshots:
|
|||||||
|
|
||||||
send@1.2.1:
|
send@1.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3
|
debug: 4.4.3(supports-color@10.2.2)
|
||||||
encodeurl: 2.0.0
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
etag: 1.8.1
|
etag: 1.8.1
|
||||||
@@ -8743,6 +8904,8 @@ snapshots:
|
|||||||
|
|
||||||
stylis@4.4.0: {}
|
stylis@4.4.0: {}
|
||||||
|
|
||||||
|
supports-color@10.2.2: {}
|
||||||
|
|
||||||
supports-color@7.2.0:
|
supports-color@7.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-flag: 4.0.0
|
has-flag: 4.0.0
|
||||||
@@ -8795,6 +8958,8 @@ snapshots:
|
|||||||
|
|
||||||
tw-animate-css@1.4.0: {}
|
tw-animate-css@1.4.0: {}
|
||||||
|
|
||||||
|
type-fest@4.41.0: {}
|
||||||
|
|
||||||
type-graphql@2.0.0-rc.1(class-validator@0.14.4)(graphql-scalars@1.25.0(graphql@16.13.2))(graphql@16.13.2):
|
type-graphql@2.0.0-rc.1(class-validator@0.14.4)(graphql-scalars@1.25.0(graphql@16.13.2))(graphql@16.13.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@graphql-yoga/subscription': 5.0.5
|
'@graphql-yoga/subscription': 5.0.5
|
||||||
@@ -8910,6 +9075,8 @@ snapshots:
|
|||||||
|
|
||||||
untruncate-json@0.0.1: {}
|
untruncate-json@0.0.1: {}
|
||||||
|
|
||||||
|
uri-js-replace@1.0.1: {}
|
||||||
|
|
||||||
urlpattern-polyfill@10.1.0: {}
|
urlpattern-polyfill@10.1.0: {}
|
||||||
|
|
||||||
urql@4.2.2(@urql/core@5.2.0(graphql@16.13.2))(react@19.2.5):
|
urql@4.2.2(@urql/core@5.2.0(graphql@16.13.2))(react@19.2.5):
|
||||||
@@ -9070,6 +9237,8 @@ snapshots:
|
|||||||
|
|
||||||
y18n@5.0.8: {}
|
y18n@5.0.8: {}
|
||||||
|
|
||||||
|
yaml-ast-parser@0.0.43: {}
|
||||||
|
|
||||||
yargs-parser@21.1.1: {}
|
yargs-parser@21.1.1: {}
|
||||||
|
|
||||||
yargs@17.7.2:
|
yargs@17.7.2:
|
||||||
|
|||||||
4058
frontend/src/lib/api-types.gen.ts
Normal file
4058
frontend/src/lib/api-types.gen.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,10 @@
|
|||||||
|
import type { components } from "./api-types.gen";
|
||||||
|
|
||||||
|
/** Schemas generated from the backend OpenAPI spec (pnpm gen:api). Aliasing
|
||||||
|
* the app's read types to them makes backend schema drift a typecheck error
|
||||||
|
* instead of a runtime surprise (review ARCH-16 / FE-14 / plan 3.4). */
|
||||||
|
type Schema<K extends keyof components["schemas"]> = components["schemas"][K];
|
||||||
|
|
||||||
const BASE_URL = "/api/v1";
|
const BASE_URL = "/api/v1";
|
||||||
|
|
||||||
class ApiError extends Error {
|
class ApiError extends Error {
|
||||||
@@ -125,91 +132,22 @@ export async function logout() {
|
|||||||
|
|
||||||
// ─── Types ──────────────────────────────────────────────────────────────────
|
// ─── Types ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export interface Account {
|
export type Account = Schema<'AccountRead'>;
|
||||||
id: number;
|
|
||||||
bank: string;
|
|
||||||
currency: string;
|
|
||||||
label: string;
|
|
||||||
balance: number;
|
|
||||||
account_type: string;
|
|
||||||
next_payment: number | null;
|
|
||||||
updated_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Category {
|
export type Category = Schema<'CategoryRead'>;
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
icon: string;
|
|
||||||
auto_match_patterns: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SkippedDuplicate {
|
export type SkippedDuplicate = Schema<'SkippedDuplicate'>;
|
||||||
line: number;
|
|
||||||
merchant: string;
|
|
||||||
date: string;
|
|
||||||
amount: number;
|
|
||||||
currency: string;
|
|
||||||
existing_id: number;
|
|
||||||
existing_merchant: string;
|
|
||||||
existing_date: string;
|
|
||||||
existing_amount: number;
|
|
||||||
existing_source: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImportResult {
|
export type ImportResult = Schema<'PasteImportResult'>;
|
||||||
imported: number;
|
|
||||||
duplicates: number;
|
|
||||||
errors: string[];
|
|
||||||
skipped: SkippedDuplicate[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Transaction {
|
export type Transaction = Schema<'TransactionRead'>;
|
||||||
id: number;
|
|
||||||
amount: number;
|
|
||||||
currency: string;
|
|
||||||
merchant: string;
|
|
||||||
city: string | null;
|
|
||||||
date: string;
|
|
||||||
card_type: string | null;
|
|
||||||
card_last4: string | null;
|
|
||||||
authorization_code: string | null;
|
|
||||||
reference: string | null;
|
|
||||||
transaction_type: string;
|
|
||||||
source: string;
|
|
||||||
bank: string;
|
|
||||||
notes: string | null;
|
|
||||||
category_id: number | null;
|
|
||||||
category: Category | null;
|
|
||||||
deferred_to_next_cycle: boolean;
|
|
||||||
created_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Budget / Recurring Items ---
|
// --- Budget / Recurring Items ---
|
||||||
|
|
||||||
export type RecurringItemType = "INCOME" | "EXPENSE";
|
export type RecurringItemType = Schema<"RecurringItemType">;
|
||||||
export type RecurringFrequency =
|
export type RecurringFrequency = Schema<"RecurringFrequency">;
|
||||||
| "WEEKLY"
|
|
||||||
| "MONTHLY"
|
|
||||||
| "QUARTERLY"
|
|
||||||
| "BIANNUAL"
|
|
||||||
| "YEARLY";
|
|
||||||
|
|
||||||
export interface RecurringItem {
|
export type RecurringItem = Schema<'RecurringItemRead'>;
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
amount: number;
|
|
||||||
currency: string;
|
|
||||||
item_type: RecurringItemType;
|
|
||||||
frequency: RecurringFrequency;
|
|
||||||
day_of_month: number | null;
|
|
||||||
month_of_year: number | null;
|
|
||||||
override_amounts: Record<string, number> | null;
|
|
||||||
category_id: number | null;
|
|
||||||
is_active: boolean;
|
|
||||||
notes: string | null;
|
|
||||||
created_at: string;
|
|
||||||
category: Category | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RecurringItemCreate {
|
export interface RecurringItemCreate {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -239,76 +177,19 @@ export interface RecurringItemUpdate {
|
|||||||
notes?: string | null;
|
notes?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RecurringItemDetail {
|
export type RecurringItemDetail = Schema<'RecurringItemDetail'>;
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
amount: number;
|
|
||||||
projected_amount: number | null;
|
|
||||||
used_actual: boolean;
|
|
||||||
item_type: string;
|
|
||||||
frequency: string;
|
|
||||||
category_name: string | null;
|
|
||||||
category_id: number | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ActualsBySource {
|
export type ActualsBySource = Schema<'ActualsBySource'>;
|
||||||
source: string;
|
|
||||||
total_compra: number;
|
|
||||||
total_devolucion: number;
|
|
||||||
net: number;
|
|
||||||
count: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MonthlyProjection {
|
export type MonthlyProjection = Schema<'MonthlyProjectionResponse'>;
|
||||||
month: number;
|
|
||||||
year: number;
|
|
||||||
projected_income: number;
|
|
||||||
projected_fixed_expenses: number;
|
|
||||||
actual_credit_card: number;
|
|
||||||
actual_cash: number;
|
|
||||||
actual_transfers: number;
|
|
||||||
uncovered_actual: number;
|
|
||||||
gran_total_egresos: number;
|
|
||||||
net_balance: number;
|
|
||||||
carryover_balance: number;
|
|
||||||
cumulative_balance: number;
|
|
||||||
balance_overridden: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface YearlyProjection {
|
export type YearlyProjection = Schema<'YearlyProjectionResponse'>;
|
||||||
year: number;
|
|
||||||
months: MonthlyProjection[];
|
|
||||||
annual_income: number;
|
|
||||||
annual_expenses: number;
|
|
||||||
annual_net: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MonthlyDetail {
|
export type MonthlyDetail = Schema<'MonthlyDetailResponse'>;
|
||||||
year: number;
|
|
||||||
month: number;
|
|
||||||
income_items: RecurringItemDetail[];
|
|
||||||
expense_items: RecurringItemDetail[];
|
|
||||||
actuals_by_source: ActualsBySource[];
|
|
||||||
total_projected_income: number;
|
|
||||||
total_projected_expenses: number;
|
|
||||||
uncovered_actual: number;
|
|
||||||
gran_total_egresos: number;
|
|
||||||
net_balance: number;
|
|
||||||
cc_by_category: { category_name: string; amount: number }[];
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Savings Accrual ---
|
// --- Savings Accrual ---
|
||||||
|
|
||||||
export interface SavingsAccrual {
|
export type SavingsAccrual = Schema<'SavingsAccrualRead'>;
|
||||||
id: number;
|
|
||||||
year: number;
|
|
||||||
month: number;
|
|
||||||
memp_amount: number;
|
|
||||||
mpat_amount: number;
|
|
||||||
trigger_transaction_id: number | null;
|
|
||||||
applied_at: string;
|
|
||||||
notes: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SavingsAccrualCreate {
|
export interface SavingsAccrualCreate {
|
||||||
year: number;
|
year: number;
|
||||||
@@ -361,11 +242,7 @@ export const deleteBalanceOverride = (year: number, month: number) =>
|
|||||||
|
|
||||||
// --- Salarios ---
|
// --- Salarios ---
|
||||||
|
|
||||||
export interface SalariosSummary {
|
export type SalariosSummary = Schema<'SalariosSummary'>;
|
||||||
count: number;
|
|
||||||
total_amount: number;
|
|
||||||
latest_date: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getSalarios = (params?: { limit?: number; offset?: number }) =>
|
export const getSalarios = (params?: { limit?: number; offset?: number }) =>
|
||||||
api.get<Transaction[]>("/salarios/", { params });
|
api.get<Transaction[]>("/salarios/", { params });
|
||||||
@@ -374,32 +251,9 @@ export const getSalariosSummary = () =>
|
|||||||
|
|
||||||
// --- Pensions ---
|
// --- Pensions ---
|
||||||
|
|
||||||
export interface PensionSnapshot {
|
export type PensionSnapshot = Schema<'PensionSnapshotRead'>;
|
||||||
id: number;
|
|
||||||
fund: string;
|
|
||||||
contract_number: string;
|
|
||||||
period_start: string;
|
|
||||||
period_end: string;
|
|
||||||
saldo_anterior: number;
|
|
||||||
aportes: number;
|
|
||||||
rendimientos: number;
|
|
||||||
retiros: number;
|
|
||||||
traslados: number;
|
|
||||||
comision: number;
|
|
||||||
correccion: number;
|
|
||||||
bonificacion: number;
|
|
||||||
saldo_final: number;
|
|
||||||
source_filename: string;
|
|
||||||
created_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PensionUploadResult {
|
export type PensionUploadResult = Schema<'PensionUploadResult'>;
|
||||||
imported: number;
|
|
||||||
updated: number;
|
|
||||||
duplicates: number;
|
|
||||||
errors: string[];
|
|
||||||
snapshots: PensionSnapshot[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PensionManualEntry {
|
export interface PensionManualEntry {
|
||||||
fund: string;
|
fund: string;
|
||||||
@@ -436,51 +290,19 @@ export interface MunicipalCharge {
|
|||||||
amount: number;
|
amount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WaterMeterReading {
|
export type WaterMeterReading = Schema<'WaterMeterReadingRead'>;
|
||||||
id: number;
|
|
||||||
meter_id: string;
|
|
||||||
period: string;
|
|
||||||
reading_previous: number;
|
|
||||||
reading_current: number;
|
|
||||||
consumption_m3: number;
|
|
||||||
agua_potable: number;
|
|
||||||
serv_ambientales: number;
|
|
||||||
alcant_sanitario: number;
|
|
||||||
iva: number;
|
|
||||||
is_historical: boolean;
|
|
||||||
receipt_id: number | null;
|
|
||||||
created_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MunicipalReceipt {
|
export type MunicipalReceipt = Omit<
|
||||||
id: number;
|
Schema<'MunicipalReceiptRead'>,
|
||||||
receipt_date: string;
|
'raw_charges'
|
||||||
due_date: string;
|
> & { raw_charges: MunicipalCharge[] };
|
||||||
period: string;
|
|
||||||
account: string;
|
|
||||||
finca: string;
|
|
||||||
holder_name: string;
|
|
||||||
holder_cedula: string;
|
|
||||||
holder_address: string;
|
|
||||||
subtotal: number;
|
|
||||||
interests: number;
|
|
||||||
iva: number;
|
|
||||||
total: number;
|
|
||||||
raw_charges: MunicipalCharge[];
|
|
||||||
source_filename: string;
|
|
||||||
created_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MunicipalReceiptDetail extends MunicipalReceipt {
|
export type MunicipalReceiptDetail = Omit<
|
||||||
water_readings: WaterMeterReading[];
|
Schema<'MunicipalReceiptDetailRead'>,
|
||||||
}
|
'raw_charges'
|
||||||
|
> & { raw_charges: MunicipalCharge[] };
|
||||||
|
|
||||||
export interface MunicipalReceiptUploadResult {
|
export type MunicipalReceiptUploadResult = Schema<'MunicipalReceiptUploadResult'>;
|
||||||
imported: number;
|
|
||||||
updated: number;
|
|
||||||
errors: string[];
|
|
||||||
receipt: MunicipalReceipt | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const uploadMunicipalReceipt = (file: File) => {
|
export const uploadMunicipalReceipt = (file: File) => {
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
@@ -502,20 +324,9 @@ export const getWaterConsumption = (months?: number) =>
|
|||||||
|
|
||||||
// --- Sync Status ---
|
// --- Sync Status ---
|
||||||
|
|
||||||
export interface SyncSource {
|
export type SyncSource = Schema<'SyncSourceStatus'>;
|
||||||
key: string;
|
|
||||||
label: string;
|
|
||||||
description: string;
|
|
||||||
last_received: string | null;
|
|
||||||
age_days: number | null;
|
|
||||||
warn_after_days: number;
|
|
||||||
status: 'ok' | 'warning' | 'never';
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SyncStatusResponse {
|
export type SyncStatusResponse = Schema<'SyncStatusResponse'>;
|
||||||
sources: SyncSource[];
|
|
||||||
warnings: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getSyncStatus = () => api.get<SyncStatusResponse>('/sync-status/');
|
export const getSyncStatus = () => api.get<SyncStatusResponse>('/sync-status/');
|
||||||
|
|
||||||
@@ -523,10 +334,6 @@ export const getSyncStatus = () => api.get<SyncStatusResponse>('/sync-status/');
|
|||||||
|
|
||||||
export type UserSettingsData = Record<string, unknown>;
|
export type UserSettingsData = Record<string, unknown>;
|
||||||
|
|
||||||
export interface UserSettingsRead {
|
export type UserSettingsRead = Schema<'UserSettingsRead'>;
|
||||||
key: string;
|
|
||||||
data: UserSettingsData;
|
|
||||||
updated_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getUserSettings = () => api.get<UserSettingsRead>('/settings/');
|
export const getUserSettings = () => api.get<UserSettingsRead>('/settings/');
|
||||||
|
|||||||
Reference in New Issue
Block a user