@omnitronix/bonnys-fortune-game-engine 1.2.2 → 1.2.6

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 (26) hide show
  1. package/README.md +15 -15
  2. package/dist/__tests__/rng-gli19-compliance.test.js +222 -0
  3. package/dist/__tests__/rng-gli19-compliance.test.js.map +1 -0
  4. package/dist/__tests__/rng-seed-security.test.js +263 -0
  5. package/dist/__tests__/rng-seed-security.test.js.map +1 -0
  6. package/dist/__tests__/rng-seed-type.test.js +282 -0
  7. package/dist/__tests__/rng-seed-type.test.js.map +1 -0
  8. package/dist/__tests__/rng-stress-boundary.test.js +386 -0
  9. package/dist/__tests__/rng-stress-boundary.test.js.map +1 -0
  10. package/dist/bonnys-fortune-v1.game-engine.js +3 -1
  11. package/dist/bonnys-fortune-v1.game-engine.js.map +1 -1
  12. package/dist/config/reel-strips-config/reels-BASE.csv +0 -0
  13. package/dist/config/reel-strips-config/reels-BONUS.csv +0 -0
  14. package/dist/logic/handlers/base-game.handler.js +19 -1
  15. package/dist/logic/handlers/base-game.handler.js.map +1 -1
  16. package/dist/logic/handlers/collect-feature-bonus.handler.js +2 -2
  17. package/dist/logic/handlers/collect-feature-bonus.handler.js.map +1 -1
  18. package/dist/logic/handlers/free-spins-bonus.handler.js +4 -2
  19. package/dist/logic/handlers/free-spins-bonus.handler.js.map +1 -1
  20. package/dist/logic/handlers/steering-to-the-fortune-bonus.handler.js +4 -2
  21. package/dist/logic/handlers/steering-to-the-fortune-bonus.handler.js.map +1 -1
  22. package/dist/logic/handlers/treasure-hunt-bonus.handler.js +4 -2
  23. package/dist/logic/handlers/treasure-hunt-bonus.handler.js.map +1 -1
  24. package/dist/rng/rng-client.factory.js +45 -1
  25. package/dist/rng/rng-client.factory.js.map +1 -1
  26. package/package.json +1 -1
@@ -0,0 +1,282 @@
1
+ "use strict";
2
+ /**
3
+ * RNG Seed Type Tests - GLI-19 Compliance Verification
4
+ *
5
+ * These tests verify that the RNG seed type fix is working correctly:
6
+ * 1. Seeds are returned as numbers (internal format)
7
+ * 2. Seeds can be safely converted to strings (wire format)
8
+ * 3. Hash canonicalization produces deterministic results
9
+ * 4. Edge cases are handled correctly
10
+ *
11
+ * GLI-19 Sections:
12
+ * - 3.4: Tamper-evident audit trails
13
+ * - 3.4.2: Tamper detection
14
+ * - 4.2.1: Deterministic replay
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ const bonnys_fortune_v1_game_engine_1 = require("../bonnys-fortune-v1.game-engine");
18
+ describe('RNG Seed Type - GLI-19 Compliance', () => {
19
+ let engine;
20
+ beforeEach(() => {
21
+ engine = new bonnys_fortune_v1_game_engine_1.BonnysFortuneV1GameEngine();
22
+ });
23
+ // Helper to initialize session
24
+ async function initSession(betAmount = 1.0) {
25
+ const command = {
26
+ id: 'init',
27
+ type: 'INIT_SESSION_STATE',
28
+ payload: {
29
+ betAmount,
30
+ currency: 'EUR',
31
+ },
32
+ };
33
+ return engine.processCommand(null, null, command);
34
+ }
35
+ // Helper to execute spin
36
+ async function executeSpin(publicState, privateState) {
37
+ const spinCommand = {
38
+ id: `spin-${Date.now()}`,
39
+ type: 'SPIN',
40
+ payload: {
41
+ sessionId: 'test-session',
42
+ betAmount: 1.0,
43
+ },
44
+ };
45
+ return engine.processCommand(publicState, privateState, spinCommand);
46
+ }
47
+ describe('Seed Type Verification', () => {
48
+ it('should return rngOutcome with numeric seeds', async () => {
49
+ const init = await initSession();
50
+ const spin = await executeSpin(init.publicState, init.privateState);
51
+ expect(spin.success).toBe(true);
52
+ expect(spin.rngOutcome).toBeDefined();
53
+ // Verify all seeds are numbers
54
+ for (const [actionId, record] of Object.entries(spin.rngOutcome)) {
55
+ expect(typeof record.seed).toBe('number');
56
+ expect(Number.isInteger(record.seed)).toBe(true);
57
+ expect(Number.isSafeInteger(record.seed)).toBe(true);
58
+ }
59
+ });
60
+ it('should have seeds within safe integer range', async () => {
61
+ const init = await initSession();
62
+ // Run multiple spins to get variety of seeds
63
+ let currentPublic = init.publicState;
64
+ let currentPrivate = init.privateState;
65
+ for (let i = 0; i < 10; i++) {
66
+ const spin = await executeSpin(currentPublic, currentPrivate);
67
+ if (spin.rngOutcome) {
68
+ for (const [actionId, record] of Object.entries(spin.rngOutcome)) {
69
+ expect(record.seed).toBeLessThanOrEqual(Number.MAX_SAFE_INTEGER);
70
+ expect(record.seed).toBeGreaterThanOrEqual(Number.MIN_SAFE_INTEGER);
71
+ }
72
+ }
73
+ currentPublic = spin.publicState;
74
+ currentPrivate = spin.privateState;
75
+ }
76
+ });
77
+ it('should have consistent rngOutcome structure', async () => {
78
+ const init = await initSession();
79
+ const spin = await executeSpin(init.publicState, init.privateState);
80
+ expect(spin.rngOutcome).toBeDefined();
81
+ for (const [actionId, record] of Object.entries(spin.rngOutcome)) {
82
+ // Verify structure
83
+ expect(typeof actionId).toBe('string');
84
+ expect(actionId.length).toBeGreaterThan(0);
85
+ // Verify record fields
86
+ expect(typeof record.result).toBe('number');
87
+ expect(typeof record.seed).toBe('number');
88
+ expect(typeof record.min).toBe('number');
89
+ expect(typeof record.max).toBe('number');
90
+ // Verify result is within range
91
+ expect(record.result).toBeGreaterThanOrEqual(record.min);
92
+ expect(record.result).toBeLessThanOrEqual(record.max);
93
+ }
94
+ });
95
+ });
96
+ describe('Wire Format Conversion', () => {
97
+ it('seeds should be safely convertible to strings', async () => {
98
+ const init = await initSession();
99
+ const spin = await executeSpin(init.publicState, init.privateState);
100
+ for (const [actionId, record] of Object.entries(spin.rngOutcome)) {
101
+ const seedAsString = String(record.seed);
102
+ const backToNumber = Number(seedAsString);
103
+ // Round-trip conversion must be lossless
104
+ expect(backToNumber).toBe(record.seed);
105
+ }
106
+ });
107
+ it('string conversion should not lose precision', async () => {
108
+ // Run 50 independent sessions to test various seed values
109
+ // Each session gets fresh state to avoid bonus state complications
110
+ for (let i = 0; i < 50; i++) {
111
+ const init = await initSession();
112
+ const spin = await executeSpin(init.publicState, init.privateState);
113
+ if (spin.rngOutcome) {
114
+ for (const [, record] of Object.entries(spin.rngOutcome)) {
115
+ const original = record.seed;
116
+ const asString = String(original);
117
+ const restored = Number(asString);
118
+ expect(restored).toBe(original);
119
+ expect(asString).not.toContain('e'); // No scientific notation
120
+ expect(asString).not.toContain('.'); // Must be integer
121
+ }
122
+ }
123
+ }
124
+ });
125
+ });
126
+ describe('Hash Canonicalization Verification', () => {
127
+ /**
128
+ * Simulates the canonicalization that RGS uses for hashing.
129
+ * This must produce identical output for number vs string seeds.
130
+ */
131
+ function canonicalizeForHash(outcome) {
132
+ const entries = Object.entries(outcome)
133
+ .map(([actionId, record]) => ({
134
+ actionId,
135
+ result: Number(record.result),
136
+ seed: String(record.seed),
137
+ min: Number(record.min),
138
+ max: Number(record.max),
139
+ }))
140
+ .sort((a, b) => a.actionId.localeCompare(b.actionId));
141
+ return JSON.stringify(entries);
142
+ }
143
+ it('should produce same canonical form for number and string seeds', async () => {
144
+ const init = await initSession();
145
+ const spin = await executeSpin(init.publicState, init.privateState);
146
+ // Get canonical with number seeds (as returned by engine)
147
+ const canonicalNumber = canonicalizeForHash(spin.rngOutcome);
148
+ // Convert seeds to strings (simulating wire format)
149
+ const withStringSeeds = {};
150
+ for (const [actionId, record] of Object.entries(spin.rngOutcome)) {
151
+ withStringSeeds[actionId] = {
152
+ ...record,
153
+ seed: String(record.seed),
154
+ };
155
+ }
156
+ const canonicalString = canonicalizeForHash(withStringSeeds);
157
+ // CRITICAL: Both must produce identical canonical form
158
+ expect(canonicalNumber).toBe(canonicalString);
159
+ });
160
+ it('should produce deterministic canonical form across multiple calls', async () => {
161
+ const init = await initSession();
162
+ const spin = await executeSpin(init.publicState, init.privateState);
163
+ const canonical1 = canonicalizeForHash(spin.rngOutcome);
164
+ const canonical2 = canonicalizeForHash(spin.rngOutcome);
165
+ const canonical3 = canonicalizeForHash(spin.rngOutcome);
166
+ expect(canonical1).toBe(canonical2);
167
+ expect(canonical2).toBe(canonical3);
168
+ });
169
+ it('should sort entries alphabetically by actionId', async () => {
170
+ // Create outcome with known actionIds in reverse order
171
+ const outcome = {
172
+ z_action: { result: 1, seed: 100, min: 0, max: 10 },
173
+ a_action: { result: 2, seed: 200, min: 0, max: 10 },
174
+ m_action: { result: 3, seed: 300, min: 0, max: 10 },
175
+ };
176
+ const canonical = canonicalizeForHash(outcome);
177
+ const parsed = JSON.parse(canonical);
178
+ expect(parsed[0].actionId).toBe('a_action');
179
+ expect(parsed[1].actionId).toBe('m_action');
180
+ expect(parsed[2].actionId).toBe('z_action');
181
+ });
182
+ });
183
+ describe('Bonus Round RNG Tracking', () => {
184
+ it('should track RNG outcomes during bonus trigger', async () => {
185
+ const init = await initSession();
186
+ // Trigger a bonus via debug command
187
+ const triggerResult = await engine.processCommand(init.publicState, init.privateState, {
188
+ id: 'debug-trigger',
189
+ type: 'DEBUG_TRIGGER_BONUS',
190
+ payload: {
191
+ bonusType: 'bonusGame1', // Treasure Hunt
192
+ betAmount: 1.0,
193
+ },
194
+ });
195
+ expect(triggerResult.success).toBe(true);
196
+ // Debug trigger may or may not have rngOutcome depending on implementation
197
+ });
198
+ it('should maintain seed type consistency across bonus spins', async () => {
199
+ const init = await initSession();
200
+ // Trigger free spins bonus
201
+ const trigger = await engine.processCommand(init.publicState, init.privateState, {
202
+ id: 'debug-trigger',
203
+ type: 'DEBUG_TRIGGER_BONUS',
204
+ payload: {
205
+ bonusType: 'bonusGame2', // Free Spins
206
+ betAmount: 1.0,
207
+ },
208
+ });
209
+ if (trigger.rngOutcome) {
210
+ for (const [, record] of Object.entries(trigger.rngOutcome)) {
211
+ expect(typeof record.seed).toBe('number');
212
+ }
213
+ }
214
+ });
215
+ });
216
+ describe('Edge Cases', () => {
217
+ it('should handle zero seed correctly', () => {
218
+ const outcome = {
219
+ test_action: { result: 5, seed: 0, min: 0, max: 10 },
220
+ };
221
+ const canonical = JSON.stringify(Object.entries(outcome)
222
+ .map(([actionId, record]) => ({
223
+ actionId,
224
+ result: record.result,
225
+ seed: String(record.seed),
226
+ min: record.min,
227
+ max: record.max,
228
+ }))
229
+ .sort((a, b) => a.actionId.localeCompare(b.actionId)));
230
+ expect(canonical).toContain('"seed":"0"');
231
+ });
232
+ it('should handle negative seed correctly', () => {
233
+ const outcome = {
234
+ test_action: { result: 5, seed: -12345, min: -100, max: 100 },
235
+ };
236
+ const canonical = JSON.stringify(Object.entries(outcome)
237
+ .map(([actionId, record]) => ({
238
+ actionId,
239
+ result: record.result,
240
+ seed: String(record.seed),
241
+ min: record.min,
242
+ max: record.max,
243
+ })));
244
+ expect(canonical).toContain('"seed":"-12345"');
245
+ });
246
+ it('should handle MAX_SAFE_INTEGER seed correctly', () => {
247
+ const maxSafe = Number.MAX_SAFE_INTEGER;
248
+ const outcome = {
249
+ test_action: { result: 5, seed: maxSafe, min: 0, max: 100 },
250
+ };
251
+ const seedString = String(maxSafe);
252
+ const backToNumber = Number(seedString);
253
+ expect(backToNumber).toBe(maxSafe);
254
+ });
255
+ });
256
+ describe('Multiple Spins Consistency', () => {
257
+ it('should maintain type consistency across 100 spins', async () => {
258
+ const allSeeds = [];
259
+ // Run 100 independent sessions to avoid bonus state complications
260
+ // Each session gets fresh state
261
+ for (let i = 0; i < 100; i++) {
262
+ const init = await initSession();
263
+ const spin = await executeSpin(init.publicState, init.privateState);
264
+ if (spin.rngOutcome) {
265
+ for (const [, record] of Object.entries(spin.rngOutcome)) {
266
+ expect(typeof record.seed).toBe('number');
267
+ allSeeds.push(record.seed);
268
+ }
269
+ }
270
+ }
271
+ // Verify all seeds are safe integers
272
+ expect(allSeeds.every(s => Number.isSafeInteger(s))).toBe(true);
273
+ // Log statistics for analysis document
274
+ console.log(`\n=== RNG Seed Statistics (100 spins) - Bonny's Fortune ===`);
275
+ console.log(`Total seeds collected: ${allSeeds.length}`);
276
+ console.log(`Min seed: ${Math.min(...allSeeds)}`);
277
+ console.log(`Max seed: ${Math.max(...allSeeds)}`);
278
+ console.log(`All safe integers: ${allSeeds.every(s => Number.isSafeInteger(s))}`);
279
+ });
280
+ });
281
+ });
282
+ //# sourceMappingURL=rng-seed-type.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rng-seed-type.test.js","sourceRoot":"","sources":["../../src/__tests__/rng-seed-type.test.ts"],"names":[],"mappings":"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"}