@smartico/public-api 0.0.358 → 0.0.360

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.
@@ -4,68 +4,444 @@ import { SAWGameDifficultyType } from './SAWGameDifficulty';
4
4
  import { SAWGameLayout } from './SAWGameLayout';
5
5
  import { SAWWheelLayout } from './SAWWheelLayout';
6
6
 
7
+ /**
8
+ * UI configuration for a SAW (Spin-And-Win) mini-game template.
9
+ *
10
+ * This interface is returned as the `saw_template_ui_definition` property of
11
+ * {@link SAWTemplate} and {@link TMiniGameTemplate}. It covers all visual,
12
+ * behavioural and game-type-specific settings that the operator can configure
13
+ * in the Back-Office for every mini-game variant (Spin the Wheel, Scratch Card,
14
+ * Gift Box, MatchX / Quiz, Treasure Hunt, Lootbox, Voyager, Prize Drop, etc.).
15
+ */
7
16
  export interface SAWTemplateUI {
8
- skin: string;
9
- name: string;
10
- description?: string;
11
- over_limit_message?: string;
12
- hide_prize_names?: boolean;
13
- no_attempts_message?: string;
14
- thumbnail?: string;
15
- sectors_count: number;
16
- priority: number;
17
- flow_builder_only: boolean;
18
- background_image?: string;
19
- background_image_mobile?: string;
20
- background_sound?: string;
21
- spin_animation_duration?: number;
22
- wheel_pointer_rotation?: number;
23
- scratch_logo?: string;
24
- scratch_cover?: string;
25
- scratch_bg_desktop?: string;
26
- scratch_bg_mobile?: string;
27
- scratch_cursor?: string;
28
- custom_css?: string;
29
- custom_skin_folder?: string;
30
- jackpot_symbol?: string;
31
-
32
- promo_image?: string;
33
- promo_text?: string;
34
- matchx_banner?: string;
35
- matchx_banner_mobile?: string;
36
- matchx_seasonal_ranking?: boolean;
37
- matchx_is_completed?: boolean;
38
- matchx_general_board_users_count?: number;
39
- matchx_hide_ranking?: boolean;
40
- prize_pool_image?: string;
41
- ask_for_username?: SAWAskForUsername;
42
- show_prize_board?: boolean;
43
-
44
- max_spins_period_ms?: number;
45
- show_countdown_for_next_availability?: boolean;
46
- disable_background_music?: boolean;
47
- custom_section_id?: number;
48
- only_in_custom_section?: boolean;
49
- expose_user_spin_id?: SAWExposeUserSpinId;
50
-
51
- custom_data: any;
52
-
53
- // prize drop specific
54
- placeholder1?: string;
55
- placeholder2?: string;
56
- prize_drop_template?: {
57
- id: string;
58
- content: string;
59
- };
60
-
61
- // lootbox specific
62
- game_layout?: SAWGameLayout;
63
-
64
- // treasure hunt specific
65
- steps_to_finish_game?: number;
66
-
67
- wheel_layout?: SAWWheelLayout;
68
- background_music_volume?: number;
69
- /** Voyager specific */
70
- game_difficulty?: SAWGameDifficultyType;
71
- }
17
+
18
+ // ─── Identity & presentation ──────────────────────────────────────────────
19
+
20
+ /**
21
+ * CSS skin key that selects the overall visual theme of the game.
22
+ * Resolved at runtime to the matching skin folder / CSS bundle.
23
+ */
24
+ skin: string;
25
+
26
+ /**
27
+ * Display name of the mini-game template shown to players and in the
28
+ * Back-Office listing. Supports translations via
29
+ * `saw_template_ui_definition._translations.<lang>.name`.
30
+ */
31
+ name: string;
32
+
33
+ /**
34
+ * HTML-capable description / rules text shown to the player before or
35
+ * during the game. Supports translations via
36
+ * `saw_template_ui_definition._translations.<lang>.description`.
37
+ */
38
+ description?: string;
39
+
40
+ /**
41
+ * URL of the thumbnail image (typically 256 × 256 px) shown in
42
+ * mini-game selection lists and galleries.
43
+ */
44
+ thumbnail?: string;
45
+
46
+ // ─── Spin-limit messaging ─────────────────────────────────────────────────
47
+
48
+ /**
49
+ * HTML-capable message shown to a player who has reached the maximum
50
+ * number of allowed attempts for the current period.
51
+ * Rendered when the server rejects a spin with
52
+ * `SAWSpinErrorCode.SAW_FAILED_MAX_SPINS_REACHED`.
53
+ * Supports translations via
54
+ * `saw_template_ui_definition._translations.<lang>.over_limit_message`.
55
+ *
56
+ * Only relevant when `max_spins_count` is configured on the template.
57
+ */
58
+ over_limit_message?: string;
59
+
60
+ /**
61
+ * HTML-capable message shown when the player has no spin attempts or
62
+ * insufficient points / gems / diamonds to play.
63
+ * Supports translations via
64
+ * `saw_template_ui_definition._translations.<lang>.no_attempts_message`.
65
+ *
66
+ * Only relevant for buy-in types `Spins`, `Points`, `Gems`, or `Diamonds`.
67
+ */
68
+ no_attempts_message?: string;
69
+
70
+ // ─── Game structure ───────────────────────────────────────────────────────
71
+
72
+ /**
73
+ * Number of prize sectors on the wheel or gift-box grid.
74
+ * For Spin-the-Wheel games the Back-Office enforces a range of 3 – 10.
75
+ */
76
+ sectors_count: number;
77
+
78
+ /**
79
+ * Relative display order of the mini-game within a list.
80
+ * Lower values appear first. Configurable in the Back-Office
81
+ * "Priority" field (Advanced section).
82
+ */
83
+ priority: number;
84
+
85
+ /**
86
+ * When `true` the mini-game is **excluded from the widget's automatic
87
+ * game listing** and is only accessible when it is explicitly triggered
88
+ * via a Campaign Flow Builder action or accessed by deep links or triggered over the api.
89
+ *
90
+ * Back-Office label:
91
+ * _"Available only from campaign (won't be visible in the widget)"_
92
+ *
93
+ */
94
+ flow_builder_only: boolean;
95
+
96
+ // ─── Background assets ────────────────────────────────────────────────────
97
+
98
+ /**
99
+ * URL of the full-bleed background image shown on desktop devices.
100
+ * Not used for Plinko and Coin Flip game types.
101
+ */
102
+ background_image?: string;
103
+
104
+ /**
105
+ * URL of the full-bleed background image shown on mobile devices.
106
+ * Falls back to {@link background_image} when absent.
107
+ * Not used for Plinko and Coin Flip game types.
108
+ */
109
+ background_image_mobile?: string;
110
+
111
+ /**
112
+ * URL of the audio file (MP3 / WAV) played as background music
113
+ * during gameplay. Silenced when {@link disable_background_music}
114
+ * is `true` or the player has muted audio.
115
+ */
116
+ background_sound?: string;
117
+
118
+ /**
119
+ * Volume level of the background music, expressed as a percentage
120
+ * in the range `0` – `100`.
121
+ */
122
+ background_music_volume?: number;
123
+
124
+ /**
125
+ * When `true`, background music is muted even if a
126
+ * {@link background_sound} URL is provided.
127
+ * Defaults to `true` in the Skin Editor preview scaffolding.
128
+ */
129
+ disable_background_music?: boolean;
130
+
131
+ // ─── Spin / wheel configuration ───────────────────────────────────────────
132
+
133
+ /**
134
+ * Duration in milliseconds of the spin animation before the result
135
+ * is revealed (e.g. `3000` = 3 seconds).
136
+ * Applies to Spin-the-Wheel and similar animated game types.
137
+ */
138
+ spin_animation_duration?: number;
139
+
140
+ /**
141
+ * Rotation offset in degrees applied to the visual pointer / arrow
142
+ * on the wheel to compensate for skin-specific alignment differences.
143
+ */
144
+ wheel_pointer_rotation?: number;
145
+
146
+ /**
147
+ * Screen positioning of the wheel relative to the game panel.
148
+ *
149
+ * | Value | Meaning |
150
+ * | --- | --- |
151
+ * | `SAWWheelLayout.Centered = 1` | Wheel centred in the panel |
152
+ * | `SAWWheelLayout.LeftAligned = 2` | Wheel pinned to the left |
153
+ * | `SAWWheelLayout.RightAligned = 3` | Wheel pinned to the right |
154
+ * | `SAWWheelLayout.BottomAligned = 4` | Wheel pinned to the bottom |
155
+ *
156
+ * Applies to Spin-the-Wheel games only.
157
+ * Back-Office label: _"Wheel layout"_.
158
+ */
159
+ wheel_layout?: SAWWheelLayout;
160
+
161
+ // ─── Scratch-card assets ──────────────────────────────────────────────────
162
+
163
+ /**
164
+ * URL of the logo image overlaid on the scratch-card surface
165
+ * before the player scratches.
166
+ */
167
+ scratch_logo?: string;
168
+
169
+ /**
170
+ * URL of the cover / foil image that the player scratches away
171
+ * to reveal the prize beneath.
172
+ */
173
+ scratch_cover?: string;
174
+
175
+ /**
176
+ * URL of the background image shown behind the scratch card on
177
+ * desktop devices.
178
+ * Back-Office label: _"Scratch main desktop background"_.
179
+ */
180
+ scratch_bg_desktop?: string;
181
+
182
+ /**
183
+ * URL of the background image shown behind the scratch card on
184
+ * mobile devices.
185
+ * Back-Office label: _"Scratch main mobile background"_.
186
+ */
187
+ scratch_bg_mobile?: string;
188
+
189
+ /**
190
+ * URL of a custom cursor image used when the pointer hovers over
191
+ * the scratchable area.
192
+ * Back-Office label: _"Scratch mouse cursor"_.
193
+ */
194
+ scratch_cursor?: string;
195
+
196
+ /**
197
+ * When `true`, prize / reward names are hidden inside the scratch-card
198
+ * UI so the player does not know what they won until they have fully
199
+ * scratched the card.
200
+ *
201
+ * Only rendered for `SAWGameType.ScratchCard`.
202
+ * Back-Office label: _"Hide prize names"_.
203
+ */
204
+ hide_prize_names?: boolean;
205
+
206
+ // ─── Styling & customisation ──────────────────────────────────────────────
207
+
208
+ /**
209
+ * Raw CSS injected into the game iframe, allowing fine-grained
210
+ * overrides beyond what the selected skin provides.
211
+ */
212
+ custom_css?: string;
213
+
214
+ /**
215
+ * Path to an alternative folder from which skin assets (images,
216
+ * CSS, JS) are loaded instead of the default skin bundle.
217
+ */
218
+ custom_skin_folder?: string;
219
+
220
+ // ─── Jackpot display ──────────────────────────────────────────────────────
221
+
222
+ /**
223
+ * Label / symbol appended to the jackpot amount to give it semantic
224
+ * meaning (e.g. `"EUR"`, `"Free spins"`).
225
+ * Displayed alongside {@link SAWTemplate.jackpot_current}.
226
+ * Back-Office label: _"Jackpot symbol"_.
227
+ */
228
+ jackpot_symbol?: string;
229
+
230
+ // ─── Promotional content ──────────────────────────────────────────────────
231
+
232
+ /**
233
+ * URL of a promotional banner image (recommended 500 × 240 px)
234
+ * displayed inside the game UI to advertise an offer or campaign.
235
+ * Supports per-language variants via
236
+ * `saw_template_ui_definition.promo_image_<lang>`.
237
+ */
238
+ promo_image?: string;
239
+
240
+ /**
241
+ * HTML-capable promotional text displayed alongside
242
+ * {@link promo_image}. Supports translations via
243
+ * `saw_template_ui_definition._translations.<lang>.promo_text`.
244
+ */
245
+ promo_text?: string;
246
+
247
+ // ─── MatchX / Quiz specific ───────────────────────────────────────────────
248
+
249
+ /**
250
+ * URL of the banner image shown at the top of the MatchX / Quiz
251
+ * tournament leaderboard on desktop.
252
+ * Back-Office label: _"Banner"_.
253
+ */
254
+ matchx_banner?: string;
255
+
256
+ /**
257
+ * URL of the mobile-optimised banner image for the MatchX / Quiz
258
+ * tournament leaderboard.
259
+ */
260
+ matchx_banner_mobile?: string;
261
+
262
+ /**
263
+ * When `true`, tournament rankings are reset on a seasonal cadence
264
+ * rather than being continuous.
265
+ */
266
+ matchx_seasonal_ranking?: boolean;
267
+
268
+ /**
269
+ * When `true`, the MatchX / Quiz tournament has concluded.
270
+ * New entries are blocked and the final leaderboard is shown.
271
+ */
272
+ matchx_is_completed?: boolean;
273
+
274
+ /**
275
+ * Maximum number of players visible on the general leaderboard
276
+ * inside the MatchX / Quiz game.
277
+ */
278
+ matchx_general_board_users_count?: number;
279
+
280
+ /**
281
+ * When `true`, the ranking / leaderboard panel is hidden from
282
+ * players inside the MatchX / Quiz game.
283
+ * Back-Office label: _"Hide ranking"_.
284
+ */
285
+ matchx_hide_ranking?: boolean;
286
+
287
+ // ─── Prize board ──────────────────────────────────────────────────────────
288
+
289
+ /**
290
+ * URL of an image used to illustrate the prize pool (e.g. a trophy
291
+ * or coins graphic).
292
+ */
293
+ prize_pool_image?: string;
294
+
295
+ /**
296
+ * When `true`, a panel listing the available prizes is displayed
297
+ * inside the game.
298
+ *
299
+ * Back-Office label: _"Show the list of the prizes"_.
300
+ * Defaults to `true` in the MatchX / Quiz game form.
301
+ */
302
+ show_prize_board?: boolean;
303
+
304
+ // ─── Spin cadence & countdown ─────────────────────────────────────────────
305
+
306
+ /**
307
+ * The rolling time-window in milliseconds within which
308
+ * `SAWTemplate.maxSpinsCount` attempts are allowed
309
+ * (e.g. `86400000` = 24 hours).
310
+ *
311
+ * Stored on the template root as `max_spins_period_ms`; mirrored here
312
+ * for convenience in UI preview payloads.
313
+ */
314
+ max_spins_period_ms?: number;
315
+
316
+ /**
317
+ * When `true`, a countdown timer showing when the next spin becomes
318
+ * available is displayed to the player.
319
+ *
320
+ * Only active when `max_spins_count === 1` **and** `max_spins_period_ms`
321
+ * is set; automatically forced to `false`.
322
+ *
323
+ * Back-Office label: _"Show time to the next available spin"_.
324
+ */
325
+ show_countdown_for_next_availability?: boolean;
326
+
327
+ // ─── Username prompt ──────────────────────────────────────────────────────
328
+
329
+ /**
330
+ * Controls when (or whether) the player is asked to provide a
331
+ * display name before or after playing.
332
+ *
333
+ * | Value | Meaning |
334
+ * | --- | --- |
335
+ * | `SAWAskForUsername.NOASK = 'no-ask'` | Never ask |
336
+ * | `SAWAskForUsername.ONSUMBIT = 'on-submit'` | Ask when submitting |
337
+ *
338
+ * Back-Office label: _"Ask for username"_.
339
+ */
340
+ ask_for_username?: SAWAskForUsername;
341
+
342
+ // ─── Custom sections ──────────────────────────────────────────────────────
343
+
344
+ /**
345
+ * ID of the custom section (category / tab) this mini-game belongs to,
346
+ * allowing operators to group games in bespoke widget sections.
347
+ * Back-Office label: _"Custom section"_.
348
+ */
349
+ custom_section_id?: number;
350
+
351
+ /**
352
+ * When `true`, the template is shown **only** inside its assigned
353
+ * custom section and is suppressed from all standard game listings.
354
+ */
355
+ only_in_custom_section?: boolean;
356
+
357
+ // ─── Spin-ID exposure ─────────────────────────────────────────────────────
358
+
359
+ /**
360
+ * Determines which identifier is forwarded in webhooks and the
361
+ * Retention API when a spin result is produced.
362
+ *
363
+ * | Value | Meaning |
364
+ * | --- | --- |
365
+ * | `SAWExposeUserSpinId.UserId = 1` | Expose the operator's external user ID |
366
+ * | `SAWExposeUserSpinId.SpinId = 2` | Expose the internal spin transaction ID |
367
+ *
368
+ * Back-Office label:
369
+ * _"Expose 'External user ID' or 'Spin transaction ID'"_.
370
+ */
371
+ expose_user_spin_id?: SAWExposeUserSpinId;
372
+
373
+ // ─── Custom data ──────────────────────────────────────────────────────────
374
+
375
+ /**
376
+ * Arbitrary operator-defined payload attached to the template.
377
+ * Can be a JSON object, plain string, or number. Passed through to
378
+ * the front-end as-is and accessible via the public API.
379
+ * Back-Office label: _"Custom data field"_.
380
+ */
381
+ custom_data: any;
382
+
383
+ // ─── Prize Drop specific ──────────────────────────────────────────────────
384
+
385
+ /**
386
+ * First free-form placeholder string used by Prize Drop game skins
387
+ * to inject operator-defined copy into the game UI.
388
+ */
389
+ placeholder1?: string;
390
+
391
+ /**
392
+ * Second free-form placeholder string used by Prize Drop game skins
393
+ * to inject operator-defined copy into the game UI.
394
+ */
395
+ placeholder2?: string;
396
+
397
+ /**
398
+ * Template definition for the Prize Drop game overlay.
399
+ * `id` is the unique template identifier; `content` is the raw HTML
400
+ * rendered inside the drop panel.
401
+ */
402
+ prize_drop_template?: {
403
+ /** Unique identifier for this prize-drop HTML template. */
404
+ id: string;
405
+ /** HTML content rendered inside the prize-drop panel. */
406
+ content: string;
407
+ };
408
+
409
+ // ─── Lootbox specific ────────────────────────────────────────────────────
410
+
411
+ /**
412
+ * Visual arrangement of items in Lootbox (Weekly / Calendar Days)
413
+ * game types.
414
+ *
415
+ * | Value | Meaning |
416
+ * | --- | --- |
417
+ * | `SAWGameLayout.Horizontal = 1` | Items laid out in a horizontal row |
418
+ * | `SAWGameLayout.VerticalMap = 2` | Items arranged as a vertical map path |
419
+ *
420
+ * Back-Office label: _"Visual layout"_.
421
+ */
422
+ game_layout?: SAWGameLayout;
423
+
424
+ // ─── Treasure Hunt specific ───────────────────────────────────────────────
425
+
426
+ /**
427
+ * Total number of path steps / cells a player must progress through
428
+ * to complete a Treasure Hunt game and receive the final prize.
429
+ * Higher values result in longer gameplay sessions.
430
+ * Back-Office label: _"Steps to finish game"_.
431
+ */
432
+ steps_to_finish_game?: number;
433
+
434
+ // ─── Voyager specific ────────────────────────────────────────────────────
435
+
436
+ /**
437
+ * Difficulty level of the Voyager (space-exploration) mini-game,
438
+ * controlling obstacle frequency and game speed.
439
+ *
440
+ * | Value | Meaning |
441
+ * | --- | --- |
442
+ * | `SAWGameDifficultyType.EASY = 1` | Easy |
443
+ * | `SAWGameDifficultyType.MEDIUM = 2` | Medium |
444
+ * | `SAWGameDifficultyType.HARD = 3` | Hard |
445
+ */
446
+ game_difficulty?: SAWGameDifficultyType;
447
+ }
@@ -5,6 +5,9 @@ import { UserAchievement } from "./UserAchievement";
5
5
  import { UserAchievementTask } from "./UserAchievementTask";
6
6
  import { BadgesTimeLimitStates } from "./BadgesTimeLimitStates";
7
7
 
8
+ type UserStateParamsKeys = 'core_fav_game_top3' | 'core_fav_game_type_top3' | 'core_fav_game_provider_top3' | 'core_recommended_deposit_amount' | 'core_recommended_casino_bet_amount' | 'casino_last_bet_amount' | 'casino_last_bet_amount_real' | 'casino_last_bet_amount_bonus' | 'acc_last_deposit_amount';
9
+ const USER_STATE_PARAMS_KEYS_GAMES: UserStateParamsKeys[] = ['core_fav_game_top3', 'core_fav_game_type_top3', 'core_fav_game_provider_top3'];
10
+ const USER_STATE_PARAMS_KEYS_BET_AMOUNT: UserStateParamsKeys[] = ['core_recommended_deposit_amount', 'core_recommended_casino_bet_amount', 'casino_last_bet_amount', 'casino_last_bet_amount_real', 'casino_last_bet_amount_bonus', 'acc_last_deposit_amount'];
8
11
  export class MissionUtils {
9
12
 
10
13
  public static getAvailabilityStatus = (mission: UserAchievement) => {
@@ -188,10 +191,10 @@ export class MissionUtils {
188
191
  let suggestedGames: string = '';
189
192
  let suggestedValue: string = '';
190
193
 
191
- userStateParamsKeys.forEach((k: 'core_fav_game_top3' | 'core_fav_game_type_top3' | 'core_fav_game_provider_top3' | 'core_recommended_deposit_amount' | 'core_recommended_casino_bet_amount') => {
194
+ userStateParamsKeys.forEach((k: UserStateParamsKeys) => {
192
195
  const operator = userStateOperator[k]?.op;
193
196
 
194
- if (k === 'core_fav_game_top3' || k === 'core_fav_game_type_top3' || k === 'core_fav_game_provider_top3') {
197
+ if (USER_STATE_PARAMS_KEYS_GAMES.includes(k)) {
195
198
  if (operatorsMulti.includes(operator)) {
196
199
  const value = userStateParams[k]?.filter(v => Boolean(v));
197
200
  if (value && value.length > 0) {
@@ -218,7 +221,7 @@ export class MissionUtils {
218
221
  }
219
222
  }
220
223
 
221
- if (k === 'core_recommended_deposit_amount' || k === 'core_recommended_casino_bet_amount') {
224
+ if (USER_STATE_PARAMS_KEYS_BET_AMOUNT.includes(k)) {
222
225
  suggestedValue = userStateParams[k];
223
226
 
224
227
  if (suggestedValue) {
@@ -1,3 +1,4 @@
1
+ import { AchRelatedGame } from '../Base/AchRelatedGame';
1
2
  import { IntUtils } from '../IntUtils';
2
3
  import { TStoreItem } from '../WSAPI/WSAPITypes';
3
4
  import { StoreItemPublicMeta } from './StoreItemPublicMeta';
@@ -12,6 +13,7 @@ export interface StoreItem {
12
13
  canBuy?: boolean;
13
14
  shopPool: number;
14
15
  activeTillDate?: number;
16
+ related_games?: AchRelatedGame[];
15
17
  }
16
18
 
17
19
  const mapPurchaseType = (purchaseType: StoreItemPurchaseType) => {
@@ -57,6 +59,19 @@ export const StoreItemTransform = (items: StoreItem[]): TStoreItem[] => {
57
59
  only_in_custom_section: r.itemPublicMeta.only_in_custom_section,
58
60
  custom_section_type_id: r.itemPublicMeta.custom_section_type_id,
59
61
  ...(r.itemPublicMeta.cant_buy_message ? { cant_buy_message: r.itemPublicMeta.cant_buy_message } : {}),
62
+ related_games: (r.related_games || []).map((g, i) => ({
63
+ ext_game_id: g.ext_game_id,
64
+ game_public_meta: {
65
+ name: g.game_public_meta.name,
66
+ link: g.game_public_meta.link,
67
+ image: g.game_public_meta.image,
68
+ enabled: g.game_public_meta.enabled,
69
+ game_categories: g.game_public_meta.game_categories,
70
+ game_provider: g.game_public_meta.game_provider,
71
+ mobile_spec_link: g.game_public_meta.mobile_spec_link,
72
+ priority: i + 1,
73
+ },
74
+ })),
60
75
  };
61
76
  return x;
62
77
  });
@@ -525,6 +525,8 @@ export interface TStoreItem {
525
525
  priority: number;
526
526
  /** The list of IDs of the related items. Can be used to show the related items in the store */
527
527
  related_item_ids: number[];
528
+ /** List of casino games (or other types of entities) related to the store item */
529
+ related_games?: AchRelatedGame[];
528
530
  /** The indicator if the user can buy the item
529
531
  * This indicator is taking into account the segment conditions for the store item, the price of item towards users balance,
530
532
  */
package/src/index.ts CHANGED
@@ -21,4 +21,5 @@ export * from './Raffle';
21
21
  export * from './OCache';
22
22
  export * from './Bonuses';
23
23
  export * from './CustomSections';
24
- export * from './ActivityLog';
24
+ export * from './ActivityLog';
25
+ export * from './Base/AchRelatedGame';