@smartico/public-api 0.0.379 → 0.0.381

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/.nvmrc +1 -1
  2. package/CLAUDE.md +103 -0
  3. package/README.md +53 -2
  4. package/dist/Base/ClassId.d.ts +2 -0
  5. package/dist/Jackpots/JackpotDetails.d.ts +14 -15
  6. package/dist/Jackpots/JackpotPot.d.ts +10 -6
  7. package/dist/Raffle/GetRaffleWonPrizesRequest.d.ts +9 -0
  8. package/dist/Raffle/GetRaffleWonPrizesResponse.d.ts +52 -0
  9. package/dist/Raffle/index.d.ts +2 -0
  10. package/dist/SmarticoAPI.d.ts +6 -1
  11. package/dist/SmarticoLib/index.d.ts +5 -1
  12. package/dist/Store/BuyStoreItemErrorCode.d.ts +9 -1
  13. package/dist/Tournaments/TournamentRegistrationError.d.ts +3 -1
  14. package/dist/WSAPI/WSAPI.d.ts +13 -1235
  15. package/dist/WSAPI/WSAPIAvatars.d.ts +296 -0
  16. package/dist/WSAPI/WSAPIBase.d.ts +71 -0
  17. package/dist/WSAPI/WSAPIBonuses.d.ts +240 -0
  18. package/dist/WSAPI/WSAPIClans.d.ts +388 -0
  19. package/dist/WSAPI/WSAPIGamePick.d.ts +593 -0
  20. package/dist/WSAPI/WSAPIGeneral.d.ts +172 -0
  21. package/dist/WSAPI/WSAPIInbox.d.ts +615 -0
  22. package/dist/WSAPI/WSAPIJackpots.d.ts +344 -0
  23. package/dist/WSAPI/WSAPILeaderBoard.d.ts +139 -0
  24. package/dist/WSAPI/WSAPIMiniGames.d.ts +510 -0
  25. package/dist/WSAPI/WSAPIMissions.d.ts +517 -0
  26. package/dist/WSAPI/WSAPIRaffles.d.ts +643 -0
  27. package/dist/WSAPI/WSAPIStore.d.ts +656 -0
  28. package/dist/WSAPI/WSAPITournaments.d.ts +501 -0
  29. package/dist/WSAPI/WSAPITypes.d.ts +376 -205
  30. package/dist/WSAPI/WSAPIUser.d.ts +533 -0
  31. package/dist/index.js +6745 -1661
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.modern.mjs +6324 -1342
  34. package/dist/index.modern.mjs.map +1 -1
  35. package/docs/Callbacks.md +162 -0
  36. package/docs/SmarticoObject.md +445 -0
  37. package/docs/Transforms.md +99 -0
  38. package/docs/api/README.md +82 -2
  39. package/docs/api/classes/WSAPIAvatars.md +344 -0
  40. package/docs/api/classes/WSAPIBonuses.md +271 -0
  41. package/docs/api/classes/WSAPIClans.md +436 -0
  42. package/docs/api/classes/WSAPIGamePick.md +710 -0
  43. package/docs/api/classes/WSAPIGeneral.md +212 -0
  44. package/docs/api/classes/WSAPIInbox.md +801 -0
  45. package/docs/api/classes/WSAPIJackpots.md +439 -0
  46. package/docs/api/classes/WSAPILeaderBoard.md +157 -0
  47. package/docs/api/classes/WSAPIMiniGames.md +612 -0
  48. package/docs/api/classes/WSAPIMissions.md +590 -0
  49. package/docs/api/classes/WSAPIRaffles.md +773 -0
  50. package/docs/api/classes/WSAPIStore.md +719 -0
  51. package/docs/api/classes/WSAPITournaments.md +571 -0
  52. package/docs/api/classes/WSAPIUser.md +637 -0
  53. package/docs/api/documents/Callbacks.md +162 -0
  54. package/docs/api/documents/SmarticoObject.md +445 -0
  55. package/docs/api/documents/Transforms.md +99 -0
  56. package/docs/api/enumerations/AchievementClaimPeriodTypeId.md +13 -0
  57. package/docs/api/enumerations/BonusStatus-1.md +11 -6
  58. package/docs/api/enumerations/BuyStoreItemErrorCode.md +32 -0
  59. package/docs/api/enumerations/JoinClanErrorCode.md +81 -0
  60. package/docs/api/enumerations/TournamentRegistrationError.md +12 -0
  61. package/docs/api/functions/clanTournamentPlayersTransform.md +13 -0
  62. package/docs/api/interfaces/AvatarCustomized.md +25 -0
  63. package/docs/api/interfaces/AvatarDefinition.md +94 -0
  64. package/docs/api/interfaces/AvatarPrompt.md +45 -0
  65. package/docs/api/interfaces/BonusMetaMap-1.md +4 -1
  66. package/docs/api/interfaces/BonusTemplateMetaMap-1.md +9 -4
  67. package/docs/api/interfaces/Clan.md +4 -0
  68. package/docs/api/interfaces/ClanInfo.md +109 -0
  69. package/docs/api/interfaces/ClanMember.md +53 -0
  70. package/docs/api/interfaces/ClanPrizePublicMeta.md +41 -0
  71. package/docs/api/interfaces/ClanPrizeStructureEntry.md +7 -1
  72. package/docs/api/interfaces/ClanPublicMeta.md +4 -0
  73. package/docs/api/interfaces/ClanTournamentPlayerRaw.md +67 -0
  74. package/docs/api/interfaces/GemsDiamondsLog.md +43 -0
  75. package/docs/api/interfaces/GetClanInfoResponse.md +61 -0
  76. package/docs/api/interfaces/GetClanTournamentPlayersResponse.md +81 -0
  77. package/docs/api/interfaces/GetRaffleWonPrizesRequest.md +59 -0
  78. package/docs/api/interfaces/GetRaffleWonPrizesResponse.md +95 -0
  79. package/docs/api/interfaces/InboxMarkMessageAction.md +10 -2
  80. package/docs/api/interfaces/JackpotDetails.md +14 -15
  81. package/docs/api/interfaces/JackpotPot.md +9 -6
  82. package/docs/api/interfaces/LeaderBoardDetailsT.md +14 -8
  83. package/docs/api/interfaces/LeaderBoardUserT.md +8 -5
  84. package/docs/api/interfaces/LeaderBoardsRewardsT.md +7 -0
  85. package/docs/api/interfaces/PointsLog.md +43 -0
  86. package/docs/api/interfaces/RaffleWonPrize.md +59 -0
  87. package/docs/api/interfaces/RaffleWonPrizePublicMeta.md +27 -0
  88. package/docs/api/interfaces/RaffleWonPrizeUser.md +43 -0
  89. package/docs/api/interfaces/SAWTemplateUI.md +10 -0
  90. package/docs/api/interfaces/TAchCategory.md +14 -4
  91. package/docs/api/interfaces/TAvatarCustomized.md +4 -4
  92. package/docs/api/interfaces/TAvatarDefinition.md +13 -14
  93. package/docs/api/interfaces/TAvatarPrompt.md +6 -6
  94. package/docs/api/interfaces/TBonus.md +16 -8
  95. package/docs/api/interfaces/TBuyStoreItemResult.md +4 -11
  96. package/docs/api/interfaces/TClaimBonusResult.md +5 -5
  97. package/docs/api/interfaces/TClan.md +8 -4
  98. package/docs/api/interfaces/TClanInfo.md +47 -0
  99. package/docs/api/interfaces/TClanJoinResult.md +11 -1
  100. package/docs/api/interfaces/TClanTournamentPlayer.md +55 -0
  101. package/docs/api/interfaces/TClanTournamentPlayersResult.md +27 -0
  102. package/docs/api/interfaces/TClans.md +3 -1
  103. package/docs/api/interfaces/TGetTranslations.md +4 -0
  104. package/docs/api/interfaces/TInboxMessage.md +14 -6
  105. package/docs/api/interfaces/TInboxMessageBody.md +18 -12
  106. package/docs/api/interfaces/TLevel.md +17 -20
  107. package/docs/api/interfaces/TLevelCurrent.md +19 -18
  108. package/docs/api/interfaces/TMiniGamePlayBatchResult.md +14 -6
  109. package/docs/api/interfaces/TMiniGamePlayResult.md +9 -4
  110. package/docs/api/interfaces/TMissionClaimRewardResult.md +6 -3
  111. package/docs/api/interfaces/TMissionOptInResult.md +6 -3
  112. package/docs/api/interfaces/TMissionOrBadge.md +5 -4
  113. package/docs/api/interfaces/TRaffleOptinResponse.md +4 -2
  114. package/docs/api/interfaces/TSegmentCheckResult.md +10 -0
  115. package/docs/api/interfaces/TSetAvatarResult.md +3 -3
  116. package/docs/api/interfaces/TStoreItem.md +11 -1
  117. package/docs/api/interfaces/TTournament.md +1 -1
  118. package/docs/api/interfaces/TTournamentDetailed.md +9 -1
  119. package/docs/api/interfaces/TTournamentRegistrationResult.md +4 -2
  120. package/docs/api/interfaces/TUICustomSection.md +23 -19
  121. package/docs/api/interfaces/TUserProfile.md +18 -16
  122. package/docs/api/interfaces/TransformedRaffleClaimPrizeResponse.md +6 -2
  123. package/docs/api/interfaces/UserAchievement.md +1 -1
  124. package/docs/api/interfaces/UserLevelExtraCountersT.md +9 -2
  125. package/docs/api/type-aliases/ActivityLogEntry.md +3 -0
  126. package/docs/native/ADDING_METHODS.md +7 -2
  127. package/docs/native/PROTOCOL.md +337 -0
  128. package/docs/ui/avatars/UIGuide_getAvatarPrompts.md +100 -0
  129. package/docs/ui/avatars/UIGuide_getAvatarsCustomized.md +90 -0
  130. package/docs/ui/avatars/UIGuide_getAvatarsList.md +105 -0
  131. package/docs/ui/avatars/UIGuide_setAvatar.md +118 -0
  132. package/docs/ui/bonuses/UIGuide_claimBonus.md +144 -0
  133. package/docs/ui/bonuses/UIGuide_getBonuses.md +176 -0
  134. package/docs/ui/clans/UIGuide_getClanInfo.md +153 -0
  135. package/docs/ui/clans/UIGuide_getClans.md +172 -0
  136. package/docs/ui/clans/UIGuide_joinClan.md +196 -0
  137. package/docs/ui/gamepick/UIGuide_gamePickGetActiveRound.md +99 -0
  138. package/docs/ui/gamepick/UIGuide_gamePickGetActiveRounds.md +76 -0
  139. package/docs/ui/gamepick/UIGuide_gamePickGetBoard.md +81 -0
  140. package/docs/ui/gamepick/UIGuide_gamePickGetGameInfo.md +78 -0
  141. package/docs/ui/gamepick/UIGuide_gamePickGetHistory.md +55 -0
  142. package/docs/ui/gamepick/UIGuide_gamePickGetRoundInfoForUser.md +71 -0
  143. package/docs/ui/gamepick/UIGuide_gamePickGetUserInfo.md +64 -0
  144. package/docs/ui/gamepick/UIGuide_gamePickSubmitSelection.md +103 -0
  145. package/docs/ui/gamepick/UIGuide_gamePickSubmitSelectionQuiz.md +67 -0
  146. package/docs/ui/general/UIGuide_getCustomSections.md +137 -0
  147. package/docs/ui/general/UIGuide_getRelatedItemsForGame.md +140 -0
  148. package/docs/ui/inbox/UIGuide_deleteInboxMessage.md +135 -0
  149. package/docs/ui/inbox/UIGuide_getInboxMessageBody.md +133 -0
  150. package/docs/ui/inbox/UIGuide_getInboxMessages.md +186 -0
  151. package/docs/ui/inbox/UIGuide_markInboxMessageAsRead.md +122 -0
  152. package/docs/ui/inbox/UIGuide_markUnmarkInboxMessageAsFavorite.md +84 -0
  153. package/docs/ui/jackpots/UIGuide_getJackpotEligibleGames.md +73 -0
  154. package/docs/ui/jackpots/UIGuide_getJackpotWinners.md +83 -0
  155. package/docs/ui/jackpots/UIGuide_jackpotGet.md +138 -0
  156. package/docs/ui/jackpots/UIGuide_jackpotOptIn.md +85 -0
  157. package/docs/ui/jackpots/UIGuide_jackpotOptOut.md +65 -0
  158. package/docs/ui/leaderboard/UIGuide_getLeaderBoard.md +166 -0
  159. package/docs/ui/minigames/UIGuide_getMiniGames.md +153 -0
  160. package/docs/ui/minigames/UIGuide_getMiniGamesHistory.md +90 -0
  161. package/docs/ui/minigames/UIGuide_playMiniGame.md +150 -0
  162. package/docs/ui/minigames/UIGuide_playMiniGameBatch.md +128 -0
  163. package/docs/ui/missions/UIGuide_getAchCategories.md +17 -0
  164. package/docs/ui/missions/UIGuide_getBadges.md +237 -0
  165. package/docs/ui/missions/UIGuide_getMissions.md +268 -0
  166. package/docs/ui/missions/UIGuide_requestMissionClaimReward.md +21 -0
  167. package/docs/ui/missions/UIGuide_requestMissionOptIn.md +16 -0
  168. package/docs/ui/raffles/UIGuide_claimRafflePrize.md +99 -0
  169. package/docs/ui/raffles/UIGuide_getRaffleDrawRun.md +117 -0
  170. package/docs/ui/raffles/UIGuide_getRaffleDrawRunsHistory.md +92 -0
  171. package/docs/ui/raffles/UIGuide_getRaffleWonPrizes.md +120 -0
  172. package/docs/ui/raffles/UIGuide_getRaffles.md +175 -0
  173. package/docs/ui/raffles/UIGuide_requestRaffleOptin.md +114 -0
  174. package/docs/ui/store/UIGuide_buyStoreItem.md +133 -0
  175. package/docs/ui/store/UIGuide_getStoreCategories.md +19 -0
  176. package/docs/ui/store/UIGuide_getStoreItems.md +264 -0
  177. package/docs/ui/store/UIGuide_getStorePurchasedItems.md +122 -0
  178. package/docs/ui/tournaments/UIGuide_getClanTournamentPlayers.md +140 -0
  179. package/docs/ui/tournaments/UIGuide_getTournamentInstanceInfo.md +265 -0
  180. package/docs/ui/tournaments/UIGuide_getTournamentsList.md +236 -0
  181. package/docs/ui/tournaments/UIGuide_registerInTournament.md +156 -0
  182. package/docs/ui/user/UIGuide_getActivityLog.md +130 -0
  183. package/docs/ui/user/UIGuide_getLevels.md +167 -0
  184. package/docs/ui/user/UIGuide_getUserProfile.md +213 -0
  185. package/package.json +3 -3
  186. package/scripts/postdoc-cleanup.js +195 -0
  187. package/src/Base/ClassId.ts +2 -0
  188. package/src/Jackpots/JackpotDetails.ts +14 -15
  189. package/src/Jackpots/JackpotPot.ts +10 -6
  190. package/src/Missions/MissionsUtils.ts +5 -2
  191. package/src/Raffle/GetRaffleWonPrizesRequest.ts +12 -0
  192. package/src/Raffle/GetRaffleWonPrizesResponse.ts +56 -0
  193. package/src/Raffle/index.ts +3 -1
  194. package/src/SmarticoAPI.ts +14 -1
  195. package/src/SmarticoLib/index.ts +4 -0
  196. package/src/Store/BuyStoreItemErrorCode.ts +8 -0
  197. package/src/Store/StoreItem.ts +1 -0
  198. package/src/Store/StoreItemPurchased.ts +1 -0
  199. package/src/Store/StoreItemType.ts +1 -1
  200. package/src/Tournaments/TournamentRegistrationError.ts +4 -0
  201. package/src/WSAPI/WSAPI.ts +27 -2007
  202. package/src/WSAPI/WSAPIAvatars.ts +345 -0
  203. package/src/WSAPI/WSAPIBase.ts +93 -0
  204. package/src/WSAPI/WSAPIBonuses.ts +268 -0
  205. package/src/WSAPI/WSAPIClans.ts +417 -0
  206. package/src/WSAPI/WSAPIGamePick.ts +667 -0
  207. package/src/WSAPI/WSAPIGeneral.ts +199 -0
  208. package/src/WSAPI/WSAPIInbox.ts +711 -0
  209. package/src/WSAPI/WSAPIJackpots.ts +448 -0
  210. package/src/WSAPI/WSAPILeaderBoard.ts +154 -0
  211. package/src/WSAPI/WSAPIMiniGames.ts +597 -0
  212. package/src/WSAPI/WSAPIMissions.ts +572 -0
  213. package/src/WSAPI/WSAPIRaffles.ts +703 -0
  214. package/src/WSAPI/WSAPIStore.ts +732 -0
  215. package/src/WSAPI/WSAPITournaments.ts +541 -0
  216. package/src/WSAPI/WSAPITypes.ts +376 -207
  217. package/src/WSAPI/WSAPIUser.ts +606 -0
  218. package/tsconfig.json +26 -2
  219. package/docs/api/classes/WSAPI.md +0 -1927
@@ -0,0 +1,703 @@
1
+ import { ECacheContext, OCache } from '../OCache';
2
+ import {
3
+ TRaffle,
4
+ TRaffleDraw,
5
+ TRaffleDrawRun,
6
+ TransformedRaffleClaimPrizeResponse,
7
+ TRaffleOptinResponse,
8
+ } from './WSAPITypes';
9
+ import {
10
+ drawRunHistoryTransform,
11
+ raffleClaimPrizeResponseTransform,
12
+ GetRaffleWonPrizesResponse,
13
+ } from '../Raffle';
14
+ import {
15
+ CACHE_DATA_SEC,
16
+ onUpdateContextKey,
17
+ } from './WSAPIBase';
18
+ import { WSAPIJackpots } from './WSAPIJackpots';
19
+
20
+ /** @group Raffles */
21
+ export class WSAPIRaffles extends WSAPIJackpots {
22
+ protected async updateRaffles() {
23
+ const payload = await this.api.getRafflesT(this.userExtId);
24
+ this.updateEntity(onUpdateContextKey.Raffles, payload);
25
+ }
26
+
27
+ /**
28
+ * Returns all raffles visible to the current user, each carrying an
29
+ * embedded `draws[]` array with per-draw state (current state, ticket
30
+ * counts, opt-in status, prize structure). Use this to power a
31
+ * raffles lobby screen and to drive per-draw CTAs (opt-in, view
32
+ * winners, claim).
33
+ *
34
+ * The embedded `draws[i]` objects are sufficient for rendering all
35
+ * draw cards — winner details with usernames / avatars require a
36
+ * follow-up {@link getRaffleDrawRun} call (the embedded form carries
37
+ * only `winners_total` / `winners_limit` / `winners_offset` metadata,
38
+ * not individual winner rows).
39
+ *
40
+ * @remarks
41
+ * **Subscription model (`onUpdate`)**
42
+ * The callback receives the FULL refreshed raffle list (never a
43
+ * diff/patch). Each subsequent call to `getRaffles({ onUpdate })`
44
+ * REPLACES the prior callback. Pass `onUpdate: undefined` (or omit
45
+ * it) to keep the prior callback in place; the callback is never
46
+ * auto-cleared.
47
+ *
48
+ * **Update triggers** — the callback fires when:
49
+ *
50
+ * 1. {@link claimRafflePrize} resolves on this connection (any
51
+ * response code) — the refreshed list reflects the new
52
+ * `has_unclaimed_prize` / `claimed_date` state.
53
+ * 2. {@link requestRaffleOptin} resolves on this connection (any
54
+ * response code) — the refreshed list reflects the new
55
+ * `user_opted_in` state on the affected draw.
56
+ *
57
+ * Does NOT fire for: server-side draw executions, ticket increments
58
+ * (other users earning tickets), or operator-side raffle/draw config
59
+ * changes. Those changes surface only on the next cache miss (after
60
+ * the 30 s TTL) — poll manually if your UI needs sub-30s freshness
61
+ * during an in-progress draw.
62
+ *
63
+ * **Reading state from the returned raffle**
64
+ * - `current_tickets_count` vs `max_tickets_count` drives the
65
+ * `ticket_cap_visualization` banner (enum
66
+ * {@link RaffleTicketCapVisualization}: `Empty` = no banner,
67
+ * `Counter` = show "X tickets remaining", `Message` = show
68
+ * sold-out message).
69
+ * - Within each draw, `current_state`
70
+ * ({@link RaffleDrawInstanceState}) buckets the draw into Open
71
+ * (accepting tickets), WinnerSelection (currently drawing), or
72
+ * Executed (winners selected).
73
+ * - `execution_type` ({@link RaffleDrawTypeExecution}) distinguishes
74
+ * one-shot (`ExecDate`), repeating (`Recurring`), or special
75
+ * one-shot (`Grand`) draws. Recurring draws share a stable
76
+ * `draws[i].id` (the schedule definition) across runs — `run_id`
77
+ * is the per-execution instance.
78
+ *
79
+ * **Cache TTL**: the SDK caches the response for 30 seconds. Cache
80
+ * is fully cleared on login / logout. The server also invalidates
81
+ * the SDK cache when a draw executes on the server side.
82
+ *
83
+ * **Idempotency / Side effects**: safe. Read-only.
84
+ *
85
+ * **UI guidance**: see [UI Guide — `getRaffles`](../../docs/ui/raffles/UIGuide_getRaffles.md).
86
+ *
87
+ * **Visitor mode**: supported. The same shape is returned, scoped
88
+ * to the brand's public raffles. Per-user fields (`my_tickets_count`,
89
+ * `my_last_tickets`, `user_opted_in`) are not meaningful for
90
+ * visitors. The `onUpdate` callback is accepted but never fires
91
+ * because the mutation methods that trigger it
92
+ * ({@link claimRafflePrize}, {@link requestRaffleOptin}) are not
93
+ * available / not effective in visitor mode.
94
+ *
95
+ * @param params Optional. Omit to fetch without subscribing.
96
+ * @param params.onUpdate Callback invoked with the full refreshed
97
+ * raffles list after every
98
+ * {@link claimRafflePrize} or
99
+ * {@link requestRaffleOptin} round-trip
100
+ * on this connection.
101
+ * @returns Promise resolving to the raffles list.
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * const raffles = await window._smartico.api.getRaffles({
106
+ * onUpdate: (refreshed) => {
107
+ * console.log('[smartico] raffles refreshed (after claim/optin) — re-render from this array:', refreshed);
108
+ * },
109
+ * });
110
+ *
111
+ * for (const raffle of raffles) {
112
+ * console.log('[smartico] render raffle', raffle.id, '—', raffle.name, ':', raffle.draws.length, 'draws');
113
+ *
114
+ * // Bucket draws: active/upcoming first (sorted by execution_ts ASC), then executed last.
115
+ * const sorted = [...raffle.draws].sort((a, b) => {
116
+ * const aDone = a.current_state === 3; // Executed
117
+ * const bDone = b.current_state === 3;
118
+ * if (aDone !== bDone) return aDone ? 1 : -1; // executed sink to the bottom
119
+ * return a.execution_ts - b.execution_ts;
120
+ * });
121
+ *
122
+ * for (const d of sorted) {
123
+ * if (d.requires_optin && !d.user_opted_in && d.is_active && d.current_state !== 3) {
124
+ * console.log('[smartico] draw', d.run_id, '— show OPT IN CTA (requires_optin + not yet opted in + still active)');
125
+ * }
126
+ * if (d.current_state === 3) {
127
+ * console.log('[smartico] draw', d.run_id, 'executed — fetch winner details via getRaffleDrawRun');
128
+ * }
129
+ * }
130
+ * }
131
+ *
132
+ * // For winner detail on an executed draw, call getRaffleDrawRun separately.
133
+ * ```
134
+ */
135
+ public async getRaffles({ onUpdate }: { onUpdate?: (data: TRaffle[]) => void } = {}): Promise<TRaffle[]> {
136
+ if (onUpdate) {
137
+ this.onUpdateCallback.set(onUpdateContextKey.Raffles, onUpdate);
138
+ }
139
+
140
+ return OCache.use(onUpdateContextKey.Raffles, ECacheContext.WSAPI, () => this.api.getRafflesT(this.userExtId), CACHE_DATA_SEC);
141
+ }
142
+
143
+ /**
144
+ * Returns the full detail of a single raffle draw run — same shape
145
+ * as the embedded `TRaffleDraw` in {@link getRaffles}, but populated
146
+ * with paginated `prizes[].winners[]` rows including usernames and
147
+ * avatars. Use this to render a draw detail / winners screen, or to
148
+ * page through the winner list of an executed draw.
149
+ *
150
+ * Each call is a fresh server round-trip — there is no client cache.
151
+ * Re-call to refresh.
152
+ *
153
+ * @remarks
154
+ * **Preconditions**
155
+ * Pass `raffle_id` (the parent raffle's `id`) and `run_id` (the
156
+ * specific run instance — `TRaffleDraw.run_id` from
157
+ * {@link getRaffles}'s embedded draws). Note that
158
+ * `TRaffleDraw.id` is the *schedule_id* (stable across runs of a
159
+ * recurring draw) — that's NOT what this method takes; it takes the
160
+ * per-instance `run_id`.
161
+ *
162
+ * **Refresh model**
163
+ * - **No subscription.** One-shot promise.
164
+ * - **No client cache.** Every call sends a network request.
165
+ * - **No push event** refreshes the response. Live winner-list
166
+ * updates require a fresh call.
167
+ * - The default Smartico UI polls this method on a variable cadence
168
+ * while a draw is in flight: every 3 s during `WinnerSelection`,
169
+ * every 10 s when the countdown is under 5 minutes, every 30 s
170
+ * otherwise.
171
+ *
172
+ * **Winner pagination**
173
+ * `winners_from` / `winners_to` define a half-open range of winner
174
+ * indices. The default window is `0–20` (20 winners). The server
175
+ * caps the window at 50 rows per call — passing a larger range
176
+ * silently truncates. For "load more" pagination, advance
177
+ * `winners_from` by the prior page size and pass the same
178
+ * `winners_to` offset. `winners_total` on the returned
179
+ * `TRaffleDraw` is the authoritative total count for pagination.
180
+ *
181
+ * The current user's own winning rows (if any) are server-sorted
182
+ * to the top of the result.
183
+ *
184
+ * **Throws**
185
+ * Both `raffle_id` and `run_id` are required — the SDK throws
186
+ * synchronously when either is missing or falsy.
187
+ *
188
+ * **Idempotency / Side effects**: safe. Read-only.
189
+ *
190
+ * **UI guidance**: see [UI Guide — `getRaffleDrawRun`](../../docs/ui/raffles/UIGuide_getRaffleDrawRun.md).
191
+ *
192
+ * **Visitor mode**: supported.
193
+ *
194
+ * @param props.raffle_id The parent raffle's `id` (from `TRaffle.id`).
195
+ * @param props.run_id The draw run instance ID (from
196
+ * `TRaffleDraw.run_id`, not `TRaffleDraw.id`).
197
+ * @param props.winners_from First winner index to return (0-based).
198
+ * Defaults to `0`.
199
+ * @param props.winners_to Last winner index (exclusive).
200
+ * Defaults to `20`. Server caps the
201
+ * window at 50 rows per call.
202
+ * @returns Promise resolving to `TRaffleDraw`
203
+ * with `prizes[].winners[]` populated
204
+ * and `winners_total` set.
205
+ *
206
+ * @example
207
+ * ```ts
208
+ * const raffles = await window._smartico.api.getRaffles();
209
+ * const raffle = raffles[0];
210
+ * const draw = raffle.draws.find(d => d.current_state === 3); // Executed
211
+ *
212
+ * if (!draw) {
213
+ * console.log('[smartico] no executed draw — skip detail view');
214
+ * return;
215
+ * }
216
+ *
217
+ * // First page of winners.
218
+ * const detail = await window._smartico.api.getRaffleDrawRun({
219
+ * raffle_id: raffle.id,
220
+ * run_id: draw.run_id, // NOTE: run_id, NOT draw.id
221
+ * winners_from: 0,
222
+ * winners_to: 20,
223
+ * });
224
+ *
225
+ * for (const prize of detail.prizes) {
226
+ * console.log('[smartico] prize', prize.name, '— winners on this page:', prize.winners.length);
227
+ * const myWin = prize.winners.find(w => w.username === currentUsername); // or another match
228
+ * if (myWin) {
229
+ * console.log('[smartico] current user won this prize — surface a Claim CTA if not yet claimed');
230
+ * }
231
+ * }
232
+ *
233
+ * // Load more — pagination via winners_from / winners_to.
234
+ * if ((detail.winners_total ?? 0) > 20) {
235
+ * const next = await window._smartico.api.getRaffleDrawRun({
236
+ * raffle_id: raffle.id,
237
+ * run_id: draw.run_id,
238
+ * winners_from: 20,
239
+ * winners_to: 40,
240
+ * });
241
+ * console.log('[smartico] page 2 loaded — append', next.prizes.flatMap(p => p.winners).length, 'winners');
242
+ * }
243
+ * ```
244
+ */
245
+ public async getRaffleDrawRun(props: { raffle_id: number; run_id: number; winners_from?: number; winners_to?: number }): Promise<TRaffleDraw> {
246
+ if (!props.raffle_id || !props.run_id) {
247
+ throw new Error('both raffle_id and run_id are required');
248
+ }
249
+
250
+ return await this.api.getRaffleDrawRunT(this.userExtId, props.raffle_id, props.run_id, props.winners_from, props.winners_to);
251
+ }
252
+
253
+ /**
254
+ * Returns the history of past-executed draw runs for a raffle —
255
+ * optionally scoped to a single recurring draw schedule. Each row
256
+ * is a previously-executed run with its scheduled and
257
+ * actual-execution timestamps, the user's win status, and an
258
+ * unclaimed-prize flag for surfacing a Claim CTA on history rows.
259
+ *
260
+ * @remarks
261
+ * **Preconditions**
262
+ * `raffle_id` is required. `draw_id` is optional — when omitted,
263
+ * the response includes history for ALL draws of the raffle; when
264
+ * supplied, it scopes to that one draw's recurring history. The
265
+ * `draw_id` to pass is `TRaffleDraw.id` (the schedule_id, stable
266
+ * across runs), not `run_id`.
267
+ *
268
+ * **Server-side filtering**
269
+ * Draws configured by the operator to hide their history are
270
+ * excluded from the response automatically. Cancelled runs are
271
+ * also excluded.
272
+ *
273
+ * **Sort order**
274
+ * Server returns rows by scheduled `execution_ts` descending
275
+ * (newest first). No client-side sort required.
276
+ *
277
+ * **Refresh model**
278
+ * - **No subscription.** One-shot promise.
279
+ * - **No client cache.** Every call hits the server.
280
+ * - **No push event** refreshes the response. Re-call manually to
281
+ * pick up newly-executed runs or `has_unclaimed_prize` flips
282
+ * after a {@link claimRafflePrize} call.
283
+ *
284
+ * **Idempotency / Side effects**: safe. Read-only.
285
+ *
286
+ * **UI guidance**: see [UI Guide — `getRaffleDrawRunsHistory`](../../docs/ui/raffles/UIGuide_getRaffleDrawRunsHistory.md).
287
+ *
288
+ * **Visitor mode**: supported. The same shape is returned with
289
+ * `is_winner` and `has_unclaimed_prize` always `false` for visitors.
290
+ *
291
+ * @param props.raffle_id The parent raffle's `id` (from `TRaffle.id`).
292
+ * Required.
293
+ * @param props.draw_id Optional — the draw's schedule_id
294
+ * (`TRaffleDraw.id`). When set, scopes the
295
+ * history to that one draw's runs. When
296
+ * omitted, includes all draws of the raffle.
297
+ * @returns Promise resolving to a `TRaffleDrawRun[]`
298
+ * ordered newest-first. Empty if no executed
299
+ * runs exist.
300
+ *
301
+ * @example
302
+ * ```ts
303
+ * const raffles = await window._smartico.api.getRaffles();
304
+ * const raffle = raffles[0];
305
+ *
306
+ * // History across all draws of the raffle.
307
+ * const allHistory = await window._smartico.api.getRaffleDrawRunsHistory({
308
+ * raffle_id: raffle.id,
309
+ * });
310
+ *
311
+ * // Highlight rows where the user has an unclaimed prize.
312
+ * const unclaimed = allHistory.filter(r => r.has_unclaimed_prize);
313
+ * if (unclaimed.length > 0) {
314
+ * console.log('[smartico] surface a "Claim" CTA on these', unclaimed.length, 'history rows:', unclaimed.map(r => r.run_id));
315
+ * }
316
+ *
317
+ * // Scoped history of one recurring draw (use draw.id, the schedule_id).
318
+ * const oneDrawHistory = await window._smartico.api.getRaffleDrawRunsHistory({
319
+ * raffle_id: raffle.id,
320
+ * draw_id: raffle.draws[0].id, // schedule_id (stable across recurring runs)
321
+ * });
322
+ * console.log('[smartico] render history rows for the daily draw — newest first:', oneDrawHistory.length, 'rows');
323
+ * ```
324
+ */
325
+ public async getRaffleDrawRunsHistory(props: { raffle_id: number; draw_id?: number }): Promise<TRaffleDrawRun[]> {
326
+
327
+ const res = await this.api.getRaffleDrawRunsHistory(this.userExtId, props);
328
+
329
+ if (!props.raffle_id) {
330
+ throw new Error('raffle_id is required');
331
+ }
332
+
333
+ return drawRunHistoryTransform(res);
334
+ }
335
+
336
+ /**
337
+ * Claims a raffle prize the user has won. Call this when the user
338
+ * has a winning row with `should_claim === true` and an unclaimed
339
+ * `won_id` (read from a `TRafflePrizeWinner` on a
340
+ * {@link getRaffleDrawRun} result, or surfaced by `has_unclaimed_prize`
341
+ * on a {@link getRaffleDrawRunsHistory} row that the consumer drills
342
+ * into).
343
+ *
344
+ * On success (`errorCode === 0`), the server records the claim and
345
+ * triggers prize delivery through the operator's integration —
346
+ * delivery is server-side, not part of this response.
347
+ *
348
+ * @remarks
349
+ * **Result shape note**: this method returns
350
+ * `TransformedRaffleClaimPrizeResponse` with `errorCode` /
351
+ * `errorMessage` (camelCase full-word) — different from most other
352
+ * SDK result types which use `err_code` / `err_message` (snake_case
353
+ * short-word). Branch on the camelCase keys when reading this
354
+ * method's result.
355
+ *
356
+ * **Preconditions**
357
+ * Pass a `won_id` that identifies an unclaimed winning row for the
358
+ * current user. The `won_id` comes from
359
+ * `TRafflePrizeWinner.raf_won_id` returned by
360
+ * {@link getRaffleDrawRun}.
361
+ *
362
+ * **Error codes** (in `errorCode`)
363
+ * - `0` — success; the claim is recorded and prize delivery is
364
+ * queued server-side.
365
+ * - `1` — generic claim failure. The `errorMessage` distinguishes
366
+ * the specific cause (the server uses one error code for several
367
+ * distinct conditions): the prize has already been claimed, the
368
+ * `won_id` doesn't match a winning row for this user, or the user
369
+ * is in a control group for this raffle. Treat `1` as a retryable
370
+ * error if the message suggests a transient condition; treat as
371
+ * idempotent success if the message indicates already-claimed
372
+ * (the underlying state is what the consumer wants either way —
373
+ * the prize is claimed).
374
+ * - other non-zero — generic server error. Surface `errorMessage`
375
+ * if any.
376
+ *
377
+ * **Claim window**
378
+ * There is no server-enforced claim deadline. Won prizes remain
379
+ * claimable indefinitely until the operator archives them.
380
+ *
381
+ * **Idempotency**: NOT idempotent. A second call on the same
382
+ * `won_id` returns `errorCode === 1` with `errorMessage` indicating
383
+ * the prize has already been claimed. The SDK does NOT enforce an
384
+ * in-flight lock. Guard the call site against double-clicks (set
385
+ * a local "claiming" flag on click, clear it on response).
386
+ *
387
+ * **Refresh after success (and after failure)**
388
+ * The SDK automatically refreshes the raffles cache on every
389
+ * response — both success and failure paths fire the `onUpdate`
390
+ * callback registered via {@link getRaffles}. After `errorCode === 0`,
391
+ * the affected `TRaffleDrawRun.has_unclaimed_prize` (in history)
392
+ * and the winner row's `claimed_date` reflect the claim on the next
393
+ * refresh.
394
+ *
395
+ * **Side effects** (on `errorCode === 0`)
396
+ * - The winner row's `claimed_date` is set server-side.
397
+ * - Prize delivery is queued for the operator's integration to
398
+ * process. Balance / bonus / inbox updates that result from the
399
+ * delivery arrive through their own channels — not in this
400
+ * response.
401
+ *
402
+ * **Throws**
403
+ * `won_id` is required — the SDK throws synchronously when missing
404
+ * or falsy.
405
+ *
406
+ * **UI guidance**: see [UI Guide — `claimRafflePrize`](../../docs/ui/raffles/UIGuide_claimRafflePrize.md).
407
+ *
408
+ * **Visitor mode**: not meaningfully supported. The SDK does not
409
+ * block the call, but visitor sessions have no win history and the
410
+ * server will reject it.
411
+ *
412
+ * @param props.won_id The winning row's `raf_won_id` (from
413
+ * `TRafflePrizeWinner` returned by
414
+ * {@link getRaffleDrawRun}).
415
+ * @returns `{ errorCode, errorMessage? }`; success when
416
+ * `errorCode === 0`. Note camelCase keys (see "Result
417
+ * shape note" above).
418
+ *
419
+ * @example
420
+ * ```ts
421
+ * const detail = await window._smartico.api.getRaffleDrawRun({
422
+ * raffle_id: raffleId,
423
+ * run_id: runId,
424
+ * });
425
+ * const myWin = detail.prizes.flatMap(p => p.winners).find(w => /* user match here *\/ true);
426
+ *
427
+ * if (!myWin || !myWin.raf_won_id || myWin.claimed_date) {
428
+ * console.log('[smartico] nothing to claim — keep CTA hidden');
429
+ * return;
430
+ * }
431
+ *
432
+ * console.log('[smartico] claim starting — set in-flight flag, show loading dots on the Claim button, keep the modal open');
433
+ * const r = await window._smartico.api.claimRafflePrize({ won_id: myWin.raf_won_id });
434
+ * console.log('[smartico] claim response received — clear in-flight flag');
435
+ *
436
+ * if (r.errorCode === 0) {
437
+ * console.log('[smartico] claim succeeded — show a success toast; getRaffles onUpdate above will fire with refreshed state; prize delivery happens server-side');
438
+ * } else if (r.errorCode === 1 && r.errorMessage?.toLowerCase().includes('already claimed')) {
439
+ * console.log('[smartico] prize was already claimed (perhaps from another tab) — treat as success, hide the Claim CTA');
440
+ * } else {
441
+ * console.error('[smartico] claim failed — surface this error message to the user and allow retry:', r.errorMessage);
442
+ * }
443
+ * ```
444
+ */
445
+ public async claimRafflePrize(props: { won_id: number }): Promise<TransformedRaffleClaimPrizeResponse> {
446
+ if (!props.won_id) {
447
+ throw new Error('won_id is required');
448
+ }
449
+
450
+ const res = await this.api.claimRafflePrize(this.userExtId, { won_id: props.won_id });
451
+ return raffleClaimPrizeResponseTransform(res);
452
+ }
453
+
454
+ /**
455
+ * Opts the current user into a specific raffle draw run. Required
456
+ * for draws where `TRaffleDraw.requires_optin === true` — without
457
+ * opt-in, the user's tickets do NOT participate in that run, even
458
+ * if they hold tickets for the raffle.
459
+ *
460
+ * Opt-in is per-run: a recurring draw's next run requires a fresh
461
+ * opt-in. The user's `TRaffleDraw.user_opted_in` flag reflects the
462
+ * current state for the current run only.
463
+ *
464
+ * @remarks
465
+ * **Preconditions**
466
+ * Read the candidate draw from {@link getRaffles}'s embedded
467
+ * `draws[]` and gate the call on
468
+ * `requires_optin === true && !user_opted_in && is_active &&
469
+ * current_state !== Executed`. Calling without these guards may
470
+ * return a non-zero `err_code`.
471
+ *
472
+ * **Argument mapping** — the three IDs come from different fields:
473
+ * - `raffle_id` — the parent raffle's `TRaffle.id`
474
+ * - `draw_id` — `TRaffleDraw.id` (schedule_id, stable across runs)
475
+ * - `raffle_run_id` — `TRaffleDraw.run_id` (instance ID for this
476
+ * specific run)
477
+ *
478
+ * **Error codes** (in `err_code`)
479
+ * - `0` — success; the user is opted into this run. Tickets
480
+ * collected after the run's `ticket_start_ts` will participate.
481
+ * - `1` — generic opt-in failure. The `err_message` distinguishes
482
+ * the specific cause: the draw doesn't require opt-in
483
+ * (`requires_optin === false`), `raffle_id` doesn't match the
484
+ * `draw_id`, the user is already opted in (or the draw has
485
+ * completed), or the user is in a control group for this raffle.
486
+ * - other non-zero — generic server error. Surface `err_message`.
487
+ *
488
+ * **Idempotency**: NOT idempotent. A second call on the same
489
+ * `raffle_run_id` returns `err_code === 1` with `err_message`
490
+ * indicating the user is already opted in. Treat as success in
491
+ * the UI — the underlying state is what the consumer wants.
492
+ * Guard the call site against double-clicks.
493
+ *
494
+ * **Refresh after success (and after failure)**
495
+ * The SDK automatically refreshes the raffles cache on every
496
+ * response and fires the `onUpdate` callback registered via
497
+ * {@link getRaffles}. After `err_code === 0`, the affected draw's
498
+ * `user_opted_in` flips to `true` on the refreshed list.
499
+ *
500
+ * **Side effects** (on `err_code === 0`)
501
+ * - The user is registered for this run. Tickets earned within
502
+ * the run's eligibility window will participate in the draw.
503
+ * - No balance change. No CRM-side rewards. Opt-in is a metadata
504
+ * operation only.
505
+ *
506
+ * **Throws**
507
+ * `raffle_id`, `draw_id`, and `raffle_run_id` are all required —
508
+ * the SDK throws synchronously when any is missing or falsy.
509
+ *
510
+ * **UI guidance**: see [UI Guide — `requestRaffleOptin`](../../docs/ui/raffles/UIGuide_requestRaffleOptin.md).
511
+ *
512
+ * **Visitor mode**: not supported.
513
+ *
514
+ * @param props.raffle_id The parent raffle's `id`.
515
+ * @param props.draw_id The draw's schedule_id (`TRaffleDraw.id`).
516
+ * @param props.raffle_run_id The run instance ID (`TRaffleDraw.run_id`).
517
+ * @returns `{ err_code, err_message? }`; success
518
+ * when `err_code === 0` (treat
519
+ * "already opted in" as idempotent
520
+ * success).
521
+ *
522
+ * @example
523
+ * ```ts
524
+ * const raffles = await window._smartico.api.getRaffles({
525
+ * onUpdate: (refreshed) => console.log('[smartico] raffles refreshed — re-render', refreshed),
526
+ * });
527
+ * const raffle = raffles[0];
528
+ * const draw = raffle.draws.find(d =>
529
+ * d.requires_optin && !d.user_opted_in && d.is_active && d.current_state !== 3
530
+ * );
531
+ *
532
+ * if (!draw) {
533
+ * console.log('[smartico] no opt-in-required draw available — keep CTA hidden');
534
+ * return;
535
+ * }
536
+ *
537
+ * console.log('[smartico] opt-in starting — set in-flight flag, show loading dots on the Opt-in button');
538
+ * const r = await window._smartico.api.requestRaffleOptin({
539
+ * raffle_id: raffle.id,
540
+ * draw_id: draw.id, // schedule_id, NOT run_id
541
+ * raffle_run_id: draw.run_id,
542
+ * });
543
+ * console.log('[smartico] opt-in response received — clear in-flight flag');
544
+ *
545
+ * if (r.err_code === 0) {
546
+ * console.log('[smartico] opted in successfully — show "Fully opted in" state on the draw card; onUpdate above will fire with user_opted_in: true');
547
+ * } else if (r.err_code === 1 && r.err_message?.toLowerCase().includes('already opted in')) {
548
+ * console.log('[smartico] already opted in (perhaps from another tab) — treat as success, show "Fully opted in"');
549
+ * } else {
550
+ * console.error('[smartico] opt-in failed — surface this error to the user:', r.err_message);
551
+ * }
552
+ * ```
553
+ */
554
+ public async requestRaffleOptin(props: { raffle_id: number; draw_id: number; raffle_run_id: number }): Promise<TRaffleOptinResponse> {
555
+ if (!props.raffle_id) {
556
+ throw new Error('raffle_id is required');
557
+ }
558
+ if (!props.draw_id) {
559
+ throw new Error('draw_id is required');
560
+ }
561
+ if (!props.raffle_run_id) {
562
+ throw new Error('raffle_run_id is required');
563
+ }
564
+
565
+ const r = await this.api.raffleOptin(this.userExtId, props);
566
+
567
+ return {
568
+ err_code: r.errCode,
569
+ err_message: r.errMsg,
570
+ };
571
+ }
572
+
573
+ /**
574
+ * Returns every prize the current user has won within a single raffle —
575
+ * across ALL of that raffle's draws, newest-won first — in one paginated
576
+ * call. Use this to power a "my prizes" screen for a raffle (prize name,
577
+ * prize image, the user's name/avatar) without walking
578
+ * {@link getRaffleDrawRunsHistory} and then paging
579
+ * {@link getRaffleDrawRun}'s per-draw winner lists.
580
+ *
581
+ * Each row carries its own `raf_won_id`, which IS the `won_id` to pass to
582
+ * {@link claimRafflePrize}: a row with `requires_claim === true` and no
583
+ * `claimed_date` is directly claimable.
584
+ *
585
+ * @remarks
586
+ * **Authentication required**
587
+ * Works only for an identified (logged-in) user. Visitor / anonymous
588
+ * sessions are rejected — call this only after identify.
589
+ *
590
+ * **Preconditions**
591
+ * `raffle_id` is required — the SDK throws synchronously when it is
592
+ * missing or falsy.
593
+ *
594
+ * **Coverage & sort order**
595
+ * Includes the user's wins from every draw of the raffle — recurring,
596
+ * one-shot, and grand draws, across all historical runs. Rows are ordered
597
+ * newest-win first; there is no "unclaimed first" ordering, so sort
598
+ * client-side if you want claimable prizes at the top.
599
+ *
600
+ * **Pagination**
601
+ * `offset` / `limit` page the `won_prizes[]` rows (the SDK defaults to
602
+ * `0` / `20`). `total` is the authoritative full count of the user's wins
603
+ * for this raffle across all draws — drive "load more" from it
604
+ * (`offset + won_prizes.length < total`). An `offset` past the end returns
605
+ * an empty `won_prizes[]` with the real `total` and `errCode 0` — not an
606
+ * error. The server does NOT clamp `limit`, so always pass an explicit,
607
+ * sane page size.
608
+ *
609
+ * **Rate limit**
610
+ * The server caps this at roughly 30 calls per minute with a ~5-second
611
+ * minimum gap between calls. Fetch on screen open and on explicit "load
612
+ * more" — don't poll it on a timer.
613
+ *
614
+ * **Error codes** (in `errCode`)
615
+ * - `0` — success. Also returned with an empty `won_prizes[]` and
616
+ * `total 0` when the user has no wins, or is not eligible to see this
617
+ * raffle.
618
+ * - `1` — generic server error; surface `errMsg` if present.
619
+ *
620
+ * There are no granular codes — an unknown raffle, an ineligible user,
621
+ * and "no wins" all surface as `errCode 0` with an empty list.
622
+ *
623
+ * **Reading the result**
624
+ * - Null-check `user` before reading it — it is `null` whenever
625
+ * `won_prizes` is empty.
626
+ * - For the avatar, use `user.avatar_id` (already a full URL for a system
627
+ * avatar, otherwise an avatar token to resolve against the widget's
628
+ * avatar domain); `user.avatar_url` is always `null`.
629
+ * - Render `public_username` as-is (it is server-masked for privacy, e.g.
630
+ * `"32:r*****"`) and substitute a "You" label for the current user.
631
+ * - Treat `claimed_date` as the claim flag: `null` until claimed, then
632
+ * epoch ms.
633
+ *
634
+ * **Idempotency / Side effects**: safe and read-only — one-shot promise,
635
+ * no client cache, no subscription. The server caches the response
636
+ * briefly; a successful {@link claimRafflePrize} invalidates that cache,
637
+ * so a follow-up call reflects the new `claimed_date`. This method does
638
+ * NOT refresh the {@link getRaffles} list or fire its `onUpdate` — re-call
639
+ * manually to pick up newly-won prizes or a `claimed_date` flip.
640
+ *
641
+ * **UI guidance**: see [UI Guide — `getRaffleWonPrizes`](../../docs/ui/raffles/UIGuide_getRaffleWonPrizes.md).
642
+ *
643
+ * **Visitor mode**: not supported (see "Authentication required").
644
+ *
645
+ * @param props.raffle_id The parent raffle's `id` (from `TRaffle.id`). Required.
646
+ * @param props.offset Zero-based index of the first row to return. Defaults to `0`.
647
+ * @param props.limit Page size. Defaults to `20`.
648
+ * @returns Promise resolving to {@link GetRaffleWonPrizesResponse}
649
+ * (`user`, this page of `won_prizes`, and `total`;
650
+ * `errCode 0` on success).
651
+ *
652
+ * @example
653
+ * ```ts
654
+ * const raffles = await window._smartico.api.getRaffles();
655
+ * const raffle = raffles[0];
656
+ *
657
+ * // First page of the user's won prizes for this raffle.
658
+ * const page = await window._smartico.api.getRaffleWonPrizes({
659
+ * raffle_id: raffle.id,
660
+ * offset: 0,
661
+ * limit: 20,
662
+ * });
663
+ *
664
+ * if (page.errCode !== 0) {
665
+ * console.error('[smartico] could not load won prizes — show a retry state:', page.errMsg);
666
+ * return;
667
+ * }
668
+ * if (page.won_prizes.length === 0) {
669
+ * console.log('[smartico] no wins in this raffle (or not eligible) — render the empty state');
670
+ * return;
671
+ * }
672
+ *
673
+ * console.log('[smartico]', page.user?.public_username, 'won', page.total, 'prizes total');
674
+ * for (const prize of page.won_prizes) {
675
+ * console.log('[smartico] render prize card —', prize.public_meta.name, prize.public_meta.image_url);
676
+ * if (prize.requires_claim && !prize.claimed_date) {
677
+ * console.log('[smartico] show a Claim CTA — on click call claimRafflePrize({ won_id:', prize.raf_won_id, '})');
678
+ * }
679
+ * }
680
+ *
681
+ * // Load more.
682
+ * if (page.offset + page.won_prizes.length < page.total) {
683
+ * const next = await window._smartico.api.getRaffleWonPrizes({
684
+ * raffle_id: raffle.id,
685
+ * offset: page.offset + page.limit,
686
+ * limit: 20,
687
+ * });
688
+ * console.log('[smartico] appended', next.won_prizes.length, 'more prizes');
689
+ * }
690
+ * ```
691
+ */
692
+ public async getRaffleWonPrizes(props: { raffle_id: number; offset?: number; limit?: number }): Promise<GetRaffleWonPrizesResponse> {
693
+ if (!props.raffle_id) {
694
+ throw new Error('raffle_id is required');
695
+ }
696
+
697
+ return await this.api.getRaffleWonPrizes(this.userExtId, {
698
+ raffle_id: props.raffle_id,
699
+ offset: props.offset ?? 0,
700
+ limit: props.limit ?? 20,
701
+ });
702
+ }
703
+ }