@smartico/public-api 0.0.384 → 0.0.386

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.
@@ -900,6 +900,9 @@ const InboxMessagesTransform = items => {
900
900
  };
901
901
 
902
902
  const InboxMessageBodyTransform = item => {
903
+ if (!item) {
904
+ return null;
905
+ }
903
906
  const x = {
904
907
  action: item.action,
905
908
  icon: item.image,
@@ -1882,7 +1885,7 @@ TournamentUtils.getPrizeTransformed = prize => {
1882
1885
  };
1883
1886
 
1884
1887
  const TournamentItemsTransform = items => {
1885
- return items.filter(r => r.tournamentId >= 1).map(r => {
1888
+ return items.filter(r => r != null && r.tournamentId >= 1).map(r => {
1886
1889
  const x = _extends({
1887
1890
  instance_id: r.tournamentInstanceId,
1888
1891
  tournament_id: r.tournamentId,
@@ -2006,20 +2009,50 @@ const tournamentInfoItemTransform = t => {
2006
2009
  return response;
2007
2010
  };
2008
2011
 
2012
+ /**
2013
+ * Error codes returned in `err_code` by the `registerInTournament` method.
2014
+ *
2015
+ * These are terse value definitions for lookup. The full per-code narrative —
2016
+ * when each fires and how the consumer's UI should react — lives in the
2017
+ * `registerInTournament` method TSDoc, which owns the error table.
2018
+ *
2019
+ * Note the numbering break: the gems / diamonds codes are 6-digit
2020
+ * (`300010` / `300011`) while the rest of the tournament block is 5-digit;
2021
+ * they were appended after the original `30001`–`30009` range was occupied.
2022
+ * Branch on the exact numeric value, not on digit count.
2023
+ */
2009
2024
  var TournamentRegistrationError;
2010
2025
  (function (TournamentRegistrationError) {
2026
+ /** Success — registration persisted; buy-in (if any) deducted. */
2011
2027
  TournamentRegistrationError[TournamentRegistrationError["NO_ERROR"] = 0] = "NO_ERROR";
2028
+ /** Clan-based tournament and the user does not belong to a clan yet. */
2012
2029
  TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_USER_CANNOT_JOIN_WITHOUT_CLAN"] = 1010] = "TOURNAMENT_USER_CANNOT_JOIN_WITHOUT_CLAN";
2030
+ /** Instance id is invalid or the tournament was deleted. */
2013
2031
  TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_INSTANCE_NOT_FOUND"] = 30001] = "TOURNAMENT_INSTANCE_NOT_FOUND";
2032
+ /** Insufficient points balance for a points-priced buy-in. */
2014
2033
  TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_REGISTRATION_NOT_ENOUGH_POINTS"] = 30002] = "TOURNAMENT_REGISTRATION_NOT_ENOUGH_POINTS";
2034
+ /** Tournament is no longer in a registerable state (finished, cancelled, finalizing, or not yet open). */
2015
2035
  TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_INSTANCE_NOT_IN_STATE"] = 30003] = "TOURNAMENT_INSTANCE_NOT_IN_STATE";
2036
+ /** User is already registered; treat as an idempotent success. */
2016
2037
  TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_ALREADY_REGISTERED"] = 30004] = "TOURNAMENT_ALREADY_REGISTERED";
2038
+ /** User does not satisfy the tournament's segment / entry conditions. */
2017
2039
  TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_USER_DONT_MATCH_CONDITIONS"] = 30005] = "TOURNAMENT_USER_DONT_MATCH_CONDITIONS";
2040
+ /** User is not registered; anomalous on a register call (usually a server-side race). */
2018
2041
  TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_USER_NOT_REGISTERED"] = 30006] = "TOURNAMENT_USER_NOT_REGISTERED";
2042
+ /** Registration status transition is not allowed (e.g. re-registering a finished tournament). */
2019
2043
  TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_CANT_CHANGE_REGISTRATION_STATUS"] = 30007] = "TOURNAMENT_CANT_CHANGE_REGISTRATION_STATUS";
2044
+ /** Tournament filled up — maximum registrations reached. */
2020
2045
  TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_MAX_REGISTRATIONS_REACHED"] = 30008] = "TOURNAMENT_MAX_REGISTRATIONS_REACHED";
2021
- TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_REGISTRATION_NOT_ENOUGH_GEMS"] = 30010] = "TOURNAMENT_REGISTRATION_NOT_ENOUGH_GEMS";
2022
- TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_REGISTRATION_NOT_ENOUGH_DIAMONDS"] = 30011] = "TOURNAMENT_REGISTRATION_NOT_ENOUGH_DIAMONDS";
2046
+ /**
2047
+ * The user's wallet currency could not be resolved. Emitted server-side
2048
+ * during tournament score processing, NOT during registration — it is
2049
+ * never returned by `registerInTournament`. Included for completeness.
2050
+ */
2051
+ TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_INVALID_USER_CURRENCY"] = 30009] = "TOURNAMENT_INVALID_USER_CURRENCY";
2052
+ /** Insufficient gems balance for a gems-priced buy-in. */
2053
+ TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_REGISTRATION_NOT_ENOUGH_GEMS"] = 300010] = "TOURNAMENT_REGISTRATION_NOT_ENOUGH_GEMS";
2054
+ /** Insufficient diamonds balance for a diamonds-priced buy-in. */
2055
+ TournamentRegistrationError[TournamentRegistrationError["TOURNAMENT_REGISTRATION_NOT_ENOUGH_DIAMONDS"] = 300011] = "TOURNAMENT_REGISTRATION_NOT_ENOUGH_DIAMONDS";
2023
2056
  })(TournamentRegistrationError || (TournamentRegistrationError = {}));
2024
2057
 
2025
2058
  var TournamentType;
@@ -2741,12 +2774,25 @@ class WSAPIUser extends WSAPIBase {
2741
2774
  * `ach_points_ever` and {@link getLevels} would also work, but
2742
2775
  * `progress` saves the math.
2743
2776
  *
2744
- * **Cache TTL**: the SDK caches the response for 30 seconds. There is
2745
- * no push event that refreshes this cache; a server-side level change
2746
- * (visible immediately on {@link getUserProfile}'s `ach_level_current_id`
2747
- * via the user-properties update channel) becomes visible on this
2748
- * method only after the cache TTL expires, or after
2749
- * `_smartico.api.clearCaches()` is called.
2777
+ * **Cache TTL & freshness**
2778
+ * The response is cached for 30 seconds, but the SDK automatically
2779
+ * drops that cache whenever a user-properties update arrives — the
2780
+ * same live channel that backs {@link getUserProfile}. The practical
2781
+ * effect depends on the label's leveling logic:
2782
+ * - **Points-based or operator-manual leveling**: a points or level
2783
+ * change flows through the user-properties channel, so the cache is
2784
+ * busted at that moment and the next `getCurrentLevel()` call
2785
+ * returns up-to-date data without waiting out the TTL.
2786
+ * - **Counter-based leveling** (level driven by sliding-window
2787
+ * counters such as deposit or wagering totals over a recent window —
2788
+ * see {@link getUserLevelExtraCounters}): ordinary progress changes
2789
+ * are recomputed by a periodic server job and do NOT emit a
2790
+ * user-properties update, so they become visible on this method only
2791
+ * after the 30 s TTL expires (or after `_smartico.api.clearCaches()`).
2792
+ *
2793
+ * Avoid calling `clearCaches()` on the points/manual path — it's
2794
+ * unnecessary there (the cache is already refreshed on the property
2795
+ * update) and forces a slower extra round-trip.
2750
2796
  *
2751
2797
  * **Leveling logic**
2752
2798
  * The semantics of how a user advances depends on the label's
@@ -2774,10 +2820,10 @@ class WSAPIUser extends WSAPIBase {
2774
2820
  * console.log('[smartico] render level badge — name:', level.name,
2775
2821
  * 'progress:', Math.round(level.progress), '%');
2776
2822
  *
2777
- * // Detect level-up via getUserProfile's push channel.
2823
+ * // Detect level-up via getUserProfile's push channel. No clearCaches()
2824
+ * // needed — the SDK already drops the level cache on this update.
2778
2825
  * window._smartico.on('props_change', async (changed) => {
2779
2826
  * if ('ach_level_current_id' in changed) {
2780
- * await window._smartico.api.clearCaches(); // bust the 30 s cache
2781
2827
  * const fresh = await window._smartico.api.getCurrentLevel();
2782
2828
  * console.log('[smartico] user levelled up — animate badge to new level:', fresh.name);
2783
2829
  * }
@@ -2812,14 +2858,12 @@ class WSAPIUser extends WSAPIBase {
2812
2858
  * `levelsCounter2Name`.
2813
2859
  *
2814
2860
  * **Refresh cadence**
2815
- * Sliding-window counters are recomputed by a server-side job that
2816
- * runs roughly every 60 seconds against the operator's BigQuery
2817
- * dataset; level transitions driven by counter changes have a
2818
- * latency of up to several minutes after the underlying activity
2819
- * (e.g. a deposit). The SDK caches the response for 30 seconds; no
2820
- * push event refreshes this cache. After a level change visible on
2821
- * {@link getUserProfile}'s `ach_level_current_id`, call
2822
- * `_smartico.api.clearCaches()` to force a fresh fetch.
2861
+ * Sliding-window counters are recomputed by a periodic server-side
2862
+ * job. Its rebuild cadence is operator-configured per brand —
2863
+ * commonly daily, though it can be set more frequent — so level
2864
+ * transitions driven by counter changes surface with a latency tied
2865
+ * to that rebuild schedule after the underlying activity (e.g. a
2866
+ * deposit), not in real time.
2823
2867
  *
2824
2868
  * **Idempotency**: safe. Read-only. Repeated calls within the cache
2825
2869
  * window return a deep-cloned cached value without a network
@@ -3310,8 +3354,14 @@ class WSAPIMissions extends WSAPIGeneral {
3310
3354
  * **Idempotency / Side effects**: fetch-only; safe to call repeatedly.
3311
3355
  * The cache layer deduplicates concurrent calls within the TTL window.
3312
3356
  *
3357
+ * **Visitor mode**: not supported. Badges are an authenticated-only
3358
+ * feature; calling this on the visitor-mode handle (`_smartico.vapi`)
3359
+ * throws synchronously rather than silently returning an empty list.
3360
+ *
3313
3361
  * **UI guidance**: see [UI Guide — `getBadges`](../../docs/ui/missions/UIGuide_getBadges.md).
3314
3362
  *
3363
+ * @throws `Error("getBadges is not available in visitor mode")` when
3364
+ * called from a visitor-mode session.
3315
3365
  * @returns Promise resolving to `TMissionOrBadge[]`. Every item has
3316
3366
  * `type === 'badge'`. Cached for 30 s under the `Badges` key.
3317
3367
  *
@@ -3353,6 +3403,12 @@ class WSAPIMissions extends WSAPIGeneral {
3353
3403
  * ```
3354
3404
  */
3355
3405
  async getBadges() {
3406
+ // Badges are an authenticated-only feature. The visitor-mode WSAPI
3407
+ // instance (`_smartico.vapi`) is constructed without a tracker, so the
3408
+ // server would silently return nothing; throw a clear error instead.
3409
+ if (!this.api.tracker) {
3410
+ throw new Error('getBadges is not available in visitor mode');
3411
+ }
3356
3412
  return OCache.use(onUpdateContextKey.Badges, ECacheContext.WSAPI, () => this.api.badgetsGetItemsT(this.userExtId), CACHE_DATA_SEC);
3357
3413
  }
3358
3414
  /**
@@ -5431,12 +5487,10 @@ class WSAPIClans extends WSAPITournaments {
5431
5487
  * tournament requires the user to be in a clan first.
5432
5488
  * - `1006` (`JOIN_CLAN_COOLDOWN_ACTIVE`) — user is inside the
5433
5489
  * switch-cooldown window from a previous clan join (default
5434
- * 7 days, configurable per label). Surface the
5490
+ * 7 days, configurable per label). Only reachable when the user is
5491
+ * already in a *different* clan (this call is then a clan switch);
5492
+ * a first-time join never returns `1006`. Surface the
5435
5493
  * `TClans.cooldown_until` expiry in the disabled CTA.
5436
- * - `1007` (`JOIN_CLAN_ARCHIVED`) — defined on the public enum but
5437
- * the server does NOT emit this code in practice (archived clans
5438
- * are reported as `1001`). Handle it as a synonym for `1001`
5439
- * defensively, but do not rely on it.
5440
5494
  * - `1011` (`JOIN_CLAN_JOINED_AFTER_TOURNAMENT_START`) — this
5441
5495
  * method does NOT return `1011` directly. The code fires on
5442
5496
  * {@link registerInTournament} responses when the user joined
@@ -5643,6 +5697,9 @@ class WSAPIJackpots extends WSAPIClans {
5643
5697
  let pots = [];
5644
5698
  jackpots = await OCache.use(onUpdateContextKey.Jackpots, ECacheContext.WSAPI, async function () {
5645
5699
  const _jackpots = await _this.api.jackpotGet(_this.userExtId, filter);
5700
+ if (!(_jackpots != null && _jackpots.items)) {
5701
+ return [];
5702
+ }
5646
5703
  const _pots = _jackpots.items.map(jp => jp.pot);
5647
5704
  _jackpots.items.forEach(jp => {
5648
5705
  jp.jp_public_meta.custom_data = IntUtils.JsonOrText(jp.jp_public_meta.custom_data);
@@ -7151,6 +7208,9 @@ class WSAPIMiniGames extends WSAPIRaffles {
7151
7208
  async updateOnSpin(data) {
7152
7209
  const templates = await OCache.use(onUpdateContextKey.Saw, ECacheContext.WSAPI, () => this.api.sawGetTemplatesT(this.userExtId), CACHE_DATA_SEC);
7153
7210
  const index = templates.findIndex(t => t.id === data.saw_template_id);
7211
+ if (index === -1) {
7212
+ return;
7213
+ }
7154
7214
  templates[index].spin_count = data.spin_count;
7155
7215
  this.updateEntity(onUpdateContextKey.Saw, templates);
7156
7216
  }
@@ -8171,15 +8231,8 @@ class WSAPILeaderBoard extends WSAPIGamePick {
8171
8231
  * the array is the prize for place 1, the second for place 2, and
8172
8232
  * so on. The array length is the number of paid places.
8173
8233
  *
8174
- * **Cache TTL — single shared key (known limitation)**
8175
- * The SDK caches the response for 30 seconds under a SINGLE shared
8176
- * key — calling `getLeaderBoard(DAILY)` followed by
8177
- * `getLeaderBoard(WEEKLY)` within the same 30 s window returns the
8178
- * cached DAILY result for the WEEKLY call. Same applies to
8179
- * switching `getPreviousPeriod`. To force a fresh fetch when
8180
- * switching periods or current/previous, call
8181
- * `_smartico.api.clearCaches()` before the second call, or simply
8182
- * wait out the TTL.
8234
+ * **Cache TTL**
8235
+ * The SDK caches each response for 30 seconds.
8183
8236
  *
8184
8237
  * **Period boundaries**
8185
8238
  * The server finalizes each period on a server-configurable
@@ -8249,8 +8302,7 @@ class WSAPILeaderBoard extends WSAPIGamePick {
8249
8302
  * }
8250
8303
  * }
8251
8304
  *
8252
- * // Switch to previous period view — but bust the cache first to avoid the shared-key collision.
8253
- * await window._smartico.api.clearCaches();
8305
+ * // Switch to previous period view — cached separately from the current period.
8254
8306
  * const prev = await window._smartico.api.getLeaderBoard(LeaderBoardPeriodType.WEEKLY, true);
8255
8307
  * console.log('[smartico] previous-week standings — render with greyed-out "ended" treatment:', prev?.users.length, 'finalists');
8256
8308
  *
@@ -8259,7 +8311,10 @@ class WSAPILeaderBoard extends WSAPIGamePick {
8259
8311
  * ```
8260
8312
  */
8261
8313
  async getLeaderBoard(periodType, getPreviousPeriod) {
8262
- return OCache.use(onUpdateContextKey.LeaderBoards, ECacheContext.WSAPI, () => this.api.leaderboardsGetT(this.userExtId, periodType, getPreviousPeriod), CACHE_DATA_SEC);
8314
+ // Cache per (periodType, current/previous) so switching tabs or
8315
+ // current↔previous within the TTL doesn't return a colliding board.
8316
+ const cacheKey = `${onUpdateContextKey.LeaderBoards}:${periodType}:${getPreviousPeriod ? 1 : 0}`;
8317
+ return OCache.use(cacheKey, ECacheContext.WSAPI, () => this.api.leaderboardsGetT(this.userExtId, periodType, getPreviousPeriod), CACHE_DATA_SEC);
8263
8318
  }
8264
8319
  }
8265
8320
 
@@ -8984,6 +9039,7 @@ class WSAPI extends WSAPIInbox {
8984
9039
  if ((data == null || (_data$props3 = data.props) == null ? void 0 : _data$props3.ach_points_balance) !== undefined || (data == null || (_data$props4 = data.props) == null ? void 0 : _data$props4.ach_gems_balance) !== undefined || (data == null || (_data$props5 = data.props) == null ? void 0 : _data$props5.ach_diamonds_balance) !== undefined) {
8985
9040
  this.notifyActivityLogUpdate();
8986
9041
  }
9042
+ OCache.clear(ECacheContext.WSAPI, onUpdateContextKey.CurrentLevel);
8987
9043
  });
8988
9044
  on(ClassId.RAF_OPTIN_RESPONSE, () => this.updateRaffles());
8989
9045
  }
@@ -10879,31 +10935,37 @@ const AvatarCustomizeErrorMessage = {
10879
10935
  [AvatarCustomizeErrorCode.AVATAR_LABEL_LIMIT]: 'The custom avatars are not available, please try again later'
10880
10936
  };
10881
10937
 
10882
- /*
10883
- * Possible error codes returned in JOIN_CLAN_RESPONSE.errCode (cid: 575).
10884
- * Clan-protocol-specific numeric codes defined in the handler spec.
10938
+ /**
10939
+ * Error codes returned in `errCode` by the `joinClan` method (also carried
10940
+ * on `TClanJoinResult`). These are terse value definitions for lookup; the
10941
+ * full per-code narrative and UI handling lives in the `joinClan` method
10942
+ * TSDoc, which owns the error table.
10885
10943
  */
10886
10944
  var JoinClanErrorCode;
10887
10945
  (function (JoinClanErrorCode) {
10888
- /** No error, join completed */
10946
+ /** Success — join completed; entry fee (if any) deducted. */
10889
10947
  JoinClanErrorCode[JoinClanErrorCode["JOIN_CLAN_OK"] = 0] = "JOIN_CLAN_OK";
10890
- /** Invalid parameters */
10948
+ /** Request was malformed (missing or invalid parameters). */
10891
10949
  JoinClanErrorCode[JoinClanErrorCode["JOIN_CLAN_INVALID_PARAMETERS"] = 1000] = "JOIN_CLAN_INVALID_PARAMETERS";
10892
- /** clan_id doesn't exist for this label */
10950
+ /** Clan doesn't exist for this label. Archived clans are also reported as `1001`. */
10893
10951
  JoinClanErrorCode[JoinClanErrorCode["JOIN_CLAN_NOT_FOUND"] = 1001] = "JOIN_CLAN_NOT_FOUND";
10894
- /** members_count >= capacity_limit */
10952
+ /** Clan is full — member capacity reached. */
10895
10953
  JoinClanErrorCode[JoinClanErrorCode["JOIN_CLAN_FULL"] = 1002] = "JOIN_CLAN_FULL";
10896
- /** Not enough Points / Gems / Diamonds for entry fee */
10954
+ /** Insufficient balance for the entry fee (points / gems / diamonds). */
10897
10955
  JoinClanErrorCode[JoinClanErrorCode["JOIN_CLAN_INSUFFICIENT_FUNDS"] = 1003] = "JOIN_CLAN_INSUFFICIENT_FUNDS";
10898
- /** User doesn't satisfy entry_conditions / entry_segment_id */
10956
+ /** User doesn't meet the clan's entry segment or conditions. */
10899
10957
  JoinClanErrorCode[JoinClanErrorCode["JOIN_CLAN_SEGMENT_MISMATCH"] = 1004] = "JOIN_CLAN_SEGMENT_MISMATCH";
10900
- /** User is not in a clan */
10958
+ /**
10959
+ * User is not in a clan. Note: a `registerInTournament` response code
10960
+ * that shares this enum — never returned by `joinClan`.
10961
+ */
10901
10962
  JoinClanErrorCode[JoinClanErrorCode["JOIN_CLAN_USER_IS_NOT_IN_CLAN"] = 1005] = "JOIN_CLAN_USER_IS_NOT_IN_CLAN";
10902
- /** User is within the CLAN_COOLDOWN_DAYS window */
10963
+ /** User is within the clan-switch cooldown window (switch only). */
10903
10964
  JoinClanErrorCode[JoinClanErrorCode["JOIN_CLAN_COOLDOWN_ACTIVE"] = 1006] = "JOIN_CLAN_COOLDOWN_ACTIVE";
10904
- /** clan_status_id != 1 (clan is archived) */
10905
- JoinClanErrorCode[JoinClanErrorCode["JOIN_CLAN_ARCHIVED"] = 1007] = "JOIN_CLAN_ARCHIVED";
10906
- /** Clan joined after tournament start */
10965
+ /**
10966
+ * Clan joined after tournament start. Note: a `registerInTournament`
10967
+ * response code that shares this enum — never returned by `joinClan`.
10968
+ */
10907
10969
  JoinClanErrorCode[JoinClanErrorCode["JOIN_CLAN_JOINED_AFTER_TOURNAMENT_START"] = 1011] = "JOIN_CLAN_JOINED_AFTER_TOURNAMENT_START";
10908
10970
  })(JoinClanErrorCode || (JoinClanErrorCode = {}));
10909
10971