@pokertools/engine 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 (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +607 -0
  3. package/dist/actions/betting.d.ts +21 -0
  4. package/dist/actions/betting.js +410 -0
  5. package/dist/actions/dealing.d.ts +9 -0
  6. package/dist/actions/dealing.js +206 -0
  7. package/dist/actions/management.d.ts +9 -0
  8. package/dist/actions/management.js +58 -0
  9. package/dist/actions/showdownActions.d.ts +9 -0
  10. package/dist/actions/showdownActions.js +119 -0
  11. package/dist/actions/special.d.ts +14 -0
  12. package/dist/actions/special.js +98 -0
  13. package/dist/actions/streetProgression.d.ts +13 -0
  14. package/dist/actions/streetProgression.js +157 -0
  15. package/dist/actions/tournament.d.ts +5 -0
  16. package/dist/actions/tournament.js +38 -0
  17. package/dist/actions/validation.d.ts +6 -0
  18. package/dist/actions/validation.js +182 -0
  19. package/dist/engine/PokerEngine.d.ts +92 -0
  20. package/dist/engine/PokerEngine.js +246 -0
  21. package/dist/engine/gameReducer.d.ts +10 -0
  22. package/dist/engine/gameReducer.js +135 -0
  23. package/dist/errors/ConfigError.d.ts +8 -0
  24. package/dist/errors/ConfigError.js +15 -0
  25. package/dist/errors/CriticalStateError.d.ts +8 -0
  26. package/dist/errors/CriticalStateError.js +15 -0
  27. package/dist/errors/ErrorCodes.d.ts +38 -0
  28. package/dist/errors/ErrorCodes.js +46 -0
  29. package/dist/errors/IllegalActionError.d.ts +9 -0
  30. package/dist/errors/IllegalActionError.js +15 -0
  31. package/dist/errors/PokerEngineError.d.ts +8 -0
  32. package/dist/errors/PokerEngineError.js +19 -0
  33. package/dist/errors/index.d.ts +5 -0
  34. package/dist/errors/index.js +22 -0
  35. package/dist/history/exporter.d.ts +28 -0
  36. package/dist/history/exporter.js +60 -0
  37. package/dist/history/formats/json.d.ts +14 -0
  38. package/dist/history/formats/json.js +46 -0
  39. package/dist/history/formats/pokerstars.d.ts +10 -0
  40. package/dist/history/formats/pokerstars.js +188 -0
  41. package/dist/history/handHistoryBuilder.d.ts +10 -0
  42. package/dist/history/handHistoryBuilder.js +179 -0
  43. package/dist/history/types.d.ts +73 -0
  44. package/dist/history/types.js +5 -0
  45. package/dist/index.d.ts +8 -0
  46. package/dist/index.js +38 -0
  47. package/dist/rules/actionOrder.d.ts +14 -0
  48. package/dist/rules/actionOrder.js +211 -0
  49. package/dist/rules/blinds.d.ts +24 -0
  50. package/dist/rules/blinds.js +64 -0
  51. package/dist/rules/headsUp.d.ts +15 -0
  52. package/dist/rules/headsUp.js +44 -0
  53. package/dist/rules/showdown.d.ts +9 -0
  54. package/dist/rules/showdown.js +164 -0
  55. package/dist/rules/sidePots.d.ts +32 -0
  56. package/dist/rules/sidePots.js +173 -0
  57. package/dist/tsconfig.tsbuildinfo +1 -0
  58. package/dist/utils/cardUtils.d.ts +12 -0
  59. package/dist/utils/cardUtils.js +30 -0
  60. package/dist/utils/constants.d.ts +38 -0
  61. package/dist/utils/constants.js +41 -0
  62. package/dist/utils/deck.d.ts +46 -0
  63. package/dist/utils/deck.js +126 -0
  64. package/dist/utils/invariants.d.ts +39 -0
  65. package/dist/utils/invariants.js +163 -0
  66. package/dist/utils/positioning.d.ts +36 -0
  67. package/dist/utils/positioning.js +97 -0
  68. package/dist/utils/rake.d.ts +13 -0
  69. package/dist/utils/rake.js +45 -0
  70. package/dist/utils/serialization.d.ts +53 -0
  71. package/dist/utils/serialization.js +106 -0
  72. package/dist/utils/validation.d.ts +20 -0
  73. package/dist/utils/validation.js +52 -0
  74. package/dist/utils/viewMasking.d.ts +20 -0
  75. package/dist/utils/viewMasking.js +90 -0
  76. package/package.json +58 -0
@@ -0,0 +1,92 @@
1
+ import { GameState, TableConfig, Action, PublicState } from "@pokertools/types";
2
+ import { Snapshot } from "../utils/serialization";
3
+ import { HandHistory, ExportOptions } from "../history/types";
4
+ /**
5
+ * Event listener callback type
6
+ */
7
+ type EventListener = (action: Action, oldState: GameState, newState: GameState) => void;
8
+ /**
9
+ * Time provider function type for dependency injection
10
+ */
11
+ type TimeProvider = () => number;
12
+ /**
13
+ * Main Poker Engine class
14
+ * Wraps the pure reducer with a stateful API
15
+ */
16
+ export declare class PokerEngine {
17
+ private currentState;
18
+ private listeners;
19
+ private timeProvider;
20
+ constructor(config: TableConfig, timeProvider?: TimeProvider);
21
+ /**
22
+ * Add a player to the table
23
+ */
24
+ sit(seat: number, id: string, name: string, stack: number): void;
25
+ /**
26
+ * Remove a player from the table
27
+ */
28
+ stand(id: string): void;
29
+ /**
30
+ * Deal a new hand
31
+ */
32
+ deal(): void;
33
+ /**
34
+ * Execute an action
35
+ * If action.timestamp is not provided, the engine will automatically set it
36
+ */
37
+ act(action: Action): GameState;
38
+ /**
39
+ * Undo last action
40
+ */
41
+ undo(): boolean;
42
+ /**
43
+ * Get current game state (full, unmasked)
44
+ */
45
+ get state(): GameState;
46
+ /**
47
+ * Get player view (masked)
48
+ */
49
+ view(playerId?: string): PublicState;
50
+ /**
51
+ * Get snapshot for serialization
52
+ */
53
+ get snapshot(): Snapshot;
54
+ /**
55
+ * Restore from snapshot (static factory method)
56
+ */
57
+ static restore(snapshot: Snapshot): PokerEngine;
58
+ /**
59
+ * Subscribe to state changes
60
+ */
61
+ on(callback: EventListener): () => void;
62
+ /**
63
+ * Advance to next blind level (tournament)
64
+ */
65
+ nextBlindLevel(): void;
66
+ /**
67
+ * Export hand history in specified format
68
+ *
69
+ * @param options Export format options
70
+ * @returns Formatted hand history string
71
+ */
72
+ history(options?: ExportOptions): string;
73
+ /**
74
+ * Get structured hand history object
75
+ *
76
+ * @returns Hand history object
77
+ */
78
+ getHandHistory(): HandHistory;
79
+ /**
80
+ * Dispatch action through reducer
81
+ */
82
+ private dispatch;
83
+ /**
84
+ * Validate configuration
85
+ */
86
+ private validateConfig;
87
+ /**
88
+ * Create initial game state
89
+ */
90
+ private createInitialState;
91
+ }
92
+ export {};
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PokerEngine = void 0;
4
+ const gameReducer_1 = require("./gameReducer");
5
+ const viewMasking_1 = require("../utils/viewMasking");
6
+ const serialization_1 = require("../utils/serialization");
7
+ const ConfigError_1 = require("../errors/ConfigError");
8
+ const exporter_1 = require("../history/exporter");
9
+ const validation_1 = require("../utils/validation");
10
+ /**
11
+ * Main Poker Engine class
12
+ * Wraps the pure reducer with a stateful API
13
+ */
14
+ class PokerEngine {
15
+ constructor(config, timeProvider = () => Date.now()) {
16
+ this.listeners = [];
17
+ // Validate config
18
+ this.validateConfig(config);
19
+ // Initialize time provider
20
+ this.timeProvider = timeProvider;
21
+ // Initialize state
22
+ this.currentState = this.createInitialState(config);
23
+ }
24
+ /**
25
+ * Add a player to the table
26
+ */
27
+ sit(seat, id, name, stack) {
28
+ // Validate chip amount is a non-negative integer
29
+ (0, validation_1.validateChipAmount)(stack, "Sit stack");
30
+ const action = {
31
+ type: "SIT" /* ActionType.SIT */,
32
+ playerId: id,
33
+ playerName: name,
34
+ seat,
35
+ stack,
36
+ timestamp: this.timeProvider(),
37
+ };
38
+ this.dispatch(action);
39
+ }
40
+ /**
41
+ * Remove a player from the table
42
+ */
43
+ stand(id) {
44
+ const action = {
45
+ type: "STAND" /* ActionType.STAND */,
46
+ playerId: id,
47
+ timestamp: this.timeProvider(),
48
+ };
49
+ this.dispatch(action);
50
+ }
51
+ /**
52
+ * Deal a new hand
53
+ */
54
+ deal() {
55
+ const action = {
56
+ type: "DEAL" /* ActionType.DEAL */,
57
+ timestamp: this.timeProvider(),
58
+ };
59
+ this.dispatch(action);
60
+ }
61
+ /**
62
+ * Execute an action
63
+ * If action.timestamp is not provided, the engine will automatically set it
64
+ */
65
+ act(action) {
66
+ // Ensure timestamp is set
67
+ const timestamp = action.timestamp ?? this.timeProvider();
68
+ // Validate timestamp if provided by caller
69
+ if (action.timestamp !== undefined) {
70
+ (0, validation_1.validateTimestamp)(timestamp, this.currentState.timestamp);
71
+ }
72
+ // Validate chip amounts for betting actions
73
+ if ("amount" in action && typeof action.amount === "number") {
74
+ (0, validation_1.validateChipAmount)(action.amount, `${action.type} amount`);
75
+ }
76
+ const actionWithTimestamp = {
77
+ ...action,
78
+ timestamp,
79
+ };
80
+ this.dispatch(actionWithTimestamp);
81
+ return this.currentState;
82
+ }
83
+ /**
84
+ * Undo last action
85
+ */
86
+ undo() {
87
+ if (this.currentState.previousStates.length === 0) {
88
+ return false;
89
+ }
90
+ const previousState = this.currentState.previousStates[this.currentState.previousStates.length - 1];
91
+ this.currentState = previousState;
92
+ return true;
93
+ }
94
+ /**
95
+ * Get current game state (full, unmasked)
96
+ */
97
+ get state() {
98
+ return this.currentState;
99
+ }
100
+ /**
101
+ * Get player view (masked)
102
+ */
103
+ view(playerId) {
104
+ return (0, viewMasking_1.createPublicView)(this.currentState, playerId ?? null);
105
+ }
106
+ /**
107
+ * Get snapshot for serialization
108
+ */
109
+ get snapshot() {
110
+ return (0, serialization_1.createSnapshot)(this.currentState);
111
+ }
112
+ /**
113
+ * Restore from snapshot (static factory method)
114
+ */
115
+ static restore(snapshot) {
116
+ const state = (0, serialization_1.restoreFromSnapshot)(snapshot);
117
+ const engine = new PokerEngine(state.config);
118
+ engine.currentState = state;
119
+ return engine;
120
+ }
121
+ /**
122
+ * Subscribe to state changes
123
+ */
124
+ on(callback) {
125
+ this.listeners.push(callback);
126
+ // Return unsubscribe function
127
+ return () => {
128
+ const index = this.listeners.indexOf(callback);
129
+ if (index > -1) {
130
+ this.listeners.splice(index, 1);
131
+ }
132
+ };
133
+ }
134
+ /**
135
+ * Advance to next blind level (tournament)
136
+ */
137
+ nextBlindLevel() {
138
+ if (!this.currentState.config.blindStructure) {
139
+ return;
140
+ }
141
+ const nextLevel = this.currentState.blindLevel + 1;
142
+ if (nextLevel >= this.currentState.config.blindStructure.length) {
143
+ return; // At max level
144
+ }
145
+ // Dispatch NEXT_BLIND_LEVEL action to notify listeners
146
+ this.dispatch({
147
+ type: "NEXT_BLIND_LEVEL" /* ActionType.NEXT_BLIND_LEVEL */,
148
+ timestamp: this.timeProvider(),
149
+ });
150
+ }
151
+ /**
152
+ * Export hand history in specified format
153
+ *
154
+ * @param options Export format options
155
+ * @returns Formatted hand history string
156
+ */
157
+ history(options) {
158
+ return (0, exporter_1.exportHandHistory)(this.currentState, options);
159
+ }
160
+ /**
161
+ * Get structured hand history object
162
+ *
163
+ * @returns Hand history object
164
+ */
165
+ getHandHistory() {
166
+ return (0, exporter_1.getHandHistory)(this.currentState);
167
+ }
168
+ /**
169
+ * Dispatch action through reducer
170
+ */
171
+ dispatch(action) {
172
+ const oldState = this.currentState;
173
+ try {
174
+ this.currentState = (0, gameReducer_1.gameReducer)(this.currentState, action);
175
+ // Notify listeners
176
+ for (const listener of this.listeners) {
177
+ listener(action, oldState, this.currentState);
178
+ }
179
+ }
180
+ catch (error) {
181
+ // Re-throw error but keep old state
182
+ throw error;
183
+ }
184
+ }
185
+ /**
186
+ * Validate configuration
187
+ */
188
+ validateConfig(config) {
189
+ if (config.smallBlind <= 0) {
190
+ throw new ConfigError_1.ConfigError("Small blind must be positive", {
191
+ smallBlind: config.smallBlind,
192
+ });
193
+ }
194
+ if (config.bigBlind <= config.smallBlind) {
195
+ throw new ConfigError_1.ConfigError("Big blind must be greater than small blind", {
196
+ smallBlind: config.smallBlind,
197
+ bigBlind: config.bigBlind,
198
+ });
199
+ }
200
+ const maxPlayers = config.maxPlayers ?? 9;
201
+ if (maxPlayers < 2 || maxPlayers > 10) {
202
+ throw new ConfigError_1.ConfigError("Max players must be between 2 and 10", {
203
+ maxPlayers,
204
+ });
205
+ }
206
+ }
207
+ /**
208
+ * Create initial game state
209
+ */
210
+ createInitialState(config) {
211
+ const maxPlayers = config.maxPlayers ?? 9;
212
+ const players = Array(maxPlayers).fill(null);
213
+ // For tournaments, use blindStructure[0] for initial blinds/ante
214
+ const isTournament = !!config.blindStructure;
215
+ const initialBlinds = isTournament ? config.blindStructure[0] : null;
216
+ return {
217
+ config,
218
+ players,
219
+ maxPlayers,
220
+ handNumber: 0,
221
+ buttonSeat: null,
222
+ deck: [],
223
+ board: [],
224
+ street: "PREFLOP" /* Street.PREFLOP */,
225
+ pots: [],
226
+ currentBets: new Map(),
227
+ minRaise: initialBlinds?.bigBlind ?? config.bigBlind,
228
+ lastRaiseAmount: 0,
229
+ actionTo: null,
230
+ lastAggressorSeat: null,
231
+ activePlayers: [],
232
+ winners: null,
233
+ rakeThisHand: 0,
234
+ smallBlind: initialBlinds?.smallBlind ?? config.smallBlind,
235
+ bigBlind: initialBlinds?.bigBlind ?? config.bigBlind,
236
+ ante: initialBlinds?.ante ?? config.ante ?? 0,
237
+ blindLevel: 0,
238
+ timeBanks: new Map(),
239
+ actionHistory: [],
240
+ previousStates: [],
241
+ timestamp: Date.now(),
242
+ handId: "initial",
243
+ };
244
+ }
245
+ }
246
+ exports.PokerEngine = PokerEngine;
@@ -0,0 +1,10 @@
1
+ import { GameState, Action } from "@pokertools/types";
2
+ /**
3
+ * Pure game reducer: f(state, action) => newState
4
+ * This is the heart of the poker engine
5
+ *
6
+ * @param state Current game state
7
+ * @param action Action to apply
8
+ * @returns New game state
9
+ */
10
+ export declare function gameReducer(state: GameState, action: Action): GameState;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.gameReducer = gameReducer;
4
+ const validation_1 = require("../actions/validation");
5
+ const dealing_1 = require("../actions/dealing");
6
+ const betting_1 = require("../actions/betting");
7
+ const management_1 = require("../actions/management");
8
+ const showdownActions_1 = require("../actions/showdownActions");
9
+ const tournament_1 = require("../actions/tournament");
10
+ const special_1 = require("../actions/special");
11
+ const streetProgression_1 = require("../actions/streetProgression");
12
+ const sidePots_1 = require("../rules/sidePots");
13
+ const showdown_1 = require("../rules/showdown");
14
+ const invariants_1 = require("../utils/invariants");
15
+ const constants_1 = require("../utils/constants");
16
+ /**
17
+ * Pure game reducer: f(state, action) => newState
18
+ * This is the heart of the poker engine
19
+ *
20
+ * @param state Current game state
21
+ * @param action Action to apply
22
+ * @returns New game state
23
+ */
24
+ function gameReducer(state, action) {
25
+ // Validate action
26
+ (0, validation_1.validateAction)(state, action);
27
+ // Apply action based on type
28
+ let newState;
29
+ switch (action.type) {
30
+ // Management actions
31
+ case "SIT" /* ActionType.SIT */:
32
+ newState = (0, management_1.handleSit)(state, action);
33
+ break;
34
+ case "STAND" /* ActionType.STAND */:
35
+ newState = (0, management_1.handleStand)(state, action);
36
+ break;
37
+ // Dealing
38
+ case "DEAL" /* ActionType.DEAL */:
39
+ newState = (0, dealing_1.handleDeal)(state, action);
40
+ break;
41
+ // Betting actions
42
+ case "FOLD" /* ActionType.FOLD */:
43
+ newState = (0, betting_1.handleFold)(state, action);
44
+ break;
45
+ case "CHECK" /* ActionType.CHECK */:
46
+ newState = (0, betting_1.handleCheck)(state, action);
47
+ break;
48
+ case "CALL" /* ActionType.CALL */:
49
+ newState = (0, betting_1.handleCall)(state, action);
50
+ break;
51
+ case "BET" /* ActionType.BET */:
52
+ // Auto-convert BET to appropriate action if there's already a bet
53
+ // This handles UI implementations that don't distinguish between BET/CALL/RAISE buttons
54
+ // Note: action.amount is the TOTAL bet size, not the amount to add
55
+ const currentBet = Math.max(...Array.from(state.currentBets.values()), 0);
56
+ if (currentBet > 0 && "amount" in action) {
57
+ if (action.amount === currentBet) {
58
+ // Amount equals current bet -> Convert to CALL
59
+ const callAction = {
60
+ type: "CALL" /* ActionType.CALL */,
61
+ playerId: action.playerId,
62
+ timestamp: action.timestamp,
63
+ };
64
+ newState = (0, betting_1.handleCall)(state, callAction);
65
+ }
66
+ else if (action.amount > currentBet) {
67
+ // Amount exceeds current bet -> Convert to RAISE
68
+ const raiseAction = {
69
+ type: "RAISE" /* ActionType.RAISE */,
70
+ playerId: action.playerId,
71
+ amount: action.amount,
72
+ timestamp: action.timestamp,
73
+ };
74
+ newState = (0, betting_1.handleRaise)(state, raiseAction);
75
+ }
76
+ else {
77
+ // Amount is less than current bet -> Keep as BET (will fail validation)
78
+ newState = (0, betting_1.handleBet)(state, action);
79
+ }
80
+ }
81
+ else {
82
+ newState = (0, betting_1.handleBet)(state, action);
83
+ }
84
+ break;
85
+ case "RAISE" /* ActionType.RAISE */:
86
+ newState = (0, betting_1.handleRaise)(state, action);
87
+ break;
88
+ // Showdown actions
89
+ case "SHOW" /* ActionType.SHOW */:
90
+ newState = (0, showdownActions_1.handleShow)(state, action);
91
+ break;
92
+ case "MUCK" /* ActionType.MUCK */:
93
+ newState = (0, showdownActions_1.handleMuck)(state, action);
94
+ break;
95
+ // Special actions
96
+ case "TIMEOUT" /* ActionType.TIMEOUT */:
97
+ newState = (0, special_1.handleTimeout)(state, action);
98
+ break;
99
+ case "TIME_BANK" /* ActionType.TIME_BANK */:
100
+ newState = (0, special_1.handleTimeBank)(state, action);
101
+ break;
102
+ case "NEXT_BLIND_LEVEL" /* ActionType.NEXT_BLIND_LEVEL */:
103
+ newState = (0, tournament_1.handleNextBlindLevel)(state, action);
104
+ break;
105
+ default:
106
+ // Unknown action type
107
+ newState = state;
108
+ break;
109
+ }
110
+ // Check if we should progress to next street
111
+ if ((0, streetProgression_1.shouldProgressStreet)(newState)) {
112
+ // Recalculate pots before progressing
113
+ newState = (0, sidePots_1.recalculatePots)(newState);
114
+ newState = (0, streetProgression_1.progressStreet)(newState);
115
+ }
116
+ // Check if we should go to showdown
117
+ if ((0, showdown_1.shouldShowdown)(newState)) {
118
+ newState = {
119
+ ...newState,
120
+ street: newState.street, // Keep current street for showdown
121
+ };
122
+ newState = (0, showdown_1.determineWinners)(newState);
123
+ }
124
+ // Audit chip conservation (throws on failure)
125
+ // Enabled by default, can be disabled via config (not recommended for production)
126
+ if (newState.config.validateIntegrity !== false) {
127
+ (0, invariants_1.validateGameStateIntegrity)(newState);
128
+ }
129
+ // Add to previous states for undo
130
+ const previousStates = [...newState.previousStates, state].slice(-constants_1.MAX_UNDO_HISTORY);
131
+ return {
132
+ ...newState,
133
+ previousStates,
134
+ };
135
+ }
@@ -0,0 +1,8 @@
1
+ import { PokerEngineError } from "./PokerEngineError";
2
+ /**
3
+ * Error indicating invalid configuration
4
+ * Should fail at engine initialization
5
+ */
6
+ export declare class ConfigError extends PokerEngineError {
7
+ constructor(message: string, context?: Record<string, unknown>);
8
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfigError = void 0;
4
+ const PokerEngineError_1 = require("./PokerEngineError");
5
+ /**
6
+ * Error indicating invalid configuration
7
+ * Should fail at engine initialization
8
+ */
9
+ class ConfigError extends PokerEngineError_1.PokerEngineError {
10
+ constructor(message, context = {}) {
11
+ super("INVALID_CONFIG", message, context);
12
+ this.name = "ConfigError";
13
+ }
14
+ }
15
+ exports.ConfigError = ConfigError;
@@ -0,0 +1,8 @@
1
+ import { PokerEngineError } from "./PokerEngineError";
2
+ /**
3
+ * Critical error indicating state corruption or invariant violation
4
+ * When this occurs, the table should be FROZEN immediately
5
+ */
6
+ export declare class CriticalStateError extends PokerEngineError {
7
+ constructor(message: string, context?: Record<string, unknown>);
8
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CriticalStateError = void 0;
4
+ const PokerEngineError_1 = require("./PokerEngineError");
5
+ /**
6
+ * Critical error indicating state corruption or invariant violation
7
+ * When this occurs, the table should be FROZEN immediately
8
+ */
9
+ class CriticalStateError extends PokerEngineError_1.PokerEngineError {
10
+ constructor(message, context = {}) {
11
+ super("CRITICAL_INVARIANT_FAILURE", message, context);
12
+ this.name = "CriticalStateError";
13
+ }
14
+ }
15
+ exports.CriticalStateError = CriticalStateError;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Standardized error codes for IllegalActionError
3
+ *
4
+ * Using a const enum pattern for:
5
+ * - Type safety at compile time
6
+ * - Autocomplete in IDEs
7
+ * - Documentation of all possible error codes
8
+ * - Easy refactoring
9
+ */
10
+ export declare const ErrorCodes: {
11
+ readonly INVALID_ACTION: "INVALID_ACTION";
12
+ readonly PLAYER_NOT_FOUND: "PLAYER_NOT_FOUND";
13
+ readonly PLAYER_NOT_ACTIVE: "PLAYER_NOT_ACTIVE";
14
+ readonly NOT_YOUR_TURN: "NOT_YOUR_TURN";
15
+ readonly NO_CHIPS: "NO_CHIPS";
16
+ readonly CANNOT_CHECK: "CANNOT_CHECK";
17
+ readonly NOTHING_TO_CALL: "NOTHING_TO_CALL";
18
+ readonly CANNOT_BET: "CANNOT_BET";
19
+ readonly BET_TOO_SMALL: "BET_TOO_SMALL";
20
+ readonly CANNOT_RAISE: "CANNOT_RAISE";
21
+ readonly CANNOT_RERAISE: "CANNOT_RERAISE";
22
+ readonly RAISE_TOO_SMALL: "RAISE_TOO_SMALL";
23
+ readonly CANNOT_DEAL: "CANNOT_DEAL";
24
+ readonly NOT_ENOUGH_PLAYERS: "NOT_ENOUGH_PLAYERS";
25
+ readonly INVALID_SEAT: "INVALID_SEAT";
26
+ readonly SEAT_OCCUPIED: "SEAT_OCCUPIED";
27
+ readonly INVALID_STACK: "INVALID_STACK";
28
+ readonly INVALID_AMOUNT: "INVALID_AMOUNT";
29
+ readonly INVALID_TIMESTAMP: "INVALID_TIMESTAMP";
30
+ };
31
+ /**
32
+ * Type representing all valid error codes
33
+ */
34
+ export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
35
+ /**
36
+ * Helper to check if an error message contains a specific error code
37
+ */
38
+ export declare function hasErrorCode(error: Error, code: ErrorCode): boolean;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorCodes = void 0;
4
+ exports.hasErrorCode = hasErrorCode;
5
+ /**
6
+ * Standardized error codes for IllegalActionError
7
+ *
8
+ * Using a const enum pattern for:
9
+ * - Type safety at compile time
10
+ * - Autocomplete in IDEs
11
+ * - Documentation of all possible error codes
12
+ * - Easy refactoring
13
+ */
14
+ exports.ErrorCodes = {
15
+ // Generic errors
16
+ INVALID_ACTION: "INVALID_ACTION",
17
+ // Player errors
18
+ PLAYER_NOT_FOUND: "PLAYER_NOT_FOUND",
19
+ PLAYER_NOT_ACTIVE: "PLAYER_NOT_ACTIVE",
20
+ NOT_YOUR_TURN: "NOT_YOUR_TURN",
21
+ NO_CHIPS: "NO_CHIPS",
22
+ // Betting action errors
23
+ CANNOT_CHECK: "CANNOT_CHECK",
24
+ NOTHING_TO_CALL: "NOTHING_TO_CALL",
25
+ CANNOT_BET: "CANNOT_BET",
26
+ BET_TOO_SMALL: "BET_TOO_SMALL",
27
+ CANNOT_RAISE: "CANNOT_RAISE",
28
+ CANNOT_RERAISE: "CANNOT_RERAISE",
29
+ RAISE_TOO_SMALL: "RAISE_TOO_SMALL",
30
+ // Deal errors
31
+ CANNOT_DEAL: "CANNOT_DEAL",
32
+ NOT_ENOUGH_PLAYERS: "NOT_ENOUGH_PLAYERS",
33
+ // Seat errors
34
+ INVALID_SEAT: "INVALID_SEAT",
35
+ SEAT_OCCUPIED: "SEAT_OCCUPIED",
36
+ INVALID_STACK: "INVALID_STACK",
37
+ // Validation errors
38
+ INVALID_AMOUNT: "INVALID_AMOUNT",
39
+ INVALID_TIMESTAMP: "INVALID_TIMESTAMP",
40
+ };
41
+ /**
42
+ * Helper to check if an error message contains a specific error code
43
+ */
44
+ function hasErrorCode(error, code) {
45
+ return error.message.includes(code);
46
+ }
@@ -0,0 +1,9 @@
1
+ import { PokerEngineError } from "./PokerEngineError";
2
+ import { ErrorCode } from "./ErrorCodes";
3
+ /**
4
+ * Error indicating an illegal or invalid action
5
+ * Action should be rejected and error sent to client
6
+ */
7
+ export declare class IllegalActionError extends PokerEngineError {
8
+ constructor(code: ErrorCode, message: string, context?: Record<string, unknown>);
9
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IllegalActionError = void 0;
4
+ const PokerEngineError_1 = require("./PokerEngineError");
5
+ /**
6
+ * Error indicating an illegal or invalid action
7
+ * Action should be rejected and error sent to client
8
+ */
9
+ class IllegalActionError extends PokerEngineError_1.PokerEngineError {
10
+ constructor(code, message, context = {}) {
11
+ super(code, message, context);
12
+ this.name = "IllegalActionError";
13
+ }
14
+ }
15
+ exports.IllegalActionError = IllegalActionError;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Base error class for all poker engine errors
3
+ */
4
+ export declare class PokerEngineError extends Error {
5
+ readonly code: string;
6
+ readonly context: Record<string, unknown>;
7
+ constructor(code: string, message: string, context?: Record<string, unknown>);
8
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PokerEngineError = void 0;
4
+ /**
5
+ * Base error class for all poker engine errors
6
+ */
7
+ class PokerEngineError extends Error {
8
+ constructor(code, message, context = {}) {
9
+ super(message);
10
+ this.name = "PokerEngineError";
11
+ this.code = code;
12
+ this.context = context;
13
+ // Maintains proper stack trace for where error was thrown (V8 only)
14
+ if (Error.captureStackTrace) {
15
+ Error.captureStackTrace(this, this.constructor);
16
+ }
17
+ }
18
+ }
19
+ exports.PokerEngineError = PokerEngineError;
@@ -0,0 +1,5 @@
1
+ export * from "./PokerEngineError";
2
+ export * from "./CriticalStateError";
3
+ export * from "./IllegalActionError";
4
+ export * from "./ConfigError";
5
+ export * from "./ErrorCodes";