@hizi.io/engine-sdk 0.1.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.
- package/README.md +212 -0
- package/lib/api.d.ts +198 -0
- package/lib/api.js +352 -0
- package/lib/constants.d.ts +44 -0
- package/lib/constants.js +56 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +37 -0
- package/lib/network.d.ts +9 -0
- package/lib/network.js +63 -0
- package/lib/types/balance.d.ts +20 -0
- package/lib/types/balance.js +2 -0
- package/lib/types/blackjack.d.ts +163 -0
- package/lib/types/blackjack.js +22 -0
- package/lib/types/buyFeatureOption.d.ts +11 -0
- package/lib/types/buyFeatureOption.js +2 -0
- package/lib/types/collectOptions.d.ts +8 -0
- package/lib/types/collectOptions.js +2 -0
- package/lib/types/crash.d.ts +223 -0
- package/lib/types/crash.js +80 -0
- package/lib/types/freePlayInfo.d.ts +11 -0
- package/lib/types/freePlayInfo.js +2 -0
- package/lib/types/gameResult.d.ts +48 -0
- package/lib/types/gameResult.js +2 -0
- package/lib/types/gameRoundInfo.d.ts +19 -0
- package/lib/types/gameRoundInfo.js +2 -0
- package/lib/types/gameSettings.d.ts +133 -0
- package/lib/types/gameSettings.js +16 -0
- package/lib/types/gameState.d.ts +20 -0
- package/lib/types/gameState.js +2 -0
- package/lib/types/index.d.ts +32 -0
- package/lib/types/index.js +22 -0
- package/lib/types/keno.d.ts +34 -0
- package/lib/types/keno.js +18 -0
- package/lib/types/loadConfigConfig.d.ts +42 -0
- package/lib/types/loadConfigConfig.js +2 -0
- package/lib/types/loginOptions.d.ts +7 -0
- package/lib/types/loginOptions.js +2 -0
- package/lib/types/mines.d.ts +26 -0
- package/lib/types/mines.js +19 -0
- package/lib/types/network.d.ts +24 -0
- package/lib/types/network.js +2 -0
- package/lib/types/pfVerifyOptions.d.ts +48 -0
- package/lib/types/pfVerifyOptions.js +2 -0
- package/lib/types/placeBetOptions.d.ts +16 -0
- package/lib/types/placeBetOptions.js +2 -0
- package/lib/types/progressionCounter.d.ts +65 -0
- package/lib/types/progressionCounter.js +2 -0
- package/lib/types/replies.d.ts +107 -0
- package/lib/types/replies.js +2 -0
- package/lib/types/roulette.d.ts +53 -0
- package/lib/types/roulette.js +11 -0
- package/lib/types/scenarioInfo.d.ts +12 -0
- package/lib/types/scenarioInfo.js +2 -0
- package/lib/types/sessionOptions.d.ts +7 -0
- package/lib/types/sessionOptions.js +2 -0
- package/lib/types/spinAward.d.ts +31 -0
- package/lib/types/spinAward.js +12 -0
- package/lib/types/spinInfo.d.ts +9 -0
- package/lib/types/spinInfo.js +2 -0
- package/lib/types/tokenData.d.ts +7 -0
- package/lib/types/tokenData.js +2 -0
- package/lib/websocket.d.ts +27 -0
- package/lib/websocket.js +186 -0
- package/package.json +19 -0
package/lib/api.js
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.login = login;
|
|
4
|
+
exports.loadConfig = loadConfig;
|
|
5
|
+
exports.placeBet = placeBet;
|
|
6
|
+
exports.collect = collect;
|
|
7
|
+
exports.pfVerify = pfVerify;
|
|
8
|
+
exports.refresh = refresh;
|
|
9
|
+
exports.reportAnimationEnd = reportAnimationEnd;
|
|
10
|
+
exports.updateBalance = updateBalance;
|
|
11
|
+
exports.getFreePlaysRemaining = getFreePlaysRemaining;
|
|
12
|
+
exports.getFreePlayStake = getFreePlayStake;
|
|
13
|
+
const constants_js_1 = require("./constants.js");
|
|
14
|
+
const network_js_1 = require("./network.js");
|
|
15
|
+
/** Parse an error response from login/refresh endpoints. */
|
|
16
|
+
function parseErrorResponse(data, statusText) {
|
|
17
|
+
return {
|
|
18
|
+
success: false,
|
|
19
|
+
error: {
|
|
20
|
+
code: String(data?.errorId ?? data?.code ?? constants_js_1.API_RETURNCODES.UNEXPECTED),
|
|
21
|
+
message: (data?.errorText ?? data?.message ?? statusText),
|
|
22
|
+
...(data?.passThroughData !== undefined && data?.passThroughData !== 'undefined' ? { passThroughData: data.passThroughData } : {}),
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** Parse a connect reply (used by both login and refresh). */
|
|
27
|
+
function parseConnectReply(data) {
|
|
28
|
+
return {
|
|
29
|
+
token: data.token,
|
|
30
|
+
backendURL: (data.backendUrl ?? data.backendURL),
|
|
31
|
+
refreshURL: (data.refreshUrl ?? data.refreshURL),
|
|
32
|
+
logoutURL: (data.logoutUrl ?? data.logoutURL),
|
|
33
|
+
webSocketURL: (data.webSocketUrl ?? data.webSocketURL),
|
|
34
|
+
balance: data.balance,
|
|
35
|
+
gameSettings: data.gameSettings,
|
|
36
|
+
tokenData: data.tokenData,
|
|
37
|
+
freePlaysAvailable: data.freePlaysAvailable,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Exchange a launch token for a session token.
|
|
42
|
+
*
|
|
43
|
+
* The `loginURL` and `launchToken` are provided as URL query parameters
|
|
44
|
+
* when the game is launched by the operator.
|
|
45
|
+
*
|
|
46
|
+
* @param options - Login credentials from the launch URL.
|
|
47
|
+
* @param options.loginURL - The operator-provided login endpoint URL.
|
|
48
|
+
* @param options.launchToken - Short-lived token from the launch URL query string.
|
|
49
|
+
* @returns A session token, backend URL, and platform settings on success.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* const response = await login({ loginURL, launchToken });
|
|
54
|
+
* if (response.success) {
|
|
55
|
+
* const { token, backendURL } = response.result;
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
async function login(options) {
|
|
60
|
+
try {
|
|
61
|
+
const url = new URL(options.loginURL);
|
|
62
|
+
url.searchParams.set('token', options.launchToken);
|
|
63
|
+
const response = await fetch(url.href, {
|
|
64
|
+
method: 'GET',
|
|
65
|
+
headers: { Accept: 'application/json' },
|
|
66
|
+
signal: AbortSignal.timeout(constants_js_1.defaultNetworkTimeout),
|
|
67
|
+
});
|
|
68
|
+
const data = await response.json();
|
|
69
|
+
if (!response.ok) {
|
|
70
|
+
return parseErrorResponse(data, response.statusText);
|
|
71
|
+
}
|
|
72
|
+
return { success: true, result: parseConnectReply(data) };
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
error: {
|
|
78
|
+
code: String(constants_js_1.API_RETURNCODES.NETWORKERROR),
|
|
79
|
+
message: error instanceof Error ? error.message : 'Network error',
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Load the game configuration including available stakes, RTP, and buy features.
|
|
86
|
+
*
|
|
87
|
+
* Call this once after {@link login} to retrieve the game's configuration before
|
|
88
|
+
* placing any bets. If a previous round was interrupted, the response includes
|
|
89
|
+
* `gameResult` and `amountToCollect` for resumption.
|
|
90
|
+
*
|
|
91
|
+
* @param options - Session credentials from the login response.
|
|
92
|
+
* @param options.backendURL - Backend URL from the login response.
|
|
93
|
+
* @param options.token - Session token.
|
|
94
|
+
* @returns Game configuration, balance, and any in-progress round data.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* const response = await loadConfig({ backendURL, token });
|
|
99
|
+
* if (response.success) {
|
|
100
|
+
* const { stakes, rtp, buyFeatures } = response.result.config;
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
async function loadConfig(options) {
|
|
105
|
+
return (0, network_js_1.request)(options.backendURL, {
|
|
106
|
+
op: 'loadConfig',
|
|
107
|
+
token: options.token,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Place a bet and receive a game result, or continue an in-progress round.
|
|
112
|
+
*
|
|
113
|
+
* - **New spin** — pass the desired `stake` amount.
|
|
114
|
+
* - **Continue round** — omit `stake` when `engineData.inProgress` is `true`.
|
|
115
|
+
* - **Buy feature** — pass `featureToBuy` to enter a bonus directly (engine computes the price).
|
|
116
|
+
* - **Player choice** — pass `playerChoiceIndex` when `engineData.playerChoice` is set.
|
|
117
|
+
*
|
|
118
|
+
* @param options - Bet parameters.
|
|
119
|
+
* @param options.backendURL - Backend URL from the login response.
|
|
120
|
+
* @param options.token - Session token.
|
|
121
|
+
* @param options.stake - Stake amount in minor currency units. Required for the first call of a game round.
|
|
122
|
+
* @param options.featureToBuy - Buy-feature ID (e.g. `'freespin'`).
|
|
123
|
+
* @param options.playerChoiceIndex - Index of the selected option when `engineData.playerChoice` is set.
|
|
124
|
+
* @param options.useTicket - Set `true` to consume a free play ticket.
|
|
125
|
+
* @param options.useTicketFeatureType - Feature type of the free play ticket.
|
|
126
|
+
* @param options.additionalData - Additional game-specific parameters.
|
|
127
|
+
* @returns The game result including scenario data, engine state, and cumulative win.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* // New spin
|
|
132
|
+
* const response = await placeBet({ backendURL, token, stake });
|
|
133
|
+
*
|
|
134
|
+
* // Buy feature
|
|
135
|
+
* const response = await placeBet({ backendURL, token, stake, featureToBuy: 'freespin' });
|
|
136
|
+
*
|
|
137
|
+
* // Continue round
|
|
138
|
+
* const response = await placeBet({ backendURL, token });
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
async function placeBet(options) {
|
|
142
|
+
const { backendURL, token, stake, useTicket, useTicketFeatureType, featureToBuy, playerChoiceIndex, additionalData } = options;
|
|
143
|
+
const body = {
|
|
144
|
+
...additionalData,
|
|
145
|
+
op: 'placeBet',
|
|
146
|
+
token,
|
|
147
|
+
};
|
|
148
|
+
if (stake !== undefined)
|
|
149
|
+
body.stake = stake;
|
|
150
|
+
if (useTicket !== undefined)
|
|
151
|
+
body.useTicket = useTicket;
|
|
152
|
+
if (useTicketFeatureType !== undefined)
|
|
153
|
+
body.useTicketFeatureType = useTicketFeatureType;
|
|
154
|
+
if (featureToBuy !== undefined)
|
|
155
|
+
body.featureToBuy = featureToBuy;
|
|
156
|
+
if (playerChoiceIndex !== undefined)
|
|
157
|
+
body.playerChoiceIndex = playerChoiceIndex;
|
|
158
|
+
return (0, network_js_1.request)(backendURL, body);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Collect winnings after a completed round.
|
|
162
|
+
*
|
|
163
|
+
* Only available for games with wager features (`config.wagerFeatures` is present).
|
|
164
|
+
* Games without wager features auto-end the round and credit winnings automatically.
|
|
165
|
+
*
|
|
166
|
+
* @param options - Session credentials and optional partial amount.
|
|
167
|
+
* @param options.backendURL - Backend URL from the login response.
|
|
168
|
+
* @param options.token - Session token.
|
|
169
|
+
* @param options.amount - Amount to collect. Omit to collect the full available amount.
|
|
170
|
+
* @returns The credited amount and updated balance.
|
|
171
|
+
* @throws When called on a game without wager features, or when no winnings are available.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* if (gameResult.engineData.canCollect) {
|
|
176
|
+
* const response = await collect({ backendURL, token });
|
|
177
|
+
* }
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
async function collect(options) {
|
|
181
|
+
const body = {
|
|
182
|
+
...options.additionalData,
|
|
183
|
+
op: 'collect',
|
|
184
|
+
token: options.token,
|
|
185
|
+
};
|
|
186
|
+
if (options.amount !== undefined)
|
|
187
|
+
body.collectAmount = options.amount;
|
|
188
|
+
return (0, network_js_1.request)(options.backendURL, body);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Re-run a past round against its revealed PF seeds and get back the
|
|
192
|
+
* engine's offline replay — the per-call RNG audit (`rngData`) and the
|
|
193
|
+
* per-step game outcomes (`steps`) — so the caller can diff them against
|
|
194
|
+
* what they recorded live.
|
|
195
|
+
*
|
|
196
|
+
* Only meaningful for rounds played with `config.rng === 'pf'`. The
|
|
197
|
+
* endpoint never touches the wallet, progression counters, or operator
|
|
198
|
+
* caps; it's pure compute.
|
|
199
|
+
*
|
|
200
|
+
* Two checks make up a passing verification:
|
|
201
|
+
*
|
|
202
|
+
* 1. **Audit replay** — `reply.rngData` matches the live `pf.rngData`
|
|
203
|
+
* element-wise. A swapped server seed would yield different draws, so
|
|
204
|
+
* this transitively proves the revealed seed is the one committed to.
|
|
205
|
+
* 2. **Result replay** — `reply.steps[i].scenario` / `totalWin` match the
|
|
206
|
+
* live round at each step. The terminal step is `steps[steps.length - 1]`.
|
|
207
|
+
*
|
|
208
|
+
* @param options - Verify parameters; see {@link IPfVerifyOptions}.
|
|
209
|
+
* @param options.backendURL - Backend URL from the login response.
|
|
210
|
+
* @param options.token - Session token (used to resolve the game config).
|
|
211
|
+
* @param options.serverSeed - Revealed server seed from the round's `pf` block.
|
|
212
|
+
* @param options.clientSeed - Client seed bound to the round.
|
|
213
|
+
* @param options.startNonce - Defaults to `0`. Set when the round opened mid-PF-session.
|
|
214
|
+
* @param options.stake - Stake the round opened with (required by games that need it to settle).
|
|
215
|
+
* @param options.featureToBuy - Buy-feature id the round opened on, if any.
|
|
216
|
+
* @param options.initialData - Mirror the round's opening payload (blackjack side bets, …).
|
|
217
|
+
* @param options.bets - Roulette / crash opening bets.
|
|
218
|
+
* @param options.playerNumbers - Keno picks, if the player chose their own.
|
|
219
|
+
* @param options.actions - Continuation actions in order; shape per game (see {@link IPfVerifyAction}).
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```ts
|
|
223
|
+
* // Verify a one-shot roulette round.
|
|
224
|
+
* const reply = await pfVerify({
|
|
225
|
+
* backendURL, token,
|
|
226
|
+
* serverSeed: pf.revealedServerSeed,
|
|
227
|
+
* clientSeed: pf.clientSeed,
|
|
228
|
+
* stake: 200,
|
|
229
|
+
* bets: [{ type: 'straight', selection: 17, stake: 100 }, { type: 'red', stake: 100 }],
|
|
230
|
+
* });
|
|
231
|
+
* if (reply.success) {
|
|
232
|
+
* const rngOk = deepEqual(reply.result.rngData, pf.rngData);
|
|
233
|
+
* const pocketOk = (reply.result.steps[0].scenario as { pocket: number }).pocket === liveScenario.pocket;
|
|
234
|
+
* }
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
async function pfVerify(options) {
|
|
238
|
+
const { backendURL, token, serverSeed, clientSeed, startNonce, stake, featureToBuy, initialData, bets, playerNumbers, actions } = options;
|
|
239
|
+
const body = { op: 'pfVerify', token, serverSeed, clientSeed };
|
|
240
|
+
// Engine defaults startNonce to 0 when omitted; only spend bytes when non-zero.
|
|
241
|
+
if (startNonce !== undefined && startNonce > 0)
|
|
242
|
+
body.startNonce = startNonce;
|
|
243
|
+
if (stake !== undefined)
|
|
244
|
+
body.stake = stake;
|
|
245
|
+
if (featureToBuy !== undefined)
|
|
246
|
+
body.featureToBuy = featureToBuy;
|
|
247
|
+
if (initialData !== undefined)
|
|
248
|
+
body.initialData = initialData;
|
|
249
|
+
if (bets !== undefined)
|
|
250
|
+
body.bets = bets;
|
|
251
|
+
if (playerNumbers !== undefined)
|
|
252
|
+
body.playerNumbers = playerNumbers;
|
|
253
|
+
if (actions !== undefined)
|
|
254
|
+
body.actions = actions;
|
|
255
|
+
return (0, network_js_1.request)(backendURL, body);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Refresh the session token when it expires.
|
|
259
|
+
*
|
|
260
|
+
* Call this when API requests start returning `SESSIONINVALID` or `NOTLOGGEDON`
|
|
261
|
+
* errors. The new session token and URLs are returned in the response.
|
|
262
|
+
*
|
|
263
|
+
* @param refreshURL - The refresh endpoint URL from the {@link login} response (`result.refreshURL`).
|
|
264
|
+
* @returns A new session token and updated platform info.
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```ts
|
|
268
|
+
* const response = await refresh(refreshURL);
|
|
269
|
+
* if (response.success) {
|
|
270
|
+
* token = response.result.token;
|
|
271
|
+
* }
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
async function refresh(refreshURL) {
|
|
275
|
+
try {
|
|
276
|
+
const response = await fetch(refreshURL, {
|
|
277
|
+
method: 'GET',
|
|
278
|
+
headers: { 'Content-Type': 'application/json' },
|
|
279
|
+
signal: AbortSignal.timeout(constants_js_1.defaultNetworkTimeout),
|
|
280
|
+
});
|
|
281
|
+
const data = await response.json();
|
|
282
|
+
if (!response.ok) {
|
|
283
|
+
return parseErrorResponse(data, response.statusText);
|
|
284
|
+
}
|
|
285
|
+
return { success: true, result: parseConnectReply(data) };
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
return {
|
|
289
|
+
success: false,
|
|
290
|
+
error: {
|
|
291
|
+
code: String(constants_js_1.API_RETURNCODES.NETWORKERROR),
|
|
292
|
+
message: error instanceof Error ? error.message : 'Network error',
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Report that the game animation has finished playing.
|
|
299
|
+
*
|
|
300
|
+
* Only needed when `gameSettings.reportAnimationEnd` is `true` (set by the operator).
|
|
301
|
+
* Call this after your spin/win animation completes.
|
|
302
|
+
*
|
|
303
|
+
* @param options - Session credentials.
|
|
304
|
+
* @param options.backendURL - Backend URL from the login response.
|
|
305
|
+
* @param options.token - Session token.
|
|
306
|
+
*/
|
|
307
|
+
async function reportAnimationEnd(options) {
|
|
308
|
+
return (0, network_js_1.request)(options.backendURL, {
|
|
309
|
+
op: 'reportAnimationEnd',
|
|
310
|
+
token: options.token,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Request an updated balance from the server.
|
|
315
|
+
*
|
|
316
|
+
* Use this to refresh the displayed balance outside of the normal
|
|
317
|
+
* `placeBet`/`collect` flow (e.g. after an external deposit).
|
|
318
|
+
*
|
|
319
|
+
* @param options - Session credentials.
|
|
320
|
+
* @param options.backendURL - Backend URL from the login response.
|
|
321
|
+
* @param options.token - Session token.
|
|
322
|
+
* @returns The player's current balance.
|
|
323
|
+
*/
|
|
324
|
+
async function updateBalance(options) {
|
|
325
|
+
return (0, network_js_1.request)(options.backendURL, {
|
|
326
|
+
op: 'updateBalance',
|
|
327
|
+
token: options.token,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
// ---- Helper Functions ----
|
|
331
|
+
/**
|
|
332
|
+
* Get the total number of free plays remaining.
|
|
333
|
+
*
|
|
334
|
+
* @param freePlaysAvailable - The `freePlaysAvailable` array from a `loadConfig` or `placeBet` response.
|
|
335
|
+
* @returns Total free play count across all entries, or `0` if none available.
|
|
336
|
+
*/
|
|
337
|
+
function getFreePlaysRemaining(freePlaysAvailable) {
|
|
338
|
+
if (!freePlaysAvailable)
|
|
339
|
+
return 0;
|
|
340
|
+
return freePlaysAvailable.reduce((total, fp) => total + fp.count, 0);
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Get the stake amount for available free plays.
|
|
344
|
+
*
|
|
345
|
+
* @param freePlaysAvailable - The `freePlaysAvailable` array from a `loadConfig` or `placeBet` response.
|
|
346
|
+
* @returns The first free play's stake amount, or `undefined` if none available.
|
|
347
|
+
*/
|
|
348
|
+
function getFreePlayStake(freePlaysAvailable) {
|
|
349
|
+
if (!freePlaysAvailable || freePlaysAvailable.length === 0)
|
|
350
|
+
return undefined;
|
|
351
|
+
return freePlaysAvailable[0].stake;
|
|
352
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Error codes returned by the Hizi RGS platform. */
|
|
2
|
+
export declare enum API_RETURNCODES {
|
|
3
|
+
SUCCESS = 0,
|
|
4
|
+
PLAYERNOTFOUND = 1,
|
|
5
|
+
PLAYERBLOCKED = 2,
|
|
6
|
+
BALANCETOOLOW = 10,
|
|
7
|
+
BETLIMITREACHED = 11,
|
|
8
|
+
GAMEROUNDALREADYSTARTED = 12,
|
|
9
|
+
GAMEROUNDNOTACTIVE = 13,
|
|
10
|
+
GAMEROUNDNOTFOUND = 14,
|
|
11
|
+
GAMEROUNDNOTSTARTED = 15,
|
|
12
|
+
TRANSACTIONCOUNTWRONG = 16,
|
|
13
|
+
GAMEROUNDPLAYERMISMATCH = 17,
|
|
14
|
+
CURRENCYINVALID = 18,
|
|
15
|
+
INVALIDPARAMETER = 19,
|
|
16
|
+
TRANSACTIONAFTEREND = 20,
|
|
17
|
+
GAMEROUNDISLOCKED = 21,
|
|
18
|
+
GAMEROUNDISCLOSING = 22,
|
|
19
|
+
SPINNOTAVAILABLE = 23,
|
|
20
|
+
COOLOFFPERIODACTIVE = 25,
|
|
21
|
+
NOTLOGGEDON = 29,
|
|
22
|
+
RESPONSIBLEGAMINGLIMITREACHED = 30,
|
|
23
|
+
RESPONSIBLESGAMINGSESSIONEXPIRED = 31,
|
|
24
|
+
PLAYERNOAUTHENTICATED = 32,
|
|
25
|
+
GENERICBETERROR = 34,
|
|
26
|
+
GENERICWINERROR = 35,
|
|
27
|
+
OPERATIONBEINGPROCESSED = 36,
|
|
28
|
+
REALITYCHECK = 38,
|
|
29
|
+
SIGNATUREWRONG = 1001,
|
|
30
|
+
PARAMETERMISSING = 1004,
|
|
31
|
+
GAMECODENOTFOUND = 1006,
|
|
32
|
+
SESSIONINVALID = 1008,
|
|
33
|
+
RNGFAILURE = 1009,
|
|
34
|
+
NETWORKERROR = 1010,
|
|
35
|
+
RATELIMITEXCEEDED = 1300,
|
|
36
|
+
UNEXPECTED = -1
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Error codes that can be retried (e.g. balance too low, rate limit, network error).
|
|
40
|
+
* Use this to decide whether to show a retry option or a fatal error screen.
|
|
41
|
+
*/
|
|
42
|
+
export declare const recoverableErrorCodes: string[];
|
|
43
|
+
/** Default timeout for HTTP and WebSocket requests, in milliseconds. */
|
|
44
|
+
export declare const defaultNetworkTimeout = 30000;
|
package/lib/constants.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultNetworkTimeout = exports.recoverableErrorCodes = exports.API_RETURNCODES = void 0;
|
|
4
|
+
/** Error codes returned by the Hizi RGS platform. */
|
|
5
|
+
var API_RETURNCODES;
|
|
6
|
+
(function (API_RETURNCODES) {
|
|
7
|
+
API_RETURNCODES[API_RETURNCODES["SUCCESS"] = 0] = "SUCCESS";
|
|
8
|
+
API_RETURNCODES[API_RETURNCODES["PLAYERNOTFOUND"] = 1] = "PLAYERNOTFOUND";
|
|
9
|
+
API_RETURNCODES[API_RETURNCODES["PLAYERBLOCKED"] = 2] = "PLAYERBLOCKED";
|
|
10
|
+
API_RETURNCODES[API_RETURNCODES["BALANCETOOLOW"] = 10] = "BALANCETOOLOW";
|
|
11
|
+
API_RETURNCODES[API_RETURNCODES["BETLIMITREACHED"] = 11] = "BETLIMITREACHED";
|
|
12
|
+
API_RETURNCODES[API_RETURNCODES["GAMEROUNDALREADYSTARTED"] = 12] = "GAMEROUNDALREADYSTARTED";
|
|
13
|
+
API_RETURNCODES[API_RETURNCODES["GAMEROUNDNOTACTIVE"] = 13] = "GAMEROUNDNOTACTIVE";
|
|
14
|
+
API_RETURNCODES[API_RETURNCODES["GAMEROUNDNOTFOUND"] = 14] = "GAMEROUNDNOTFOUND";
|
|
15
|
+
API_RETURNCODES[API_RETURNCODES["GAMEROUNDNOTSTARTED"] = 15] = "GAMEROUNDNOTSTARTED";
|
|
16
|
+
API_RETURNCODES[API_RETURNCODES["TRANSACTIONCOUNTWRONG"] = 16] = "TRANSACTIONCOUNTWRONG";
|
|
17
|
+
API_RETURNCODES[API_RETURNCODES["GAMEROUNDPLAYERMISMATCH"] = 17] = "GAMEROUNDPLAYERMISMATCH";
|
|
18
|
+
API_RETURNCODES[API_RETURNCODES["CURRENCYINVALID"] = 18] = "CURRENCYINVALID";
|
|
19
|
+
API_RETURNCODES[API_RETURNCODES["INVALIDPARAMETER"] = 19] = "INVALIDPARAMETER";
|
|
20
|
+
API_RETURNCODES[API_RETURNCODES["TRANSACTIONAFTEREND"] = 20] = "TRANSACTIONAFTEREND";
|
|
21
|
+
API_RETURNCODES[API_RETURNCODES["GAMEROUNDISLOCKED"] = 21] = "GAMEROUNDISLOCKED";
|
|
22
|
+
API_RETURNCODES[API_RETURNCODES["GAMEROUNDISCLOSING"] = 22] = "GAMEROUNDISCLOSING";
|
|
23
|
+
API_RETURNCODES[API_RETURNCODES["SPINNOTAVAILABLE"] = 23] = "SPINNOTAVAILABLE";
|
|
24
|
+
API_RETURNCODES[API_RETURNCODES["COOLOFFPERIODACTIVE"] = 25] = "COOLOFFPERIODACTIVE";
|
|
25
|
+
API_RETURNCODES[API_RETURNCODES["NOTLOGGEDON"] = 29] = "NOTLOGGEDON";
|
|
26
|
+
API_RETURNCODES[API_RETURNCODES["RESPONSIBLEGAMINGLIMITREACHED"] = 30] = "RESPONSIBLEGAMINGLIMITREACHED";
|
|
27
|
+
API_RETURNCODES[API_RETURNCODES["RESPONSIBLESGAMINGSESSIONEXPIRED"] = 31] = "RESPONSIBLESGAMINGSESSIONEXPIRED";
|
|
28
|
+
API_RETURNCODES[API_RETURNCODES["PLAYERNOAUTHENTICATED"] = 32] = "PLAYERNOAUTHENTICATED";
|
|
29
|
+
API_RETURNCODES[API_RETURNCODES["GENERICBETERROR"] = 34] = "GENERICBETERROR";
|
|
30
|
+
API_RETURNCODES[API_RETURNCODES["GENERICWINERROR"] = 35] = "GENERICWINERROR";
|
|
31
|
+
API_RETURNCODES[API_RETURNCODES["OPERATIONBEINGPROCESSED"] = 36] = "OPERATIONBEINGPROCESSED";
|
|
32
|
+
API_RETURNCODES[API_RETURNCODES["REALITYCHECK"] = 38] = "REALITYCHECK";
|
|
33
|
+
API_RETURNCODES[API_RETURNCODES["SIGNATUREWRONG"] = 1001] = "SIGNATUREWRONG";
|
|
34
|
+
API_RETURNCODES[API_RETURNCODES["PARAMETERMISSING"] = 1004] = "PARAMETERMISSING";
|
|
35
|
+
API_RETURNCODES[API_RETURNCODES["GAMECODENOTFOUND"] = 1006] = "GAMECODENOTFOUND";
|
|
36
|
+
API_RETURNCODES[API_RETURNCODES["SESSIONINVALID"] = 1008] = "SESSIONINVALID";
|
|
37
|
+
API_RETURNCODES[API_RETURNCODES["RNGFAILURE"] = 1009] = "RNGFAILURE";
|
|
38
|
+
API_RETURNCODES[API_RETURNCODES["NETWORKERROR"] = 1010] = "NETWORKERROR";
|
|
39
|
+
API_RETURNCODES[API_RETURNCODES["RATELIMITEXCEEDED"] = 1300] = "RATELIMITEXCEEDED";
|
|
40
|
+
API_RETURNCODES[API_RETURNCODES["UNEXPECTED"] = -1] = "UNEXPECTED";
|
|
41
|
+
})(API_RETURNCODES || (exports.API_RETURNCODES = API_RETURNCODES = {}));
|
|
42
|
+
/**
|
|
43
|
+
* Error codes that can be retried (e.g. balance too low, rate limit, network error).
|
|
44
|
+
* Use this to decide whether to show a retry option or a fatal error screen.
|
|
45
|
+
*/
|
|
46
|
+
exports.recoverableErrorCodes = [
|
|
47
|
+
API_RETURNCODES.BALANCETOOLOW,
|
|
48
|
+
API_RETURNCODES.BETLIMITREACHED,
|
|
49
|
+
API_RETURNCODES.NETWORKERROR,
|
|
50
|
+
API_RETURNCODES.RATELIMITEXCEEDED,
|
|
51
|
+
API_RETURNCODES.GENERICBETERROR,
|
|
52
|
+
API_RETURNCODES.RNGFAILURE,
|
|
53
|
+
API_RETURNCODES.OPERATIONBEINGPROCESSED,
|
|
54
|
+
].map(String);
|
|
55
|
+
/** Default timeout for HTTP and WebSocket requests, in milliseconds. */
|
|
56
|
+
exports.defaultNetworkTimeout = 30000;
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { login, loadConfig, placeBet, collect, pfVerify, refresh, reportAnimationEnd, updateBalance, getFreePlaysRemaining, getFreePlayStake } from './api.js';
|
|
2
|
+
export { enableWebSockets } from './websocket.js';
|
|
3
|
+
export type { WebSocketHandler } from './websocket.js';
|
|
4
|
+
export type { TNetworkResponse, TNetworkSuccess, TNetworkError, IErrorResponse, IBalanceEntry, IBalanceReply, IGameSettings, ITokenData, IGameState, IGameRoundInfo, IFreePlayInfo, IScenarioInfo, ISpinInfo, TPlayerChoiceFeatureAward, TPlayerChoiceCashAward, TPlayerChoiceAward, IGameResult, IBuyFeatureOption, ILoadConfigConfig, IProgressionCounterConfig, IProgressionEvent, TRandomChoiceAward, TRandomChoiceFeatureAward, TRandomChoiceCashAward, TProgressionAwarded, IConnectReply, ILoadConfigReply, IPlaceBetReply, ICollectReply, ISessionOptions, ILoginOptions, IPlaceBetOptions, ICollectOptions, IPfVerifyOptions, IPfVerifyAction, IPfVerifyReply, IRngDataEntry, TRouletteBetType, TRouletteBetSelection, TRouletteEvenMoneyBetType, IRouletteBet, IRouletteBetSettlement, IRouletteScenario, TBlackjackRank, TBlackjackSuit, IBlackjackCard, TBlackjackAction, TBlackjackActionKind, IBlackjackSideBets, IBlackjackInitialBet, IBlackjackChoice, IBlackjackHand, IBlackjackDealer, IBlackjackPerfectPairsBet, IBlackjackTwentyOnePlusThreeBet, IBlackjackInsuranceBet, IBlackjackScenario, ICrashBetRequest, ICrashBet, ICrashScenario, ICrashLoadConfig, TCrashEventName, ICrashRoundStartedPayload, ICrashRoundTickPayload, ICrashBetCashedOutPayload, ICrashRoundEndedPayload, ICrashBalanceUpdatedPayload, TCrashEvent, TMinesTile, IMinesScenario, IKenoScenario, } from './types/index.js';
|
|
5
|
+
export { rouletteAdditionalData, blackjackInitialData, blackjackActionData, CRASH_EVENTS, crashPlaceBetData, crashCollectData, minesPickData, kenoPickData, } from './types/index.js';
|
|
6
|
+
export { isCashChoice, isFeatureChoice } from './types/index.js';
|
|
7
|
+
export { API_RETURNCODES, recoverableErrorCodes, defaultNetworkTimeout } from './constants.js';
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultNetworkTimeout = exports.recoverableErrorCodes = exports.API_RETURNCODES = exports.isFeatureChoice = exports.isCashChoice = exports.kenoPickData = exports.minesPickData = exports.crashCollectData = exports.crashPlaceBetData = exports.CRASH_EVENTS = exports.blackjackActionData = exports.blackjackInitialData = exports.rouletteAdditionalData = exports.enableWebSockets = exports.getFreePlayStake = exports.getFreePlaysRemaining = exports.updateBalance = exports.reportAnimationEnd = exports.refresh = exports.pfVerify = exports.collect = exports.placeBet = exports.loadConfig = exports.login = void 0;
|
|
4
|
+
// API functions
|
|
5
|
+
var api_js_1 = require("./api.js");
|
|
6
|
+
Object.defineProperty(exports, "login", { enumerable: true, get: function () { return api_js_1.login; } });
|
|
7
|
+
Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return api_js_1.loadConfig; } });
|
|
8
|
+
Object.defineProperty(exports, "placeBet", { enumerable: true, get: function () { return api_js_1.placeBet; } });
|
|
9
|
+
Object.defineProperty(exports, "collect", { enumerable: true, get: function () { return api_js_1.collect; } });
|
|
10
|
+
Object.defineProperty(exports, "pfVerify", { enumerable: true, get: function () { return api_js_1.pfVerify; } });
|
|
11
|
+
Object.defineProperty(exports, "refresh", { enumerable: true, get: function () { return api_js_1.refresh; } });
|
|
12
|
+
Object.defineProperty(exports, "reportAnimationEnd", { enumerable: true, get: function () { return api_js_1.reportAnimationEnd; } });
|
|
13
|
+
Object.defineProperty(exports, "updateBalance", { enumerable: true, get: function () { return api_js_1.updateBalance; } });
|
|
14
|
+
Object.defineProperty(exports, "getFreePlaysRemaining", { enumerable: true, get: function () { return api_js_1.getFreePlaysRemaining; } });
|
|
15
|
+
Object.defineProperty(exports, "getFreePlayStake", { enumerable: true, get: function () { return api_js_1.getFreePlayStake; } });
|
|
16
|
+
// WebSocket
|
|
17
|
+
var websocket_js_1 = require("./websocket.js");
|
|
18
|
+
Object.defineProperty(exports, "enableWebSockets", { enumerable: true, get: function () { return websocket_js_1.enableWebSockets; } });
|
|
19
|
+
// Game-specific helpers
|
|
20
|
+
var index_js_1 = require("./types/index.js");
|
|
21
|
+
Object.defineProperty(exports, "rouletteAdditionalData", { enumerable: true, get: function () { return index_js_1.rouletteAdditionalData; } });
|
|
22
|
+
Object.defineProperty(exports, "blackjackInitialData", { enumerable: true, get: function () { return index_js_1.blackjackInitialData; } });
|
|
23
|
+
Object.defineProperty(exports, "blackjackActionData", { enumerable: true, get: function () { return index_js_1.blackjackActionData; } });
|
|
24
|
+
Object.defineProperty(exports, "CRASH_EVENTS", { enumerable: true, get: function () { return index_js_1.CRASH_EVENTS; } });
|
|
25
|
+
Object.defineProperty(exports, "crashPlaceBetData", { enumerable: true, get: function () { return index_js_1.crashPlaceBetData; } });
|
|
26
|
+
Object.defineProperty(exports, "crashCollectData", { enumerable: true, get: function () { return index_js_1.crashCollectData; } });
|
|
27
|
+
Object.defineProperty(exports, "minesPickData", { enumerable: true, get: function () { return index_js_1.minesPickData; } });
|
|
28
|
+
Object.defineProperty(exports, "kenoPickData", { enumerable: true, get: function () { return index_js_1.kenoPickData; } });
|
|
29
|
+
// Type guards
|
|
30
|
+
var index_js_2 = require("./types/index.js");
|
|
31
|
+
Object.defineProperty(exports, "isCashChoice", { enumerable: true, get: function () { return index_js_2.isCashChoice; } });
|
|
32
|
+
Object.defineProperty(exports, "isFeatureChoice", { enumerable: true, get: function () { return index_js_2.isFeatureChoice; } });
|
|
33
|
+
// Constants
|
|
34
|
+
var constants_js_1 = require("./constants.js");
|
|
35
|
+
Object.defineProperty(exports, "API_RETURNCODES", { enumerable: true, get: function () { return constants_js_1.API_RETURNCODES; } });
|
|
36
|
+
Object.defineProperty(exports, "recoverableErrorCodes", { enumerable: true, get: function () { return constants_js_1.recoverableErrorCodes; } });
|
|
37
|
+
Object.defineProperty(exports, "defaultNetworkTimeout", { enumerable: true, get: function () { return constants_js_1.defaultNetworkTimeout; } });
|
package/lib/network.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TNetworkResponse } from './types/index.js';
|
|
2
|
+
declare let wsTransport: {
|
|
3
|
+
send: <T>(body: Record<string, unknown>) => Promise<TNetworkResponse<T>>;
|
|
4
|
+
isConnected: () => boolean;
|
|
5
|
+
} | null;
|
|
6
|
+
export declare function setWsTransport(transport: typeof wsTransport): void;
|
|
7
|
+
export declare function getWsTransport(): typeof wsTransport;
|
|
8
|
+
export declare function request<T>(url: string, body: Record<string, unknown>): Promise<TNetworkResponse<T>>;
|
|
9
|
+
export {};
|
package/lib/network.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setWsTransport = setWsTransport;
|
|
4
|
+
exports.getWsTransport = getWsTransport;
|
|
5
|
+
exports.request = request;
|
|
6
|
+
const constants_js_1 = require("./constants.js");
|
|
7
|
+
let wsTransport = null;
|
|
8
|
+
function setWsTransport(transport) {
|
|
9
|
+
wsTransport = transport;
|
|
10
|
+
}
|
|
11
|
+
function getWsTransport() {
|
|
12
|
+
return wsTransport;
|
|
13
|
+
}
|
|
14
|
+
async function request(url, body) {
|
|
15
|
+
if (wsTransport?.isConnected()) {
|
|
16
|
+
return wsTransport.send(body);
|
|
17
|
+
}
|
|
18
|
+
return httpRequest(url, body);
|
|
19
|
+
}
|
|
20
|
+
function decodeBase64Utf8(value) {
|
|
21
|
+
try {
|
|
22
|
+
const binary = atob(value);
|
|
23
|
+
const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
|
|
24
|
+
return new TextDecoder('utf-8').decode(bytes);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function httpRequest(url, body) {
|
|
31
|
+
try {
|
|
32
|
+
const response = await fetch(url, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: { 'Content-Type': 'application/json' },
|
|
35
|
+
body: JSON.stringify(body),
|
|
36
|
+
signal: AbortSignal.timeout(constants_js_1.defaultNetworkTimeout),
|
|
37
|
+
});
|
|
38
|
+
const data = await response.json();
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
const errorMsgBase64 = response.headers.get('x-h-error-msg-base64');
|
|
41
|
+
const headerMsg = errorMsgBase64 ? decodeBase64Utf8(errorMsgBase64) : response.headers.get('x-h-error-msg');
|
|
42
|
+
const headerId = response.headers.get('x-h-error-id');
|
|
43
|
+
const error = {
|
|
44
|
+
code: String(headerId ?? data?.errorId ?? data?.code ?? constants_js_1.API_RETURNCODES.UNEXPECTED),
|
|
45
|
+
message: headerMsg ?? data?.errorText ?? data?.message ?? response.statusText,
|
|
46
|
+
};
|
|
47
|
+
if (data?.passThroughData !== undefined && data?.passThroughData !== 'undefined') {
|
|
48
|
+
error.passThroughData = data.passThroughData;
|
|
49
|
+
}
|
|
50
|
+
return { success: false, error };
|
|
51
|
+
}
|
|
52
|
+
return { success: true, result: data };
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return {
|
|
56
|
+
success: false,
|
|
57
|
+
error: {
|
|
58
|
+
code: String(constants_js_1.API_RETURNCODES.NETWORKERROR),
|
|
59
|
+
message: error instanceof Error ? error.message : 'Network error',
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** A single balance bucket (e.g. real money, bonus, free-play credit). */
|
|
2
|
+
export interface IBalanceEntry {
|
|
3
|
+
/** Balance type identifier (e.g. "real", "bonus"). */
|
|
4
|
+
type: string;
|
|
5
|
+
/** ISO 4217 currency code. */
|
|
6
|
+
currency: string;
|
|
7
|
+
/** Balance amount in minor currency units. */
|
|
8
|
+
amount: number;
|
|
9
|
+
}
|
|
10
|
+
/** Player balance breakdown, returned in most API responses. */
|
|
11
|
+
export interface IBalanceReply {
|
|
12
|
+
/** Sum of all balance buckets. */
|
|
13
|
+
totalBalance: number;
|
|
14
|
+
/** Balance mode identifier (operator-specific). */
|
|
15
|
+
mode: string;
|
|
16
|
+
/** ISO 4217 currency code. */
|
|
17
|
+
currency: string;
|
|
18
|
+
/** Individual balance buckets. */
|
|
19
|
+
balances: IBalanceEntry[];
|
|
20
|
+
}
|