@pokertools/engine 1.0.7 → 1.0.9

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 (50) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/actions/betting.js +8 -8
  3. package/dist/actions/dealing.js +6 -4
  4. package/dist/actions/management.js +3 -0
  5. package/dist/actions/{showdownActions.js → showdown-actions.js} +10 -10
  6. package/dist/actions/special.js +20 -3
  7. package/dist/actions/{streetProgression.js → street-progression.js} +7 -7
  8. package/dist/actions/validation.js +48 -27
  9. package/dist/browser.d.ts +5 -5
  10. package/dist/browser.js +6 -6
  11. package/dist/engine/{gameReducer.js → game-reducer.js} +11 -8
  12. package/dist/engine/{PokerEngine.js → poker-engine.js} +10 -10
  13. package/dist/errors/{ConfigError.d.ts → config-error.d.ts} +1 -1
  14. package/dist/errors/{ConfigError.js → config-error.js} +2 -2
  15. package/dist/errors/{CriticalStateError.d.ts → critical-state-error.d.ts} +1 -1
  16. package/dist/errors/{CriticalStateError.js → critical-state-error.js} +2 -2
  17. package/dist/errors/{IllegalActionError.d.ts → illegal-action-error.d.ts} +2 -2
  18. package/dist/errors/{IllegalActionError.js → illegal-action-error.js} +2 -2
  19. package/dist/errors/index.d.ts +4 -4
  20. package/dist/errors/index.js +4 -4
  21. package/dist/history/exporter.js +4 -4
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.js +4 -4
  24. package/dist/rules/{actionOrder.js → action-order.js} +10 -10
  25. package/dist/rules/blinds.js +2 -2
  26. package/dist/rules/showdown.js +34 -1
  27. package/dist/rules/{sidePots.js → side-pots.js} +2 -2
  28. package/dist/utils/invariants.js +16 -10
  29. package/dist/utils/serialization.d.ts +1 -0
  30. package/dist/utils/serialization.js +9 -3
  31. package/dist/utils/validation.js +8 -8
  32. package/dist/utils/{viewMasking.js → view-masking.js} +16 -6
  33. package/package.json +5 -5
  34. /package/dist/actions/{showdownActions.d.ts → showdown-actions.d.ts} +0 -0
  35. /package/dist/actions/{streetProgression.d.ts → street-progression.d.ts} +0 -0
  36. /package/dist/engine/{gameReducer.d.ts → game-reducer.d.ts} +0 -0
  37. /package/dist/engine/{PokerEngine.d.ts → poker-engine.d.ts} +0 -0
  38. /package/dist/errors/{ErrorCodes.d.ts → error-codes.d.ts} +0 -0
  39. /package/dist/errors/{ErrorCodes.js → error-codes.js} +0 -0
  40. /package/dist/errors/{PokerEngineError.d.ts → poker-engine-error.d.ts} +0 -0
  41. /package/dist/errors/{PokerEngineError.js → poker-engine-error.js} +0 -0
  42. /package/dist/history/{handHistoryBuilder.d.ts → hand-history-builder.d.ts} +0 -0
  43. /package/dist/history/{handHistoryBuilder.js → hand-history-builder.js} +0 -0
  44. /package/dist/rules/{actionOrder.d.ts → action-order.d.ts} +0 -0
  45. /package/dist/rules/{headsUp.d.ts → heads-up.d.ts} +0 -0
  46. /package/dist/rules/{headsUp.js → heads-up.js} +0 -0
  47. /package/dist/rules/{sidePots.d.ts → side-pots.d.ts} +0 -0
  48. /package/dist/utils/{cardUtils.d.ts → card-utils.d.ts} +0 -0
  49. /package/dist/utils/{cardUtils.js → card-utils.js} +0 -0
  50. /package/dist/utils/{viewMasking.d.ts → view-masking.d.ts} +0 -0
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.progressStreet = progressStreet;
4
4
  exports.shouldProgressStreet = shouldProgressStreet;
5
5
  const deck_1 = require("../utils/deck");
6
- const cardUtils_1 = require("../utils/cardUtils");
7
- const actionOrder_1 = require("../rules/actionOrder");
6
+ const card_utils_1 = require("../utils/card-utils");
7
+ const action_order_1 = require("../rules/action-order");
8
8
  /**
9
9
  * Progress to next street
10
10
  * - Collects bets into pots
@@ -38,7 +38,7 @@ function progressStreet(state) {
38
38
  // Keep timestamp from last action (street progression is not a user action)
39
39
  };
40
40
  // Set first to act
41
- const firstToAct = (0, actionOrder_1.getFirstToAct)(newState);
41
+ const firstToAct = (0, action_order_1.getFirstToAct)(newState);
42
42
  return {
43
43
  ...newState,
44
44
  actionTo: firstToAct,
@@ -69,21 +69,21 @@ function dealCommunityCards(state, street) {
69
69
  // Burn 1, deal 3
70
70
  const [flopCards, flopDeck] = (0, deck_1.burnAndDeal)(deck, 3);
71
71
  return {
72
- board: [...currentBoard, ...(0, cardUtils_1.cardCodesToStrings)(flopCards)],
72
+ board: [...currentBoard, ...(0, card_utils_1.cardCodesToStrings)(flopCards)],
73
73
  deck: flopDeck,
74
74
  };
75
75
  case "TURN" /* Street.TURN */:
76
76
  // Burn 1, deal 1
77
77
  const [turnCards, turnDeck] = (0, deck_1.burnAndDeal)(deck, 1);
78
78
  return {
79
- board: [...currentBoard, ...(0, cardUtils_1.cardCodesToStrings)(turnCards)],
79
+ board: [...currentBoard, ...(0, card_utils_1.cardCodesToStrings)(turnCards)],
80
80
  deck: turnDeck,
81
81
  };
82
82
  case "RIVER" /* Street.RIVER */:
83
83
  // Burn 1, deal 1
84
84
  const [riverCards, riverDeck] = (0, deck_1.burnAndDeal)(deck, 1);
85
85
  return {
86
- board: [...currentBoard, ...(0, cardUtils_1.cardCodesToStrings)(riverCards)],
86
+ board: [...currentBoard, ...(0, card_utils_1.cardCodesToStrings)(riverCards)],
87
87
  deck: riverDeck,
88
88
  };
89
89
  default:
@@ -153,5 +153,5 @@ function shouldProgressStreet(state) {
153
153
  return false; // Already at showdown
154
154
  }
155
155
  // Check if all active players have acted
156
- return (0, actionOrder_1.isActionComplete)(state);
156
+ return (0, action_order_1.isActionComplete)(state);
157
157
  }
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validateAction = validateAction;
4
- const IllegalActionError_1 = require("../errors/IllegalActionError");
5
- const ErrorCodes_1 = require("../errors/ErrorCodes");
4
+ const illegal_action_error_1 = require("../errors/illegal-action-error");
5
+ const error_codes_1 = require("../errors/error-codes");
6
6
  const positioning_1 = require("../utils/positioning");
7
7
  /**
8
8
  * Validate that an action is legal in the current game state
@@ -44,16 +44,16 @@ function validateAction(state, action) {
44
44
  }
45
45
  function validateBettingAction(state, action) {
46
46
  if (!("playerId" in action)) {
47
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.INVALID_ACTION, "Action missing playerId");
47
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.INVALID_ACTION, "Action missing playerId");
48
48
  }
49
49
  const result = (0, positioning_1.getPlayerById)(state, action.playerId);
50
50
  if (!result) {
51
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.PLAYER_NOT_FOUND, `Player ${action.playerId} not found`, { playerId: action.playerId });
51
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.PLAYER_NOT_FOUND, `Player ${action.playerId} not found`, { playerId: action.playerId });
52
52
  }
53
53
  const { player, seat } = result;
54
54
  // Check if it's player's turn
55
55
  if (state.actionTo !== seat) {
56
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.NOT_YOUR_TURN, `Player ${action.playerId} attempted to act, but action is on seat ${state.actionTo}`, {
56
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.NOT_YOUR_TURN, `Player ${action.playerId} attempted to act, but action is on seat ${state.actionTo}`, {
57
57
  playerId: action.playerId,
58
58
  playerSeat: seat,
59
59
  actionTo: state.actionTo,
@@ -62,11 +62,11 @@ function validateBettingAction(state, action) {
62
62
  }
63
63
  // Check player status
64
64
  if (player.status !== "ACTIVE" /* PlayerStatus.ACTIVE */) {
65
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.PLAYER_NOT_ACTIVE, `Player ${action.playerId} cannot act with status ${player.status}`, { playerId: action.playerId, status: player.status });
65
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.PLAYER_NOT_ACTIVE, `Player ${action.playerId} cannot act with status ${player.status}`, { playerId: action.playerId, status: player.status });
66
66
  }
67
67
  // Check player has chips
68
68
  if (player.stack === 0 && action.type !== "FOLD" /* ActionType.FOLD */) {
69
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.NO_CHIPS, `Player ${action.playerId} has no chips`, {
69
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.NO_CHIPS, `Player ${action.playerId} has no chips`, {
70
70
  playerId: action.playerId,
71
71
  });
72
72
  }
@@ -77,25 +77,29 @@ function validateBettingAction(state, action) {
77
77
  switch (action.type) {
78
78
  case "CHECK" /* ActionType.CHECK */:
79
79
  if (toCall > 0) {
80
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.CANNOT_CHECK, `Player ${action.playerId} cannot check with ${toCall} to call`, { playerId: action.playerId, toCall });
80
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.CANNOT_CHECK, `Player ${action.playerId} cannot check with ${toCall} to call`, { playerId: action.playerId, toCall });
81
81
  }
82
82
  break;
83
83
  case "CALL" /* ActionType.CALL */:
84
84
  if (toCall === 0) {
85
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.NOTHING_TO_CALL, `Player ${action.playerId} has nothing to call`, { playerId: action.playerId });
85
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.NOTHING_TO_CALL, `Player ${action.playerId} has nothing to call`, { playerId: action.playerId });
86
86
  }
87
87
  break;
88
88
  case "BET" /* ActionType.BET */:
89
89
  // Note: We allow BET even when currentBet > 0 because the reducer will auto-convert it to RAISE or CALL
90
90
  // This handles UI implementations that don't distinguish between BET and RAISE buttons
91
91
  if ("amount" in action) {
92
+ if (currentBet > 0) {
93
+ validateBetAsRaise(state, action, seat, playerBet, currentBet, player.stack);
94
+ break;
95
+ }
92
96
  // Reject bets below the current bet (string bet exploit)
93
- if (currentBet > 0 && action.amount < currentBet) {
94
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.BET_TOO_SMALL, `Bet of ${action.amount} is below current bet ${currentBet}`, { amount: action.amount, currentBet });
97
+ if (action.amount < currentBet) {
98
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.BET_TOO_SMALL, `Bet of ${action.amount} is below current bet ${currentBet}`, { amount: action.amount, currentBet });
95
99
  }
96
100
  // Reject bets below big blind (when no current bet)
97
101
  if (action.amount < state.bigBlind && action.amount < player.stack) {
98
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.BET_TOO_SMALL, `Bet of ${action.amount} is below minimum ${state.bigBlind}`, { amount: action.amount, minimum: state.bigBlind });
102
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.BET_TOO_SMALL, `Bet of ${action.amount} is below minimum ${state.bigBlind}`, { amount: action.amount, minimum: state.bigBlind });
99
103
  }
100
104
  }
101
105
  break;
@@ -104,26 +108,26 @@ function validateBettingAction(state, action) {
104
108
  // intermediate actions (like calls or incomplete all-in raises) did NOT
105
109
  // reopen the betting. Therefore, they cannot re-raise their own bet.
106
110
  if (state.lastAggressorSeat === seat) {
107
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.CANNOT_RERAISE, "Betting has not been re-opened to you (incomplete raise or no action)", {
111
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.CANNOT_RERAISE, "Betting has not been re-opened to you (incomplete raise or no action)", {
108
112
  playerId: action.playerId,
109
113
  seat,
110
114
  lastAggressor: state.lastAggressorSeat,
111
115
  });
112
116
  }
113
117
  if (currentBet === 0) {
114
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.CANNOT_RAISE, `Player ${action.playerId} cannot raise when there's no bet`, { playerId: action.playerId });
118
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.CANNOT_RAISE, `Player ${action.playerId} cannot raise when there's no bet`, { playerId: action.playerId });
115
119
  }
116
120
  if ("amount" in action) {
117
121
  // Check if player is going all-in (incomplete raise exception)
118
122
  const isAllIn = action.amount >= playerBet + player.stack;
119
123
  // Reject raises that don't exceed current bet (unless all-in)
120
124
  if (action.amount <= currentBet && !isAllIn) {
121
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.RAISE_TOO_SMALL, `Raise to ${action.amount} must be greater than current bet ${currentBet}`, { amount: action.amount, currentBet });
125
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.RAISE_TOO_SMALL, `Raise to ${action.amount} must be greater than current bet ${currentBet}`, { amount: action.amount, currentBet });
122
126
  }
123
127
  // Check minimum raise requirement (unless player is going all-in)
124
128
  const raiseIncrement = action.amount - currentBet;
125
129
  if (!isAllIn && action.amount < state.minRaise) {
126
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.RAISE_TOO_SMALL, `Raise to ${action.amount} is below minimum ${state.minRaise}`, {
130
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.RAISE_TOO_SMALL, `Raise to ${action.amount} is below minimum ${state.minRaise}`, {
127
131
  amount: action.amount,
128
132
  currentBet,
129
133
  raiseIncrement,
@@ -134,63 +138,80 @@ function validateBettingAction(state, action) {
134
138
  break;
135
139
  }
136
140
  }
141
+ function validateBetAsRaise(state, action, seat, playerBet, currentBet, playerStack) {
142
+ if (!("amount" in action))
143
+ return;
144
+ const amount = action.amount;
145
+ if (typeof amount !== "number")
146
+ return;
147
+ if (state.lastAggressorSeat === seat) {
148
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.CANNOT_RERAISE, "Betting has not been re-opened to you (incomplete raise or no action)", { playerId: action.playerId, seat, lastAggressor: state.lastAggressorSeat });
149
+ }
150
+ const isAllIn = amount >= playerBet + playerStack;
151
+ if (amount <= currentBet && !isAllIn) {
152
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.RAISE_TOO_SMALL, `Raise to ${amount} must be greater than current bet ${currentBet}`, { amount, currentBet });
153
+ }
154
+ if (!isAllIn && amount < state.minRaise) {
155
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.RAISE_TOO_SMALL, `Raise to ${amount} is below minimum ${state.minRaise}`, { amount, currentBet, minRaise: state.minRaise });
156
+ }
157
+ }
137
158
  function validateDealAction(state) {
138
159
  if (state.street !== "PREFLOP" /* Street.PREFLOP */ || state.handNumber > 0) {
139
160
  // Allow dealing if we're at showdown (hand complete) or haven't started
140
161
  if (state.street !== "SHOWDOWN" /* Street.SHOWDOWN */ && state.handNumber > 0) {
141
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.CANNOT_DEAL, "Cannot deal while hand is in progress", { street: state.street });
162
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.CANNOT_DEAL, "Cannot deal while hand is in progress", { street: state.street });
142
163
  }
143
164
  }
144
165
  // Check we have enough players
145
166
  const activePlayers = state.players.filter((p) => p && p.stack > 0 && !p.isSittingOut);
146
167
  if (activePlayers.length < 2) {
147
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.NOT_ENOUGH_PLAYERS, `Need at least 2 players to deal, found ${activePlayers.length}`, { playerCount: activePlayers.length });
168
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.NOT_ENOUGH_PLAYERS, `Need at least 2 players to deal, found ${activePlayers.length}`, { playerCount: activePlayers.length });
148
169
  }
149
170
  }
150
171
  function validateSitAction(state, action) {
151
172
  if (action.seat < 0 || action.seat >= state.maxPlayers) {
152
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.INVALID_SEAT, `Seat ${action.seat} is invalid (max: ${state.maxPlayers - 1})`, { seat: action.seat, maxPlayers: state.maxPlayers });
173
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.INVALID_SEAT, `Seat ${action.seat} is invalid (max: ${state.maxPlayers - 1})`, { seat: action.seat, maxPlayers: state.maxPlayers });
153
174
  }
154
175
  const existingPlayer = state.players[action.seat];
155
176
  if (existingPlayer !== null) {
156
177
  // Allow claiming the seat if it is RESERVED by THIS player
157
178
  const isMyReservation = existingPlayer.status === "RESERVED" /* PlayerStatus.RESERVED */ && existingPlayer.id === action.playerId;
158
179
  if (!isMyReservation) {
159
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.SEAT_OCCUPIED, `Seat ${action.seat} is already occupied`, { seat: action.seat });
180
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.SEAT_OCCUPIED, `Seat ${action.seat} is already occupied`, { seat: action.seat });
160
181
  }
161
182
  }
162
183
  if (action.stack <= 0) {
163
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.INVALID_STACK, `Stack must be positive, got ${action.stack}`, { stack: action.stack });
184
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.INVALID_STACK, `Stack must be positive, got ${action.stack}`, { stack: action.stack });
164
185
  }
165
186
  }
166
187
  function validateStandAction(state, action) {
167
188
  const result = (0, positioning_1.getPlayerById)(state, action.playerId);
168
189
  if (!result) {
169
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.PLAYER_NOT_FOUND, `Player ${action.playerId} not found`, { playerId: action.playerId });
190
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.PLAYER_NOT_FOUND, `Player ${action.playerId} not found`, { playerId: action.playerId });
170
191
  }
171
192
  }
172
193
  function validateTimeAction(state, action) {
173
194
  const result = (0, positioning_1.getPlayerById)(state, action.playerId);
174
195
  if (!result) {
175
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.PLAYER_NOT_FOUND, `Player ${action.playerId} not found`, { playerId: action.playerId });
196
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.PLAYER_NOT_FOUND, `Player ${action.playerId} not found`, { playerId: action.playerId });
176
197
  }
177
198
  const { seat } = result;
178
199
  if (state.actionTo !== seat) {
179
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.NOT_YOUR_TURN, `Player ${action.playerId} cannot use time action when it's not their turn`, { playerId: action.playerId, actionTo: state.actionTo });
200
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.NOT_YOUR_TURN, `Player ${action.playerId} cannot use time action when it's not their turn`, { playerId: action.playerId, actionTo: state.actionTo });
180
201
  }
181
202
  }
182
203
  function validateAddChipsAction(state, action) {
183
204
  const result = (0, positioning_1.getPlayerById)(state, action.playerId);
184
205
  if (!result) {
185
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.PLAYER_NOT_FOUND, `Player ${action.playerId} not found`, { playerId: action.playerId });
206
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.PLAYER_NOT_FOUND, `Player ${action.playerId} not found`, { playerId: action.playerId });
186
207
  }
187
208
  }
188
209
  function validateReserveSeatAction(state, action) {
189
210
  if (action.seat < 0 || action.seat >= state.maxPlayers) {
190
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.INVALID_SEAT, `Seat ${action.seat} is invalid (max: ${state.maxPlayers - 1})`, { seat: action.seat, maxPlayers: state.maxPlayers });
211
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.INVALID_SEAT, `Seat ${action.seat} is invalid (max: ${state.maxPlayers - 1})`, { seat: action.seat, maxPlayers: state.maxPlayers });
191
212
  }
192
213
  if (state.players[action.seat] !== null) {
193
- throw new IllegalActionError_1.IllegalActionError(ErrorCodes_1.ErrorCodes.SEAT_OCCUPIED, `Seat ${action.seat} is already occupied`, { seat: action.seat });
214
+ throw new illegal_action_error_1.IllegalActionError(error_codes_1.ErrorCodes.SEAT_OCCUPIED, `Seat ${action.seat} is already occupied`, { seat: action.seat });
194
215
  }
195
216
  }
196
217
  /**
package/dist/browser.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * This file provides a browser-safe RNG using Web Crypto API
5
5
  * and re-exports all engine functionality for use in web applications.
6
6
  */
7
- import { PokerEngine } from "./engine/PokerEngine";
7
+ import { PokerEngine } from "./engine/poker-engine";
8
8
  import type { TableConfig } from "@pokertools/types";
9
9
  /**
10
10
  * Browser-compatible RNG using Web Crypto API
@@ -15,13 +15,13 @@ export declare function getBrowserRNG(): () => number;
15
15
  * Create a PokerEngine instance with browser-compatible RNG
16
16
  */
17
17
  export declare function createBrowserEngine(config: TableConfig): PokerEngine;
18
- export * from "./engine/PokerEngine";
18
+ export * from "./engine/poker-engine";
19
19
  export * from "./actions/betting";
20
20
  export * from "./actions/dealing";
21
21
  export * from "./actions/management";
22
- export * from "./actions/showdownActions";
22
+ export * from "./actions/showdown-actions";
23
23
  export * from "./actions/special";
24
- export * from "./utils/viewMasking";
24
+ export * from "./utils/view-masking";
25
25
  export * from "./utils/serialization";
26
- export * from "./utils/cardUtils";
26
+ export * from "./utils/card-utils";
27
27
  export * from "./history/exporter";
package/dist/browser.js CHANGED
@@ -22,7 +22,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
23
  exports.getBrowserRNG = getBrowserRNG;
24
24
  exports.createBrowserEngine = createBrowserEngine;
25
- const PokerEngine_1 = require("./engine/PokerEngine");
25
+ const poker_engine_1 = require("./engine/poker-engine");
26
26
  /**
27
27
  * Browser-compatible RNG using Web Crypto API
28
28
  * Falls back to Math.random() only in environments without crypto
@@ -55,19 +55,19 @@ function getBrowserRNG() {
55
55
  * Create a PokerEngine instance with browser-compatible RNG
56
56
  */
57
57
  function createBrowserEngine(config) {
58
- return new PokerEngine_1.PokerEngine({
58
+ return new poker_engine_1.PokerEngine({
59
59
  ...config,
60
60
  randomProvider: getBrowserRNG(),
61
61
  });
62
62
  }
63
63
  // Re-export everything from main engine
64
- __exportStar(require("./engine/PokerEngine"), exports);
64
+ __exportStar(require("./engine/poker-engine"), exports);
65
65
  __exportStar(require("./actions/betting"), exports);
66
66
  __exportStar(require("./actions/dealing"), exports);
67
67
  __exportStar(require("./actions/management"), exports);
68
- __exportStar(require("./actions/showdownActions"), exports);
68
+ __exportStar(require("./actions/showdown-actions"), exports);
69
69
  __exportStar(require("./actions/special"), exports);
70
- __exportStar(require("./utils/viewMasking"), exports);
70
+ __exportStar(require("./utils/view-masking"), exports);
71
71
  __exportStar(require("./utils/serialization"), exports);
72
- __exportStar(require("./utils/cardUtils"), exports);
72
+ __exportStar(require("./utils/card-utils"), exports);
73
73
  __exportStar(require("./history/exporter"), exports);
@@ -5,11 +5,11 @@ const validation_1 = require("../actions/validation");
5
5
  const dealing_1 = require("../actions/dealing");
6
6
  const betting_1 = require("../actions/betting");
7
7
  const management_1 = require("../actions/management");
8
- const showdownActions_1 = require("../actions/showdownActions");
8
+ const showdown_actions_1 = require("../actions/showdown-actions");
9
9
  const tournament_1 = require("../actions/tournament");
10
10
  const special_1 = require("../actions/special");
11
- const streetProgression_1 = require("../actions/streetProgression");
12
- const sidePots_1 = require("../rules/sidePots");
11
+ const street_progression_1 = require("../actions/street-progression");
12
+ const side_pots_1 = require("../rules/side-pots");
13
13
  const showdown_1 = require("../rules/showdown");
14
14
  const invariants_1 = require("../utils/invariants");
15
15
  const constants_1 = require("../utils/constants");
@@ -93,10 +93,10 @@ function gameReducer(state, action) {
93
93
  break;
94
94
  // Showdown actions
95
95
  case "SHOW" /* ActionType.SHOW */:
96
- newState = (0, showdownActions_1.handleShow)(state, action);
96
+ newState = (0, showdown_actions_1.handleShow)(state, action);
97
97
  break;
98
98
  case "MUCK" /* ActionType.MUCK */:
99
- newState = (0, showdownActions_1.handleMuck)(state, action);
99
+ newState = (0, showdown_actions_1.handleMuck)(state, action);
100
100
  break;
101
101
  // Special actions
102
102
  case "TIMEOUT" /* ActionType.TIMEOUT */:
@@ -114,10 +114,10 @@ function gameReducer(state, action) {
114
114
  break;
115
115
  }
116
116
  // Check if we should progress to next street
117
- if ((0, streetProgression_1.shouldProgressStreet)(newState)) {
117
+ if ((0, street_progression_1.shouldProgressStreet)(newState)) {
118
118
  // Recalculate pots before progressing
119
- newState = (0, sidePots_1.recalculatePots)(newState);
120
- newState = (0, streetProgression_1.progressStreet)(newState);
119
+ newState = (0, side_pots_1.recalculatePots)(newState);
120
+ newState = (0, street_progression_1.progressStreet)(newState);
121
121
  }
122
122
  // Check if we should go to showdown
123
123
  if ((0, showdown_1.shouldShowdown)(newState)) {
@@ -127,6 +127,9 @@ function gameReducer(state, action) {
127
127
  };
128
128
  newState = (0, showdown_1.determineWinners)(newState);
129
129
  }
130
+ if (newState.actionTo !== null && newState.players[newState.actionTo]?.isSittingOut) {
131
+ newState = { ...newState, actionTo: null };
132
+ }
130
133
  // Audit chip conservation (throws on failure)
131
134
  // Enabled by default, can be disabled via config (not recommended for production)
132
135
  if (newState.config.validateIntegrity !== false) {
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PokerEngine = void 0;
4
- const gameReducer_1 = require("./gameReducer");
5
- const viewMasking_1 = require("../utils/viewMasking");
4
+ const game_reducer_1 = require("./game-reducer");
5
+ const view_masking_1 = require("../utils/view-masking");
6
6
  const serialization_1 = require("../utils/serialization");
7
- const ConfigError_1 = require("../errors/ConfigError");
7
+ const config_error_1 = require("../errors/config-error");
8
8
  const exporter_1 = require("../history/exporter");
9
9
  const validation_1 = require("../utils/validation");
10
10
  /**
@@ -89,7 +89,7 @@ class PokerEngine {
89
89
  // Dry-run the reducer
90
90
  // We don't need to deep clone state because reducer is immutable
91
91
  // and pure, and we discard the result.
92
- (0, gameReducer_1.gameReducer)(this.currentState, action);
92
+ (0, game_reducer_1.gameReducer)(this.currentState, action);
93
93
  return { valid: true };
94
94
  }
95
95
  catch (err) {
@@ -129,7 +129,7 @@ class PokerEngine {
129
129
  optimisticAct(action) {
130
130
  const timestamp = action.timestamp ?? this.timeProvider();
131
131
  const actionWithTimestamp = { ...action, timestamp };
132
- return (0, gameReducer_1.gameReducer)(this.currentState, actionWithTimestamp);
132
+ return (0, game_reducer_1.gameReducer)(this.currentState, actionWithTimestamp);
133
133
  }
134
134
  /**
135
135
  * Undo last action
@@ -152,7 +152,7 @@ class PokerEngine {
152
152
  * Get player view (masked)
153
153
  */
154
154
  view(playerId, version) {
155
- return (0, viewMasking_1.createPublicView)(this.currentState, playerId ?? null, version ?? 0);
155
+ return (0, view_masking_1.createPublicView)(this.currentState, playerId ?? null, version ?? 0);
156
156
  }
157
157
  /**
158
158
  * Get snapshot for serialization
@@ -222,7 +222,7 @@ class PokerEngine {
222
222
  dispatch(action) {
223
223
  const oldState = this.currentState;
224
224
  try {
225
- this.currentState = (0, gameReducer_1.gameReducer)(this.currentState, action);
225
+ this.currentState = (0, game_reducer_1.gameReducer)(this.currentState, action);
226
226
  // Notify listeners
227
227
  for (const listener of this.listeners) {
228
228
  listener(action, oldState, this.currentState);
@@ -238,19 +238,19 @@ class PokerEngine {
238
238
  */
239
239
  validateConfig(config) {
240
240
  if (config.smallBlind <= 0) {
241
- throw new ConfigError_1.ConfigError("Small blind must be positive", {
241
+ throw new config_error_1.ConfigError("Small blind must be positive", {
242
242
  smallBlind: config.smallBlind,
243
243
  });
244
244
  }
245
245
  if (config.bigBlind <= config.smallBlind) {
246
- throw new ConfigError_1.ConfigError("Big blind must be greater than small blind", {
246
+ throw new config_error_1.ConfigError("Big blind must be greater than small blind", {
247
247
  smallBlind: config.smallBlind,
248
248
  bigBlind: config.bigBlind,
249
249
  });
250
250
  }
251
251
  const maxPlayers = config.maxPlayers ?? 9;
252
252
  if (maxPlayers < 2 || maxPlayers > 10) {
253
- throw new ConfigError_1.ConfigError("Max players must be between 2 and 10", {
253
+ throw new config_error_1.ConfigError("Max players must be between 2 and 10", {
254
254
  maxPlayers,
255
255
  });
256
256
  }
@@ -1,4 +1,4 @@
1
- import { PokerEngineError } from "./PokerEngineError";
1
+ import { PokerEngineError } from "./poker-engine-error";
2
2
  /**
3
3
  * Error indicating invalid configuration
4
4
  * Should fail at engine initialization
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ConfigError = void 0;
4
- const PokerEngineError_1 = require("./PokerEngineError");
4
+ const poker_engine_error_1 = require("./poker-engine-error");
5
5
  /**
6
6
  * Error indicating invalid configuration
7
7
  * Should fail at engine initialization
8
8
  */
9
- class ConfigError extends PokerEngineError_1.PokerEngineError {
9
+ class ConfigError extends poker_engine_error_1.PokerEngineError {
10
10
  constructor(message, context = {}) {
11
11
  super("INVALID_CONFIG", message, context);
12
12
  this.name = "ConfigError";
@@ -1,4 +1,4 @@
1
- import { PokerEngineError } from "./PokerEngineError";
1
+ import { PokerEngineError } from "./poker-engine-error";
2
2
  /**
3
3
  * Critical error indicating state corruption or invariant violation
4
4
  * When this occurs, the table should be FROZEN immediately
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CriticalStateError = void 0;
4
- const PokerEngineError_1 = require("./PokerEngineError");
4
+ const poker_engine_error_1 = require("./poker-engine-error");
5
5
  /**
6
6
  * Critical error indicating state corruption or invariant violation
7
7
  * When this occurs, the table should be FROZEN immediately
8
8
  */
9
- class CriticalStateError extends PokerEngineError_1.PokerEngineError {
9
+ class CriticalStateError extends poker_engine_error_1.PokerEngineError {
10
10
  constructor(message, context = {}) {
11
11
  super("CRITICAL_INVARIANT_FAILURE", message, context);
12
12
  this.name = "CriticalStateError";
@@ -1,5 +1,5 @@
1
- import { PokerEngineError } from "./PokerEngineError";
2
- import { ErrorCode } from "./ErrorCodes";
1
+ import { PokerEngineError } from "./poker-engine-error";
2
+ import { ErrorCode } from "./error-codes";
3
3
  /**
4
4
  * Error indicating an illegal or invalid action
5
5
  * Action should be rejected and error sent to client
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.IllegalActionError = void 0;
4
- const PokerEngineError_1 = require("./PokerEngineError");
4
+ const poker_engine_error_1 = require("./poker-engine-error");
5
5
  /**
6
6
  * Error indicating an illegal or invalid action
7
7
  * Action should be rejected and error sent to client
8
8
  */
9
- class IllegalActionError extends PokerEngineError_1.PokerEngineError {
9
+ class IllegalActionError extends poker_engine_error_1.PokerEngineError {
10
10
  constructor(code, message, context = {}) {
11
11
  super(code, message, context);
12
12
  this.name = "IllegalActionError";
@@ -1,4 +1,4 @@
1
- export * from "./PokerEngineError";
2
- export * from "./CriticalStateError";
3
- export * from "./IllegalActionError";
4
- export * from "./ConfigError";
1
+ export * from "./poker-engine-error";
2
+ export * from "./critical-state-error";
3
+ export * from "./illegal-action-error";
4
+ export * from "./config-error";
@@ -15,8 +15,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  // Export all errors
18
- __exportStar(require("./PokerEngineError"), exports);
19
- __exportStar(require("./CriticalStateError"), exports);
20
- __exportStar(require("./IllegalActionError"), exports);
21
- __exportStar(require("./ConfigError"), exports);
18
+ __exportStar(require("./poker-engine-error"), exports);
19
+ __exportStar(require("./critical-state-error"), exports);
20
+ __exportStar(require("./illegal-action-error"), exports);
21
+ __exportStar(require("./config-error"), exports);
22
22
  // ErrorCodes now exported from @pokertools/types
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.exportHandHistory = exportHandHistory;
7
7
  exports.getHandHistory = getHandHistory;
8
8
  exports.exportMultipleHands = exportMultipleHands;
9
- const handHistoryBuilder_1 = require("./handHistoryBuilder");
9
+ const hand_history_builder_1 = require("./hand-history-builder");
10
10
  const pokerstars_1 = require("./formats/pokerstars");
11
11
  const json_1 = require("./formats/json");
12
12
  /**
@@ -18,7 +18,7 @@ const json_1 = require("./formats/json");
18
18
  */
19
19
  function exportHandHistory(state, options = { format: "json" }) {
20
20
  // Build structured history
21
- const history = (0, handHistoryBuilder_1.buildHandHistory)(state);
21
+ const history = (0, hand_history_builder_1.buildHandHistory)(state);
22
22
  // Export to requested format
23
23
  switch (options.format) {
24
24
  case "pokerstars":
@@ -38,7 +38,7 @@ function exportHandHistory(state, options = { format: "json" }) {
38
38
  * @returns Structured hand history object
39
39
  */
40
40
  function getHandHistory(state) {
41
- return (0, handHistoryBuilder_1.buildHandHistory)(state);
41
+ return (0, hand_history_builder_1.buildHandHistory)(state);
42
42
  }
43
43
  /**
44
44
  * Export multiple hands to a single file
@@ -54,7 +54,7 @@ function exportMultipleHands(states, options = { format: "json" }) {
54
54
  }
55
55
  else {
56
56
  // JSON format: array of hands
57
- const histories = states.map((state) => (0, handHistoryBuilder_1.buildHandHistory)(state));
57
+ const histories = states.map((state) => (0, hand_history_builder_1.buildHandHistory)(state));
58
58
  return JSON.stringify(histories, null, options.format === "compact" ? 0 : 2);
59
59
  }
60
60
  }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export { PokerEngine } from "./engine/PokerEngine";
1
+ export { PokerEngine } from "./engine/poker-engine";
2
2
  export * from "@pokertools/types";
3
3
  export * from "./errors";
4
4
  export { createSnapshot, restoreFromSnapshot, Snapshot } from "./utils/serialization";
5
- export { createPublicView } from "./utils/viewMasking";
5
+ export { createPublicView } from "./utils/view-masking";
6
6
  export { calculateTotalChips, auditChipConservation } from "./utils/invariants";
7
7
  export { exportHandHistory, getHandHistory, exportMultipleHands } from "./history/exporter";
8
8
  export { HandHistory, HandHistoryPlayer, StreetHistory, ExportOptions } from "@pokertools/types";
package/dist/index.js CHANGED
@@ -16,8 +16,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.exportMultipleHands = exports.getHandHistory = exports.exportHandHistory = exports.auditChipConservation = exports.calculateTotalChips = exports.createPublicView = exports.restoreFromSnapshot = exports.createSnapshot = exports.PokerEngine = void 0;
18
18
  // Main Engine Class
19
- var PokerEngine_1 = require("./engine/PokerEngine");
20
- Object.defineProperty(exports, "PokerEngine", { enumerable: true, get: function () { return PokerEngine_1.PokerEngine; } });
19
+ var poker_engine_1 = require("./engine/poker-engine");
20
+ Object.defineProperty(exports, "PokerEngine", { enumerable: true, get: function () { return poker_engine_1.PokerEngine; } });
21
21
  // Types (re-exported from @pokertools/types for convenience)
22
22
  __exportStar(require("@pokertools/types"), exports);
23
23
  // Errors
@@ -26,8 +26,8 @@ __exportStar(require("./errors"), exports);
26
26
  var serialization_1 = require("./utils/serialization");
27
27
  Object.defineProperty(exports, "createSnapshot", { enumerable: true, get: function () { return serialization_1.createSnapshot; } });
28
28
  Object.defineProperty(exports, "restoreFromSnapshot", { enumerable: true, get: function () { return serialization_1.restoreFromSnapshot; } });
29
- var viewMasking_1 = require("./utils/viewMasking");
30
- Object.defineProperty(exports, "createPublicView", { enumerable: true, get: function () { return viewMasking_1.createPublicView; } });
29
+ var view_masking_1 = require("./utils/view-masking");
30
+ Object.defineProperty(exports, "createPublicView", { enumerable: true, get: function () { return view_masking_1.createPublicView; } });
31
31
  var invariants_1 = require("./utils/invariants");
32
32
  Object.defineProperty(exports, "calculateTotalChips", { enumerable: true, get: function () { return invariants_1.calculateTotalChips; } });
33
33
  Object.defineProperty(exports, "auditChipConservation", { enumerable: true, get: function () { return invariants_1.auditChipConservation; } });