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