@kalamba/sdk 0.42.0 → 0.48.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.
package/dist/wrapper.cjs CHANGED
@@ -3,757 +3,808 @@
3
3
  * Copyright (c) 2026, Kalamba Games Limited
4
4
  */
5
5
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
6
- const require_errors = require('./errors-BUjKnbx5.cjs');
6
+ const require_errors = require('./errors-DXZbBm5R.cjs');
7
7
  let lodash_es = require("lodash-es");
8
8
  let uuid = require("uuid");
9
+ let zustand_vanilla = require("zustand/vanilla");
9
10
 
10
- //#region src/common/PayloadInjectionManager.ts
11
- /**
12
- * PayloadInjectionManager manages payload injection from multiple sources.
13
- * Each source can register either static payload data or async functions that will be merged together when creating the final payload for injection.
14
- */
15
- var PayloadInjectionManager = class {
16
- #injectors = /* @__PURE__ */ new Map();
17
- /**
18
- * Register or update payload injector from a specific source
19
- * @param source - Unique identifier for the payload source (e.g., 'bspot', 'freeRounds')
20
- * @param payload - Payload data or async function that receives playPayload and returns payload data
21
- */
22
- register(source, payloadProvider) {
23
- this.#injectors.set(source, payloadProvider);
24
- }
25
- /**
26
- * Remove payload injector from a specific source
27
- * @param source - Source identifier to remove
28
- */
29
- unregister(source) {
30
- this.#injectors.delete(source);
31
- }
32
- /**
33
- * Get merged payload from all registered injectors
34
- * @param playPayload - The play payload that will be passed to registered functions
35
- * @returns Promise resolving to merged payload object or undefined if no injectors registered
36
- */
37
- async getPayload(playPayload) {
38
- if (this.#injectors.size === 0) return;
39
- const merged = {};
40
- for (const payloadProvider of this.#injectors.values()) (0, lodash_es.merge)(merged, typeof payloadProvider === "function" ? await payloadProvider(playPayload) : payloadProvider);
41
- return merged;
11
+ //#region src/common/config/SdkConfigManager.ts
12
+ var SdkConfigManager = class {
13
+ config;
14
+ constructor() {
15
+ this.config = {
16
+ api: {
17
+ brand: "",
18
+ cashierUrl: void 0,
19
+ coinValueInCents: 1,
20
+ country: "",
21
+ currency: "",
22
+ game: "",
23
+ gameHistoryUrl: "",
24
+ homeUrl: void 0,
25
+ integration: "",
26
+ jurisdiction: null,
27
+ playMode: "FUN",
28
+ user: "",
29
+ username: "",
30
+ sessionId: (0, uuid.v4)(),
31
+ backendSessionId: void 0
32
+ },
33
+ ui: {
34
+ autoplay: {
35
+ enabled: false,
36
+ rounds: {
37
+ enabled: false,
38
+ showNoLimit: false,
39
+ showCustomLimit: false,
40
+ options: []
41
+ },
42
+ lossLimit: {
43
+ enabled: false,
44
+ showNoLimit: false,
45
+ showCustomLimit: false,
46
+ options: []
47
+ },
48
+ winLimit: {
49
+ enabled: false,
50
+ showNoLimit: false,
51
+ showCustomLimit: false,
52
+ options: []
53
+ },
54
+ simple: false,
55
+ stopOnFeature: false
56
+ },
57
+ cashier: {
58
+ enabled: false,
59
+ balanceThreshold: [0]
60
+ },
61
+ feature: {
62
+ allowTelemetry: false,
63
+ allowFullscreen: false,
64
+ allowGamble: false,
65
+ allowQuickStop: false,
66
+ showCashier: false,
67
+ showClock: false,
68
+ showCloseGame: false,
69
+ showCurrency: true,
70
+ showDeconstructedBet: false,
71
+ showFastPlay: false,
72
+ showFeatureBuy: false,
73
+ showFeatureIntro: false,
74
+ showFeatureOutro: false,
75
+ showFunModeBanner: false,
76
+ showHistory: false,
77
+ showLowWinCelebration: false,
78
+ showMaximumWin: false,
79
+ showNetPosition: false,
80
+ showPaylineLines: false,
81
+ showPaytable: false,
82
+ showPromoPanel: true,
83
+ showRoundId: false,
84
+ showRtp: false,
85
+ showRules: false,
86
+ showSessionDuration: false,
87
+ showUi: true
88
+ },
89
+ language: "en",
90
+ minimumSpinDuration: 0,
91
+ requestTimeoutMs: 1e4,
92
+ incompleteGameResolution: { type: "NONE" },
93
+ realityCheck: {
94
+ sessionDurationPeriodFormat: "minutes",
95
+ showCloseGame: false,
96
+ showHistory: false,
97
+ showNetPosition: false,
98
+ showSessionDuration: false,
99
+ showSumBets: false,
100
+ showSumWins: false
101
+ },
102
+ skipInsufficientFundsCheck: false,
103
+ skipSplash: false,
104
+ cheatPanel: false
105
+ }
106
+ };
42
107
  }
43
108
  };
44
109
 
45
110
  //#endregion
46
- //#region src/wrapper/KalambaSdkWrapper.ts
47
- const logIn = () => {};
48
- const logOut = () => {};
49
- var KalambaSdkWrapper = class {
50
- #messagePort;
51
- #plugins;
52
- #config = {
53
- gameName: "UNKNOWN",
54
- gameVersion: "unknown",
55
- showErrors: true,
56
- showFreeRounds: true,
57
- showPromoPanel: false,
58
- showRealityCheck: true,
59
- showBars: true,
60
- skipErrors: []
61
- };
62
- #state = {
63
- isSdkConfigured: false,
64
- balance: 0,
65
- bet: {
66
- base: 0,
67
- multiplier: 0
68
- },
69
- updateBalance: true,
70
- openGameResponse: void 0,
71
- lastPlayResponse: void 0,
72
- freeRoundId: void 0
73
- };
74
- #sdkConfigManager;
75
- #payloadInjectionManager;
76
- #wakeLock;
77
- constructor({ messagePort, plugins, sdkConfigManager }) {
78
- this.#messagePort = messagePort;
79
- this.#sdkConfigManager = new sdkConfigManager();
80
- this.#payloadInjectionManager = new PayloadInjectionManager();
81
- this.injectPayload = this.injectPayload.bind(this);
82
- this.#plugins = {
83
- rgs: new plugins.rgs(this.config, this.sdkConfig, this.state),
84
- casino: plugins.casino.map((casinoPlugin) => new casinoPlugin(this.config, this.sdkConfig, this.state, this.injectPayload)),
85
- telemetry: plugins.telemetry.map(({ plugin, trackers }) => new plugin(trackers.map((tracker) => new tracker(this.config, this.sdkConfig)), this.config, this.sdkConfig))
86
- };
87
- this.on("balance", ({ balance }) => {
88
- this.setState((state) => ({
89
- ...state,
90
- balance
91
- }));
92
- });
93
- this.on("bet", (bet) => {
94
- this.setState((state) => ({
95
- ...state,
96
- bet
97
- }));
98
- });
99
- this.on("sdk:playCycleStart", async () => {
100
- await this.requestWakeLock();
101
- if (this.state.freeRoundId) return;
102
- this.setState((state) => ({
103
- ...state,
104
- balance: state.balance - state.bet.base * state.bet.multiplier
105
- }));
106
- });
107
- this.on("sdk:play", async (payload) => {
108
- const payloadToInject = await this.#payloadInjectionManager.getPayload(payload.contract);
109
- this.send("play", {
110
- ...payload,
111
- payloadToInject
112
- });
113
- });
114
- this.on("sdk:configure", (payload) => {
115
- Object.assign(this.#config, payload);
116
- });
117
- this.on("freeRoundsPopup", () => {
118
- const freeRound = (this.state.lastPlayResponse ?? this.state.openGameResponse)?.freeRounds[0];
119
- if (freeRound && this.state.freeRoundId) this.send("freeRoundsInfo", freeRound);
120
- });
121
- this.on("rgs:openGameResponse", async (response) => {
122
- this.on("playReady", () => {
123
- this.handleFreeRounds(response.contract.freeRounds[0]);
124
- });
125
- this.sdkConfig.ui = await this.#sdkConfigManager.getConfig();
126
- this.setState((state) => ({
127
- ...state,
128
- isSdkConfigured: true
129
- }));
130
- this.send("configured", this.sdkConfig);
131
- this.send("legalBets", response.contract.bet.available);
132
- this.send("bet", response.contract.bet.lastPaid ?? response.contract.bet.default);
133
- this.setState((state) => ({
134
- ...state,
135
- openGameResponse: response.contract
136
- }));
137
- if (this.state.updateBalance) this.setState((state) => ({
138
- ...state,
139
- balance: response.contract.balance.coins
140
- }));
141
- });
142
- this.on("rgs:openGameError", async (error) => {
143
- if (error.type === "timeout" && !this.config.skipErrors.includes("TIMEOUT")) this.send("error", {
144
- messageKey: `Error.TIMEOUT`,
145
- messageCode: "TIMEOUT",
146
- type: "RELOAD"
147
- });
148
- if (error.type === "error" && !this.config.skipErrors.includes(error.data.code)) this.send("error", {
149
- messageKey: `RgsError.${error.data.code}`,
150
- messageCode: error.data.code,
151
- type: require_errors.RgsErrorAction[error.data.code]
152
- });
153
- });
154
- this.on("rgs:playResponse", async (response) => {
155
- this.setState((state) => ({
156
- ...state,
157
- lastPlayResponse: response.contract
158
- }));
159
- });
160
- this.on("playCycleEnd", () => {
161
- this.releaseWakeLock();
162
- if (this.state.updateBalance) this.setState((state) => ({
163
- ...state,
164
- balance: this.state.lastPlayResponse.balance.coins
165
- }));
166
- this.handleFreeRounds(this.state.lastPlayResponse.freeRounds[0]);
167
- });
168
- this.on("rgs:playError", async (error) => {
169
- if (error.type === "timeout" && !this.config.skipErrors.includes("TIMEOUT")) this.send("error", {
170
- messageKey: `Error.TIMEOUT`,
171
- messageCode: "TIMEOUT",
172
- type: "RELOAD"
173
- });
174
- if (error.type === "error" && !this.config.skipErrors.includes(error.data.code)) this.send("error", {
175
- messageKey: `RgsError.${error.data.code}`,
176
- messageCode: error.data.code,
177
- type: require_errors.RgsErrorAction[error.data.code]
178
- });
179
- });
180
- this.on("rgs:freeRoundsResponse", async (response) => {
181
- if (response.action === "ACCEPT") {
182
- const freeRound = (this.state.lastPlayResponse ?? this.state.openGameResponse)?.freeRounds[0];
183
- this.activateFreeRounds(freeRound);
184
- }
185
- });
186
- this.on("rgs:freeRoundsError", async (error) => {
187
- if (error.type === "timeout" && !this.config.skipErrors.includes("TIMEOUT")) this.send("error", {
188
- messageKey: `Error.TIMEOUT`,
189
- messageCode: "TIMEOUT",
190
- type: "RELOAD"
191
- });
192
- if (error.type === "error" && !this.config.skipErrors.includes(error.data.code)) this.send("error", {
193
- messageKey: `RgsError.${error.data.code}`,
194
- messageCode: error.data.code,
195
- type: require_errors.RgsErrorAction[error.data.code]
196
- });
197
- });
198
- this.forwardMessages();
199
- document.addEventListener("visibilitychange", async () => {
200
- if (this.#wakeLock && document.visibilityState === "visible") await this.requestWakeLock();
201
- });
111
+ //#region src/common/config/KalambaSdkConfigManager.ts
112
+ function jurisdictionConfigOverrides(config, jurisdiction) {
113
+ function limitRounds(autoPlayRounds, { maxCount }) {
114
+ const limitCount = (rounds) => rounds?.filter((count) => count <= maxCount) ?? [];
115
+ const castToNumber = (rounds) => rounds?.map((count) => Number(count)) ?? [];
116
+ const rounds = [...autoPlayRounds, maxCount];
117
+ return (0, lodash_es.flow)([
118
+ castToNumber,
119
+ limitCount,
120
+ lodash_es.sortBy,
121
+ lodash_es.sortedUniq
122
+ ])(rounds);
202
123
  }
203
- get state() {
204
- const that = this;
205
- return new Proxy({}, {
206
- get(_target, prop) {
207
- return Reflect.get(that.#state, prop);
124
+ switch (jurisdiction) {
125
+ case "BG": return { autoplay: {
126
+ lossLimit: {
127
+ enabled: true,
128
+ showNoLimit: false
129
+ },
130
+ winLimit: { enabled: true }
131
+ } };
132
+ case "BR": return {
133
+ autoplay: {
134
+ lossLimit: {
135
+ enabled: true,
136
+ showNoLimit: false
137
+ },
138
+ winLimit: { enabled: true }
139
+ },
140
+ feature: { showPaylineLines: true }
141
+ };
142
+ case "CA": return {
143
+ autoplay: { enabled: false },
144
+ feature: {
145
+ showFastPlay: false,
146
+ allowQuickStop: false,
147
+ showFeatureBuy: false
148
+ },
149
+ minimumSpinDuration: 2.5
150
+ };
151
+ case "CO": return {
152
+ autoplay: { rounds: {
153
+ showNoLimit: false,
154
+ showCustomLimit: false,
155
+ options: limitRounds(config.autoplay.rounds.options, { maxCount: 100 })
156
+ } },
157
+ feature: {
158
+ showFastPlay: false,
159
+ allowQuickStop: false
160
+ },
161
+ minimumSpinDuration: 3
162
+ };
163
+ case "CZ": return {
164
+ feature: {
165
+ showFastPlay: false,
166
+ showFeatureBuy: false,
167
+ allowGamble: false
168
+ },
169
+ minimumSpinDuration: 2
170
+ };
171
+ case "DE": return {
172
+ autoplay: { enabled: false },
173
+ feature: {
174
+ showFastPlay: false,
175
+ allowQuickStop: false,
176
+ showFeatureBuy: false,
177
+ showPromoPanel: false
178
+ },
179
+ minimumSpinDuration: 5
180
+ };
181
+ case "DK": return { minimumSpinDuration: 3 };
182
+ case "ES": return {
183
+ autoplay: { rounds: {
184
+ showNoLimit: false,
185
+ showCustomLimit: false,
186
+ options: limitRounds(config.autoplay.rounds.options, { maxCount: 100 })
187
+ } },
188
+ feature: {
189
+ showFastPlay: false,
190
+ allowQuickStop: false
191
+ },
192
+ minimumSpinDuration: 3
193
+ };
194
+ case "GR": return {
195
+ feature: {
196
+ showFastPlay: false,
197
+ allowQuickStop: false,
198
+ showFeatureBuy: false
199
+ },
200
+ minimumSpinDuration: 3
201
+ };
202
+ case "IT": return { feature: {
203
+ showDeconstructedBet: true,
204
+ showPaylineLines: true
205
+ } };
206
+ case "NL": return {
207
+ autoplay: { enabled: false },
208
+ feature: { showFeatureBuy: false }
209
+ };
210
+ case "PT": return {
211
+ autoplay: { rounds: {
212
+ showNoLimit: false,
213
+ showCustomLimit: false,
214
+ options: limitRounds(config.autoplay.rounds.options, { maxCount: 100 })
215
+ } },
216
+ feature: {
217
+ showFeatureBuy: false,
218
+ showFastPlay: false,
219
+ allowQuickStop: false
208
220
  },
209
- set(_target, prop, value) {
210
- that.setState((state) => ({
211
- ...state,
212
- [prop]: value
213
- }));
214
- return true;
215
- }
216
- });
217
- }
218
- setState(setter) {
219
- this.#state = setter(this.#state);
220
- this.send("state", this.#state);
221
- }
222
- forwardMessages() {
223
- this.forwardToPlugins("casino", [
224
- "sdk:autoplay",
225
- "sdk:bet",
226
- "sdk:cashier",
227
- "sdk:choice",
228
- "sdk:close",
229
- "sdk:error",
230
- "sdk:history",
231
- "sdk:loadEnd",
232
- "sdk:loadProgress",
233
- "sdk:loadStart",
234
- "sdk:playReady",
235
- "sdk:playCycleEnd",
236
- "sdk:playCycleStart",
237
- "sdk:playEnd",
238
- "sdk:playStart",
239
- "sdk:settings",
240
- "sdk:openGame",
241
- "sdk:configure",
242
- "sdk:fullscreen"
243
- ]);
244
- this.forwardToPlugins("casino", ["rgs:playResponse", "rgs:openGameResponse"]);
245
- this.forwardToPlugins("rgs", ["sdk:openGame", "sdk:history"]);
246
- this.forwardToPlugins("rgs", [
247
- "casino:play",
248
- "casino:cashier",
249
- "casino:close",
250
- "casino:history",
251
- "casino:getBalance"
252
- ]);
253
- this.forwardToPlugins("telemetry", [
254
- "sdk:autoplay",
255
- "sdk:error",
256
- "sdk:playCycleStart",
257
- "sdk:playCycleEnd",
258
- "sdk:loadStart",
259
- "sdk:loadProgress",
260
- "sdk:loadEnd",
261
- "sdk:telemetry.click",
262
- "sdk:telemetry.orientationChange"
263
- ]);
264
- this.forwardToPlugins("telemetry", ["rgs:openGameResponse", "rgs:playResponse"]);
265
- this.forwardToSdk([
266
- "casino:balance",
267
- "casino:bet",
268
- "casino:choice",
269
- "casino:freeze",
270
- "casino:help",
271
- "casino:paytable",
272
- "casino:resume",
273
- "casino:settings",
274
- "casino:suspend",
275
- "casino:unfreeze"
276
- ]);
277
- this.forwardToSdk([
278
- "rgs:balance",
279
- "rgs:openGameError",
280
- "rgs:openGameResponse",
281
- "rgs:playError",
282
- "rgs:playResponse",
283
- "rgs:realityCheck"
284
- ]);
285
- }
286
- get config() {
287
- const that = this;
288
- return new Proxy({}, {
289
- get(_target, prop) {
290
- return Reflect.get(that.#config, prop);
221
+ minimumSpinDuration: 3
222
+ };
223
+ case "SE": return {
224
+ autoplay: { rounds: {
225
+ showNoLimit: false,
226
+ showCustomLimit: false,
227
+ options: limitRounds(config.autoplay.rounds.options, { maxCount: 100 })
228
+ } },
229
+ feature: {
230
+ showFastPlay: false,
231
+ allowQuickStop: false
291
232
  },
292
- set(_target, prop, value) {
293
- return Reflect.set(that.#config, prop, value);
233
+ minimumSpinDuration: 3
234
+ };
235
+ case "UK": return {
236
+ autoplay: { enabled: false },
237
+ feature: {
238
+ showFastPlay: false,
239
+ allowQuickStop: false,
240
+ showFeatureBuy: false
241
+ },
242
+ minimumSpinDuration: 2.5
243
+ };
244
+ case "US": return { feature: { showPaylineLines: true } };
245
+ case "MT": return { feature: { showClock: true } };
246
+ case "SOCIAL": return { feature: { showHistory: false } };
247
+ case "CLASS2": return {
248
+ autoplay: { enabled: false },
249
+ feature: {
250
+ showFeatureBuy: false,
251
+ showPromoPanel: false
294
252
  }
295
- });
253
+ };
296
254
  }
297
- get sdkConfig() {
298
- return this.#sdkConfigManager.config;
255
+ return {};
256
+ }
257
+ var KalambaSdkConfigManager = class extends SdkConfigManager {
258
+ async getConfig() {
259
+ let uiConfig = this.config.ui;
260
+ const operatorConfig = await this.fetchOperatorConfig();
261
+ uiConfig = (0, lodash_es.merge)({}, uiConfig, operatorConfig);
262
+ const searchParams = new URLSearchParams(window.location.search);
263
+ const badgeOverrides = JSON.parse(searchParams.get("badgeParameters") ?? "{}");
264
+ uiConfig = (0, lodash_es.merge)({}, uiConfig, badgeOverrides);
265
+ const jurisdictionOverrides = jurisdictionConfigOverrides(uiConfig, this.config.api.jurisdiction);
266
+ uiConfig = (0, lodash_es.merge)({}, uiConfig, jurisdictionOverrides);
267
+ return uiConfig;
299
268
  }
300
- forwardToPlugins(targetDomain, messages) {
301
- messages.forEach((message) => {
302
- const onMessage = (event) => {
303
- if (event.data.message !== `kalamba:${message}`) return;
304
- logIn("wrapper:forwardToPlugins", targetDomain, event.data.message.replace(/^kalamba:/, ""), event.data.payload);
305
- window.postMessage({
306
- message: `kalamba:wrapper-${targetDomain}:${message.replace(/^(.+):/, "")}`,
307
- payload: event.data.payload
308
- });
309
- };
310
- window.addEventListener("message", onMessage);
311
- });
269
+ get mappedIntegration() {
270
+ const integration = this.config.api.integration.toLowerCase();
271
+ const brand = this.config.api.brand.toLowerCase();
272
+ if (integration === "spinomenal") {
273
+ if (brand.startsWith("gg-")) return "groove";
274
+ } else if (integration === "pariplay") {
275
+ if (brand.startsWith("8x1")) return "pariplay-8x1";
276
+ } else if (/openbox-.*/.test(integration)) return "openbox";
277
+ else if (/oryx-.*/.test(integration)) return "oryx";
278
+ else if (/relax-.*/.test(integration)) return "relax";
279
+ return integration;
312
280
  }
313
- forwardToSdk(messages) {
314
- messages.forEach((message) => {
315
- const onMessage = (event) => {
316
- if (event.data.message !== `kalamba:${message}`) return;
317
- logOut("wrapper:forwardToSdk", event.data.message.replace(/^kalamba:/, ""), event.data.payload);
318
- this.#messagePort.postMessage({
319
- message: `kalamba:wrapper:${message.replace(/^(.+):/, "")}`,
320
- payload: event.data.payload
321
- }, "*");
322
- };
323
- window.addEventListener("message", onMessage);
324
- });
281
+ get mappedBrand() {
282
+ const integration = this.config.api.integration.toLowerCase();
283
+ const brand = this.config.api.brand.toLowerCase();
284
+ if (integration === "bspot" && this.config.api.playMode.toLowerCase() === "fun") return "demo";
285
+ return brand;
325
286
  }
326
- on(message, listener, options) {
327
- const onMessage = function onMessage(event) {
328
- if (!new RegExp(`^kalamba:${message.includes(":") ? "" : "(.+):"}${message}$`).test(event.data.message) || new RegExp(`^kalamba:wrapper-(.+):${message}`).test(event.data.message) || new RegExp(`^kalamba:(.+)-wrapper:${message}`).test(event.data.message)) return;
329
- logIn("on", event.data.message.replace(/^kalamba:/, ""), event.data.payload);
330
- listener(event.data.payload);
331
- if (options?.once) window.removeEventListener("message", onMessage);
287
+ mapUiConfig(config) {
288
+ if (!config) return {};
289
+ return {
290
+ autoplay: {
291
+ enabled: config.badge.autoplayType !== 5,
292
+ rounds: {
293
+ enabled: config.badge.autoplayType !== 5,
294
+ showNoLimit: false,
295
+ showCustomLimit: false,
296
+ options: config.badge.autoplayRounds ?? [
297
+ 5,
298
+ 10,
299
+ 25,
300
+ 75,
301
+ 100
302
+ ]
303
+ },
304
+ lossLimit: {
305
+ enabled: config.badge.autoplayType === 1 || config.badge.autoplayType === 4,
306
+ showNoLimit: config.badge.autoplayType === 1,
307
+ showCustomLimit: config.badge.autoplayType !== 6,
308
+ options: [
309
+ 5,
310
+ 25,
311
+ 50
312
+ ]
313
+ },
314
+ winLimit: {
315
+ enabled: config.badge.autoplayType === 1 || config.badge.autoplayType === 4,
316
+ showNoLimit: true,
317
+ showCustomLimit: config.badge.autoplayType !== 6,
318
+ options: [
319
+ 10,
320
+ 20,
321
+ 75
322
+ ]
323
+ },
324
+ simple: config.badge.autoplayType === 3
325
+ },
326
+ cashier: {
327
+ enabled: config.badge.showQuickDeposit,
328
+ balanceThreshold: config.badge.quickDepositBalanceThresholds
329
+ },
330
+ feature: {
331
+ allowTelemetry: true,
332
+ allowFullscreen: config.defaults.fullscreen === "true",
333
+ allowGamble: config.badge.gambleHideWithAutoCollect === void 0 ? true : !config.badge.gambleHideWithAutoCollect,
334
+ allowQuickStop: config.badge.minimumSpinDuration === 0,
335
+ showCashier: config.badge.showQuickDeposit,
336
+ showClock: config.badge.showClock,
337
+ showCloseGame: config.badge.showCloseGameButton && (!config.badge.showCloseGameButtonOptional || !!this.config.api.homeUrl),
338
+ showCurrency: config.badge.showCurrency,
339
+ showDeconstructedBet: config.badge.showDeconstructedBet,
340
+ showFastPlay: config.badge.showTurboButton,
341
+ showFeatureBuy: config.badge.showHyperBonus,
342
+ showFunModeBanner: config.badge.showFunBanner,
343
+ showHistory: config.badge.showGameHistory,
344
+ showPaylineLines: config.badge.showPaylineLines,
345
+ showPromoPanel: config.defaults.showMetafeatures !== "false",
346
+ showRoundId: config.badge.showRoundId,
347
+ showRules: config.badge.showGameRules,
348
+ showSessionDuration: config.badge.realityCheckShowSessionDuration,
349
+ showUi: config.badge.showGameUi
350
+ },
351
+ minimumSpinDuration: config.badge.minimumSpinDuration,
352
+ requestTimeoutMs: config.badge.requestTimeoutMs,
353
+ incompleteGameResolution: {
354
+ daysToAutoResolution: config.badge.incompleteGamesResolutionType === 3 ? config.badge.daysToAutoResolution ?? 90 : void 0,
355
+ type: config.badge.incompleteGamesResolutionType === 2 ? "MANUAL" : config.badge.incompleteGamesResolutionType === 3 ? "AUTOMATIC" : void 0
356
+ },
357
+ realityCheck: {
358
+ sessionDurationPeriodFormat: config.badge.realityCheckPeriodFormat,
359
+ showCloseGame: config.badge.realityCheckShowCloseGame,
360
+ showHistory: config.badge.realityCheckShowHistoryLink,
361
+ showNetPosition: config.badge.realityCheckShowNetGamingActivity,
362
+ showSessionDuration: config.badge.realityCheckShowSessionDuration,
363
+ showSumBets: config.badge.realityCheckShowSumBets,
364
+ showSumWins: config.badge.realityCheckShowSumWins
365
+ },
366
+ skipInsufficientFundsCheck: config.badge.skipInsufficientFundsCheck,
367
+ skipSplash: config.badge.loaderAutoContinue
332
368
  };
333
- window.addEventListener("message", onMessage);
334
- return () => window.removeEventListener("message", onMessage);
335
- }
336
- send(message, ...[payload]) {
337
- logOut("wrapper:send", message, payload);
338
- window.postMessage({
339
- message: `kalamba:wrapper:${message}`,
340
- payload
341
- });
342
- this.#messagePort.postMessage({
343
- message: `kalamba:wrapper:${message}`,
344
- payload
345
- }, "*");
346
- }
347
- injectPayload(...[source, payload]) {
348
- this.#payloadInjectionManager.register(source, payload);
349
- return () => this.#payloadInjectionManager.unregister(source);
350
- }
351
- activateFreeRounds(freeRound) {
352
- if (!freeRound) return;
353
- this.setState((state) => ({
354
- ...state,
355
- freeRoundId: freeRound.id
356
- }));
357
- this.#payloadInjectionManager.register("freeRounds", { freeRoundId: freeRound.id });
358
- this.send("legalBets", { [freeRound.conf.base]: [freeRound.conf.multiplier] });
359
- this.send("bet", {
360
- base: freeRound.conf.base,
361
- multiplier: freeRound.conf.multiplier
362
- });
363
369
  }
364
- handleFreeRounds(freeRound) {
365
- if (!freeRound) return;
366
- switch (freeRound.status) {
367
- case "ACTIVE":
368
- this.activateFreeRounds(freeRound);
369
- break;
370
- case "PENDING":
371
- this.send("freeRoundsOffer", freeRound);
372
- break;
373
- case "FINISHED":
374
- this.send("freeRoundsComplete", freeRound);
375
- this.setState((state) => ({
376
- ...state,
377
- freeRoundId: void 0
378
- }));
379
- this.#payloadInjectionManager.unregister("freeRounds");
380
- this.send("legalBets", this.state.openGameResponse.bet.available);
381
- this.send("bet", this.state.openGameResponse.bet.default);
382
- break;
383
- default: break;
370
+ async fetchOperatorConfig() {
371
+ const rootUrl = "https://awscdn.kalamba.net/games/games/build/";
372
+ const integration = this.mappedIntegration;
373
+ const brand = this.mappedBrand;
374
+ let config = {};
375
+ try {
376
+ config = await fetch(`${rootUrl}config/${integration}/cage/${brand}.json`).then((r) => r.json());
377
+ } catch (e) {
378
+ try {
379
+ config = await fetch(`${rootUrl}config/${integration}/operator.json`).then((r) => r.json());
380
+ } catch (e) {
381
+ config = await fetch(`${rootUrl}config/fun/operator.json`).then((r) => r.json());
382
+ }
384
383
  }
384
+ return this.mapUiConfig(config);
385
385
  }
386
- async requestWakeLock() {
387
- try {
388
- this.#wakeLock = await navigator.wakeLock.request("screen");
389
- } catch {}
386
+ };
387
+
388
+ //#endregion
389
+ //#region src/common/PayloadInjectionManager.ts
390
+ /**
391
+ * PayloadInjectionManager manages payload injection from multiple sources.
392
+ * Each source can register either static payload data or async functions that will be merged together when creating the final payload for injection.
393
+ */
394
+ var PayloadInjectionManager = class {
395
+ #injectors = /* @__PURE__ */ new Map();
396
+ /**
397
+ * Register or update payload injector from a specific source
398
+ * @param source - Unique identifier for the payload source (e.g., 'bspot', 'freeRounds')
399
+ * @param payload - Payload data or async function that receives playPayload and returns payload data
400
+ */
401
+ register(source, payloadProvider) {
402
+ this.#injectors.set(source, payloadProvider);
390
403
  }
391
- async releaseWakeLock() {
392
- if (!this.#wakeLock) return;
393
- await this.#wakeLock.release();
394
- this.#wakeLock = void 0;
404
+ /**
405
+ * Remove payload injector from a specific source
406
+ * @param source - Source identifier to remove
407
+ */
408
+ unregister(source) {
409
+ this.#injectors.delete(source);
410
+ }
411
+ /**
412
+ * Get merged payload from all registered injectors
413
+ * @param playPayload - The play payload that will be passed to registered functions
414
+ * @returns Promise resolving to merged payload object or undefined if no injectors registered
415
+ */
416
+ async getPayload(playPayload) {
417
+ if (this.#injectors.size === 0) return;
418
+ const merged = {};
419
+ for (const payloadProvider of this.#injectors.values()) (0, lodash_es.merge)(merged, typeof payloadProvider === "function" ? await payloadProvider(playPayload) : payloadProvider);
420
+ return merged;
395
421
  }
396
422
  };
397
423
 
398
424
  //#endregion
399
- //#region src/common/config/SdkConfigManager.ts
400
- var SdkConfigManager = class {
401
- config;
402
- constructor() {
403
- this.config = {
404
- api: {
405
- brand: "",
406
- cashierUrl: void 0,
407
- coinValueInCents: 1,
408
- country: "",
409
- currency: "",
410
- game: "",
411
- gameHistoryUrl: "",
412
- homeUrl: void 0,
413
- integration: "",
414
- jurisdiction: null,
415
- playMode: "FUN",
416
- user: "",
417
- sessionId: (0, uuid.v4)(),
418
- backendSessionId: void 0
419
- },
420
- ui: {
421
- autoplay: {
422
- enabled: false,
423
- rounds: {
424
- enabled: false,
425
- showNoLimit: false,
426
- showCustomLimit: false,
427
- options: []
428
- },
429
- lossLimit: {
430
- enabled: false,
431
- showNoLimit: false,
432
- showCustomLimit: false,
433
- options: []
434
- },
435
- winLimit: {
436
- enabled: false,
437
- showNoLimit: false,
438
- showCustomLimit: false,
439
- options: []
440
- },
441
- simple: false,
442
- stopOnFeature: false
443
- },
444
- cashier: {
445
- enabled: false,
446
- balanceThreshold: [0]
447
- },
448
- feature: {
449
- allowTelemetry: false,
450
- allowFullscreen: false,
451
- allowGamble: false,
452
- allowQuickStop: false,
453
- showCashier: false,
454
- showClock: false,
455
- showCloseGame: false,
456
- showCurrency: true,
457
- showDeconstructedBet: false,
458
- showFastPlay: false,
459
- showFeatureBuy: false,
460
- showFeatureIntro: false,
461
- showFeatureOutro: false,
462
- showFunModeBanner: false,
463
- showHistory: false,
464
- showLowWinCelebration: false,
465
- showMaximumWin: false,
466
- showNetPosition: false,
467
- showPaylineLines: false,
468
- showPaytable: false,
469
- showRoundId: false,
470
- showRtp: false,
471
- showRules: false,
472
- showSessionDuration: false,
473
- showUi: true
474
- },
475
- language: "en",
476
- minimumSpinDuration: 0,
477
- requestTimeoutMs: 1e4,
478
- incompleteGameResolution: { type: "NONE" },
479
- realityCheck: {
480
- sessionDurationPeriodFormat: "minutes",
481
- showCloseGame: false,
482
- showHistory: false,
483
- showNetPosition: false,
484
- showSessionDuration: false,
485
- showSumBets: false,
486
- showSumWins: false
487
- },
488
- skipInsufficientFundsCheck: false,
489
- skipSplash: false,
490
- cheatPanel: false
425
+ //#region src/wrapper/KalambaSdkWrapper.ts
426
+ /**
427
+ * Compare two semver strings. Returns:
428
+ * -1 if a < b, 0 if a === b, 1 if a > b
429
+ */
430
+ function compareSemver(a, b) {
431
+ const pa = a.split(".").map(Number);
432
+ const pb = b.split(".").map(Number);
433
+ for (let i = 0; i < 3; i++) {
434
+ if ((pa[i] ?? 0) < (pb[i] ?? 0)) return -1;
435
+ if ((pa[i] ?? 0) > (pb[i] ?? 0)) return 1;
436
+ }
437
+ return 0;
438
+ }
439
+ const logIn = () => {};
440
+ const logOut = () => {};
441
+ var KalambaSdkWrapper = class {
442
+ #messagePort;
443
+ #plugins;
444
+ #config = {
445
+ gameName: "UNKNOWN",
446
+ gameVersion: "unknown",
447
+ showErrors: true,
448
+ showFreeRounds: true,
449
+ showPromoPanel: true,
450
+ showRealityCheck: true,
451
+ showBars: true,
452
+ skipErrors: []
453
+ };
454
+ #store = (0, zustand_vanilla.createStore)(() => ({
455
+ isSdkConfigured: false,
456
+ balance: 0,
457
+ bet: {
458
+ base: 0,
459
+ multiplier: 0
460
+ },
461
+ updateBalance: true,
462
+ openGameResponse: void 0,
463
+ lastPlayResponse: void 0,
464
+ freeRoundId: void 0,
465
+ playBlockers: []
466
+ }));
467
+ #sdkConfigManager;
468
+ #payloadInjectionManager;
469
+ #wakeLock;
470
+ #compatibility;
471
+ constructor({ messagePort, plugins, sdkConfigManager, compatibility }) {
472
+ this.#messagePort = messagePort;
473
+ this.#sdkConfigManager = new sdkConfigManager();
474
+ this.#compatibility = compatibility;
475
+ this.#payloadInjectionManager = new PayloadInjectionManager();
476
+ this.injectPayload = this.injectPayload.bind(this);
477
+ this.#plugins = {
478
+ rgs: new plugins.rgs(this.config, this.sdkConfig, this.state),
479
+ casino: plugins.casino.map((casinoPlugin) => new casinoPlugin(this.config, this.sdkConfig, this.state, this.injectPayload)),
480
+ telemetry: plugins.telemetry.map(({ plugin, trackers }) => new plugin(trackers.map((tracker) => new tracker(this.config, this.sdkConfig)), this.config, this.sdkConfig))
481
+ };
482
+ this.on("balance", ({ balance }) => {
483
+ this.store.setState((state) => ({
484
+ ...state,
485
+ balance
486
+ }));
487
+ });
488
+ this.on("bet", (bet) => {
489
+ this.store.setState((state) => ({
490
+ ...state,
491
+ bet
492
+ }));
493
+ });
494
+ this.on("sdk:playCycleStart", async () => {
495
+ await this.requestWakeLock();
496
+ if (this.state.freeRoundId) return;
497
+ this.send("balance", { balance: this.state.balance - this.state.bet.base * this.state.bet.multiplier });
498
+ });
499
+ this.on("sdk:play", async (payload) => {
500
+ this.store.setState((state) => ({
501
+ ...state,
502
+ playBlockers: []
503
+ }));
504
+ const payloadToInject = await this.#payloadInjectionManager.getPayload(payload.contract);
505
+ this.send("play", {
506
+ ...payload,
507
+ payloadToInject
508
+ });
509
+ });
510
+ this.on("sdk:configure", (payload) => {
511
+ Object.assign(this.#config, payload);
512
+ const result = this.checkCompatibility(payload.sdkVersion);
513
+ this.#compatibility.onCheck(result, () => this.send("wrapperConfigured"));
514
+ });
515
+ this.on("freeRoundsPopup", () => {
516
+ const freeRound = (this.state.lastPlayResponse ?? this.state.openGameResponse)?.freeRounds[0];
517
+ if (freeRound && this.state.freeRoundId) this.send("freeRoundsInfo", freeRound);
518
+ });
519
+ this.on("rgs:openGameResponse", async (response) => {
520
+ this.on("playReady", () => {
521
+ this.handleFreeRounds(response.contract.freeRounds[0]);
522
+ }, { once: true });
523
+ this.sdkConfig.ui = await this.#sdkConfigManager.getConfig();
524
+ this.store.setState((state) => ({
525
+ ...state,
526
+ isSdkConfigured: true
527
+ }));
528
+ this.send("configured", this.sdkConfig);
529
+ this.send("legalBets", response.contract.bet.available);
530
+ this.send("bet", response.contract.bet.lastPaid ?? response.contract.bet.default);
531
+ this.store.setState((state) => ({
532
+ ...state,
533
+ openGameResponse: response.contract
534
+ }));
535
+ if (this.state.updateBalance) this.send("balance", { balance: response.contract.balance.coins });
536
+ });
537
+ this.on("rgs:openGameError", async (error) => {
538
+ if (error.type === "timeout" && !this.config.skipErrors.includes("TIMEOUT")) this.send("error", {
539
+ messageKey: `Error.TIMEOUT`,
540
+ messageCode: "TIMEOUT",
541
+ type: "RELOAD"
542
+ });
543
+ if (error.type === "error" && !this.config.skipErrors.includes(error.data.code)) this.send("error", {
544
+ messageKey: `RgsError.${error.data.code}`,
545
+ messageCode: error.data.code,
546
+ type: require_errors.RgsErrorAction[error.data.code]
547
+ });
548
+ });
549
+ this.on("rgs:playResponse", async (response) => {
550
+ this.store.setState((state) => ({
551
+ ...state,
552
+ lastPlayResponse: response.contract
553
+ }));
554
+ });
555
+ this.on("playEnd", async () => {
556
+ await Promise.all(this.state.playBlockers);
557
+ this.send("playReady");
558
+ });
559
+ this.on("playCycleEnd", () => {
560
+ this.releaseWakeLock();
561
+ if (this.state.updateBalance) this.send("balance", { balance: this.state.lastPlayResponse.balance.coins });
562
+ this.handleFreeRounds(this.state.lastPlayResponse.freeRounds[0]);
563
+ });
564
+ this.on("rgs:playError", async (error) => {
565
+ if (error.type === "timeout" && !this.config.skipErrors.includes("TIMEOUT")) this.send("error", {
566
+ messageKey: `Error.TIMEOUT`,
567
+ messageCode: "TIMEOUT",
568
+ type: "RELOAD"
569
+ });
570
+ if (error.type === "error" && !this.config.skipErrors.includes(error.data.code)) this.send("error", {
571
+ messageKey: `RgsError.${error.data.code}`,
572
+ messageCode: error.data.code,
573
+ type: require_errors.RgsErrorAction[error.data.code]
574
+ });
575
+ });
576
+ this.on("rgs:freeRoundsResponse", async (response) => {
577
+ if (response.action === "ACCEPT") {
578
+ const freeRound = (this.state.lastPlayResponse ?? this.state.openGameResponse)?.freeRounds[0];
579
+ this.activateFreeRounds(freeRound);
491
580
  }
492
- };
581
+ });
582
+ this.on("rgs:freeRoundsError", async (error) => {
583
+ if (error.type === "timeout" && !this.config.skipErrors.includes("TIMEOUT")) this.send("error", {
584
+ messageKey: `Error.TIMEOUT`,
585
+ messageCode: "TIMEOUT",
586
+ type: "RELOAD"
587
+ });
588
+ if (error.type === "error" && !this.config.skipErrors.includes(error.data.code)) this.send("error", {
589
+ messageKey: `RgsError.${error.data.code}`,
590
+ messageCode: error.data.code,
591
+ type: require_errors.RgsErrorAction[error.data.code]
592
+ });
593
+ });
594
+ this.forwardMessages();
595
+ document.addEventListener("visibilitychange", async () => {
596
+ if (this.#wakeLock && document.visibilityState === "visible") await this.requestWakeLock();
597
+ });
493
598
  }
494
- };
495
-
496
- //#endregion
497
- //#region src/common/config/KalambaSdkConfigManager.ts
498
- function jurisdictionConfigOverrides(config, jurisdiction) {
499
- function limitRounds(autoPlayRounds, { maxCount }) {
500
- const limitCount = (rounds) => rounds?.filter((count) => count <= maxCount) ?? [];
501
- const castToNumber = (rounds) => rounds?.map((count) => Number(count)) ?? [];
502
- const rounds = [...autoPlayRounds, maxCount];
503
- return (0, lodash_es.flow)([
504
- castToNumber,
505
- limitCount,
506
- lodash_es.sortBy,
507
- lodash_es.sortedUniq
508
- ])(rounds);
599
+ get store() {
600
+ return this.#store;
509
601
  }
510
- switch (jurisdiction) {
511
- case "BG": return { autoplay: {
512
- lossLimit: {
513
- enabled: true,
514
- showNoLimit: false
515
- },
516
- winLimit: { enabled: true }
517
- } };
518
- case "BR": return { feature: { showPaylineLines: true } };
519
- case "CA": return {
520
- autoplay: { enabled: false },
521
- feature: {
522
- showFastPlay: false,
523
- allowQuickStop: false,
524
- showFeatureBuy: false
525
- },
526
- minimumSpinDuration: 2.5
527
- };
528
- case "CO": return {
529
- autoplay: { rounds: {
530
- showNoLimit: false,
531
- showCustomLimit: false,
532
- options: limitRounds(config.autoplay.rounds.options, { maxCount: 100 })
533
- } },
534
- feature: {
535
- showFastPlay: false,
536
- allowQuickStop: false
537
- },
538
- minimumSpinDuration: 3
539
- };
540
- case "CZ": return {
541
- feature: {
542
- showFastPlay: false,
543
- showFeatureBuy: false,
544
- allowGamble: false
545
- },
546
- minimumSpinDuration: 2
547
- };
548
- case "DE": return {
549
- autoplay: { enabled: false },
550
- feature: {
551
- showFastPlay: false,
552
- allowQuickStop: false,
553
- showFeatureBuy: false
554
- },
555
- minimumSpinDuration: 5
556
- };
557
- case "DK": return { minimumSpinDuration: 3 };
558
- case "ES": return {
559
- autoplay: { rounds: {
560
- showNoLimit: false,
561
- showCustomLimit: false,
562
- options: limitRounds(config.autoplay.rounds.options, { maxCount: 100 })
563
- } },
564
- feature: {
565
- showFastPlay: false,
566
- allowQuickStop: false
567
- },
568
- minimumSpinDuration: 3
569
- };
570
- case "GR": return {
571
- feature: {
572
- showFastPlay: false,
573
- allowQuickStop: false,
574
- showFeatureBuy: false
602
+ get state() {
603
+ const that = this;
604
+ return new Proxy({}, {
605
+ get(_target, prop) {
606
+ return Reflect.get(that.#store.getState(), prop);
575
607
  },
576
- minimumSpinDuration: 3
577
- };
578
- case "IT": return { feature: {
579
- showDeconstructedBet: true,
580
- showPaylineLines: true
581
- } };
582
- case "NL": return {
583
- autoplay: { enabled: false },
584
- feature: { showFeatureBuy: false }
608
+ set(_target, prop, value) {
609
+ that.#store.setState((state) => ({
610
+ ...state,
611
+ [prop]: value
612
+ }));
613
+ return true;
614
+ }
615
+ });
616
+ }
617
+ checkCompatibility(sdkVersion) {
618
+ const { manifest } = this.#compatibility;
619
+ const currentEntry = manifest[0];
620
+ if (!currentEntry || !sdkVersion || currentEntry.minSdk === "newest") return {
621
+ status: "compatible",
622
+ sdkVersion
585
623
  };
586
- case "PT": return {
587
- autoplay: { rounds: {
588
- showNoLimit: false,
589
- showCustomLimit: false,
590
- options: limitRounds(config.autoplay.rounds.options, { maxCount: 100 })
591
- } },
592
- feature: {
593
- showFeatureBuy: false,
594
- showFastPlay: false,
595
- allowQuickStop: false
596
- },
597
- minimumSpinDuration: 3
624
+ if (compareSemver(sdkVersion, currentEntry.minSdk) >= 0) return {
625
+ status: "compatible",
626
+ sdkVersion,
627
+ eol: currentEntry.eol
598
628
  };
599
- case "SE": return {
600
- autoplay: { rounds: {
601
- showNoLimit: false,
602
- showCustomLimit: false,
603
- options: limitRounds(config.autoplay.rounds.options, { maxCount: 100 })
604
- } },
605
- feature: {
606
- showFastPlay: false,
607
- allowQuickStop: false
608
- },
609
- minimumSpinDuration: 3
629
+ return {
630
+ status: "incompatible",
631
+ sdkVersion,
632
+ fallback: manifest.filter((entry) => entry.wrapper && compareSemver(sdkVersion, entry.minSdk) >= 0 && (!entry.eol || /* @__PURE__ */ new Date() <= new Date(entry.eol))).sort((a, b) => compareSemver(b.wrapper, a.wrapper))[0]
610
633
  };
611
- case "UK": return {
612
- autoplay: { enabled: false },
613
- feature: {
614
- showFastPlay: false,
615
- allowQuickStop: false,
616
- showFeatureBuy: false
634
+ }
635
+ forwardMessages() {
636
+ this.forwardToPlugins("casino", [
637
+ "sdk:autoplay",
638
+ "sdk:bet",
639
+ "sdk:cashier",
640
+ "sdk:choice",
641
+ "sdk:close",
642
+ "sdk:error",
643
+ "sdk:history",
644
+ "sdk:loadEnd",
645
+ "sdk:loadProgress",
646
+ "sdk:loadStart",
647
+ "sdk:playReady",
648
+ "sdk:playCycleEnd",
649
+ "sdk:playCycleStart",
650
+ "sdk:playEnd",
651
+ "sdk:playStart",
652
+ "sdk:settings",
653
+ "sdk:openGame",
654
+ "sdk:configure",
655
+ "sdk:fullscreen"
656
+ ]);
657
+ this.forwardToPlugins("casino", ["rgs:playResponse", "rgs:openGameResponse"]);
658
+ this.forwardToPlugins("rgs", ["sdk:openGame", "sdk:history"]);
659
+ this.forwardToPlugins("rgs", [
660
+ "casino:play",
661
+ "casino:cashier",
662
+ "casino:close",
663
+ "casino:history",
664
+ "casino:getBalance"
665
+ ]);
666
+ this.forwardToPlugins("telemetry", [
667
+ "sdk:autoplay",
668
+ "sdk:error",
669
+ "sdk:playCycleStart",
670
+ "sdk:playCycleEnd",
671
+ "sdk:loadStart",
672
+ "sdk:loadProgress",
673
+ "sdk:loadEnd",
674
+ "sdk:telemetry.click",
675
+ "sdk:telemetry.orientationChange"
676
+ ]);
677
+ this.forwardToPlugins("telemetry", ["rgs:openGameResponse", "rgs:playResponse"]);
678
+ this.forwardToSdk([
679
+ "casino:balance",
680
+ "casino:bet",
681
+ "casino:choice",
682
+ "casino:freeze",
683
+ "casino:help",
684
+ "casino:paytable",
685
+ "casino:resume",
686
+ "casino:settings",
687
+ "casino:suspend",
688
+ "casino:unfreeze"
689
+ ]);
690
+ this.forwardToSdk([
691
+ "rgs:balance",
692
+ "rgs:openGameError",
693
+ "rgs:openGameResponse",
694
+ "rgs:playError",
695
+ "rgs:playResponse",
696
+ "rgs:realityCheck"
697
+ ]);
698
+ }
699
+ get config() {
700
+ const that = this;
701
+ return new Proxy({}, {
702
+ get(_target, prop) {
703
+ return Reflect.get(that.#config, prop);
617
704
  },
618
- minimumSpinDuration: 2.5
619
- };
620
- case "US": return { feature: { showPaylineLines: true } };
621
- case "MT": return { feature: { showClock: true } };
622
- case "SOCIAL": return { feature: { showHistory: false } };
623
- case "CLASS2": return {
624
- autoplay: { enabled: false },
625
- feature: { showFeatureBuy: false }
626
- };
705
+ set(_target, prop, value) {
706
+ return Reflect.set(that.#config, prop, value);
707
+ }
708
+ });
627
709
  }
628
- return {};
629
- }
630
- var KalambaSdkConfigManager = class extends SdkConfigManager {
631
- async getConfig() {
632
- let uiConfig = this.config.ui;
633
- const operatorConfig = await this.fetchOperatorConfig();
634
- uiConfig = (0, lodash_es.merge)({}, uiConfig, operatorConfig);
635
- const searchParams = new URLSearchParams(window.location.search);
636
- const badgeOverrides = JSON.parse(searchParams.get("badgeParameters") ?? "{}");
637
- uiConfig = (0, lodash_es.merge)({}, uiConfig, badgeOverrides);
638
- const jurisdictionOverrides = jurisdictionConfigOverrides(uiConfig, this.config.api.jurisdiction);
639
- uiConfig = (0, lodash_es.merge)({}, uiConfig, jurisdictionOverrides);
640
- return uiConfig;
710
+ get sdkConfig() {
711
+ return this.#sdkConfigManager.config;
641
712
  }
642
- get mappedIntegration() {
643
- const integration = this.config.api.integration.toLowerCase();
644
- const brand = this.config.api.brand.toLowerCase();
645
- if (integration === "spinomenal") {
646
- if (brand.startsWith("gg-")) return "groove";
647
- } else if (integration === "pariplay") {
648
- if (brand.startsWith("8x1")) return "pariplay-8x1";
649
- } else if (/openbox-.*/.test(integration)) return "openbox";
650
- else if (/oryx-.*/.test(integration)) return "oryx";
651
- else if (/relax-.*/.test(integration)) return "relax";
652
- return integration;
713
+ forwardToPlugins(targetDomain, messages) {
714
+ messages.forEach((message) => {
715
+ const onMessage = (event) => {
716
+ if (event.data.message !== `kalamba:${message}`) return;
717
+ logIn("wrapper:forwardToPlugins", targetDomain, event.data.message.replace(/^kalamba:/, ""), event.data.payload);
718
+ window.postMessage({
719
+ message: `kalamba:wrapper-${targetDomain}:${message.replace(/^(.+):/, "")}`,
720
+ payload: event.data.payload
721
+ });
722
+ };
723
+ window.addEventListener("message", onMessage);
724
+ });
653
725
  }
654
- get mappedBrand() {
655
- const integration = this.config.api.integration.toLowerCase();
656
- const brand = this.config.api.brand.toLowerCase();
657
- if (integration === "bspot" && this.config.api.playMode.toLowerCase() === "fun") return "demo";
658
- return brand;
726
+ forwardToSdk(messages) {
727
+ messages.forEach((message) => {
728
+ const onMessage = (event) => {
729
+ if (event.data.message !== `kalamba:${message}`) return;
730
+ logOut("wrapper:forwardToSdk", event.data.message.replace(/^kalamba:/, ""), event.data.payload);
731
+ this.#messagePort.postMessage({
732
+ message: `kalamba:wrapper:${message.replace(/^(.+):/, "")}`,
733
+ payload: event.data.payload
734
+ }, "*");
735
+ };
736
+ window.addEventListener("message", onMessage);
737
+ });
659
738
  }
660
- mapUiConfig(config) {
661
- if (!config) return {};
662
- return {
663
- autoplay: {
664
- enabled: config.badge.autoplayType !== 5,
665
- rounds: {
666
- enabled: config.badge.autoplayType !== 5,
667
- showNoLimit: false,
668
- showCustomLimit: false,
669
- options: config.badge.autoplayRounds ?? [
670
- 5,
671
- 10,
672
- 25,
673
- 75,
674
- 100
675
- ]
676
- },
677
- lossLimit: {
678
- enabled: config.badge.autoplayType === 1 || config.badge.autoplayType === 4,
679
- showNoLimit: config.badge.autoplayType === 1,
680
- showCustomLimit: config.badge.autoplayType !== 6,
681
- options: [
682
- 5,
683
- 25,
684
- 50
685
- ]
686
- },
687
- winLimit: {
688
- enabled: config.badge.autoplayType === 1 || config.badge.autoplayType === 4,
689
- showNoLimit: true,
690
- showCustomLimit: config.badge.autoplayType !== 6,
691
- options: [
692
- 10,
693
- 20,
694
- 75
695
- ]
696
- },
697
- simple: config.badge.autoplayType === 3
698
- },
699
- cashier: {
700
- enabled: config.badge.showQuickDeposit,
701
- balanceThreshold: config.badge.quickDepositBalanceThresholds
702
- },
703
- feature: {
704
- allowTelemetry: true,
705
- allowFullscreen: config.defaults.fullscreen === "true",
706
- allowGamble: config.badge.gambleHideWithAutoCollect === void 0 ? true : !config.badge.gambleHideWithAutoCollect,
707
- allowQuickStop: config.badge.minimumSpinDuration === 0,
708
- showCashier: config.badge.showQuickDeposit,
709
- showClock: config.badge.showClock,
710
- showCloseGame: config.badge.showCloseGameButton && (!config.badge.showCloseGameButtonOptional || !!this.config.api.homeUrl),
711
- showCurrency: config.badge.showCurrency,
712
- showDeconstructedBet: config.badge.showDeconstructedBet,
713
- showFastPlay: config.badge.showTurboButton,
714
- showFeatureBuy: config.badge.showHyperBonus,
715
- showFunModeBanner: config.badge.showFunBanner,
716
- showHistory: config.badge.showGameHistory,
717
- showPaylineLines: config.badge.showPaylineLines,
718
- showRoundId: config.badge.showRoundId,
719
- showRules: config.badge.showGameRules,
720
- showSessionDuration: config.badge.realityCheckShowSessionDuration,
721
- showUi: config.badge.showGameUi
722
- },
723
- minimumSpinDuration: config.badge.minimumSpinDuration,
724
- requestTimeoutMs: config.badge.requestTimeoutMs,
725
- incompleteGameResolution: {
726
- daysToAutoResolution: config.badge.incompleteGamesResolutionType === 3 ? config.badge.daysToAutoResolution ?? 90 : void 0,
727
- type: config.badge.incompleteGamesResolutionType === 2 ? "MANUAL" : config.badge.incompleteGamesResolutionType === 3 ? "AUTOMATIC" : void 0
728
- },
729
- realityCheck: {
730
- sessionDurationPeriodFormat: config.badge.realityCheckPeriodFormat,
731
- showCloseGame: config.badge.realityCheckShowCloseGame,
732
- showHistory: config.badge.realityCheckShowHistoryLink,
733
- showNetPosition: config.badge.realityCheckShowNetGamingActivity,
734
- showSessionDuration: config.badge.realityCheckShowSessionDuration,
735
- showSumBets: config.badge.realityCheckShowSumBets,
736
- showSumWins: config.badge.realityCheckShowSumWins
737
- },
738
- skipInsufficientFundsCheck: config.badge.skipInsufficientFundsCheck,
739
- skipSplash: config.badge.loaderAutoContinue
739
+ on(message, listener, options) {
740
+ const onMessage = function onMessage(event) {
741
+ if (!new RegExp(`^kalamba:${message.includes(":") ? "" : "(.+):"}${message}$`).test(event.data.message) || new RegExp(`^kalamba:wrapper-(.+):${message}`).test(event.data.message) || new RegExp(`^kalamba:(.+)-wrapper:${message}`).test(event.data.message)) return;
742
+ logIn("on", event.data.message.replace(/^kalamba:/, ""), event.data.payload);
743
+ listener(event.data.payload);
744
+ if (options?.once) window.removeEventListener("message", onMessage);
740
745
  };
746
+ window.addEventListener("message", onMessage);
747
+ return () => window.removeEventListener("message", onMessage);
741
748
  }
742
- async fetchOperatorConfig() {
743
- const rootUrl = "https://awscdn.kalamba.net/games/games/build/";
744
- const integration = this.mappedIntegration;
745
- const brand = this.mappedBrand;
746
- let config = {};
747
- try {
748
- config = await fetch(`${rootUrl}config/${integration}/cage/${brand}.json`).then((r) => r.json());
749
- } catch (e) {
750
- try {
751
- config = await fetch(`${rootUrl}config/${integration}/operator.json`).then((r) => r.json());
752
- } catch (e) {
753
- config = await fetch(`${rootUrl}config/fun/operator.json`).then((r) => r.json());
754
- }
749
+ send(message, ...[payload]) {
750
+ logOut("wrapper:send", message, payload);
751
+ window.postMessage({
752
+ message: `kalamba:wrapper:${message}`,
753
+ payload
754
+ });
755
+ this.#messagePort.postMessage({
756
+ message: `kalamba:wrapper:${message}`,
757
+ payload
758
+ }, "*");
759
+ }
760
+ injectPayload(...[source, payload]) {
761
+ this.#payloadInjectionManager.register(source, payload);
762
+ return () => this.#payloadInjectionManager.unregister(source);
763
+ }
764
+ activateFreeRounds(freeRound) {
765
+ if (!freeRound || this.state.freeRoundId) return;
766
+ this.store.setState((state) => ({
767
+ ...state,
768
+ freeRoundId: freeRound.id
769
+ }));
770
+ this.#payloadInjectionManager.register("freeRounds", { freeRoundId: freeRound.id });
771
+ this.send("legalBets", { [freeRound.conf.base]: [freeRound.conf.multiplier] });
772
+ this.send("bet", {
773
+ base: freeRound.conf.base,
774
+ multiplier: freeRound.conf.multiplier
775
+ });
776
+ }
777
+ handleFreeRounds(freeRound) {
778
+ if (!freeRound) return;
779
+ switch (freeRound.status) {
780
+ case "ACTIVE":
781
+ this.activateFreeRounds(freeRound);
782
+ break;
783
+ case "PENDING":
784
+ this.send("freeRoundsOffer", freeRound);
785
+ break;
786
+ case "FINISHED":
787
+ this.send("freeRoundsComplete", freeRound);
788
+ this.store.setState((state) => ({
789
+ ...state,
790
+ freeRoundId: void 0
791
+ }));
792
+ this.#payloadInjectionManager.unregister("freeRounds");
793
+ this.send("legalBets", this.state.openGameResponse.bet.available);
794
+ this.send("bet", this.state.openGameResponse.bet.default);
795
+ break;
796
+ default: break;
755
797
  }
756
- return this.mapUiConfig(config);
798
+ }
799
+ async requestWakeLock() {
800
+ try {
801
+ this.#wakeLock = await navigator.wakeLock.request("screen");
802
+ } catch {}
803
+ }
804
+ async releaseWakeLock() {
805
+ if (!this.#wakeLock) return;
806
+ await this.#wakeLock.release();
807
+ this.#wakeLock = void 0;
757
808
  }
758
809
  };
759
810