SPB Git

spb/findata

Public

FinData OS: phase 0–4 foundation (discovery, lakehouse, ingest, API, SDK, tests)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed (Nov 1, 2026) Browse files

135 changed files +17,015 −0

135 changed files
added .env.example +22 −0
@@ -0,0 +1,22 @@
1+# FinData OS — runtime configuration (copy to .env on the node; mode 600; never commit)
2+FINDATA_ENV=production
3+FINDATA_ROOT=/Users/simon-pierreboucher/apps/findata
4+FINDATA_LAKE=/Users/simon-pierreboucher/findata-lake
5+FINDATA_DATABASE_URL=postgresql://findata:CHANGE_ME@127.0.0.1:5432/findata
6+FINDATA_BIND_HOST=127.0.0.1
7+FINDATA_BIND_PORT=8600
8+FINDATA_PUBLIC_URL=https://findata.spboucher.ai
9+# 32+ random bytes, base64 — session cookie signing
10+FINDATA_SECRET_KEY=CHANGE_ME
11+# Vendor credentials (FirstRate Data customer id). Never logged, never sent to the browser.
12+FRD_USERID=CHANGE_ME
13+# SEC EDGAR fair-access User-Agent (name + contact email). Leave empty to keep the connector "pending configuration".
14+SEC_EDGAR_USER_AGENT=
15+# Optional AI assistant (phase 2) — server-side BYOK only
16+ANTHROPIC_API_KEY=
17+OPENAI_API_KEY=
18+# Lake budget (GB)
19+FINDATA_LAKE_SOFT_LIMIT_GB=250
20+FINDATA_LAKE_HARD_MIN_FREE_GB=60
21+# Backup target (rsync over SSH, LAN)
22+FINDATA_BACKUP_TARGET=M4M64a:~/backups/findata
added .gitignore +18 −0
@@ -0,0 +1,18 @@
1+.venv/
2+__pycache__/
3+*.pyc
4+.pytest_cache/
5+.ruff_cache/
6+.env
7+.env.*
8+!.env.example
9+*.secret
10+node_modules/
11+apps/web/.next/
12+apps/web/out/
13+apps/web/next-env.d.ts
14+data/
15+logs/
16+backups/
17+.DS_Store
18+/tests/_tmp/
added Makefile +10 −0
@@ -0,0 +1,10 @@
1+.PHONY: sync test lint web migrate api worker status audit
2+sync: ; uv sync
3+test: ; uv run pytest -q
4+lint: ; uv run ruff check .
5+audit: ; uv run pip-audit --strict || true
6+web: ; cd apps/web && pnpm install --frozen-lockfile && pnpm build
7+migrate: ; uv run findata migrate
8+api: ; uv run uvicorn findata_api.main:app --host 127.0.0.1 --port 8600 --reload
9+worker: ; uv run findata worker
10+status: ; uv run findata status
added README.md +14 −0
@@ -0,0 +1,14 @@
1+# FinData OS
2+
3+Private, research-grade financial data lakehouse for the MacLustr cluster — https://findata.spboucher.ai (owner only).
4+
5+- Vendor: **FirstRate Data** (market data bundles + US fundamentals API). License: private use, no redistribution.
6+- Node: M3U96a (1 TB NVMe), lake `~/findata-lake`, PostgreSQL 17 metadata, DuckDB reads, FastAPI `/api/v1`, Next.js console.
7+- Docs: `docs/DISCOVERY.md` (phase 0 evidence), `docs/ARCHITECTURE.md`, `docs/DATA_DICTIONARY.md`, `docs/OPERATIONS.md`, `docs/SECURITY.md`, `docs/STATUS.md`.
8+
9+```bash
10+uv sync && make test # 36 tests (unit + integration against local Postgres `findata_test`)
11+make web # build the console (apps/web/out)
12+uv run findata --help # operator CLI
13+```
14+Python SDK: `packages/python-sdk` — `from findata_sdk import FinData`.
added apps/web/.gitignore +6 −0
@@ -0,0 +1,6 @@
1+node_modules/
2+.next/
3+out/
4+next-env.d.ts
5+*.tsbuildinfo
6+.DS_Store
added apps/web/.npmrc +1 −0
@@ -0,0 +1 @@
1+node-linker=hoisted
added apps/web/next.config.ts +23 −0
@@ -0,0 +1,23 @@
1+import type { NextConfig } from "next";
2+
3+const isDev = process.env.NODE_ENV === "development";
4+
5+const nextConfig: NextConfig = {
6+ // Static export: the Python API (FastAPI StaticFiles, html=True) serves apps/web/out
7+ // with directory index.html fallback, so every route must end with a slash.
8+ output: "export",
9+ trailingSlash: true,
10+ images: { unoptimized: true },
11+ reactStrictMode: true,
12+ poweredByHeader: false,
13+ // Dev only: proxy the API to the local FastAPI instance. Ignored by `next build` (static export).
14+ ...(isDev
15+ ? {
16+ async rewrites() {
17+ return [{ source: "/api/:path*", destination: "http://127.0.0.1:8600/api/:path*" }];
18+ },
19+ }
20+ : {}),
21+};
22+
23+export default nextConfig;
added apps/web/package.json +31 −0
@@ -0,0 +1,31 @@
1+{
2+ "name": "findata-web",
3+ "version": "1.0.0",
4+ "private": true,
5+ "description": "FinData OS — private web console (static export served by the Python API)",
6+ "scripts": {
7+ "dev": "next dev -p 3000",
8+ "build": "next build",
9+ "typecheck": "tsc --noEmit",
10+ "lint": "next lint"
11+ },
12+ "dependencies": {
13+ "clsx": "^2.1.1",
14+ "lucide-react": "^1.66.0",
15+ "next": "^15.5.0",
16+ "react": "^19.0.0",
17+ "react-dom": "^19.0.0",
18+ "recharts": "^3.10.1"
19+ },
20+ "devDependencies": {
21+ "@tailwindcss/postcss": "^4.1.0",
22+ "@types/node": "^22.0.0",
23+ "@types/react": "^19.0.0",
24+ "@types/react-dom": "^19.0.0",
25+ "tailwindcss": "^4.1.0",
26+ "typescript": "^5.7.0"
27+ },
28+ "engines": {
29+ "node": ">=20"
30+ }
31+}
added apps/web/pnpm-lock.yaml +1338 −0
@@ -0,0 +1,1338 @@
1+lockfileVersion: '9.0'
2+
3+settings:
4+ autoInstallPeers: true
5+ excludeLinksFromLockfile: false
6+
7+importers:
8+
9+ .:
10+ dependencies:
11+ clsx:
12+ specifier: ^2.1.1
13+ version: 2.1.1
14+ lucide-react:
15+ specifier: ^1.66.0
16+ version: 1.66.0(@types/react@19.3.0)(react@19.3.1)
17+ next:
18+ specifier: ^15.5.0
19+ version: 15.5.28(@types/node@22.20.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)
20+ react:
21+ specifier: ^19.0.0
22+ version: 19.3.1
23+ react-dom:
24+ specifier: ^19.0.0
25+ version: 19.3.1(react@19.3.1)
26+ recharts:
27+ specifier: ^3.10.1
28+ version: 3.10.1(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react-is@18.3.1)(react@19.3.1)(redux@5.0.1)
29+ devDependencies:
30+ '@tailwindcss/postcss':
31+ specifier: ^4.1.0
32+ version: 4.3.3
33+ '@types/node':
34+ specifier: ^22.0.0
35+ version: 22.20.5
36+ '@types/react':
37+ specifier: ^19.0.0
38+ version: 19.3.0
39+ '@types/react-dom':
40+ specifier: ^19.0.0
41+ version: 19.3.0(@types/react@19.3.0)
42+ tailwindcss:
43+ specifier: ^4.1.0
44+ version: 4.3.3
45+ typescript:
46+ specifier: ^5.7.0
47+ version: 5.9.3
48+
49+packages:
50+
51+ '@alloc/quick-lru@5.3.0':
52+ resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==}
53+ engines: {node: '>=10'}
54+
55+ '@emnapi/runtime@1.11.3':
56+ resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==}
57+
58+ '@img/colour@1.1.0':
59+ resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
60+ engines: {node: '>=18'}
61+
62+ '@img/sharp-darwin-arm64@0.35.5':
63+ resolution: {integrity: sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==}
64+ engines: {node: '>=20.9.0'}
65+ cpu: [arm64]
66+ os: [darwin]
67+
68+ '@img/sharp-darwin-x64@0.35.5':
69+ resolution: {integrity: sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==}
70+ engines: {node: '>=20.9.0'}
71+ cpu: [x64]
72+ os: [darwin]
73+
74+ '@img/sharp-freebsd-wasm32@0.35.5':
75+ resolution: {integrity: sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==}
76+ engines: {node: '>=20.9.0'}
77+ os: [freebsd]
78+
79+ '@img/sharp-libvips-darwin-arm64@1.3.4':
80+ resolution: {integrity: sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==}
81+ cpu: [arm64]
82+ os: [darwin]
83+
84+ '@img/sharp-libvips-darwin-x64@1.3.4':
85+ resolution: {integrity: sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==}
86+ cpu: [x64]
87+ os: [darwin]
88+
89+ '@img/sharp-libvips-linux-arm64@1.3.4':
90+ resolution: {integrity: sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==}
91+ cpu: [arm64]
92+ os: [linux]
93+ libc: [glibc]
94+
95+ '@img/sharp-libvips-linux-arm@1.3.4':
96+ resolution: {integrity: sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==}
97+ cpu: [arm]
98+ os: [linux]
99+ libc: [glibc]
100+
101+ '@img/sharp-libvips-linux-ppc64@1.3.4':
102+ resolution: {integrity: sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==}
103+ cpu: [ppc64]
104+ os: [linux]
105+ libc: [glibc]
106+
107+ '@img/sharp-libvips-linux-riscv64@1.3.4':
108+ resolution: {integrity: sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==}
109+ cpu: [riscv64]
110+ os: [linux]
111+ libc: [glibc]
112+
113+ '@img/sharp-libvips-linux-s390x@1.3.4':
114+ resolution: {integrity: sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==}
115+ cpu: [s390x]
116+ os: [linux]
117+ libc: [glibc]
118+
119+ '@img/sharp-libvips-linux-x64@1.3.4':
120+ resolution: {integrity: sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==}
121+ cpu: [x64]
122+ os: [linux]
123+ libc: [glibc]
124+
125+ '@img/sharp-libvips-linuxmusl-arm64@1.3.4':
126+ resolution: {integrity: sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==}
127+ cpu: [arm64]
128+ os: [linux]
129+ libc: [musl]
130+
131+ '@img/sharp-libvips-linuxmusl-x64@1.3.4':
132+ resolution: {integrity: sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==}
133+ cpu: [x64]
134+ os: [linux]
135+ libc: [musl]
136+
137+ '@img/sharp-linux-arm64@0.35.5':
138+ resolution: {integrity: sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==}
139+ engines: {node: '>=20.9.0'}
140+ cpu: [arm64]
141+ os: [linux]
142+ libc: [glibc]
143+
144+ '@img/sharp-linux-arm@0.35.5':
145+ resolution: {integrity: sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==}
146+ engines: {node: '>=20.9.0'}
147+ cpu: [arm]
148+ os: [linux]
149+ libc: [glibc]
150+
151+ '@img/sharp-linux-ppc64@0.35.5':
152+ resolution: {integrity: sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==}
153+ engines: {node: '>=20.9.0'}
154+ cpu: [ppc64]
155+ os: [linux]
156+ libc: [glibc]
157+
158+ '@img/sharp-linux-riscv64@0.35.5':
159+ resolution: {integrity: sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==}
160+ engines: {node: '>=20.9.0'}
161+ cpu: [riscv64]
162+ os: [linux]
163+ libc: [glibc]
164+
165+ '@img/sharp-linux-s390x@0.35.5':
166+ resolution: {integrity: sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==}
167+ engines: {node: '>=20.9.0'}
168+ cpu: [s390x]
169+ os: [linux]
170+ libc: [glibc]
171+
172+ '@img/sharp-linux-x64@0.35.5':
173+ resolution: {integrity: sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==}
174+ engines: {node: '>=20.9.0'}
175+ cpu: [x64]
176+ os: [linux]
177+ libc: [glibc]
178+
179+ '@img/sharp-linuxmusl-arm64@0.35.5':
180+ resolution: {integrity: sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==}
181+ engines: {node: '>=20.9.0'}
182+ cpu: [arm64]
183+ os: [linux]
184+ libc: [musl]
185+
186+ '@img/sharp-linuxmusl-x64@0.35.5':
187+ resolution: {integrity: sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==}
188+ engines: {node: '>=20.9.0'}
189+ cpu: [x64]
190+ os: [linux]
191+ libc: [musl]
192+
193+ '@img/sharp-wasm32@0.35.5':
194+ resolution: {integrity: sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==}
195+ engines: {node: '>=20.9.0'}
196+
197+ '@img/sharp-webcontainers-wasm32@0.35.5':
198+ resolution: {integrity: sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==}
199+ engines: {node: '>=20.9.0'}
200+ cpu: [wasm32]
201+
202+ '@img/sharp-win32-arm64@0.35.5':
203+ resolution: {integrity: sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==}
204+ engines: {node: '>=20.9.0'}
205+ cpu: [arm64]
206+ os: [win32]
207+
208+ '@img/sharp-win32-ia32@0.35.5':
209+ resolution: {integrity: sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==}
210+ engines: {node: ^20.9.0}
211+ cpu: [ia32]
212+ os: [win32]
213+
214+ '@img/sharp-win32-x64@0.35.5':
215+ resolution: {integrity: sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==}
216+ engines: {node: '>=20.9.0'}
217+ cpu: [x64]
218+ os: [win32]
219+
220+ '@jridgewell/gen-mapping@0.3.13':
221+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
222+
223+ '@jridgewell/remapping@2.3.5':
224+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
225+
226+ '@jridgewell/resolve-uri@3.1.2':
227+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
228+ engines: {node: '>=6.0.0'}
229+
230+ '@jridgewell/sourcemap-codec@1.6.0':
231+ resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==}
232+
233+ '@jridgewell/trace-mapping@0.3.31':
234+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
235+
236+ '@next/env@15.5.28':
237+ resolution: {integrity: sha512-xxW5EBI8fMPuVTPBW7LL980IRbuDXlbkUAwp9DDhtb4Lnich3nJ13uYpvrX4VE74hWPf6AvHHAMmGCidcHjbfg==}
238+
239+ '@next/swc-darwin-arm64@15.5.28':
240+ resolution: {integrity: sha512-dPoQYXcfSIqx5o+TOXVXO7kONK5qbtNRDeiTfII0bT3puGIT6VF5e0QwmxNZfEZ5Zety5f3m9P/p4xqwfiLlPg==}
241+ engines: {node: '>= 10'}
242+ cpu: [arm64]
243+ os: [darwin]
244+
245+ '@next/swc-darwin-x64@15.5.28':
246+ resolution: {integrity: sha512-RgCJ7buBivTH+6sddqaVm+/v8kwMHlFkobvdt3DfETutws5HrxnToMIWSN9X3MZ3aAi7BbKrGZZWUDQLEycXqw==}
247+ engines: {node: '>= 10'}
248+ cpu: [x64]
249+ os: [darwin]
250+
251+ '@next/swc-linux-arm64-gnu@15.5.28':
252+ resolution: {integrity: sha512-OHXQe13olE59aKe++zHavGcJPh5SLHXi6Anret3BBeq1+qhSuOJDNAli/EDDfxs6UTqA4Qddo4uyYry2slyjiQ==}
253+ engines: {node: '>= 10'}
254+ cpu: [arm64]
255+ os: [linux]
256+ libc: [glibc]
257+
258+ '@next/swc-linux-arm64-musl@15.5.28':
259+ resolution: {integrity: sha512-nTB7bB6vfn4ezCJNYP43ukt2o8L3+WxKF/sTcTxepdXsJh3SM9RhlU7wrZYbH7L4HO5M87dqDTwm8587vAkCiw==}
260+ engines: {node: '>= 10'}
261+ cpu: [arm64]
262+ os: [linux]
263+ libc: [musl]
264+
265+ '@next/swc-linux-x64-gnu@15.5.28':
266+ resolution: {integrity: sha512-WXCfVI32rW3xCusoUX1RpZKtyChWU2Zwe27JUDmM3KrXwcDNc9vV4zEq0GKFAURnuQ/Ouo/XqPvB0yh445XZCg==}
267+ engines: {node: '>= 10'}
268+ cpu: [x64]
269+ os: [linux]
270+ libc: [glibc]
271+
272+ '@next/swc-linux-x64-musl@15.5.28':
273+ resolution: {integrity: sha512-Miq+NDb/HWsXuxseYxMM6fuEOQXgTziarkKIRpVKCn8W69cEfhQaQr+90pO+u4q2CbJR2wzXmUuCFyZaJs/Nng==}
274+ engines: {node: '>= 10'}
275+ cpu: [x64]
276+ os: [linux]
277+ libc: [musl]
278+
279+ '@next/swc-win32-arm64-msvc@15.5.28':
280+ resolution: {integrity: sha512-5LR79lemgDlgxvG7MQJ+zHCkVcrUoQuO7CiIvq3I58vNW4goSOE2b+19Z6FujRWMouvni4gvudYFuFuNxolGWA==}
281+ engines: {node: '>= 10'}
282+ cpu: [arm64]
283+ os: [win32]
284+
285+ '@next/swc-win32-x64-msvc@15.5.28':
286+ resolution: {integrity: sha512-GNipvXUYROSTf4PXEyH95FrWImIB5zdaK6uEOg0RP1/X2drnvoMwiBkJ0VWdzX7w3iiBm3y5g2TxkKDGVTOQcg==}
287+ engines: {node: '>= 10'}
288+ cpu: [x64]
289+ os: [win32]
290+
291+ '@reduxjs/toolkit@2.13.0':
292+ resolution: {integrity: sha512-f6jwVRfwW30+tnllz4YcsHHpPYYOE7abcHkyUCovD+P7DyhdAI5prz2Fh/8TLhakjpN+7aIEion1s5L/tvlYlA==}
293+ peerDependencies:
294+ react: ^16.9.0 || ^17.0.0 || ^18 || ^19
295+ react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
296+ peerDependenciesMeta:
297+ react:
298+ optional: true
299+ react-redux:
300+ optional: true
301+
302+ '@standard-schema/spec@1.1.0':
303+ resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
304+
305+ '@standard-schema/utils@0.3.0':
306+ resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
307+
308+ '@swc/helpers@0.5.15':
309+ resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
310+
311+ '@tailwindcss/node@4.3.3':
312+ resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==}
313+
314+ '@tailwindcss/oxide-android-arm64@4.3.3':
315+ resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==}
316+ engines: {node: '>= 20'}
317+ cpu: [arm64]
318+ os: [android]
319+
320+ '@tailwindcss/oxide-darwin-arm64@4.3.3':
321+ resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==}
322+ engines: {node: '>= 20'}
323+ cpu: [arm64]
324+ os: [darwin]
325+
326+ '@tailwindcss/oxide-darwin-x64@4.3.3':
327+ resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==}
328+ engines: {node: '>= 20'}
329+ cpu: [x64]
330+ os: [darwin]
331+
332+ '@tailwindcss/oxide-freebsd-x64@4.3.3':
333+ resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==}
334+ engines: {node: '>= 20'}
335+ cpu: [x64]
336+ os: [freebsd]
337+
338+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3':
339+ resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==}
340+ engines: {node: '>= 20'}
341+ cpu: [arm]
342+ os: [linux]
343+
344+ '@tailwindcss/oxide-linux-arm64-gnu@4.3.3':
345+ resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==}
346+ engines: {node: '>= 20'}
347+ cpu: [arm64]
348+ os: [linux]
349+ libc: [glibc]
350+
351+ '@tailwindcss/oxide-linux-arm64-musl@4.3.3':
352+ resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==}
353+ engines: {node: '>= 20'}
354+ cpu: [arm64]
355+ os: [linux]
356+ libc: [musl]
357+
358+ '@tailwindcss/oxide-linux-x64-gnu@4.3.3':
359+ resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==}
360+ engines: {node: '>= 20'}
361+ cpu: [x64]
362+ os: [linux]
363+ libc: [glibc]
364+
365+ '@tailwindcss/oxide-linux-x64-musl@4.3.3':
366+ resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==}
367+ engines: {node: '>= 20'}
368+ cpu: [x64]
369+ os: [linux]
370+ libc: [musl]
371+
372+ '@tailwindcss/oxide-wasm32-wasi@4.3.3':
373+ resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==}
374+ engines: {node: '>=14.0.0'}
375+ cpu: [wasm32]
376+ bundledDependencies:
377+ - '@napi-rs/wasm-runtime'
378+ - '@emnapi/core'
379+ - '@emnapi/runtime'
380+ - '@tybys/wasm-util'
381+ - '@emnapi/wasi-threads'
382+ - tslib
383+
384+ '@tailwindcss/oxide-win32-arm64-msvc@4.3.3':
385+ resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==}
386+ engines: {node: '>= 20'}
387+ cpu: [arm64]
388+ os: [win32]
389+
390+ '@tailwindcss/oxide-win32-x64-msvc@4.3.3':
391+ resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==}
392+ engines: {node: '>= 20'}
393+ cpu: [x64]
394+ os: [win32]
395+
396+ '@tailwindcss/oxide@4.3.3':
397+ resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==}
398+ engines: {node: '>= 20'}
399+
400+ '@tailwindcss/postcss@4.3.3':
401+ resolution: {integrity: sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==}
402+
403+ '@types/d3-array@3.2.2':
404+ resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
405+
406+ '@types/d3-color@3.1.3':
407+ resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
408+
409+ '@types/d3-ease@3.0.2':
410+ resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==}
411+
412+ '@types/d3-interpolate@3.0.4':
413+ resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
414+
415+ '@types/d3-path@3.1.1':
416+ resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==}
417+
418+ '@types/d3-scale@4.0.9':
419+ resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==}
420+
421+ '@types/d3-shape@3.2.0':
422+ resolution: {integrity: sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw==}
423+
424+ '@types/d3-time@3.0.4':
425+ resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==}
426+
427+ '@types/d3-timer@3.0.2':
428+ resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
429+
430+ '@types/node@22.20.5':
431+ resolution: {integrity: sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==}
432+
433+ '@types/react-dom@19.3.0':
434+ resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==}
435+ peerDependencies:
436+ '@types/react': ^19.3.0
437+
438+ '@types/react@19.3.0':
439+ resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==}
440+
441+ '@types/use-sync-external-store@0.0.6':
442+ resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==}
443+
444+ caniuse-lite@1.0.30001820:
445+ resolution: {integrity: sha512-gfWD6MxqVCqAOwmODfZf7DchWvlrA+SRdNX7ceLfg3xRqe5ssjjpF7EgslC/0tiLiNTajdaNN/q8c/5u/7Gz8w==}
446+
447+ client-only@0.0.1:
448+ resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
449+
450+ clsx@2.1.1:
451+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
452+ engines: {node: '>=6'}
453+
454+ csstype@3.2.3:
455+ resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
456+
457+ d3-array@3.2.4:
458+ resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
459+ engines: {node: '>=12'}
460+
461+ d3-color@3.1.0:
462+ resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
463+ engines: {node: '>=12'}
464+
465+ d3-ease@3.0.1:
466+ resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
467+ engines: {node: '>=12'}
468+
469+ d3-format@3.1.2:
470+ resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==}
471+ engines: {node: '>=12'}
472+
473+ d3-interpolate@3.0.1:
474+ resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
475+ engines: {node: '>=12'}
476+
477+ d3-path@3.1.0:
478+ resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
479+ engines: {node: '>=12'}
480+
481+ d3-scale@4.0.2:
482+ resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
483+ engines: {node: '>=12'}
484+
485+ d3-shape@3.2.0:
486+ resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
487+ engines: {node: '>=12'}
488+
489+ d3-time-format@4.1.0:
490+ resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
491+ engines: {node: '>=12'}
492+
493+ d3-time@3.1.0:
494+ resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
495+ engines: {node: '>=12'}
496+
497+ d3-timer@3.0.1:
498+ resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
499+ engines: {node: '>=12'}
500+
501+ decimal.js-light@2.5.1:
502+ resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
503+
504+ detect-libc@2.1.2:
505+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
506+ engines: {node: '>=8'}
507+
508+ enhanced-resolve@5.26.0:
509+ resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==}
510+ engines: {node: '>=10.13.0'}
511+
512+ es-toolkit@1.53.1:
513+ resolution: {integrity: sha512-VhMc6IXmexu8iYFfL2aaAww6IvJTdHlqBLruLoEUs33YD4IcP5DdZcLOybMsMmmLsiy1c8PsiLsrM0DdIuuRUA==}
514+
515+ eventemitter3@5.0.4:
516+ resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
517+
518+ graceful-fs@4.2.11:
519+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
520+
521+ immer@11.2.9:
522+ resolution: {integrity: sha512-IQ4UEtXjZjyefyWjtLEDXUSrF6T2hwjKPi6BIJl3bY/2XXW24d6cNGdXJSBOA/+KNnuiXkZY6DR0C3efolhitA==}
523+
524+ internmap@2.0.3:
525+ resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
526+ engines: {node: '>=12'}
527+
528+ jiti@2.7.0:
529+ resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
530+ hasBin: true
531+
532+ lightningcss-android-arm64@1.32.0:
533+ resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
534+ engines: {node: '>= 12.0.0'}
535+ cpu: [arm64]
536+ os: [android]
537+
538+ lightningcss-darwin-arm64@1.32.0:
539+ resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
540+ engines: {node: '>= 12.0.0'}
541+ cpu: [arm64]
542+ os: [darwin]
543+
544+ lightningcss-darwin-x64@1.32.0:
545+ resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==}
546+ engines: {node: '>= 12.0.0'}
547+ cpu: [x64]
548+ os: [darwin]
549+
550+ lightningcss-freebsd-x64@1.32.0:
551+ resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==}
552+ engines: {node: '>= 12.0.0'}
553+ cpu: [x64]
554+ os: [freebsd]
555+
556+ lightningcss-linux-arm-gnueabihf@1.32.0:
557+ resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==}
558+ engines: {node: '>= 12.0.0'}
559+ cpu: [arm]
560+ os: [linux]
561+
562+ lightningcss-linux-arm64-gnu@1.32.0:
563+ resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
564+ engines: {node: '>= 12.0.0'}
565+ cpu: [arm64]
566+ os: [linux]
567+ libc: [glibc]
568+
569+ lightningcss-linux-arm64-musl@1.32.0:
570+ resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
571+ engines: {node: '>= 12.0.0'}
572+ cpu: [arm64]
573+ os: [linux]
574+ libc: [musl]
575+
576+ lightningcss-linux-x64-gnu@1.32.0:
577+ resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
578+ engines: {node: '>= 12.0.0'}
579+ cpu: [x64]
580+ os: [linux]
581+ libc: [glibc]
582+
583+ lightningcss-linux-x64-musl@1.32.0:
584+ resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
585+ engines: {node: '>= 12.0.0'}
586+ cpu: [x64]
587+ os: [linux]
588+ libc: [musl]
589+
590+ lightningcss-win32-arm64-msvc@1.32.0:
591+ resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
592+ engines: {node: '>= 12.0.0'}
593+ cpu: [arm64]
594+ os: [win32]
595+
596+ lightningcss-win32-x64-msvc@1.32.0:
597+ resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
598+ engines: {node: '>= 12.0.0'}
599+ cpu: [x64]
600+ os: [win32]
601+
602+ lightningcss@1.32.0:
603+ resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
604+ engines: {node: '>= 12.0.0'}
605+
606+ lucide-react@1.66.0:
607+ resolution: {integrity: sha512-8zjbi/Us+ETXqfBwmXF/FHrWGIqOdE6zT1yUdRJLQVoptomSkB0zdFWVIM667t9K8djWDaXdkBkqi2qVTuDNiw==}
608+ peerDependencies:
609+ '@types/react': '*'
610+ react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
611+ peerDependenciesMeta:
612+ '@types/react':
613+ optional: true
614+
615+ magic-string@0.30.21:
616+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
617+
618+ nanoid@3.3.20:
619+ resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==}
620+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
621+ hasBin: true
622+
623+ next@15.5.28:
624+ resolution: {integrity: sha512-JjhLBBY1PNnuwPtcZ7t8yxVeJVYvD2Jyp633J+gRCNbzSt7N0E+xqCf6uQiff3+3qmUkwcF/ksfSsK1xsZ76Tw==}
625+ engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
626+ hasBin: true
627+ peerDependencies:
628+ '@opentelemetry/api': ^1.1.0
629+ '@playwright/test': ^1.51.1
630+ babel-plugin-react-compiler: '*'
631+ react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
632+ react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
633+ sass: ^1.3.0
634+ peerDependenciesMeta:
635+ '@opentelemetry/api':
636+ optional: true
637+ '@playwright/test':
638+ optional: true
639+ babel-plugin-react-compiler:
640+ optional: true
641+ sass:
642+ optional: true
643+
644+ picocolors@1.1.1:
645+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
646+
647+ postcss@8.4.31:
648+ resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
649+ engines: {node: ^10 || ^12 || >=14}
650+
651+ postcss@8.5.32:
652+ resolution: {integrity: sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==}
653+ engines: {node: ^10 || ^12 || >=14}
654+
655+ react-dom@19.3.1:
656+ resolution: {integrity: sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==}
657+ peerDependencies:
658+ react: ^19.3.1
659+
660+ react-is@18.3.1:
661+ resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
662+
663+ react-redux@9.3.1:
664+ resolution: {integrity: sha512-vxMLT0lalUjbZPkoTepWyKAZbjIIFssNx/CEL9lTfwQBU6XpkGSmCNdcCIrkOBUgB68uftZMnbXVb6DwGnhRKQ==}
665+ peerDependencies:
666+ '@types/react': ^18.2.25 || ^19
667+ react: ^18.0 || ^19
668+ redux: ^5.0.0
669+ peerDependenciesMeta:
670+ '@types/react':
671+ optional: true
672+ redux:
673+ optional: true
674+
675+ react@19.3.1:
676+ resolution: {integrity: sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==}
677+ engines: {node: '>=0.10.0'}
678+
679+ recharts@3.10.1:
680+ resolution: {integrity: sha512-QXFrvt6IVcw7eeZCoyXTwkIJAX3Dv1nyVhMicXJ47GsGDDpcN8z6o644DibE9XjpBTThtsomLKnTV6lc+cVFUA==}
681+ engines: {node: '>=18'}
682+ peerDependencies:
683+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
684+ react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
685+ react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
686+
687+ redux-thunk@3.1.0:
688+ resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==}
689+ peerDependencies:
690+ redux: ^5.0.0
691+
692+ redux@5.0.1:
693+ resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==}
694+
695+ reselect@5.2.0:
696+ resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==}
697+
698+ scheduler@0.28.0:
699+ resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==}
700+
701+ semver@7.8.5:
702+ resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==}
703+ engines: {node: '>=10'}
704+ hasBin: true
705+
706+ sharp@0.35.5:
707+ resolution: {integrity: sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==}
708+ engines: {node: '>=20.9.0'}
709+ peerDependencies:
710+ '@types/node': '*'
711+ peerDependenciesMeta:
712+ '@types/node':
713+ optional: true
714+
715+ source-map-js@1.2.2:
716+ resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==}
717+ engines: {node: '>=0.10.0'}
718+
719+ styled-jsx@5.1.6:
720+ resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
721+ engines: {node: '>= 12.0.0'}
722+ peerDependencies:
723+ '@babel/core': '*'
724+ babel-plugin-macros: '*'
725+ react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0'
726+ peerDependenciesMeta:
727+ '@babel/core':
728+ optional: true
729+ babel-plugin-macros:
730+ optional: true
731+
732+ tailwindcss@4.3.3:
733+ resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==}
734+
735+ tapable@2.3.3:
736+ resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
737+ engines: {node: '>=6'}
738+
739+ tiny-invariant@1.3.3:
740+ resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
741+
742+ tslib@2.9.1:
743+ resolution: {integrity: sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==}
744+
745+ typescript@5.9.3:
746+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
747+ engines: {node: '>=14.17'}
748+ hasBin: true
749+
750+ undici-types@6.21.0:
751+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
752+
753+ use-sync-external-store@1.7.0:
754+ resolution: {integrity: sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==}
755+ peerDependencies:
756+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
757+
758+ victory-vendor@37.4.1:
759+ resolution: {integrity: sha512-geV4p2GVfVM9lgm9ZRS3pvsbAPS+BUGhM9W9nPzPHTKi+/+KjNrFXdgP6KkG+XspNZuvcXmchcrtklfuQ4gniw==}
760+
761+snapshots:
762+
763+ '@alloc/quick-lru@5.3.0': {}
764+
765+ '@emnapi/runtime@1.11.3':
766+ dependencies:
767+ tslib: 2.9.1
768+ optional: true
769+
770+ '@img/colour@1.1.0':
771+ optional: true
772+
773+ '@img/sharp-darwin-arm64@0.35.5':
774+ optionalDependencies:
775+ '@img/sharp-libvips-darwin-arm64': 1.3.4
776+ optional: true
777+
778+ '@img/sharp-darwin-x64@0.35.5':
779+ optionalDependencies:
780+ '@img/sharp-libvips-darwin-x64': 1.3.4
781+ optional: true
782+
783+ '@img/sharp-freebsd-wasm32@0.35.5':
784+ dependencies:
785+ '@img/sharp-wasm32': 0.35.5
786+ optional: true
787+
788+ '@img/sharp-libvips-darwin-arm64@1.3.4':
789+ optional: true
790+
791+ '@img/sharp-libvips-darwin-x64@1.3.4':
792+ optional: true
793+
794+ '@img/sharp-libvips-linux-arm64@1.3.4':
795+ optional: true
796+
797+ '@img/sharp-libvips-linux-arm@1.3.4':
798+ optional: true
799+
800+ '@img/sharp-libvips-linux-ppc64@1.3.4':
801+ optional: true
802+
803+ '@img/sharp-libvips-linux-riscv64@1.3.4':
804+ optional: true
805+
806+ '@img/sharp-libvips-linux-s390x@1.3.4':
807+ optional: true
808+
809+ '@img/sharp-libvips-linux-x64@1.3.4':
810+ optional: true
811+
812+ '@img/sharp-libvips-linuxmusl-arm64@1.3.4':
813+ optional: true
814+
815+ '@img/sharp-libvips-linuxmusl-x64@1.3.4':
816+ optional: true
817+
818+ '@img/sharp-linux-arm64@0.35.5':
819+ optionalDependencies:
820+ '@img/sharp-libvips-linux-arm64': 1.3.4
821+ optional: true
822+
823+ '@img/sharp-linux-arm@0.35.5':
824+ optionalDependencies:
825+ '@img/sharp-libvips-linux-arm': 1.3.4
826+ optional: true
827+
828+ '@img/sharp-linux-ppc64@0.35.5':
829+ optionalDependencies:
830+ '@img/sharp-libvips-linux-ppc64': 1.3.4
831+ optional: true
832+
833+ '@img/sharp-linux-riscv64@0.35.5':
834+ optionalDependencies:
835+ '@img/sharp-libvips-linux-riscv64': 1.3.4
836+ optional: true
837+
838+ '@img/sharp-linux-s390x@0.35.5':
839+ optionalDependencies:
840+ '@img/sharp-libvips-linux-s390x': 1.3.4
841+ optional: true
842+
843+ '@img/sharp-linux-x64@0.35.5':
844+ optionalDependencies:
845+ '@img/sharp-libvips-linux-x64': 1.3.4
846+ optional: true
847+
848+ '@img/sharp-linuxmusl-arm64@0.35.5':
849+ optionalDependencies:
850+ '@img/sharp-libvips-linuxmusl-arm64': 1.3.4
851+ optional: true
852+
853+ '@img/sharp-linuxmusl-x64@0.35.5':
854+ optionalDependencies:
855+ '@img/sharp-libvips-linuxmusl-x64': 1.3.4
856+ optional: true
857+
858+ '@img/sharp-wasm32@0.35.5':
859+ dependencies:
860+ '@emnapi/runtime': 1.11.3
861+ optional: true
862+
863+ '@img/sharp-webcontainers-wasm32@0.35.5':
864+ dependencies:
865+ '@img/sharp-wasm32': 0.35.5
866+ optional: true
867+
868+ '@img/sharp-win32-arm64@0.35.5':
869+ optional: true
870+
871+ '@img/sharp-win32-ia32@0.35.5':
872+ optional: true
873+
874+ '@img/sharp-win32-x64@0.35.5':
875+ optional: true
876+
877+ '@jridgewell/gen-mapping@0.3.13':
878+ dependencies:
879+ '@jridgewell/sourcemap-codec': 1.6.0
880+ '@jridgewell/trace-mapping': 0.3.31
881+
882+ '@jridgewell/remapping@2.3.5':
883+ dependencies:
884+ '@jridgewell/gen-mapping': 0.3.13
885+ '@jridgewell/trace-mapping': 0.3.31
886+
887+ '@jridgewell/resolve-uri@3.1.2': {}
888+
889+ '@jridgewell/sourcemap-codec@1.6.0': {}
890+
891+ '@jridgewell/trace-mapping@0.3.31':
892+ dependencies:
893+ '@jridgewell/resolve-uri': 3.1.2
894+ '@jridgewell/sourcemap-codec': 1.6.0
895+
896+ '@next/env@15.5.28': {}
897+
898+ '@next/swc-darwin-arm64@15.5.28':
899+ optional: true
900+
901+ '@next/swc-darwin-x64@15.5.28':
902+ optional: true
903+
904+ '@next/swc-linux-arm64-gnu@15.5.28':
905+ optional: true
906+
907+ '@next/swc-linux-arm64-musl@15.5.28':
908+ optional: true
909+
910+ '@next/swc-linux-x64-gnu@15.5.28':
911+ optional: true
912+
913+ '@next/swc-linux-x64-musl@15.5.28':
914+ optional: true
915+
916+ '@next/swc-win32-arm64-msvc@15.5.28':
917+ optional: true
918+
919+ '@next/swc-win32-x64-msvc@15.5.28':
920+ optional: true
921+
922+ '@reduxjs/toolkit@2.13.0(react-redux@9.3.1(@types/react@19.3.0)(react@19.3.1)(redux@5.0.1))(react@19.3.1)':
923+ dependencies:
924+ '@standard-schema/spec': 1.1.0
925+ '@standard-schema/utils': 0.3.0
926+ immer: 11.2.9
927+ redux: 5.0.1
928+ redux-thunk: 3.1.0(redux@5.0.1)
929+ reselect: 5.2.0
930+ optionalDependencies:
931+ react: 19.3.1
932+ react-redux: 9.3.1(@types/react@19.3.0)(react@19.3.1)(redux@5.0.1)
933+
934+ '@standard-schema/spec@1.1.0': {}
935+
936+ '@standard-schema/utils@0.3.0': {}
937+
938+ '@swc/helpers@0.5.15':
939+ dependencies:
940+ tslib: 2.9.1
941+
942+ '@tailwindcss/node@4.3.3':
943+ dependencies:
944+ '@jridgewell/remapping': 2.3.5
945+ enhanced-resolve: 5.26.0
946+ jiti: 2.7.0
947+ lightningcss: 1.32.0
948+ magic-string: 0.30.21
949+ source-map-js: 1.2.2
950+ tailwindcss: 4.3.3
951+
952+ '@tailwindcss/oxide-android-arm64@4.3.3':
953+ optional: true
954+
955+ '@tailwindcss/oxide-darwin-arm64@4.3.3':
956+ optional: true
957+
958+ '@tailwindcss/oxide-darwin-x64@4.3.3':
959+ optional: true
960+
961+ '@tailwindcss/oxide-freebsd-x64@4.3.3':
962+ optional: true
963+
964+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3':
965+ optional: true
966+
967+ '@tailwindcss/oxide-linux-arm64-gnu@4.3.3':
968+ optional: true
969+
970+ '@tailwindcss/oxide-linux-arm64-musl@4.3.3':
971+ optional: true
972+
973+ '@tailwindcss/oxide-linux-x64-gnu@4.3.3':
974+ optional: true
975+
976+ '@tailwindcss/oxide-linux-x64-musl@4.3.3':
977+ optional: true
978+
979+ '@tailwindcss/oxide-wasm32-wasi@4.3.3':
980+ optional: true
981+
982+ '@tailwindcss/oxide-win32-arm64-msvc@4.3.3':
983+ optional: true
984+
985+ '@tailwindcss/oxide-win32-x64-msvc@4.3.3':
986+ optional: true
987+
988+ '@tailwindcss/oxide@4.3.3':
989+ optionalDependencies:
990+ '@tailwindcss/oxide-android-arm64': 4.3.3
991+ '@tailwindcss/oxide-darwin-arm64': 4.3.3
992+ '@tailwindcss/oxide-darwin-x64': 4.3.3
993+ '@tailwindcss/oxide-freebsd-x64': 4.3.3
994+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3
995+ '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3
996+ '@tailwindcss/oxide-linux-arm64-musl': 4.3.3
997+ '@tailwindcss/oxide-linux-x64-gnu': 4.3.3
998+ '@tailwindcss/oxide-linux-x64-musl': 4.3.3
999+ '@tailwindcss/oxide-wasm32-wasi': 4.3.3
1000+ '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3
1001+ '@tailwindcss/oxide-win32-x64-msvc': 4.3.3
1002+
1003+ '@tailwindcss/postcss@4.3.3':
1004+ dependencies:
1005+ '@alloc/quick-lru': 5.3.0
1006+ '@tailwindcss/node': 4.3.3
1007+ '@tailwindcss/oxide': 4.3.3
1008+ postcss: 8.5.32
1009+ tailwindcss: 4.3.3
1010+
1011+ '@types/d3-array@3.2.2': {}
1012+
1013+ '@types/d3-color@3.1.3': {}
1014+
1015+ '@types/d3-ease@3.0.2': {}
1016+
1017+ '@types/d3-interpolate@3.0.4':
1018+ dependencies:
1019+ '@types/d3-color': 3.1.3
1020+
1021+ '@types/d3-path@3.1.1': {}
1022+
1023+ '@types/d3-scale@4.0.9':
1024+ dependencies:
1025+ '@types/d3-time': 3.0.4
1026+
1027+ '@types/d3-shape@3.2.0':
1028+ dependencies:
1029+ '@types/d3-path': 3.1.1
1030+
1031+ '@types/d3-time@3.0.4': {}
1032+
1033+ '@types/d3-timer@3.0.2': {}
1034+
1035+ '@types/node@22.20.5':
1036+ dependencies:
1037+ undici-types: 6.21.0
1038+
1039+ '@types/react-dom@19.3.0(@types/react@19.3.0)':
1040+ dependencies:
1041+ '@types/react': 19.3.0
1042+
1043+ '@types/react@19.3.0':
1044+ dependencies:
1045+ csstype: 3.2.3
1046+
1047+ '@types/use-sync-external-store@0.0.6': {}
1048+
1049+ caniuse-lite@1.0.30001820: {}
1050+
1051+ client-only@0.0.1: {}
1052+
1053+ clsx@2.1.1: {}
1054+
1055+ csstype@3.2.3: {}
1056+
1057+ d3-array@3.2.4:
1058+ dependencies:
1059+ internmap: 2.0.3
1060+
1061+ d3-color@3.1.0: {}
1062+
1063+ d3-ease@3.0.1: {}
1064+
1065+ d3-format@3.1.2: {}
1066+
1067+ d3-interpolate@3.0.1:
1068+ dependencies:
1069+ d3-color: 3.1.0
1070+
1071+ d3-path@3.1.0: {}
1072+
1073+ d3-scale@4.0.2:
1074+ dependencies:
1075+ d3-array: 3.2.4
1076+ d3-format: 3.1.2
1077+ d3-interpolate: 3.0.1
1078+ d3-time: 3.1.0
1079+ d3-time-format: 4.1.0
1080+
1081+ d3-shape@3.2.0:
1082+ dependencies:
1083+ d3-path: 3.1.0
1084+
1085+ d3-time-format@4.1.0:
1086+ dependencies:
1087+ d3-time: 3.1.0
1088+
1089+ d3-time@3.1.0:
1090+ dependencies:
1091+ d3-array: 3.2.4
1092+
1093+ d3-timer@3.0.1: {}
1094+
1095+ decimal.js-light@2.5.1: {}
1096+
1097+ detect-libc@2.1.2: {}
1098+
1099+ enhanced-resolve@5.26.0:
1100+ dependencies:
1101+ graceful-fs: 4.2.11
1102+ tapable: 2.3.3
1103+
1104+ es-toolkit@1.53.1: {}
1105+
1106+ eventemitter3@5.0.4: {}
1107+
1108+ graceful-fs@4.2.11: {}
1109+
1110+ immer@11.2.9: {}
1111+
1112+ internmap@2.0.3: {}
1113+
1114+ jiti@2.7.0: {}
1115+
1116+ lightningcss-android-arm64@1.32.0:
1117+ optional: true
1118+
1119+ lightningcss-darwin-arm64@1.32.0:
1120+ optional: true
1121+
1122+ lightningcss-darwin-x64@1.32.0:
1123+ optional: true
1124+
1125+ lightningcss-freebsd-x64@1.32.0:
1126+ optional: true
1127+
1128+ lightningcss-linux-arm-gnueabihf@1.32.0:
1129+ optional: true
1130+
1131+ lightningcss-linux-arm64-gnu@1.32.0:
1132+ optional: true
1133+
1134+ lightningcss-linux-arm64-musl@1.32.0:
1135+ optional: true
1136+
1137+ lightningcss-linux-x64-gnu@1.32.0:
1138+ optional: true
1139+
1140+ lightningcss-linux-x64-musl@1.32.0:
1141+ optional: true
1142+
1143+ lightningcss-win32-arm64-msvc@1.32.0:
1144+ optional: true
1145+
1146+ lightningcss-win32-x64-msvc@1.32.0:
1147+ optional: true
1148+
1149+ lightningcss@1.32.0:
1150+ dependencies:
1151+ detect-libc: 2.1.2
1152+ optionalDependencies:
1153+ lightningcss-android-arm64: 1.32.0
1154+ lightningcss-darwin-arm64: 1.32.0
1155+ lightningcss-darwin-x64: 1.32.0
1156+ lightningcss-freebsd-x64: 1.32.0
1157+ lightningcss-linux-arm-gnueabihf: 1.32.0
1158+ lightningcss-linux-arm64-gnu: 1.32.0
1159+ lightningcss-linux-arm64-musl: 1.32.0
1160+ lightningcss-linux-x64-gnu: 1.32.0
1161+ lightningcss-linux-x64-musl: 1.32.0
1162+ lightningcss-win32-arm64-msvc: 1.32.0
1163+ lightningcss-win32-x64-msvc: 1.32.0
1164+
1165+ lucide-react@1.66.0(@types/react@19.3.0)(react@19.3.1):
1166+ dependencies:
1167+ react: 19.3.1
1168+ optionalDependencies:
1169+ '@types/react': 19.3.0
1170+
1171+ magic-string@0.30.21:
1172+ dependencies:
1173+ '@jridgewell/sourcemap-codec': 1.6.0
1174+
1175+ nanoid@3.3.20: {}
1176+
1177+ next@15.5.28(@types/node@22.20.5)(react-dom@19.3.1(react@19.3.1))(react@19.3.1):
1178+ dependencies:
1179+ '@next/env': 15.5.28
1180+ '@swc/helpers': 0.5.15
1181+ caniuse-lite: 1.0.30001820
1182+ postcss: 8.4.31
1183+ react: 19.3.1
1184+ react-dom: 19.3.1(react@19.3.1)
1185+ styled-jsx: 5.1.6(react@19.3.1)
1186+ optionalDependencies:
1187+ '@next/swc-darwin-arm64': 15.5.28
1188+ '@next/swc-darwin-x64': 15.5.28
1189+ '@next/swc-linux-arm64-gnu': 15.5.28
1190+ '@next/swc-linux-arm64-musl': 15.5.28
1191+ '@next/swc-linux-x64-gnu': 15.5.28
1192+ '@next/swc-linux-x64-musl': 15.5.28
1193+ '@next/swc-win32-arm64-msvc': 15.5.28
1194+ '@next/swc-win32-x64-msvc': 15.5.28
1195+ sharp: 0.35.5(@types/node@22.20.5)
1196+ transitivePeerDependencies:
1197+ - '@babel/core'
1198+ - '@types/node'
1199+ - babel-plugin-macros
1200+
1201+ picocolors@1.1.1: {}
1202+
1203+ postcss@8.4.31:
1204+ dependencies:
1205+ nanoid: 3.3.20
1206+ picocolors: 1.1.1
1207+ source-map-js: 1.2.2
1208+
1209+ postcss@8.5.32:
1210+ dependencies:
1211+ nanoid: 3.3.20
1212+ picocolors: 1.1.1
1213+ source-map-js: 1.2.2
1214+
1215+ react-dom@19.3.1(react@19.3.1):
1216+ dependencies:
1217+ react: 19.3.1
1218+ scheduler: 0.28.0
1219+
1220+ react-is@18.3.1: {}
1221+
1222+ react-redux@9.3.1(@types/react@19.3.0)(react@19.3.1)(redux@5.0.1):
1223+ dependencies:
1224+ '@types/use-sync-external-store': 0.0.6
1225+ react: 19.3.1
1226+ use-sync-external-store: 1.7.0(react@19.3.1)
1227+ optionalDependencies:
1228+ '@types/react': 19.3.0
1229+ redux: 5.0.1
1230+
1231+ react@19.3.1: {}
1232+
1233+ recharts@3.10.1(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react-is@18.3.1)(react@19.3.1)(redux@5.0.1):
1234+ dependencies:
1235+ '@reduxjs/toolkit': 2.13.0(react-redux@9.3.1(@types/react@19.3.0)(react@19.3.1)(redux@5.0.1))(react@19.3.1)
1236+ clsx: 2.1.1
1237+ decimal.js-light: 2.5.1
1238+ es-toolkit: 1.53.1
1239+ eventemitter3: 5.0.4
1240+ immer: 11.2.9
1241+ react: 19.3.1
1242+ react-dom: 19.3.1(react@19.3.1)
1243+ react-is: 18.3.1
1244+ react-redux: 9.3.1(@types/react@19.3.0)(react@19.3.1)(redux@5.0.1)
1245+ reselect: 5.2.0
1246+ tiny-invariant: 1.3.3
1247+ use-sync-external-store: 1.7.0(react@19.3.1)
1248+ victory-vendor: 37.4.1
1249+ transitivePeerDependencies:
1250+ - '@types/react'
1251+ - redux
1252+
1253+ redux-thunk@3.1.0(redux@5.0.1):
1254+ dependencies:
1255+ redux: 5.0.1
1256+
1257+ redux@5.0.1: {}
1258+
1259+ reselect@5.2.0: {}
1260+
1261+ scheduler@0.28.0: {}
1262+
1263+ semver@7.8.5:
1264+ optional: true
1265+
1266+ sharp@0.35.5(@types/node@22.20.5):
1267+ dependencies:
1268+ '@img/colour': 1.1.0
1269+ detect-libc: 2.1.2
1270+ semver: 7.8.5
1271+ optionalDependencies:
1272+ '@img/sharp-darwin-arm64': 0.35.5
1273+ '@img/sharp-darwin-x64': 0.35.5
1274+ '@img/sharp-freebsd-wasm32': 0.35.5
1275+ '@img/sharp-libvips-darwin-arm64': 1.3.4
1276+ '@img/sharp-libvips-darwin-x64': 1.3.4
1277+ '@img/sharp-libvips-linux-arm': 1.3.4
1278+ '@img/sharp-libvips-linux-arm64': 1.3.4
1279+ '@img/sharp-libvips-linux-ppc64': 1.3.4
1280+ '@img/sharp-libvips-linux-riscv64': 1.3.4
1281+ '@img/sharp-libvips-linux-s390x': 1.3.4
1282+ '@img/sharp-libvips-linux-x64': 1.3.4
1283+ '@img/sharp-libvips-linuxmusl-arm64': 1.3.4
1284+ '@img/sharp-libvips-linuxmusl-x64': 1.3.4
1285+ '@img/sharp-linux-arm': 0.35.5
1286+ '@img/sharp-linux-arm64': 0.35.5
1287+ '@img/sharp-linux-ppc64': 0.35.5
1288+ '@img/sharp-linux-riscv64': 0.35.5
1289+ '@img/sharp-linux-s390x': 0.35.5
1290+ '@img/sharp-linux-x64': 0.35.5
1291+ '@img/sharp-linuxmusl-arm64': 0.35.5
1292+ '@img/sharp-linuxmusl-x64': 0.35.5
1293+ '@img/sharp-webcontainers-wasm32': 0.35.5
1294+ '@img/sharp-win32-arm64': 0.35.5
1295+ '@img/sharp-win32-ia32': 0.35.5
1296+ '@img/sharp-win32-x64': 0.35.5
1297+ '@types/node': 22.20.5
1298+ optional: true
1299+
1300+ source-map-js@1.2.2: {}
1301+
1302+ styled-jsx@5.1.6(react@19.3.1):
1303+ dependencies:
1304+ client-only: 0.0.1
1305+ react: 19.3.1
1306+
1307+ tailwindcss@4.3.3: {}
1308+
1309+ tapable@2.3.3: {}
1310+
1311+ tiny-invariant@1.3.3: {}
1312+
1313+ tslib@2.9.1: {}
1314+
1315+ typescript@5.9.3: {}
1316+
1317+ undici-types@6.21.0: {}
1318+
1319+ use-sync-external-store@1.7.0(react@19.3.1):
1320+ dependencies:
1321+ react: 19.3.1
1322+
1323+ victory-vendor@37.4.1:
1324+ dependencies:
1325+ '@types/d3-array': 3.2.2
1326+ '@types/d3-ease': 3.0.2
1327+ '@types/d3-interpolate': 3.0.4
1328+ '@types/d3-scale': 4.0.9
1329+ '@types/d3-shape': 3.2.0
1330+ '@types/d3-time': 3.0.4
1331+ '@types/d3-timer': 3.0.2
1332+ d3-array: 3.2.4
1333+ d3-ease: 3.0.1
1334+ d3-interpolate: 3.0.1
1335+ d3-scale: 4.0.2
1336+ d3-shape: 3.2.0
1337+ d3-time: 3.1.0
1338+ d3-timer: 3.0.1
added apps/web/postcss.config.mjs +2 −0
@@ -0,0 +1,2 @@
1+const config = { plugins: { "@tailwindcss/postcss": {} } };
2+export default config;
added apps/web/public/favicon.svg +1 −0
@@ -0,0 +1 @@
1+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="7" fill="#2a78d6"/><path d="M8 22V10h4v12zm6 0V14h4v8zm6 0v-5h4v5z" fill="#fff"/></svg>
added apps/web/public/robots.txt +2 −0
@@ -0,0 +1,2 @@
1+User-agent: *
2+Disallow: /
added apps/web/src/app/bars/page.tsx +237 −0
@@ -0,0 +1,237 @@
1+"use client";
2+import Link from "next/link";
3+import { useEffect, useMemo, useState, type FormEvent } from "react";
4+import { Download, Play } from "lucide-react";
5+import { api, isApiError, type Bar, type BarsOut } from "@/lib/api";
6+import { useQueryParam } from "@/lib/hooks";
7+import { useToast } from "@/lib/toast";
8+import { daysAgo, downloadText, fmtInt, fmtNum, fmtTs, toCsv, today } from "@/lib/format";
9+import { Banner, Card, Empty, ErrorState, Field, PageHeader, Tabs } from "@/components/ui";
10+import { DataTable } from "@/components/DataTable";
11+import { CloseLineChart, VolumeBarChart } from "@/components/charts";
12+
13+const MAX_SPAN: Record<string, number> = { "1m": 31, "5m": 186, "1d": 3660 };
14+
15+export default function BarsPage() {
16+ const qSymbol = useQueryParam("symbol");
17+ const qInterval = useQueryParam("interval");
18+ const [symbol, setSymbol] = useState("AAPL");
19+ const [interval, setInterval_] = useState<"1m" | "5m" | "1d">("1m");
20+ const [start, setStart] = useState(daysAgo(7));
21+ const [end, setEnd] = useState(today());
22+ const [adjustment, setAdjustment] = useState<"raw" | "split" | "split_div">("raw");
23+ const [limit, setLimit] = useState(2000);
24+ const [out, setOut] = useState<BarsOut | null>(null);
25+ const [rows, setRows] = useState<Bar[]>([]);
26+ const [busy, setBusy] = useState(false);
27+ const [error, setError] = useState<unknown>(null);
28+ const [view, setView] = useState<"chart" | "table">("chart");
29+ const toast = useToast();
30+
31+ useEffect(() => {
32+ if (qSymbol) setSymbol(qSymbol.toUpperCase());
33+ }, [qSymbol]);
34+ useEffect(() => {
35+ if (qInterval === "1m" || qInterval === "5m" || qInterval === "1d") setInterval_(qInterval);
36+ }, [qInterval]);
37+
38+ const spanDays = useMemo(() => Math.round((new Date(end).getTime() - new Date(start).getTime()) / 86_400_000), [start, end]);
39+ const tooLarge = spanDays > (MAX_SPAN[interval] ?? 31);
40+
41+ async function run(e?: FormEvent) {
42+ e?.preventDefault();
43+ setBusy(true);
44+ setError(null);
45+ try {
46+ const o = await api.get<BarsOut>("/market/bars", { symbol: symbol.trim().toUpperCase(), interval, start, end, adjustment, limit });
47+ setOut(o);
48+ setRows(o.data);
49+ } catch (err) {
50+ setError(err);
51+ setOut(null);
52+ setRows([]);
53+ } finally {
54+ setBusy(false);
55+ }
56+ }
57+
58+ async function loadMore() {
59+ if (!out?.next_cursor) return;
60+ setBusy(true);
61+ try {
62+ const o = await api.get<BarsOut>("/market/bars", { symbol: symbol.trim().toUpperCase(), interval, start, end, adjustment, limit, cursor: out.next_cursor });
63+ setOut({ ...o, data: [] });
64+ setRows((r) => [...r, ...o.data]);
65+ } catch (err) {
66+ toast.error(err);
67+ } finally {
68+ setBusy(false);
69+ }
70+ }
71+
72+ const chart = useMemo(
73+ () =>
74+ rows.map((b) => ({
75+ t: fmtTs(b.timestamp_utc),
76+ label: interval === "1d" ? b.session_date : fmtTs(b.timestamp_utc).slice(5, 16),
77+ close: b.close,
78+ open: b.open,
79+ high: b.high,
80+ low: b.low,
81+ volume: b.volume,
82+ })),
83+ [rows, interval],
84+ );
85+ const flagged = useMemo(() => rows.filter((b) => b.quality_flags && b.quality_flags.length > 0).length, [rows]);
86+ const flagCounts = useMemo(() => {
87+ const m = new Map<string, number>();
88+ for (const b of rows) for (const f of b.quality_flags ?? []) m.set(f, (m.get(f) ?? 0) + 1);
89+ return Array.from(m.entries()).sort((a, b) => b[1] - a[1]);
90+ }, [rows]);
91+
92+ const rangeErr = isApiError(error) && error.code === "range_too_large";
93+
94+ return (
95+ <>
96+ <PageHeader title="Bars explorer" subtitle="OHLCV bars stamped at bar open (UTC). Adjustments are applied at query time from corporate actions." />
97+ <Card className="mb-4">
98+ <form onSubmit={run} className="grid grid-cols-2 gap-3 md:grid-cols-3 lg:grid-cols-6 lg:items-end">
99+ <Field label="Symbol">
100+ <input className="input font-mono uppercase" value={symbol} onChange={(e) => setSymbol(e.target.value)} required />
101+ </Field>
102+ <Field label="Interval">
103+ <select className="input" value={interval} onChange={(e) => setInterval_(e.target.value as typeof interval)}>
104+ <option value="1m">1 minute</option>
105+ <option value="5m">5 minutes</option>
106+ <option value="1d">1 day</option>
107+ </select>
108+ </Field>
109+ <Field label="Start">
110+ <input type="date" className="input" value={start} max={end} onChange={(e) => setStart(e.target.value)} required />
111+ </Field>
112+ <Field label="End">
113+ <input type="date" className="input" value={end} min={start} onChange={(e) => setEnd(e.target.value)} required />
114+ </Field>
115+ <Field label="Adjustment">
116+ <select className="input" value={adjustment} onChange={(e) => setAdjustment(e.target.value as typeof adjustment)}>
117+ <option value="raw">raw (as traded)</option>
118+ <option value="split">split-adjusted</option>
119+ <option value="split_div">split + dividend</option>
120+ </select>
121+ </Field>
122+ <div className="flex items-end gap-2">
123+ <Field label="Page size" className="w-24">
124+ <input type="number" className="input" min={100} max={10000} step={100} value={limit} onChange={(e) => setLimit(Number(e.target.value) || 2000)} />
125+ </Field>
126+ <button className="btn btn-primary flex-1" disabled={busy || !symbol}>
127+ <Play className="h-3.5 w-3.5" /> {busy ? "Loading…" : "Load"}
128+ </button>
129+ </div>
130+ </form>
131+ <p className={tooLarge ? "mt-2 text-xs text-warn-ink" : "mt-2 text-xs text-ink-3"}>
132+ Range: {spanDays} day{spanDays === 1 ? "" : "s"} · limit for {interval}: {MAX_SPAN[interval]} days per call (HTTP 413 <code>range_too_large</code> beyond). Larger ranges →{" "}
133+ <Link href="/exports/" className="text-accent-ink hover:underline">
134+ Exports
135+ </Link>{" "}
136+ (async Parquet/CSV).
137+ </p>
138+ </Card>
139+
140+ {error && !rangeErr && <ErrorState error={error} retry={() => void run()} />}
141+ {rangeErr && (
142+ <Banner tone="warn" className="mb-4">
143+ <div className="font-medium">Range too large for {interval}</div>
144+ <div className="text-xs">
145+ {(error as Error).message} Use{" "}
146+ <Link href={`/exports/?symbols=${encodeURIComponent(symbol)}&start=${start}&end=${end}&adjustment=${adjustment}`} className="underline">
147+ an export
148+ </Link>{" "}
149+ for {spanDays} days, or shorten the window.
150+ </div>
151+ </Banner>
152+ )}
153+
154+ {out && (
155+ <>
156+ <div className="mb-3 flex flex-wrap items-center gap-2 text-xs text-ink-2">
157+ <span className="pill bg-surface-2">{out.meta.symbol}</span>
158+ <span className="pill bg-surface-2">{out.meta.interval}</span>
159+ <span className="pill bg-surface-2">{out.meta.adjustment}</span>
160+ {out.meta.version !== undefined && <span className="pill bg-surface-2">dataset v{String(out.meta.version)}</span>}
161+ <span className="tnum">
162+ {fmtInt(rows.length)} of {fmtInt(out.meta.rows_matching || rows.length)} rows
163+ </span>
164+ {flagged > 0 && <span className="pill bg-warn-soft text-warn-ink">{fmtInt(flagged)} flagged bars</span>}
165+ <span className="ml-auto">
166+ <Tabs value={view} onChange={setView} items={[{ value: "chart", label: "Chart" }, { value: "table", label: "Table" }]} />
167+ </span>
168+ </div>
169+ {out.meta.adjustment_notes?.length > 0 && (
170+ <Banner tone="accent" className="mb-3">
171+ <div className="text-xs font-medium">Adjustment notes</div>
172+ <ul className="list-disc pl-4 text-xs">
173+ {out.meta.adjustment_notes.map((n, i) => (
174+ <li key={i}>{n}</li>
175+ ))}
176+ </ul>
177+ </Banner>
178+ )}
179+ {flagCounts.length > 0 && (
180+ <div className="mb-3 flex flex-wrap gap-1 text-xs">
181+ <span className="text-ink-3">quality_flags:</span>
182+ {flagCounts.map(([f, n]) => (
183+ <span key={f} className="pill bg-warn-soft text-warn-ink">
184+ {f} × {fmtInt(n)}
185+ </span>
186+ ))}
187+ </div>
188+ )}
189+ {rows.length === 0 ? (
190+ <Empty>No bars for this range. Zero-volume bars are not stored; check the session coverage.</Empty>
191+ ) : view === "chart" ? (
192+ <Card title={`Close · ${out.meta.symbol} (${out.meta.adjustment})`}>
193+ <CloseLineChart data={chart} height={280} />
194+ <div className="mt-2 text-xs font-semibold text-ink-2">Volume</div>
195+ <VolumeBarChart data={chart} height={110} />
196+ <p className="mt-2 text-[11px] text-ink-3">Hover for OHLCV. Single series per chart — close and volume use separate axes by design.</p>
197+ </Card>
198+ ) : (
199+ <Card
200+ actions={
201+ <button className="btn btn-sm" onClick={() => downloadText(`${out.meta.symbol}_${interval}_${start}_${end}.csv`, toCsv(["timestamp_utc", "session_date", "open", "high", "low", "close", "volume", "vwap", "trade_count", "quality_flags"], rows.map((r) => ({ ...r, quality_flags: (r.quality_flags ?? []).join("|") }))))}>
202+ <Download className="h-3.5 w-3.5" /> CSV (loaded rows)
203+ </button>
204+ }
205+ >
206+ <DataTable
207+ rows={rows}
208+ rowKey={(r) => r.timestamp_utc}
209+ mobile="scroll"
210+ maxHeight="60dvh"
211+ columns={[
212+ { key: "timestamp_utc", header: "Timestamp (UTC, bar open)", render: (r) => <span className="tnum font-mono text-xs">{fmtTs(r.timestamp_utc)}</span> },
213+ { key: "session_date", header: "Session", hideSm: true, render: (r) => <span className="tnum">{r.session_date}</span> },
214+ { key: "open", header: "Open", num: true, render: (r) => fmtNum(r.open, 4) },
215+ { key: "high", header: "High", num: true, render: (r) => fmtNum(r.high, 4) },
216+ { key: "low", header: "Low", num: true, render: (r) => fmtNum(r.low, 4) },
217+ { key: "close", header: "Close", num: true, render: (r) => fmtNum(r.close, 4) },
218+ { key: "volume", header: "Volume", num: true, render: (r) => fmtInt(r.volume) },
219+ { key: "vwap", header: "VWAP", num: true, hideSm: true, render: (r) => (r.vwap === null || r.vwap === undefined ? "—" : fmtNum(r.vwap, 4)) },
220+ { key: "quality_flags", header: "Flags", render: (r) => (r.quality_flags?.length ? r.quality_flags.map((f) => <span key={f} className="pill mr-1 bg-warn-soft text-warn-ink">{f}</span>) : <span className="text-ink-3">—</span>) },
221+ ]}
222+ />
223+ </Card>
224+ )}
225+ <div className="mt-3 flex items-center justify-between text-xs text-ink-3">
226+ <span>{out.meta.license} · timestamps = {out.meta.timestamp_convention}</span>
227+ {out.next_cursor && (
228+ <button className="btn btn-sm" onClick={loadMore} disabled={busy}>
229+ {busy ? "Loading…" : `Load next ${fmtInt(limit)}`}
230+ </button>
231+ )}
232+ </div>
233+ </>
234+ )}
235+ </>
236+ );
237+}
added apps/web/src/app/coverage/page.tsx +134 −0
Large diff (134 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/datasets/detail/page.tsx +128 −0
Large diff (128 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/datasets/page.tsx +94 −0
Large diff (94 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/exports/page.tsx +160 −0
Large diff (160 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/globals.css +153 −0
Large diff (153 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/ingestion/page.tsx +350 −0
Large diff (350 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/keys/page.tsx +209 −0
Large diff (209 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/layout.tsx +32 −0
Large diff (32 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/login/page.tsx +170 −0
Large diff (170 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/page.tsx +156 −0
Large diff (156 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/playground/page.tsx +183 −0
Large diff (183 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/quality/page.tsx +148 −0
Large diff (148 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/storage/page.tsx +149 −0
Large diff (149 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/symbols/detail/page.tsx +136 −0
Large diff (136 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/app/symbols/page.tsx +122 −0
Large diff (122 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/ConfirmDialog.tsx +61 −0
Large diff (61 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/CopyButton.tsx +25 −0
Large diff (25 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/DataTable.tsx +88 −0
Large diff (88 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/DateRange.tsx +35 −0
Large diff (35 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/JsonView.tsx +28 −0
Large diff (28 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/Providers.tsx +16 −0
Large diff (16 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/Shell.tsx +160 −0
Large diff (160 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/Toast.tsx +40 −0
Large diff (40 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/charts.tsx +274 −0
Large diff (274 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/nav.ts +32 −0
Large diff (32 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/components/ui.tsx +220 −0
Large diff (220 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/lib/api.ts +462 −0
Large diff (462 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/lib/auth.tsx +99 −0
Large diff (99 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/lib/format.ts +148 −0
Large diff (148 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/lib/hooks.ts +112 −0
Large diff (112 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/src/lib/toast.tsx +62 −0
Large diff (62 lines) is not loaded by default to keep the page fast.Load diff
added apps/web/tsconfig.json +21 −0
Large diff (21 lines) is not loaded by default to keep the page fast.Load diff
added connectors/fundamentals/pyproject.toml +14 −0
Large diff (14 lines) is not loaded by default to keep the page fast.Load diff
added connectors/fundamentals/src/findata_fundamentals/__init__.py +2 −0
Large diff (2 lines) is not loaded by default to keep the page fast.Load diff
added connectors/fundamentals/src/findata_fundamentals/firstrate.py +138 −0
Large diff (138 lines) is not loaded by default to keep the page fast.Load diff
added connectors/fundamentals/src/findata_fundamentals/sec_edgar.py +109 −0
Large diff (109 lines) is not loaded by default to keep the page fast.Load diff
added connectors/market/pyproject.toml +14 −0
Large diff (14 lines) is not loaded by default to keep the page fast.Load diff
added connectors/market/src/findata_market_firstrate/__init__.py +3 −0
Large diff (3 lines) is not loaded by default to keep the page fast.Load diff
added connectors/market/src/findata_market_firstrate/archive.py +131 −0
Large diff (131 lines) is not loaded by default to keep the page fast.Load diff
added connectors/market/src/findata_market_firstrate/client.py +144 −0
Large diff (144 lines) is not loaded by default to keep the page fast.Load diff
added connectors/market/src/findata_market_firstrate/connector.py +173 −0
Large diff (173 lines) is not loaded by default to keep the page fast.Load diff
added docs/ARCHITECTURE.md +63 −0
Large diff (63 lines) is not loaded by default to keep the page fast.Load diff
added docs/DATA_DICTIONARY.md +60 −0
Large diff (60 lines) is not loaded by default to keep the page fast.Load diff
added docs/DISCOVERY.md +124 −0
Large diff (124 lines) is not loaded by default to keep the page fast.Load diff
added docs/OPERATIONS.md +52 −0
Large diff (52 lines) is not loaded by default to keep the page fast.Load diff
added docs/SECURITY.md +10 −0
Large diff (10 lines) is not loaded by default to keep the page fast.Load diff
added docs/evidence/phase0-probes.md +32 −0
Large diff (32 lines) is not loaded by default to keep the page fast.Load diff
added infra/mld/findata.json +34 −0
Large diff (34 lines) is not loaded by default to keep the page fast.Load diff
added infra/prometheus/findata-alerts.yml +41 −0
Large diff (41 lines) is not loaded by default to keep the page fast.Load diff
added infra/scripts/node-bootstrap.sh +10 −0
Large diff (10 lines) is not loaded by default to keep the page fast.Load diff
added packages/core/pyproject.toml +15 −0
Large diff (15 lines) is not loaded by default to keep the page fast.Load diff
added packages/core/src/findata_core/__init__.py +2 −0
Large diff (2 lines) is not loaded by default to keep the page fast.Load diff
added packages/core/src/findata_core/clock.py +15 −0
Large diff (15 lines) is not loaded by default to keep the page fast.Load diff
added packages/core/src/findata_core/config.py +72 −0
Large diff (72 lines) is not loaded by default to keep the page fast.Load diff
added packages/core/src/findata_core/db.py +85 −0
Large diff (85 lines) is not loaded by default to keep the page fast.Load diff
added packages/core/src/findata_core/logging.py +33 −0
Large diff (33 lines) is not loaded by default to keep the page fast.Load diff
added packages/core/src/findata_core/migrations/0001_init.sql +359 −0
Large diff (359 lines) is not loaded by default to keep the page fast.Load diff
added packages/core/src/findata_core/redact.py +29 −0
Large diff (29 lines) is not loaded by default to keep the page fast.Load diff
added packages/python-sdk/pyproject.toml +14 −0
Large diff (14 lines) is not loaded by default to keep the page fast.Load diff
added packages/python-sdk/src/findata_sdk/__init__.py +1 −0
Large diff (1 lines) is not loaded by default to keep the page fast.Load diff
added packages/python-sdk/src/findata_sdk/client.py +129 −0
Large diff (129 lines) is not loaded by default to keep the page fast.Load diff
added packages/schema/pyproject.toml +10 −0
Large diff (10 lines) is not loaded by default to keep the page fast.Load diff
added packages/schema/src/findata_schema/__init__.py +8 −0
Large diff (8 lines) is not loaded by default to keep the page fast.Load diff
added packages/schema/src/findata_schema/connector.py +95 −0
Large diff (95 lines) is not loaded by default to keep the page fast.Load diff
added packages/schema/src/findata_schema/contracts.py +116 −0
Large diff (116 lines) is not loaded by default to keep the page fast.Load diff
added pyproject.toml +57 −0
Large diff (57 lines) is not loaded by default to keep the page fast.Load diff
added services/api/pyproject.toml +18 −0
Large diff (18 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/auth.py +244 −0
Large diff (244 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/errors.py +8 −0
Large diff (8 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/health.py +107 −0
Large diff (107 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/main.py +127 −0
Large diff (127 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/metrics.py +18 −0
Large diff (18 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/ratelimit.py +34 −0
Large diff (34 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/admin.py +162 −0
Large diff (162 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/auth.py +93 −0
Large diff (93 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/catalog.py +60 −0
Large diff (60 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/coverage.py +48 −0
Large diff (48 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/exports.py +124 −0
Large diff (124 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/fundamentals.py +68 −0
Large diff (68 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/health.py +35 −0
Large diff (35 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/instruments.py +47 −0
Large diff (47 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/market.py +104 −0
Large diff (104 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/quality.py +31 −0
Large diff (31 lines) is not loaded by default to keep the page fast.Load diff
added services/api/src/findata_api/routers/query.py +54 −0
Large diff (54 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/pyproject.toml +19 −0
Large diff (19 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/__init__.py +1 −0
Large diff (1 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/cli.py +138 −0
Large diff (138 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/lake.py +227 −0
Large diff (227 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/queue.py +108 −0
Large diff (108 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/reader.py +161 −0
Large diff (161 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/tasks/__init__.py +13 −0
Large diff (13 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/tasks/backfill.py +111 −0
Large diff (111 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/tasks/backup.py +95 −0
Large diff (95 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/tasks/common.py +73 −0
Large diff (73 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/tasks/compaction.py +57 −0
Large diff (57 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/tasks/derive.py +56 −0
Large diff (56 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/tasks/fundamentals.py +78 −0
Large diff (78 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/tasks/incremental.py +106 −0
Large diff (106 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/tasks/metadata.py +52 −0
Large diff (52 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/tasks/quality.py +39 −0
Large diff (39 lines) is not loaded by default to keep the page fast.Load diff
added services/ingest/src/findata_ingest/worker.py +89 −0
Large diff (89 lines) is not loaded by default to keep the page fast.Load diff
added services/quality/pyproject.toml +12 −0
Large diff (12 lines) is not loaded by default to keep the page fast.Load diff
added services/quality/src/findata_quality/__init__.py +3 −0
Large diff (3 lines) is not loaded by default to keep the page fast.Load diff
added services/quality/src/findata_quality/aggregate.py +32 −0
Large diff (32 lines) is not loaded by default to keep the page fast.Load diff
added services/quality/src/findata_quality/calendar.py +65 −0
Large diff (65 lines) is not loaded by default to keep the page fast.Load diff
added services/quality/src/findata_quality/validators.py +96 −0
Large diff (96 lines) is not loaded by default to keep the page fast.Load diff
added tests/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added tests/conftest.py +158 −0
Large diff (158 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/firstrate/AAL_day_1min_UNADJUSTED.txt +554 −0
Large diff (555 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/firstrate/AAPL_day_1min_UNADJUSTED.txt +900 −0
Large diff (901 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/firstrate/A_day_1min_UNADJUSTED.txt +390 −0
Large diff (391 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/fundamentals/earnings_AAPL.json +74 −0
Large diff (75 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/fundamentals/financials_all_AAPL_quarterly.json +927 −0
Large diff (928 lines) is not loaded by default to keep the page fast.Load diff
added tests/test_fundamentals_pit.py +56 −0
Large diff (56 lines) is not loaded by default to keep the page fast.Load diff
added tests/test_ingest_lake.py +157 −0
Large diff (157 lines) is not loaded by default to keep the page fast.Load diff
added tests/test_parse_firstrate.py +72 −0
Large diff (72 lines) is not loaded by default to keep the page fast.Load diff
added tests/test_redaction.py +29 −0
Large diff (29 lines) is not loaded by default to keep the page fast.Load diff
added tests/test_validators_aggregate.py +108 −0
Large diff (108 lines) is not loaded by default to keep the page fast.Load diff
added tests/test_z_api_sdk.py +273 −0
Large diff (273 lines) is not loaded by default to keep the page fast.Load diff
added uv.lock +2198 −0
Large diff (2,199 lines) is not loaded by default to keep the page fast.Load diff
Menu

Theme