dubs-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/.claude/settings.local.json +280 -0
  2. package/CLAUDE.md +46 -0
  3. package/CONNECT4_PRODUCTION_DEPLOY.md +155 -0
  4. package/CURRENT_SESSION.md +171 -0
  5. package/CURRENT_SESSION_DRAW.md +516 -0
  6. package/MARCH_MADNESS_SURVIVOR.md +254 -0
  7. package/PANDA.md +166 -0
  8. package/Procfile +4 -0
  9. package/README.md +476 -0
  10. package/controllers/livescoresController.js +376 -0
  11. package/controllers/pickemController.js +554 -0
  12. package/controllers/survivorAdminController.js +887 -0
  13. package/controllers/survivorController.js +623 -0
  14. package/cron/oracleMonitor.js +77 -0
  15. package/cron/pickemOracleMonitor.js +73 -0
  16. package/data/jackpot-history.json +952 -0
  17. package/data/ncaaTeams.js +406 -0
  18. package/documentation/API_SECURITY_GUIDE.md +327 -0
  19. package/documentation/ARCADE_API.md +593 -0
  20. package/documentation/ARCADE_IMPLEMENTATION_SUMMARY.md +399 -0
  21. package/documentation/ARCADE_QUICKSTART.md +242 -0
  22. package/documentation/AUTOMATIC_MODE_ORACLE.md +321 -0
  23. package/documentation/BUG_FIX_COHORT_DATE_DISPLAY.md +171 -0
  24. package/documentation/CLAIM_MIGRATION_INSTRUCTIONS.md +52 -0
  25. package/documentation/CLAIM_STATUS_FIX.md +67 -0
  26. package/documentation/CLI_TOOL_GUIDE.md +372 -0
  27. package/documentation/COHORT_RETENTION_ANALYSIS.md +295 -0
  28. package/documentation/COHORT_RETENTION_IMPLEMENTATION_COMPLETE.md +461 -0
  29. package/documentation/COHORT_RETENTION_SUMMARY.md +204 -0
  30. package/documentation/COMPLETE_PROJECT_SUMMARY.md +490 -0
  31. package/documentation/DATABASE_QUERIES.md +269 -0
  32. package/documentation/DATABASE_RETENTION_POLICY.md +390 -0
  33. package/documentation/DATABASE_SETUP_GUIDE.md +361 -0
  34. package/documentation/DATABASE_SETUP_SUMMARY.md +247 -0
  35. package/documentation/DEMO_API_CURL_COMMANDS.md +656 -0
  36. package/documentation/DEPLOYMENT_SUMMARY.txt +100 -0
  37. package/documentation/DUPLICATE_NOTIFICATIONS_FIXED.md +201 -0
  38. package/documentation/EXCHANGE_RATES_INTEGRATION.md +371 -0
  39. package/documentation/FINAL_API_PROTECTION_TABLE.md +175 -0
  40. package/documentation/GAME_START_NOTIFICATIONS_DEPLOYMENT.md +256 -0
  41. package/documentation/GAME_START_NOTIFICATIONS_INTEGRATION.md +275 -0
  42. package/documentation/HEROKU_DEPLOYMENT.md +134 -0
  43. package/documentation/HEROKU_SCHEDULER_SETUP.md +271 -0
  44. package/documentation/JACKPOT_API.md +521 -0
  45. package/documentation/JACKPOT_DEPLOYMENT_GUIDE.md +362 -0
  46. package/documentation/JWT_IMPLEMENTATION_SUMMARY.md +373 -0
  47. package/documentation/JWT_QUICK_SETUP.md +268 -0
  48. package/documentation/JWT_TESTING_GUIDE.md +404 -0
  49. package/documentation/KEEPER_RECOVERY_GUIDE.md +381 -0
  50. package/documentation/KEEPER_SETUP.md +206 -0
  51. package/documentation/KEEPER_STATE_MACHINE.md +423 -0
  52. package/documentation/LATEST_PRODUCTION_SETUP.md +387 -0
  53. package/documentation/LOCAL_VOTING_TEST.md +279 -0
  54. package/documentation/ORACLE_FIXES_SUMMARY.md +188 -0
  55. package/documentation/ORACLE_POSTGRESQL_UPDATE.md +202 -0
  56. package/documentation/PAYMENT_DEPLOYMENT.md +209 -0
  57. package/documentation/PNL_TRACKING_SETUP.md +189 -0
  58. package/documentation/PREVENTING_LOCKUP_ERRORS.md +472 -0
  59. package/documentation/PRODUCTION_READY_SUMMARY.md +227 -0
  60. package/documentation/PUBLIC_VS_PRIVATE_ENDPOINTS.md +278 -0
  61. package/documentation/QUICK_AUTH_SETUP.md +99 -0
  62. package/documentation/QUICK_DEPLOY.md +224 -0
  63. package/documentation/QUICK_FIX.md +114 -0
  64. package/documentation/QUICK_START.md +152 -0
  65. package/documentation/REFEREE_MODE_GUIDE.md +392 -0
  66. package/documentation/RETENTION_CORE_ACTION_UPDATE.md +313 -0
  67. package/documentation/RETENTION_UPDATE_SUMMARY.md +108 -0
  68. package/documentation/RUN_MIGRATION_NOW.md +39 -0
  69. package/documentation/SCRIPTS_UPDATE_SUMMARY.md +251 -0
  70. package/documentation/SETUP_GUIDE.md +184 -0
  71. package/documentation/STATE_MACHINE_IMPLEMENTATION.md +250 -0
  72. package/documentation/TELEGRAM_NOTIFICATIONS_DIAGNOSIS.md +361 -0
  73. package/documentation/UNIFIED_ARCHITECTURE.md +231 -0
  74. package/documentation/VOTING_DEPLOYMENT_SUMMARY.md +392 -0
  75. package/documentation/WEBSOCKET_ARCHITECTURE.md +881 -0
  76. package/documentation/WHAT_WE_BUILT_TODAY.md +369 -0
  77. package/documentation/latest/LATEST_PRODUCTION_SETUP.md +865 -0
  78. package/ecosystem.config.js +65 -0
  79. package/env.template +125 -0
  80. package/middleware/apiKeyAuth.js +136 -0
  81. package/middleware/authenticate.js +214 -0
  82. package/middleware/developerUserAuth.js +76 -0
  83. package/middleware/socketAuth.js +69 -0
  84. package/package.json +49 -0
  85. package/postman/Dubs-API-v1-With-Voting.postman_collection.json +555 -0
  86. package/postman/Dubs-API-v1.postman_collection.json +205 -0
  87. package/postman/Dubs_Developer_API.postman_collection.json +662 -0
  88. package/postman/QUICKSTART.md +118 -0
  89. package/postman/QUICK_REFERENCE.md +246 -0
  90. package/postman/README.md +71 -0
  91. package/postman/VOTING_API_GUIDE.md +426 -0
  92. package/refactor/Animations.md +148 -0
  93. package/refactor/Chat.md +252 -0
  94. package/routes/actionsRoutes.js +699 -0
  95. package/routes/adminRoutes.js +370 -0
  96. package/routes/analyticsRoutes.js +1262 -0
  97. package/routes/arcadeRoutes.js +557 -0
  98. package/routes/authRoutes.js +2310 -0
  99. package/routes/avatarRoutes.js +85 -0
  100. package/routes/botRoutes.js +211 -0
  101. package/routes/chatRoutes.js +377 -0
  102. package/routes/cryptoPriceRoutes.js +105 -0
  103. package/routes/developerRoutes.js +4201 -0
  104. package/routes/deviceRoutes.js +214 -0
  105. package/routes/dmRoutes.js +167 -0
  106. package/routes/esportsRoutes.js +806 -0
  107. package/routes/exchangeRateRoutes.js +233 -0
  108. package/routes/gamesRoutes.js +3028 -0
  109. package/routes/jackpotRoutes.js +754 -0
  110. package/routes/keeperMonitoringRoutes.js +156 -0
  111. package/routes/keeperWebhookRoutes.js +466 -0
  112. package/routes/livescoresRoutes.js +31 -0
  113. package/routes/pickemAdminRoutes.js +199 -0
  114. package/routes/pickemRoutes.js +231 -0
  115. package/routes/playerStatsRoutes.js +147 -0
  116. package/routes/portfolioRoutes.js +217 -0
  117. package/routes/promoRoutes.js +418 -0
  118. package/routes/referralEarningsRoutes.js +392 -0
  119. package/routes/socialRoutes.js +459 -0
  120. package/routes/sportsRoutes.js +1271 -0
  121. package/routes/survivorAdminRoutes.js +345 -0
  122. package/routes/survivorRoutes.js +756 -0
  123. package/routes/uploadRoutes.js +256 -0
  124. package/routes/userProfileRoutes.js +244 -0
  125. package/routes/whatsNewRoutes.js +331 -0
  126. package/scripts/.claude/settings.local.json +15 -0
  127. package/scripts/README.md +170 -0
  128. package/scripts/RESTART_EVERYTHING.sh +104 -0
  129. package/scripts/add-claim-columns.sql +48 -0
  130. package/scripts/add-crypto-prices-cache.sql +27 -0
  131. package/scripts/add-exchange-rates-cache.sql +40 -0
  132. package/scripts/add-game-invite-column.sql +23 -0
  133. package/scripts/add-game-invite-notification.sql +33 -0
  134. package/scripts/add-game-invite-telegram-pref.sql +16 -0
  135. package/scripts/add-game-joined-notification.sql +16 -0
  136. package/scripts/add-game-joined-pref.js +40 -0
  137. package/scripts/add-game-joined-preference.sql +6 -0
  138. package/scripts/add-game-start-notifications.sql +41 -0
  139. package/scripts/add-notification-flags-to-games.sql +55 -0
  140. package/scripts/add-pending-game-dismissals.sql +19 -0
  141. package/scripts/add-preferred-currency.sql +34 -0
  142. package/scripts/add-winner-columns.js +61 -0
  143. package/scripts/add_mention_system.sql +53 -0
  144. package/scripts/add_payment_system.sql +96 -0
  145. package/scripts/add_sports_event_id_column.sql +22 -0
  146. package/scripts/analyze-cohort-data-heroku.js +276 -0
  147. package/scripts/analyze-cohort-data.js +295 -0
  148. package/scripts/analyze-prod-cohorts.sh +10 -0
  149. package/scripts/backfill-matchup-images.js +245 -0
  150. package/scripts/backfill-missing-signatures.js +175 -0
  151. package/scripts/backfill-referral-earnings.js +202 -0
  152. package/scripts/check-chat-schema.js +130 -0
  153. package/scripts/check-db.sh +14 -0
  154. package/scripts/check_oracle_in_game.js +54 -0
  155. package/scripts/cleanup-database.js +193 -0
  156. package/scripts/clear-notification-cache.js +85 -0
  157. package/scripts/convert-mnemonic.js +50 -0
  158. package/scripts/create-users-table.sql +44 -0
  159. package/scripts/debug-cohort-counts.js +248 -0
  160. package/scripts/debug-winner-calc.js +84 -0
  161. package/scripts/deploy-payment-system.sh +118 -0
  162. package/scripts/deploy-to-heroku.sh +63 -0
  163. package/scripts/diagnose-locked-round.js +143 -0
  164. package/scripts/dubs-cli.js +720 -0
  165. package/scripts/dump-account.js +65 -0
  166. package/scripts/find-vrf-offset.js +48 -0
  167. package/scripts/fix-chat-notifications-constraint.sql +122 -0
  168. package/scripts/fix-claim-columns.js +124 -0
  169. package/scripts/fix-constraint-now.js +44 -0
  170. package/scripts/fix-lock-timestamps.js +96 -0
  171. package/scripts/fix-locked-round.sh +126 -0
  172. package/scripts/fix-missing-badges.sql +91 -0
  173. package/scripts/fix-payment-notifications.sql +41 -0
  174. package/scripts/force-new-round.js +55 -0
  175. package/scripts/force-resolve-and-claim.js +278 -0
  176. package/scripts/important/README.md +115 -0
  177. package/scripts/important/authority-force-lock.js +197 -0
  178. package/scripts/important/authority-resolve-game.js +267 -0
  179. package/scripts/important/check-game-status.js +373 -0
  180. package/scripts/important/list-pending-games-by-version.js +270 -0
  181. package/scripts/important/reconcile-v1-v2-payouts.js +270 -0
  182. package/scripts/initialize-jackpot.js +111 -0
  183. package/scripts/jackpot/.claude/settings.local.json +10 -0
  184. package/scripts/jackpot/force-reset.js +84 -0
  185. package/scripts/jackpot/initialize-mainnet.js +100 -0
  186. package/scripts/jackpot/keeper.js +742 -0
  187. package/scripts/jackpot/status.js +107 -0
  188. package/scripts/jackpot/update-round-duration.js +143 -0
  189. package/scripts/keeper-bot.js +112 -0
  190. package/scripts/list-pending-games.js +131 -0
  191. package/scripts/migrate-chat-v2.js +127 -0
  192. package/scripts/migrate-chat-winners.js +84 -0
  193. package/scripts/migrate-chat.sh +17 -0
  194. package/scripts/migrate-game-invite.js +83 -0
  195. package/scripts/migrate-heroku-game-notifications.sh +159 -0
  196. package/scripts/migrations/001_analytics_tables.sql +422 -0
  197. package/scripts/migrations/002_add_matchup_image_url.sql +14 -0
  198. package/scripts/migrations/003_referral_earnings.sql +208 -0
  199. package/scripts/migrations/004_add_whats_new_notification_type.sql +62 -0
  200. package/scripts/migrations/005_add_connect4_your_turn_notification.sql +61 -0
  201. package/scripts/migrations/005_push_notifications.sql +55 -0
  202. package/scripts/migrations/006_add_draw_team_players.sql +28 -0
  203. package/scripts/migrations/006_add_game_cancelled_notification.sql +62 -0
  204. package/scripts/migrations/007_add_gif_url.sql +8 -0
  205. package/scripts/migrations/008_add_connect4_columns.sql +139 -0
  206. package/scripts/migrations/008_add_pool_tracking.sql +22 -0
  207. package/scripts/migrations/009_create_survivor_pool_tables.sql +174 -0
  208. package/scripts/migrations/010_add_survivor_pool_outcome.sql +28 -0
  209. package/scripts/migrations/011_create_developer_tables.sql +67 -0
  210. package/scripts/migrations/011_fix_keeper_tables.sql +85 -0
  211. package/scripts/migrations/012_create_developer_webhooks.sql +31 -0
  212. package/scripts/migrations/013_add_network_mode.sql +18 -0
  213. package/scripts/migrations/014_create_developer_app_users.sql +19 -0
  214. package/scripts/migrations/015_add_ui_config.sql +4 -0
  215. package/scripts/migrations/016_add_resolution_secret.sql +4 -0
  216. package/scripts/migrations/017_add_external_game_id.sql +3 -0
  217. package/scripts/migrations/018_create_pickem_tables.sql +115 -0
  218. package/scripts/migrations/019_expo_push_tokens.sql +19 -0
  219. package/scripts/migrations/create_whats_new_tables.sql +88 -0
  220. package/scripts/migrations/drop_live_games_tables.sql +34 -0
  221. package/scripts/open-jackpot-round.js +85 -0
  222. package/scripts/purge-all-data.sh +329 -0
  223. package/scripts/purge-all-data.sql +142 -0
  224. package/scripts/purge-heroku-data.sh +149 -0
  225. package/scripts/purge-heroku-data.sql +62 -0
  226. package/scripts/rebuild-heroku-database.sh +113 -0
  227. package/scripts/recover-funds.js +357 -0
  228. package/scripts/regenerate-epl-images.js +278 -0
  229. package/scripts/resize-s3-matchup-images.js +374 -0
  230. package/scripts/resolve-direct.js +88 -0
  231. package/scripts/resolve-mock-game.js +124 -0
  232. package/scripts/resolve-pickem-game.js +55 -0
  233. package/scripts/resolve-round-manual.js +83 -0
  234. package/scripts/resolve-stuck-game.js +382 -0
  235. package/scripts/resolve-stuck-round.js +42 -0
  236. package/scripts/run-connect4-migration.sh +16 -0
  237. package/scripts/run-mention-migration.sh +32 -0
  238. package/scripts/run-payment-migration.sh +51 -0
  239. package/scripts/run-preferred-currency-migration.sh +31 -0
  240. package/scripts/run-referral-earnings-migration.sh +32 -0
  241. package/scripts/run-survivor-outcome-migration.sh +16 -0
  242. package/scripts/seed-test-users.js +346 -0
  243. package/scripts/setup-auth-tables.js +78 -0
  244. package/scripts/setup-complete-database.sql +992 -0
  245. package/scripts/setup-database-fresh.sh +359 -0
  246. package/scripts/setup-heroku-keeper.sh +48 -0
  247. package/scripts/setup-keeper-database.js +83 -0
  248. package/scripts/setup-keeper-state-db.sql +110 -0
  249. package/scripts/setup-oracle.sh +39 -0
  250. package/scripts/setup-pnl-tracking.js +111 -0
  251. package/scripts/start-devnet.sh +14 -0
  252. package/scripts/test-arcade-devnet.sh +160 -0
  253. package/scripts/test-arcade-match.sh +109 -0
  254. package/scripts/test-automatic-mode.sh +239 -0
  255. package/scripts/test-connect4-cancel-claim.js +370 -0
  256. package/scripts/test-connect4-e2e.js +369 -0
  257. package/scripts/test-connect4-resolve.js +369 -0
  258. package/scripts/test-game-state-endpoint.js +136 -0
  259. package/scripts/test-invite-notification.js +86 -0
  260. package/scripts/test-jackpot-api.sh +71 -0
  261. package/scripts/test-poll-confirmation.js +267 -0
  262. package/scripts/test-resolve-game.js +271 -0
  263. package/scripts/test-resolve-signature.js +223 -0
  264. package/scripts/test-signature-preservation.js +124 -0
  265. package/scripts/test-state-machine.js +291 -0
  266. package/scripts/test-webhook-receiver.js +60 -0
  267. package/scripts/update-notification-constraint.js +52 -0
  268. package/scripts/verify-account-layout.js +145 -0
  269. package/scripts/verify-winner-algorithm.js +278 -0
  270. package/server.js +5259 -0
  271. package/services/arcadeMatchService.js +763 -0
  272. package/services/automaticGameOracle.js +1596 -0
  273. package/services/chatService.js +1612 -0
  274. package/services/connect4GameService.js +1049 -0
  275. package/services/connect4NotificationService.js +374 -0
  276. package/services/cryptoPriceService.js +223 -0
  277. package/services/customGameResolver.js +260 -0
  278. package/services/db.js +79 -0
  279. package/services/directMessageService.js +389 -0
  280. package/services/discordNotifications.js +160 -0
  281. package/services/exchangeRateService.js +289 -0
  282. package/services/expoPushService.js +314 -0
  283. package/services/gamesCacheService.js +539 -0
  284. package/services/jackpotHistory.js +331 -0
  285. package/services/jackpotService.js +856 -0
  286. package/services/keeperStateService.js +355 -0
  287. package/services/matchupImageService.js +591 -0
  288. package/services/notificationCacheService.js +407 -0
  289. package/services/pickemOracle.js +440 -0
  290. package/services/playerStatsService.js +389 -0
  291. package/services/portfolioService.js +555 -0
  292. package/services/promoService.js +757 -0
  293. package/services/promoTreasuryService.js +239 -0
  294. package/services/pushNotifications.js +353 -0
  295. package/services/redisService.js +422 -0
  296. package/services/referralEarningsService.js +728 -0
  297. package/services/s3Service.js +396 -0
  298. package/services/socialService.js +1202 -0
  299. package/services/survivorOracle.js +469 -0
  300. package/services/survivorSimulator.js +475 -0
  301. package/services/telegramNotifications.js +461 -0
  302. package/services/userProfileStatsService.js +1185 -0
  303. package/services/whatsNewService.js +388 -0
  304. package/utils/urlHelper.js +95 -0
@@ -0,0 +1,346 @@
1
+ /**
2
+ * Seed script to generate 100 test users with different game interests
3
+ * Run with: node scripts/seed-test-users.js
4
+ */
5
+
6
+ const { Pool } = require('pg');
7
+
8
+ const pool = new Pool({
9
+ connectionString: process.env.DATABASE_URL || 'postgresql://adamdahan@localhost:5432/dubs_db',
10
+ });
11
+
12
+ // Sample data for generating users
13
+ const FIRST_NAMES = [
14
+ 'Alex', 'Jordan', 'Taylor', 'Morgan', 'Casey', 'Riley', 'Quinn', 'Avery',
15
+ 'Blake', 'Cameron', 'Dakota', 'Drew', 'Ellis', 'Finley', 'Gray', 'Harper',
16
+ 'Jaden', 'Kai', 'Lane', 'Max', 'Noah', 'Parker', 'Reese', 'Sage', 'Skyler',
17
+ 'Tyler', 'Val', 'Wren', 'Zion', 'River', 'Phoenix', 'Storm', 'Ash', 'Bay'
18
+ ];
19
+
20
+ const LAST_NAMES = [
21
+ 'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis',
22
+ 'Rodriguez', 'Martinez', 'Hernandez', 'Lopez', 'Gonzalez', 'Wilson', 'Anderson',
23
+ 'Thomas', 'Taylor', 'Moore', 'Jackson', 'Martin', 'Lee', 'Perez', 'Thompson',
24
+ 'White', 'Harris', 'Sanchez', 'Clark', 'Ramirez', 'Lewis', 'Robinson'
25
+ ];
26
+
27
+ const SUFFIXES = ['_sol', '_crypto', '_degen', '_wagr', '_bet', '_play', '_game', '_pro', '_dev', ''];
28
+
29
+ // Sports events for creating games
30
+ const SPORTS_EVENTS = {
31
+ NBA: [
32
+ { home: 'Lakers', away: 'Celtics', league: 'NBA' },
33
+ { home: 'Warriors', away: 'Heat', league: 'NBA' },
34
+ { home: 'Bulls', away: 'Knicks', league: 'NBA' },
35
+ { home: 'Nets', away: 'Suns', league: 'NBA' },
36
+ { home: 'Bucks', away: 'Sixers', league: 'NBA' },
37
+ ],
38
+ NHL: [
39
+ { home: 'Bruins', away: 'Rangers', league: 'NHL' },
40
+ { home: 'Maple Leafs', away: 'Canadiens', league: 'NHL' },
41
+ { home: 'Penguins', away: 'Capitals', league: 'NHL' },
42
+ { home: 'Lightning', away: 'Panthers', league: 'NHL' },
43
+ ],
44
+ NFL: [
45
+ { home: 'Chiefs', away: 'Eagles', league: 'NFL' },
46
+ { home: 'Bills', away: 'Cowboys', league: 'NFL' },
47
+ { home: '49ers', away: 'Dolphins', league: 'NFL' },
48
+ { home: 'Ravens', away: 'Lions', league: 'NFL' },
49
+ ],
50
+ EPL: [
51
+ { home: 'Liverpool', away: 'Man City', league: 'English Premier League' },
52
+ { home: 'Arsenal', away: 'Chelsea', league: 'English Premier League' },
53
+ { home: 'Man United', away: 'Tottenham', league: 'English Premier League' },
54
+ ],
55
+ UFC: [
56
+ { home: 'Fighter A', away: 'Fighter B', league: 'UFC' },
57
+ { home: 'Fighter C', away: 'Fighter D', league: 'UFC' },
58
+ ],
59
+ };
60
+
61
+ // Generate a random wallet address
62
+ function generateWalletAddress() {
63
+ const chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
64
+ let result = '';
65
+ for (let i = 0; i < 44; i++) {
66
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
67
+ }
68
+ return result;
69
+ }
70
+
71
+ // Generate a unique username
72
+ function generateUsername(index) {
73
+ const firstName = FIRST_NAMES[Math.floor(Math.random() * FIRST_NAMES.length)];
74
+ const lastName = LAST_NAMES[Math.floor(Math.random() * LAST_NAMES.length)];
75
+ const suffix = SUFFIXES[Math.floor(Math.random() * SUFFIXES.length)];
76
+ const num = Math.floor(Math.random() * 100);
77
+ return `${firstName}${lastName}${num}${suffix}`.toLowerCase().slice(0, 20);
78
+ }
79
+
80
+ // Generate a random avatar URL using DiceBear
81
+ function generateAvatar(index) {
82
+ const styles = ['adventurer', 'avataaars', 'bottts', 'fun-emoji', 'lorelei', 'micah', 'miniavs', 'personas'];
83
+ const style = styles[Math.floor(Math.random() * styles.length)];
84
+ return `https://api.dicebear.com/7.x/${style}/svg?seed=${index}`;
85
+ }
86
+
87
+ // Generate a game ID
88
+ function generateGameId(type, index) {
89
+ return `test-${type}-${Date.now()}-${index}`;
90
+ }
91
+
92
+ async function seedTestUsers() {
93
+ const client = await pool.connect();
94
+
95
+ try {
96
+ console.log('🌱 Starting seed script...\n');
97
+
98
+ await client.query('BEGIN');
99
+
100
+ // 1. Create test games for each category
101
+ console.log('šŸ“¦ Creating test games...');
102
+ const gameIds = {
103
+ NBA: [],
104
+ NHL: [],
105
+ NFL: [],
106
+ EPL: [],
107
+ UFC: [],
108
+ connect4: [],
109
+ };
110
+
111
+ // Create sports games
112
+ for (const [category, events] of Object.entries(SPORTS_EVENTS)) {
113
+ for (let i = 0; i < events.length; i++) {
114
+ const event = events[i];
115
+ const gameId = generateGameId(category.toLowerCase(), i);
116
+ const gameAddress = generateWalletAddress();
117
+
118
+ await client.query(`
119
+ INSERT INTO games (game_id, game_address, title, game_type, created_by, sports_event, is_resolved, created_at)
120
+ VALUES ($1, $2, $3, 'sports', $4, $5, true, NOW() - interval '${Math.floor(Math.random() * 30)} days')
121
+ ON CONFLICT (game_id) DO NOTHING
122
+ `, [
123
+ gameId,
124
+ gameAddress,
125
+ `${event.home} vs ${event.away}`,
126
+ generateWalletAddress(),
127
+ JSON.stringify({
128
+ strLeague: event.league,
129
+ strHomeTeam: event.home,
130
+ strAwayTeam: event.away,
131
+ strSport: category === 'EPL' ? 'Soccer' : category === 'NHL' ? 'Ice Hockey' : category === 'NFL' ? 'American Football' : category === 'UFC' ? 'Fighting' : 'Basketball',
132
+ }),
133
+ ]);
134
+
135
+ gameIds[category].push(gameId);
136
+ }
137
+ }
138
+
139
+ // Create connect4 games
140
+ for (let i = 0; i < 5; i++) {
141
+ const gameId = generateGameId('connect4', i);
142
+ const gameAddress = generateWalletAddress();
143
+
144
+ await client.query(`
145
+ INSERT INTO games (game_id, game_address, title, game_type, created_by, is_resolved, created_at)
146
+ VALUES ($1, $2, 'Connect4 Game', 'connect4', $3, true, NOW() - interval '${Math.floor(Math.random() * 30)} days')
147
+ ON CONFLICT (game_id) DO NOTHING
148
+ `, [gameId, gameAddress, generateWalletAddress()]);
149
+
150
+ gameIds.connect4.push(gameId);
151
+ }
152
+
153
+ console.log(` Created ${Object.values(gameIds).flat().length} test games\n`);
154
+
155
+ // 2. Create 100 test users with different interests
156
+ console.log('šŸ‘„ Creating 100 test users...');
157
+
158
+ const users = [];
159
+ const usedUsernames = new Set();
160
+
161
+ for (let i = 0; i < 100; i++) {
162
+ let username = generateUsername(i);
163
+ while (usedUsernames.has(username)) {
164
+ username = generateUsername(i) + Math.floor(Math.random() * 1000);
165
+ }
166
+ usedUsernames.add(username);
167
+
168
+ const walletAddress = generateWalletAddress();
169
+ const avatar = generateAvatar(i);
170
+
171
+ const result = await client.query(`
172
+ INSERT INTO users (wallet_address, username, avatar, created_at)
173
+ VALUES ($1, $2, $3, NOW() - interval '${Math.floor(Math.random() * 60)} days')
174
+ ON CONFLICT (wallet_address) DO UPDATE SET username = EXCLUDED.username
175
+ RETURNING id, wallet_address, username
176
+ `, [walletAddress, username, avatar]);
177
+
178
+ users.push(result.rows[0]);
179
+
180
+ if ((i + 1) % 20 === 0) {
181
+ console.log(` Created ${i + 1}/100 users...`);
182
+ }
183
+ }
184
+
185
+ console.log(` Created ${users.length} test users\n`);
186
+
187
+ // 3. Assign users to games with different interest distributions
188
+ console.log('šŸŽ® Assigning users to games (creating interests)...');
189
+
190
+ // Interest distribution:
191
+ // - 30% NBA fans (some overlap with other sports)
192
+ // - 25% NHL fans
193
+ // - 25% NFL fans
194
+ // - 20% Soccer (EPL) fans
195
+ // - 15% UFC fans
196
+ // - 20% Connect4 players
197
+ // - 15% will have no games (new users)
198
+
199
+ let gameRefsCreated = 0;
200
+
201
+ for (let i = 0; i < users.length; i++) {
202
+ const user = users[i];
203
+ const rand = Math.random();
204
+
205
+ // 15% of users are "new" with no game history
206
+ if (rand < 0.15) {
207
+ continue;
208
+ }
209
+
210
+ // Randomly assign interests
211
+ const interests = [];
212
+
213
+ if (Math.random() < 0.30) interests.push('NBA');
214
+ if (Math.random() < 0.25) interests.push('NHL');
215
+ if (Math.random() < 0.25) interests.push('NFL');
216
+ if (Math.random() < 0.20) interests.push('EPL');
217
+ if (Math.random() < 0.15) interests.push('UFC');
218
+ if (Math.random() < 0.20) interests.push('connect4');
219
+
220
+ // Ensure at least one interest if not a "new" user
221
+ if (interests.length === 0) {
222
+ const categories = ['NBA', 'NHL', 'NFL', 'EPL', 'UFC', 'connect4'];
223
+ interests.push(categories[Math.floor(Math.random() * categories.length)]);
224
+ }
225
+
226
+ // Create game refs for each interest
227
+ for (const interest of interests) {
228
+ const categoryGames = gameIds[interest];
229
+ // Join 1-3 random games in each category
230
+ const numGames = Math.min(Math.floor(Math.random() * 3) + 1, categoryGames.length);
231
+ const shuffledGames = [...categoryGames].sort(() => Math.random() - 0.5);
232
+
233
+ for (let j = 0; j < numGames; j++) {
234
+ const gameId = shuffledGames[j];
235
+ const daysAgo = Math.floor(Math.random() * 30);
236
+
237
+ await client.query(`
238
+ INSERT INTO user_game_refs (wallet_address, game_id, role, team_choice, joined_at, created_at)
239
+ VALUES ($1, $2, 'player', $3, NOW() - interval '${daysAgo} days', NOW() - interval '${daysAgo} days')
240
+ ON CONFLICT (wallet_address, game_id) DO NOTHING
241
+ `, [user.wallet_address, gameId, Math.random() > 0.5 ? 'home' : 'away']);
242
+
243
+ gameRefsCreated++;
244
+ }
245
+ }
246
+ }
247
+
248
+ console.log(` Created ${gameRefsCreated} game participation records\n`);
249
+
250
+ // 4. Create sports_betting_stats for some users (top players)
251
+ console.log('šŸ† Creating sports betting stats (for Top Players)...');
252
+
253
+ // Pick random users to be "top players" with wins
254
+ const topSportsPlayers = users.slice(0, 20); // First 20 users get sports stats
255
+ for (let i = 0; i < topSportsPlayers.length; i++) {
256
+ const user = topSportsPlayers[i];
257
+ const wins = Math.floor(Math.random() * 15) + 1; // 1-15 wins
258
+ const losses = Math.floor(Math.random() * 10); // 0-9 losses
259
+ const totalWagered = (wins + losses) * (Math.random() * 0.5 + 0.1); // Random SOL wagered
260
+ const totalWon = wins * (Math.random() * 0.8 + 0.2);
261
+
262
+ await client.query(`
263
+ INSERT INTO sports_betting_stats (
264
+ wallet_address, games_created, games_joined, games_won, games_lost,
265
+ total_wagered_sol, total_won_sol, net_pnl_sol, last_played_at
266
+ )
267
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW() - interval '${Math.floor(Math.random() * 7)} days')
268
+ ON CONFLICT (wallet_address) DO UPDATE SET
269
+ games_won = EXCLUDED.games_won,
270
+ games_lost = EXCLUDED.games_lost,
271
+ total_wagered_sol = EXCLUDED.total_wagered_sol,
272
+ total_won_sol = EXCLUDED.total_won_sol
273
+ `, [
274
+ user.wallet_address,
275
+ Math.floor(Math.random() * 5),
276
+ wins + losses,
277
+ wins,
278
+ losses,
279
+ totalWagered.toFixed(4),
280
+ totalWon.toFixed(4),
281
+ (totalWon - totalWagered).toFixed(4)
282
+ ]);
283
+ }
284
+ console.log(` Created sports stats for ${topSportsPlayers.length} users\n`);
285
+
286
+ // 5. Update some connect4 games to have winners
287
+ console.log('šŸ”“ Updating connect4 games with winners...');
288
+ const connect4Games = gameIds.connect4;
289
+ for (const gameId of connect4Games) {
290
+ const winner = Math.random() > 0.5 ? 'red' : 'yellow';
291
+ await client.query(`
292
+ UPDATE games SET connect4_winner = $1, is_resolved = true WHERE game_id = $2
293
+ `, [winner, gameId]);
294
+ }
295
+ console.log(` Updated ${connect4Games.length} connect4 games with winners\n`);
296
+
297
+ await client.query('COMMIT');
298
+
299
+ // 4. Print summary
300
+ console.log('šŸ“Š Summary:');
301
+
302
+ const categoryCounts = await client.query(`
303
+ WITH category_counts AS (
304
+ SELECT
305
+ CASE
306
+ WHEN g.game_type = 'connect4' THEN 'connect4'
307
+ WHEN g.sports_event->>'strLeague' = 'NBA' THEN 'NBA'
308
+ WHEN g.sports_event->>'strLeague' = 'NHL' THEN 'NHL'
309
+ WHEN g.sports_event->>'strLeague' = 'NFL' THEN 'NFL'
310
+ WHEN g.sports_event->>'strLeague' = 'UFC' THEN 'UFC'
311
+ WHEN g.sports_event->>'strLeague' = 'English Premier League' THEN 'EPL'
312
+ ELSE NULL
313
+ END as category,
314
+ COUNT(DISTINCT ugr.wallet_address) as user_count
315
+ FROM user_game_refs ugr
316
+ JOIN games g ON g.game_id = ugr.game_id
317
+ GROUP BY 1
318
+ )
319
+ SELECT category, user_count FROM category_counts WHERE category IS NOT NULL ORDER BY user_count DESC
320
+ `);
321
+
322
+ const newUsersCount = await client.query(`
323
+ SELECT COUNT(*) as count FROM users u
324
+ WHERE NOT EXISTS (SELECT 1 FROM user_game_refs ugr WHERE ugr.wallet_address = u.wallet_address)
325
+ `);
326
+
327
+ console.log(' Users by interest:');
328
+ for (const row of categoryCounts.rows) {
329
+ const emoji = { NBA: 'šŸ€', NHL: 'šŸ’', NFL: 'šŸˆ', EPL: '⚽', UFC: '🄊', connect4: 'šŸ”“' }[row.category] || 'ā“';
330
+ console.log(` ${emoji} ${row.category}: ${row.user_count} users`);
331
+ }
332
+ console.log(` šŸ‘‹ New Users (no games): ${newUsersCount.rows[0].count} users`);
333
+
334
+ console.log('\nāœ… Seed complete! Refresh your Social page to see the users.');
335
+
336
+ } catch (error) {
337
+ await client.query('ROLLBACK');
338
+ console.error('āŒ Error seeding database:', error);
339
+ throw error;
340
+ } finally {
341
+ client.release();
342
+ await pool.end();
343
+ }
344
+ }
345
+
346
+ seedTestUsers().catch(console.error);
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Setup auth tables in Postgres
3
+ * Run with: node scripts/setup-auth-tables.js
4
+ */
5
+
6
+ const { Client } = require('pg');
7
+ require('dotenv').config();
8
+
9
+ const DATABASE_URL = process.env.DATABASE_URL;
10
+
11
+ if (!DATABASE_URL) {
12
+ console.error('āŒ DATABASE_URL environment variable not set');
13
+ console.log(' Add it to your .env file or set it in your environment');
14
+ process.exit(1);
15
+ }
16
+
17
+ async function setupTables() {
18
+ const client = new Client({
19
+ connectionString: DATABASE_URL,
20
+ ssl: DATABASE_URL.includes('amazonaws') || DATABASE_URL.includes('heroku')
21
+ ? { rejectUnauthorized: false }
22
+ : undefined
23
+ });
24
+
25
+ try {
26
+ await client.connect();
27
+ console.log('āœ… Connected to database');
28
+
29
+ // Create users table
30
+ await client.query(`
31
+ CREATE TABLE IF NOT EXISTS users (
32
+ id SERIAL PRIMARY KEY,
33
+ wallet_address VARCHAR(44) UNIQUE NOT NULL,
34
+ email VARCHAR(255),
35
+ username VARCHAR(50) NOT NULL,
36
+ avatar TEXT,
37
+ referral_code VARCHAR(50),
38
+ signature TEXT,
39
+ onboarding_complete BOOLEAN DEFAULT false,
40
+ created_at TIMESTAMP DEFAULT NOW(),
41
+ updated_at TIMESTAMP DEFAULT NOW()
42
+ );
43
+ `);
44
+ console.log('āœ… Created users table');
45
+
46
+ // Create auth_nonces table
47
+ await client.query(`
48
+ CREATE TABLE IF NOT EXISTS auth_nonces (
49
+ wallet_address VARCHAR(44) PRIMARY KEY,
50
+ nonce VARCHAR(64) NOT NULL,
51
+ expires_at TIMESTAMP NOT NULL,
52
+ used BOOLEAN DEFAULT false,
53
+ created_at TIMESTAMP DEFAULT NOW()
54
+ );
55
+ `);
56
+ console.log('āœ… Created auth_nonces table');
57
+
58
+ // Create indexes
59
+ await client.query('CREATE INDEX IF NOT EXISTS idx_users_wallet ON users(wallet_address)');
60
+ await client.query('CREATE INDEX IF NOT EXISTS idx_users_username ON users(username)');
61
+ await client.query('CREATE INDEX IF NOT EXISTS idx_nonces_expires ON auth_nonces(expires_at)');
62
+ console.log('āœ… Created indexes');
63
+
64
+ console.log('\nšŸŽ‰ Auth tables setup complete!');
65
+ console.log('\nTables created:');
66
+ console.log(' - users (user profiles)');
67
+ console.log(' - auth_nonces (signature verification)');
68
+
69
+ } catch (error) {
70
+ console.error('āŒ Error setting up tables:', error.message);
71
+ process.exit(1);
72
+ } finally {
73
+ await client.end();
74
+ }
75
+ }
76
+
77
+ setupTables();
78
+