2025-10-10 23:04:50 -07:00
|
|
|
{
|
|
|
|
|
"name": "brackt.com",
|
|
|
|
|
"private": true,
|
|
|
|
|
"type": "module",
|
|
|
|
|
"scripts": {
|
2025-10-18 22:16:04 -07:00
|
|
|
"build": "npm run build:remix && npm run build:server",
|
|
|
|
|
"build:remix": "react-router build",
|
|
|
|
|
"build:server": "node scripts/build-server.mjs",
|
2025-10-10 23:04:50 -07:00
|
|
|
"db:generate": "dotenv -- drizzle-kit generate",
|
|
|
|
|
"db:migrate": "dotenv -- drizzle-kit migrate",
|
2026-03-10 23:35:33 -07:00
|
|
|
"dev": "NODE_OPTIONS='--import ./instrument.server.mjs' dotenv -- tsx watch server.ts",
|
2026-03-11 09:06:11 -07:00
|
|
|
"start": "NODE_ENV=production NODE_OPTIONS='--import ./instrument.server.mjs' node dist/server.js",
|
|
|
|
|
"start:production": "NODE_ENV=production NODE_OPTIONS='--import ./instrument.server.mjs' node dist/server.js",
|
2025-10-21 12:47:11 -07:00
|
|
|
"test": "vitest",
|
|
|
|
|
"test:ui": "vitest --ui",
|
|
|
|
|
"test:coverage": "vitest --coverage",
|
|
|
|
|
"test:run": "vitest run",
|
|
|
|
|
"test:e2e": "cypress open",
|
|
|
|
|
"test:e2e:headless": "cypress run",
|
|
|
|
|
"test:all": "npm run test:run && npm run test:e2e:headless",
|
2025-10-18 22:16:04 -07:00
|
|
|
"typecheck": "react-router typegen && tsc -b && tsc -p tsconfig.server.json --noEmit"
|
2025-10-10 23:04:50 -07:00
|
|
|
},
|
|
|
|
|
"dependencies": {
|
2025-10-10 23:18:16 -07:00
|
|
|
"@clerk/react-router": "^2.1.0",
|
2026-02-20 19:26:11 -08:00
|
|
|
"@clerk/themes": "^2.4.55",
|
2025-10-25 21:02:16 -07:00
|
|
|
"@dnd-kit/core": "^6.3.1",
|
|
|
|
|
"@dnd-kit/sortable": "^10.0.0",
|
|
|
|
|
"@dnd-kit/utilities": "^3.2.2",
|
2025-10-25 10:04:21 -07:00
|
|
|
"@radix-ui/react-accordion": "^1.2.12",
|
2025-10-11 00:29:04 -07:00
|
|
|
"@radix-ui/react-alert-dialog": "^1.1.15",
|
2025-10-12 21:54:49 -07:00
|
|
|
"@radix-ui/react-checkbox": "^1.3.3",
|
2025-10-25 03:23:41 -07:00
|
|
|
"@radix-ui/react-collapsible": "^1.1.12",
|
2025-10-18 14:55:26 -07:00
|
|
|
"@radix-ui/react-context-menu": "^2.2.16",
|
2025-10-10 23:30:26 -07:00
|
|
|
"@radix-ui/react-dialog": "^1.1.15",
|
2025-10-11 00:07:39 -07:00
|
|
|
"@radix-ui/react-label": "^2.1.7",
|
2025-10-10 23:30:26 -07:00
|
|
|
"@radix-ui/react-navigation-menu": "^1.2.14",
|
2025-10-15 22:02:21 -07:00
|
|
|
"@radix-ui/react-popover": "^1.1.15",
|
2025-10-13 19:59:34 -07:00
|
|
|
"@radix-ui/react-radio-group": "^1.3.8",
|
2025-10-11 00:07:39 -07:00
|
|
|
"@radix-ui/react-select": "^2.2.6",
|
|
|
|
|
"@radix-ui/react-slot": "^1.2.3",
|
2025-10-21 23:22:17 -07:00
|
|
|
"@radix-ui/react-switch": "^1.2.6",
|
2025-10-25 03:23:41 -07:00
|
|
|
"@radix-ui/react-tabs": "^1.1.13",
|
2025-10-10 23:04:50 -07:00
|
|
|
"@react-router/express": "^7.7.1",
|
|
|
|
|
"@react-router/node": "^7.7.1",
|
2026-03-10 23:35:33 -07:00
|
|
|
"@sentry/react-router": "^10.43.0",
|
2026-03-11 22:02:48 -07:00
|
|
|
"@types/nprogress": "^0.2.3",
|
2025-10-10 23:30:26 -07:00
|
|
|
"class-variance-authority": "^0.7.1",
|
|
|
|
|
"clsx": "^2.1.1",
|
2025-10-10 23:04:50 -07:00
|
|
|
"compression": "^1.8.0",
|
2025-10-15 22:02:21 -07:00
|
|
|
"date-fns": "^4.1.0",
|
2025-10-13 11:04:40 -07:00
|
|
|
"drizzle-kit": "~0.28.1",
|
2025-10-10 23:04:50 -07:00
|
|
|
"drizzle-orm": "~0.36.3",
|
|
|
|
|
"express": "^5.1.0",
|
|
|
|
|
"isbot": "^5.1.27",
|
2025-10-10 23:30:26 -07:00
|
|
|
"lucide-react": "^0.545.0",
|
2025-10-10 23:04:50 -07:00
|
|
|
"morgan": "^1.10.0",
|
2025-10-11 00:29:04 -07:00
|
|
|
"next-themes": "^0.4.6",
|
2026-03-11 22:02:48 -07:00
|
|
|
"nprogress": "^0.2.0",
|
2025-10-10 23:04:50 -07:00
|
|
|
"postgres": "^3.4.5",
|
|
|
|
|
"react": "^19.1.0",
|
2025-10-15 22:02:21 -07:00
|
|
|
"react-day-picker": "^9.11.1",
|
2025-10-10 23:04:50 -07:00
|
|
|
"react-dom": "^19.1.0",
|
2025-10-10 23:30:26 -07:00
|
|
|
"react-router": "^7.7.1",
|
2025-11-14 21:18:34 -08:00
|
|
|
"recharts": "^3.4.1",
|
2025-10-17 11:13:37 -07:00
|
|
|
"socket.io": "^4.8.1",
|
|
|
|
|
"socket.io-client": "^4.8.1",
|
2025-10-11 00:29:04 -07:00
|
|
|
"sonner": "^2.0.7",
|
2025-10-11 00:53:39 -07:00
|
|
|
"svix": "^1.77.0",
|
Add Zod validation and expand export/import for EV and results data (#14)
* Include participant EV/futures data in data sync export/import
The export now includes the full participantExpectedValues records
(placement probabilities, source, sourceOdds) alongside participants.
On import, EV records are upserted in merge mode and created fresh in
replace mode (cascade handles cleanup). Backward-compatible with older
exports that lack the participantExpectedValues field.
https://claude.ai/code/session_01TVzuuDR7jPtmihaXTrsX7B
* Address all data-sync code review findings
- Wrap importSportsDataFromJSON in a db.transaction() so any mid-import
failure rolls back cleanly instead of leaving partial data
- Add zod validation of imported JSON before any DB writes, giving a
clear error on malformed/incompatible files
- Fix N+1 queries: build participantIdMap during participant import so
the EV and results sections resolve IDs from memory, not extra queries
- Fix merge mode silently skipping existing participants — now updates
shortName, externalId, and expectedValue
- Add participantResults to export/import (was deleted in replace mode
but never exported, so results were permanently lost)
- Restore calculatedAt timestamp on EV import instead of defaulting to
now(); stored as ISO string in the export for portability
- Document that onDelete:cascade covers participantExpectedValues and
participantResults when participants is deleted; remove the now-
redundant explicit participantResults delete from replace mode
- Bump export version to 1.1; old v1.0 files still import cleanly since
participantExpectedValues, participantResults, and calculatedAt are
all optional in the zod schema
- Collapse all six DB fetches in exportSportsDataToJSON into one
Promise.all for parallel execution
- Add countAllParticipants() and countAllParticipantEVs() model funcs
- Show Participants and EV Records counts on the dashboard stat cards
- Replace raw DOM form creation/submit in handleImport with useFetcher,
giving proper loading state, no full-page reload, and type-safe data
- Remove dead export intent handler from the action function
https://claude.ai/code/session_01TVzuuDR7jPtmihaXTrsX7B
---------
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 20:25:25 -08:00
|
|
|
"tailwind-merge": "^3.3.1",
|
|
|
|
|
"zod": "^4.3.6"
|
2025-10-10 23:04:50 -07:00
|
|
|
},
|
|
|
|
|
"devDependencies": {
|
|
|
|
|
"@react-router/dev": "^7.7.1",
|
|
|
|
|
"@tailwindcss/vite": "^4.1.4",
|
2025-10-21 12:47:11 -07:00
|
|
|
"@testing-library/cypress": "^10.1.0",
|
|
|
|
|
"@testing-library/jest-dom": "^6.9.1",
|
|
|
|
|
"@testing-library/react": "^16.3.0",
|
|
|
|
|
"@testing-library/user-event": "^14.6.1",
|
2025-10-18 22:16:04 -07:00
|
|
|
"@types/compression": "^1.8.1",
|
|
|
|
|
"@types/express": "^5.0.3",
|
2025-10-10 23:04:50 -07:00
|
|
|
"@types/express-serve-static-core": "^5.0.6",
|
2025-10-18 22:16:04 -07:00
|
|
|
"@types/morgan": "^1.9.10",
|
2025-10-10 23:04:50 -07:00
|
|
|
"@types/node": "^20",
|
|
|
|
|
"@types/pg": "^8.11.14",
|
|
|
|
|
"@types/react": "^19.1.2",
|
|
|
|
|
"@types/react-dom": "^19.1.2",
|
2025-10-21 12:47:11 -07:00
|
|
|
"@vitejs/plugin-react": "^5.0.4",
|
|
|
|
|
"@vitest/coverage-v8": "^3.2.4",
|
|
|
|
|
"@vitest/ui": "^3.2.4",
|
|
|
|
|
"cypress": "^14.5.4",
|
2025-10-10 23:04:50 -07:00
|
|
|
"dotenv-cli": "^8.0.0",
|
2025-10-18 22:16:04 -07:00
|
|
|
"esbuild": "^0.25.11",
|
2025-10-21 12:47:11 -07:00
|
|
|
"jsdom": "^27.0.1",
|
2026-03-15 21:52:47 -07:00
|
|
|
"shadcn": "^4.0.8",
|
2025-10-10 23:04:50 -07:00
|
|
|
"tailwindcss": "^4.1.4",
|
2025-10-18 22:16:04 -07:00
|
|
|
"tsx": "^4.20.6",
|
2025-10-10 23:30:26 -07:00
|
|
|
"tw-animate-css": "^1.4.0",
|
2025-10-10 23:04:50 -07:00
|
|
|
"typescript": "^5.8.3",
|
|
|
|
|
"vite": "^6.3.3",
|
2025-10-21 12:47:11 -07:00
|
|
|
"vite-tsconfig-paths": "^5.1.4",
|
|
|
|
|
"vitest": "^3.2.4"
|
2025-10-10 23:04:50 -07:00
|
|
|
}
|
2026-03-11 21:45:19 -07:00
|
|
|
}
|