@smartico/public-api 0.0.378 → 0.0.380

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 (99) hide show
  1. package/.nvmrc +1 -1
  2. package/README.md +31 -2
  3. package/dist/Store/BuyStoreItemErrorCode.d.ts +9 -1
  4. package/dist/Tournaments/TournamentRegistrationError.d.ts +3 -1
  5. package/dist/WSAPI/WSAPI.d.ts +13 -1235
  6. package/dist/WSAPI/WSAPIAvatars.d.ts +78 -0
  7. package/dist/WSAPI/WSAPIBase.d.ts +71 -0
  8. package/dist/WSAPI/WSAPIBonuses.d.ts +26 -0
  9. package/dist/WSAPI/WSAPIClans.d.ts +388 -0
  10. package/dist/WSAPI/WSAPIGamePick.d.ts +308 -0
  11. package/dist/WSAPI/WSAPIGeneral.d.ts +30 -0
  12. package/dist/WSAPI/WSAPIInbox.d.ts +126 -0
  13. package/dist/WSAPI/WSAPIJackpots.d.ts +109 -0
  14. package/dist/WSAPI/WSAPILeaderBoard.d.ts +25 -0
  15. package/dist/WSAPI/WSAPIMiniGames.d.ts +94 -0
  16. package/dist/WSAPI/WSAPIMissions.d.ts +517 -0
  17. package/dist/WSAPI/WSAPIRaffles.d.ts +119 -0
  18. package/dist/WSAPI/WSAPIStore.d.ts +656 -0
  19. package/dist/WSAPI/WSAPITournaments.d.ts +501 -0
  20. package/dist/WSAPI/WSAPITypes.d.ts +145 -85
  21. package/dist/WSAPI/WSAPIUser.d.ts +383 -0
  22. package/dist/index.js +3818 -1528
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.modern.mjs +3180 -981
  25. package/dist/index.modern.mjs.map +1 -1
  26. package/docs/api/README.md +56 -2
  27. package/docs/api/classes/WSAPIAvatars.md +116 -0
  28. package/docs/api/classes/WSAPIBonuses.md +50 -0
  29. package/docs/api/classes/WSAPIClans.md +66 -0
  30. package/docs/api/classes/WSAPIGamePick.md +181 -0
  31. package/docs/api/classes/WSAPIGeneral.md +63 -0
  32. package/docs/api/classes/WSAPIInbox.md +277 -0
  33. package/docs/api/classes/WSAPIJackpots.md +185 -0
  34. package/docs/api/classes/WSAPILeaderBoard.md +39 -0
  35. package/docs/api/classes/WSAPIMiniGames.md +175 -0
  36. package/docs/api/classes/WSAPIMissions.md +611 -0
  37. package/docs/api/classes/WSAPIRaffles.md +195 -0
  38. package/docs/api/classes/WSAPIStore.md +744 -0
  39. package/docs/api/classes/WSAPITournaments.md +104 -0
  40. package/docs/api/classes/WSAPIUser.md +200 -0
  41. package/docs/api/enumerations/AchievementClaimPeriodTypeId.md +13 -0
  42. package/docs/api/enumerations/BuyStoreItemErrorCode.md +32 -0
  43. package/docs/api/interfaces/ClanPrizePublicMeta.md +41 -0
  44. package/docs/api/interfaces/ClanPrizeStructureEntry.md +7 -1
  45. package/docs/api/interfaces/ClanPublicMeta.md +4 -0
  46. package/docs/api/interfaces/SAWTemplateUI.md +10 -0
  47. package/docs/api/interfaces/TAchCategory.md +19 -4
  48. package/docs/api/interfaces/TBuyStoreItemResult.md +26 -8
  49. package/docs/api/interfaces/TMissionClaimRewardResult.md +14 -3
  50. package/docs/api/interfaces/TMissionOptInResult.md +10 -3
  51. package/docs/api/interfaces/TMissionOrBadge.md +6 -2
  52. package/docs/api/interfaces/TStoreItem.md +21 -1
  53. package/docs/api/interfaces/TTournamentDetailed.md +8 -0
  54. package/docs/api/interfaces/UserAchievement.md +1 -1
  55. package/docs/ui/clans/UIGuide_getClanInfo.md +153 -0
  56. package/docs/ui/clans/UIGuide_getClans.md +172 -0
  57. package/docs/ui/clans/UIGuide_joinClan.md +196 -0
  58. package/docs/ui/missions/UIGuide_getAchCategories.md +17 -0
  59. package/docs/ui/missions/UIGuide_getBadges.md +237 -0
  60. package/docs/ui/missions/UIGuide_getMissions.md +268 -0
  61. package/docs/ui/missions/UIGuide_requestMissionClaimReward.md +21 -0
  62. package/docs/ui/missions/UIGuide_requestMissionOptIn.md +16 -0
  63. package/docs/ui/store/UIGuide_buyStoreItem.md +133 -0
  64. package/docs/ui/store/UIGuide_getStoreCategories.md +19 -0
  65. package/docs/ui/store/UIGuide_getStoreItems.md +264 -0
  66. package/docs/ui/store/UIGuide_getStorePurchasedItems.md +122 -0
  67. package/docs/ui/tournaments/UIGuide_getClanTournamentPlayers.md +140 -0
  68. package/docs/ui/tournaments/UIGuide_getTournamentInstanceInfo.md +265 -0
  69. package/docs/ui/tournaments/UIGuide_getTournamentsList.md +236 -0
  70. package/docs/ui/tournaments/UIGuide_registerInTournament.md +156 -0
  71. package/docs/ui/user/UIGuide_getLevels.md +162 -0
  72. package/docs/ui/user/UIGuide_getUserProfile.md +213 -0
  73. package/package.json +3 -3
  74. package/scripts/postdoc-cleanup.js +195 -0
  75. package/src/Missions/MissionsUtils.ts +5 -2
  76. package/src/Store/BuyStoreItemErrorCode.ts +8 -0
  77. package/src/Store/StoreItem.ts +1 -0
  78. package/src/Store/StoreItemPurchased.ts +1 -0
  79. package/src/Store/StoreItemType.ts +1 -1
  80. package/src/Tournaments/TournamentRegistrationError.ts +4 -0
  81. package/src/WSAPI/WSAPI.ts +27 -2007
  82. package/src/WSAPI/WSAPIAvatars.ts +127 -0
  83. package/src/WSAPI/WSAPIBase.ts +93 -0
  84. package/src/WSAPI/WSAPIBonuses.ts +54 -0
  85. package/src/WSAPI/WSAPIClans.ts +417 -0
  86. package/src/WSAPI/WSAPIGamePick.ts +382 -0
  87. package/src/WSAPI/WSAPIGeneral.ts +57 -0
  88. package/src/WSAPI/WSAPIInbox.ts +222 -0
  89. package/src/WSAPI/WSAPIJackpots.ts +212 -0
  90. package/src/WSAPI/WSAPILeaderBoard.ts +40 -0
  91. package/src/WSAPI/WSAPIMiniGames.ts +181 -0
  92. package/src/WSAPI/WSAPIMissions.ts +572 -0
  93. package/src/WSAPI/WSAPIRaffles.ts +175 -0
  94. package/src/WSAPI/WSAPIStore.ts +732 -0
  95. package/src/WSAPI/WSAPITournaments.ts +541 -0
  96. package/src/WSAPI/WSAPITypes.ts +145 -87
  97. package/src/WSAPI/WSAPIUser.ts +456 -0
  98. package/tsconfig.json +17 -1
  99. package/docs/api/classes/WSAPI.md +0 -1927
@@ -0,0 +1,78 @@
1
+ import { TAvatarDefinition, TAvatarCustomized, TAvatarPrompt, TSetAvatarResult } from './WSAPITypes';
2
+ import { WSAPIMiniGames } from './WSAPIMiniGames';
3
+ /** @group Avatars */
4
+ export declare class WSAPIAvatars extends WSAPIMiniGames {
5
+ /**
6
+ * Returns the list of avatars available in the catalog for the current user.
7
+ * The response includes both free avatars and earned/purchased ones.
8
+ * Avatars with `hide_until_achieved = true` and `is_given = false` should be hidden from the user.
9
+ * The result is cached for 30 seconds.
10
+ *
11
+ * **Example**:
12
+ * ```
13
+ * _smartico.api.getAvatarsList().then((result) => {
14
+ * console.log(result);
15
+ * });
16
+ * ```
17
+ *
18
+ * **Visitor mode: not supported**
19
+ */
20
+ getAvatarsList(): Promise<TAvatarDefinition[]>;
21
+ /**
22
+ * Returns the list of AI-customized avatars for the current user.
23
+ * Each entry represents a previously generated AI customization for a specific base avatar.
24
+ * The result is cached for 30 seconds.
25
+ *
26
+ * **Example**:
27
+ * ```
28
+ * _smartico.api.getAvatarsCustomized().then((result) => {
29
+ * console.log(result);
30
+ * });
31
+ * ```
32
+ *
33
+ * **Visitor mode: not supported**
34
+ */
35
+ getAvatarsCustomized(): Promise<TAvatarCustomized[]>;
36
+ /**
37
+ * Returns the list of AI customization prompts (styles) available for avatar customization.
38
+ * Each prompt represents a visual style that can be applied to a base avatar.
39
+ * The result is cached for 30 seconds.
40
+ *
41
+ * **Example**:
42
+ * ```
43
+ * _smartico.api.getAvatarPrompts().then((result) => {
44
+ * console.log(result);
45
+ * });
46
+ * ```
47
+ *
48
+ * **Visitor mode: not supported**
49
+ */
50
+ getAvatarPrompts(): Promise<TAvatarPrompt[]>;
51
+ /**
52
+ * Sets the specified avatar as the active avatar for the current user.
53
+ * Pass `avatar_url` (the `TAvatarDefinition.url` path or a CDN URL for AI-customized avatars)
54
+ * and `avatar_real_id` from the avatar catalog.
55
+ * After a successful call, the avatar list cache is cleared so the next `getAvatarsList()` call reflects `is_in_use`.
56
+ *
57
+ * **Example**:
58
+ * ```
59
+ * _smartico.api.getAvatarsList().then((avatars) => {
60
+ * const avatar = avatars.find((a) => !a.hide_until_achieved || a.is_given);
61
+ * if (avatar) {
62
+ * _smartico.api.setAvatar({
63
+ * avatar_url: avatar.url,
64
+ * avatar_real_id: avatar.avatar_real_id,
65
+ * }).then((result) => {
66
+ * console.log(result);
67
+ * });
68
+ * }
69
+ * });
70
+ * ```
71
+ *
72
+ * **Visitor mode: not supported**
73
+ */
74
+ setAvatar(props: {
75
+ avatar_url: string;
76
+ avatar_real_id: number;
77
+ }): Promise<TSetAvatarResult>;
78
+ }
@@ -0,0 +1,71 @@
1
+ import { SmarticoAPI } from '../SmarticoAPI';
2
+ /** @hidden */
3
+ export declare const CACHE_DATA_SEC = 30;
4
+ /** @hidden */
5
+ export declare const JACKPOT_TEMPLATE_CACHE_SEC = 30;
6
+ /** @hidden */
7
+ export declare const JACKPOT_POT_CACHE_SEC = 1;
8
+ /** @hidden */
9
+ export declare const JACKPOT_WINNERS_CACHE_SEC = 30;
10
+ /** @hidden */
11
+ export declare const JACKPOT_ELIGIBLE_GAMES_CACHE_SEC = 30;
12
+ /** @hidden */
13
+ export declare enum onUpdateContextKey {
14
+ Saw = "saw",
15
+ Missions = "missions",
16
+ TournamentList = "tournamentList",
17
+ InboxMessages = "inboxMessages",
18
+ Badges = "badges",
19
+ Levels = "levels",
20
+ StoreItems = "storeItems",
21
+ StoreCategories = "storeCategories",
22
+ AchCategories = "achCategories",
23
+ LeaderBoards = "leaderBoards",
24
+ LevelExtraCounters = "levelExtraCounters",
25
+ Segments = "segments",
26
+ StoreHistory = "storeHistory",
27
+ Jackpots = "jackpots",
28
+ Pots = "Pots",
29
+ CustomSections = "customSections",
30
+ Bonuses = "bonuses",
31
+ Clans = "clans",
32
+ SAWHistory = "sawHistory",
33
+ JackpotWinners = "jackpotWinners",
34
+ Raffles = "raffles",
35
+ JackpotEligibleGames = "jackpotEligibleGames",
36
+ CurrentLevel = "currentLevel",
37
+ InboxUnreadCount = "inboxUnreadCount",
38
+ ActivityLog = "activityLog",
39
+ AvatarsList = "avatarsList",
40
+ AvatarsCustomized = "avatarsCustomized",
41
+ AvatarPrompts = "avatarPrompts"
42
+ }
43
+ /**
44
+ * Abstract base of the SDK's public surface. Holds the shared state
45
+ * (`api`, `userExtId`, `onUpdateCallback` map) and the generic cache /
46
+ * subscription helper (`updateEntity`). Domain-specific methods live on
47
+ * subclasses; the terminator `WSAPI` class composes the whole chain.
48
+ *
49
+ * **Consumers should not instantiate this directly** — the SDK constructs
50
+ * the concrete `WSAPI` via `_smartico.api`.
51
+ *
52
+ * @hidden
53
+ */
54
+ export declare abstract class WSAPIBase {
55
+ protected api: SmarticoAPI;
56
+ /** @hidden */
57
+ protected onUpdateCallback: Map<onUpdateContextKey, (data: any) => void>;
58
+ /** @hidden */
59
+ protected userExtId: string;
60
+ /** @private */
61
+ constructor(api: SmarticoAPI, userExtId?: string);
62
+ /** @private */
63
+ clearCaches(): void;
64
+ /**
65
+ * Generic cache-update + subscription-notify helper. Used by domain
66
+ * classes' `update*` methods to refresh a context and fire any
67
+ * registered `onUpdate` callback.
68
+ * @hidden
69
+ */
70
+ protected updateEntity(contextKey: onUpdateContextKey, payload: any): Promise<void>;
71
+ }
@@ -0,0 +1,26 @@
1
+ import { TBonus, TClaimBonusResult } from './WSAPITypes';
2
+ import { WSAPIMissions } from './WSAPIMissions';
3
+ /** @group Bonuses */
4
+ export declare class WSAPIBonuses extends WSAPIMissions {
5
+ /**
6
+ * Returns all the bonuses for the current user
7
+ * The returned bonuses are cached for 30 seconds. But you can pass the onUpdate callback as a parameter.
8
+ * Note that each time you call getBonuses with a new onUpdate callback, the old one will be overwritten by the new one.
9
+ * The onUpdate callback will be called on bonus claimed and the updated bonuses will be passed to it.
10
+ *
11
+ * **Visitor mode: not supported**
12
+ */
13
+ getBonuses({ onUpdate }?: {
14
+ onUpdate?: (data: TBonus[]) => void;
15
+ }): Promise<TBonus[]>;
16
+ /**
17
+ * Claim the bonus by bonus_id. Returns the err_code in case of success or error.
18
+ * Note that this method can be used only on integrations where originally failed bonus can be claimed again.
19
+ * For example, user won a bonus in the mini-game, but Operator rejected this bonus.
20
+ * This bonus will be available for the user to claim again.
21
+ *
22
+ * **Visitor mode: not supported**
23
+ */
24
+ claimBonus(bonus_id: number): Promise<TClaimBonusResult>;
25
+ protected updateBonuses(): Promise<void>;
26
+ }
@@ -0,0 +1,388 @@
1
+ import { TClans, TClanInfo, TClanJoinResult } from './WSAPITypes';
2
+ import { WSAPITournaments } from './WSAPITournaments';
3
+ /** @group Clans */
4
+ export declare class WSAPIClans extends WSAPITournaments {
5
+ /**
6
+ * Returns the active clans visible to the current user along with the
7
+ * user's own membership state (`user_clan_id`, `cooldown_until`,
8
+ * `join_date`). Use this to power a clan-picker / clan-browser screen.
9
+ *
10
+ * The returned `clans[]` is server-sorted by `rating_position` ASC
11
+ * (1 = highest-ranked). The server has already filtered out archived
12
+ * clans, clans the user fails segment conditions for, and (when any
13
+ * clan has a non-zero score) clans with a zero rating score.
14
+ *
15
+ * @remarks
16
+ * **Subscription model (`onUpdate`)**
17
+ * The callback receives the FULL refreshed `TClans` payload (never a
18
+ * diff/patch). Each subsequent call to `getClans({ onUpdate })`
19
+ * REPLACES the prior callback. Pass `onUpdate: undefined` (or omit
20
+ * it) to keep the prior callback in place; the callback is never
21
+ * auto-cleared.
22
+ *
23
+ * **Update triggers** — note that, unlike most other subscription
24
+ * methods in the SDK, this callback is **poll-driven only**. There
25
+ * is NO server push that refreshes the clans list. The callback
26
+ * fires when:
27
+ *
28
+ * 1. The 30-second cache TTL expires and a subsequent `getClans()`
29
+ * call (from the consumer) triggers a fresh fetch.
30
+ *
31
+ * Consequence: clan-membership changes (other users joining your
32
+ * clan, an operator-driven kick, a clan being archived) surface
33
+ * only on the next consumer-driven fetch. If your UI needs
34
+ * near-live state, poll `getClans()` on an interval; or re-call
35
+ * after a {@link joinClan} resolves to pick up the new
36
+ * `user_clan_id` immediately.
37
+ *
38
+ * **Reading state from the returned payload**
39
+ * Drive list rendering from `clans[]` (already sorted). Identify
40
+ * the user's own clan via `clan.clan_id === user_clan_id`
41
+ * (`null` for clanless users). Detect an active switch-cooldown
42
+ * with `cooldown_until !== null` — when set, the user cannot join
43
+ * any clan until the cooldown expires, even clans they could
44
+ * normally join. The cooldown is **user-level**, not per-clan.
45
+ *
46
+ * `cooldown_until` is an ISO 8601 UTC datetime string with no
47
+ * timezone suffix (`"YYYY-MM-DDTHH:MM:SS"`). Parse as UTC:
48
+ * `new Date(cooldown_until + 'Z')` or `moment.utc(cooldown_until)`.
49
+ * Display in the user's local time. The default cooldown period
50
+ * is configured per label by the operator (typically 7 days).
51
+ *
52
+ * `rating_position` is a global rank computed server-side across
53
+ * all active clans in the label (1 = highest-rated). Because some
54
+ * clans may be hidden by per-user segment visibility, positions
55
+ * the user sees may skip (e.g. 1, 3, 7) — don't assume the array
56
+ * spans a contiguous range.
57
+ *
58
+ * The `entry_fee_currency_type_id` enum on each clan uses values
59
+ * `0` = points, `1` = gems, `2` = diamonds, `3` = free. Compare
60
+ * `entry_fee_amount` against the user's matching balance (from
61
+ * {@link getUserProfile}) to drive Join button affordability.
62
+ *
63
+ * **Cache TTL**: the SDK caches the response for 30 seconds. Cache
64
+ * is fully cleared on login / logout.
65
+ *
66
+ * **Idempotency**: safe. Read-only. Repeated calls within the
67
+ * cache window return a deep-cloned cached payload without a
68
+ * network round-trip.
69
+ *
70
+ * **Side effects**: none — pure metadata read.
71
+ *
72
+ * **UI guidance**: see [UI Guide — `getClans`](../../docs/ui/clans/UIGuide_getClans.md).
73
+ *
74
+ * **Visitor mode**: not supported.
75
+ *
76
+ * @param params Optional. Omit to fetch without subscribing.
77
+ * @param params.onUpdate Callback invoked with the full refreshed
78
+ * `TClans` payload whenever the 30 s cache
79
+ * expires and a subsequent fetch lands.
80
+ * Each call to `getClans` overwrites the
81
+ * prior callback.
82
+ * @returns Promise resolving to `TClans`. Empty
83
+ * `clans` array if no clans are visible.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * const result = await window._smartico.api.getClans({
88
+ * onUpdate: (refreshed) => {
89
+ * console.log('[smartico] clans payload refreshed (poll-driven; ~30 s cadence) — re-render the clan list from this payload:', refreshed);
90
+ * },
91
+ * });
92
+ *
93
+ * console.log('[smartico] user is', result.user_clan_id == null ? 'clanless' : 'in clan ' + result.user_clan_id);
94
+ *
95
+ * // Cooldown handling — affects ALL clans, not a specific one.
96
+ * if (result.cooldown_until) {
97
+ * const cooldownEndsUtc = new Date(result.cooldown_until + 'Z');
98
+ * console.log('[smartico] switch-cooldown active — disable all Join buttons until', cooldownEndsUtc.toLocaleString(),
99
+ * '(local). Render the cooldown end on the disabled button label.');
100
+ * }
101
+ *
102
+ * // Render clans — already sorted by rating_position ASC.
103
+ * for (const clan of result.clans) {
104
+ * const isMine = clan.clan_id === result.user_clan_id;
105
+ * const isFull = clan.member_count >= clan.capacity_limit;
106
+ *
107
+ * if (isMine) {
108
+ * console.log('[smartico] highlight clan', clan.clan_id, 'as "Your clan"; CTA label "Your clan", no-op');
109
+ * } else if (result.cooldown_until) {
110
+ * console.log('[smartico] clan', clan.clan_id, '— Join blocked by user cooldown; show disabled button with cooldown end date');
111
+ * } else if (isFull) {
112
+ * console.log('[smartico] clan', clan.clan_id, '— Clan full; show disabled "Clan is full" button');
113
+ * } else {
114
+ * const label = clan.entry_fee_amount === 0 || clan.entry_fee_currency_type_id === 3
115
+ * ? 'Join free'
116
+ * : `Join (${clan.entry_fee_amount} ${['Points','Gems','Diamonds'][clan.entry_fee_currency_type_id]})`;
117
+ * console.log('[smartico] clan', clan.clan_id, '— render enabled Join button labelled', label);
118
+ * }
119
+ * }
120
+ *
121
+ * // After a successful joinClan(), re-call getClans manually — no push refresh.
122
+ * // const r = await window._smartico.api.joinClan(targetClanId);
123
+ * // if (r.errCode === 0) await window._smartico.api.getClans();
124
+ * ```
125
+ */
126
+ getClans({ onUpdate }?: {
127
+ onUpdate?: (data: TClans) => void;
128
+ }): Promise<TClans>;
129
+ /**
130
+ * Returns the full detail of a single clan — adds the ranked
131
+ * `members[]` roster and a fresh `cooldown_until` on top of the same
132
+ * fields exposed on a `TClan` list entry. Use this to power a clan
133
+ * detail screen / popup after the user picks an item from
134
+ * {@link getClans}.
135
+ *
136
+ * Each call is a fresh server round-trip — there is no client cache
137
+ * and no push event refreshes detail state. Re-call to refresh.
138
+ *
139
+ * @remarks
140
+ * **Preconditions**
141
+ * Pass a valid `clanId` (typically read from
142
+ * `TClans.clans[i].clan_id` returned by {@link getClans}). The
143
+ * method works standalone — `getClans()` is not required first —
144
+ * but is the only stable source of valid IDs.
145
+ *
146
+ * **Refresh model**
147
+ * - **No subscription.** One-shot promise.
148
+ * - **No client cache.** Every call sends a network request.
149
+ * - **No push event** refreshes the detail. Member-join, kick, or
150
+ * contribution-score changes require a fresh `getClanInfo` call.
151
+ *
152
+ * **Returned shape — beyond `TClan`**
153
+ * `TClanInfo` adds two things on top of the same identity / capacity
154
+ * / fee / rating fields you'd see on a `TClan` list entry:
155
+ * 1. A ranked `members[]` array — each entry carries `user_id`,
156
+ * `public_username`, `avatar_id` / `avatar_real_id`, the resolved
157
+ * `avatar_url`, the member's `position` (rank within this clan),
158
+ * `contribution_score`, the `is_me` flag identifying the current
159
+ * user's row, and the optional `clean_ext_user_id`. The server
160
+ * orders members by score DESC (i.e. `position` ASC); no
161
+ * client-side re-sort is required.
162
+ * 2. A fresh `cooldown_until` on the clan info itself. This is the
163
+ * SAME user-level cooldown as `TClans.cooldown_until` (the
164
+ * cooldown is global to the user, not per clan) — but `getClans`
165
+ * returns a value cached for up to 30 s while `getClanInfo`
166
+ * always returns the current value. If the list-cached cooldown
167
+ * has just expired, this detail call will reflect it first.
168
+ *
169
+ * **Username display**: in the default Smartico UI, member rows use
170
+ * `public_username`. Some surfaces (e.g. the tournament clan
171
+ * drill-down) prefer `clean_ext_user_id` as the primary display
172
+ * with `public_username` as fallback — pick the convention that
173
+ * matches your product's identity model.
174
+ *
175
+ * **Idempotency**: safe. Read-only.
176
+ *
177
+ * **Side effects**: none — pure metadata read.
178
+ *
179
+ * **UI guidance**: see [UI Guide — `getClanInfo`](../../docs/ui/clans/UIGuide_getClanInfo.md).
180
+ *
181
+ * **Visitor mode**: not supported.
182
+ *
183
+ * @param clanId The clan ID from `TClans.clans[i].clan_id`.
184
+ * @returns Promise resolving to `TClanInfo`. Rejects if the
185
+ * clan ID is invalid or the user lacks visibility
186
+ * for it.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * const result = await window._smartico.api.getClans();
191
+ * const clan = result.clans[0];
192
+ *
193
+ * console.log('[smartico] loading detail for clan', clan.clan_id);
194
+ * const detail = await window._smartico.api.getClanInfo(clan.clan_id);
195
+ *
196
+ * console.log('[smartico] render detail with', detail.members.length, 'members');
197
+ *
198
+ * // Find current user's row to power a sticky "me" footer.
199
+ * const meRow = detail.members.find(m => m.is_me);
200
+ * if (meRow) {
201
+ * console.log('[smartico] current user rank in this clan:', meRow.position,
202
+ * 'contribution:', meRow.contribution_score, '— render sticky my-member footer');
203
+ * }
204
+ *
205
+ * // Resolve Join CTA state using the detail's cooldown (always fresh).
206
+ * const isMyClan = detail.clan_id === result.user_clan_id;
207
+ * const inCooldown = detail.cooldown_until != null;
208
+ * const isFull = detail.member_count >= detail.capacity_limit;
209
+ * if (isMyClan) {
210
+ * console.log('[smartico] this is the user\'s clan — render disabled "Your clan" button');
211
+ * } else if (inCooldown) {
212
+ * const ends = new Date(detail.cooldown_until + 'Z');
213
+ * console.log('[smartico] user is in clan-switch cooldown until', ends.toLocaleString(),
214
+ * '— render disabled cooldown button');
215
+ * } else if (isFull) {
216
+ * console.log('[smartico] clan is full — render disabled "Clan is full" button');
217
+ * } else {
218
+ * console.log('[smartico] joinable — render enabled Join button');
219
+ * }
220
+ * ```
221
+ */
222
+ getClanInfo(clanId: number): Promise<TClanInfo>;
223
+ /**
224
+ * Joins (or switches into) a clan on behalf of the current user. For
225
+ * paid clans (`entry_fee_amount > 0`), the user's balance for the
226
+ * matching currency is debited synchronously before the response
227
+ * returns. If the user is already in a clan, this is treated as an
228
+ * atomic clan-switch (deactivate old membership + insert new + debit
229
+ * fee, all in one transaction — the user is never observably
230
+ * clanless).
231
+ *
232
+ * A successful response (`errCode === 0`) means: membership is
233
+ * persisted, the fee (if any) has been debited, the user's
234
+ * switch-cooldown has restarted, and a clan-joined CRM event has
235
+ * fired server-side.
236
+ *
237
+ * @remarks
238
+ * **Result shape note**: `TClanJoinResult` uses `errCode` / `errMsg`
239
+ * (camelCase) — different from most other SDK result types in this
240
+ * library which use `err_code` / `err_message` (snake_case). Branch
241
+ * on the camelCase keys when reading this method's result.
242
+ *
243
+ * **Preconditions**
244
+ * Read the candidate from {@link getClans} and gate the call on
245
+ * `clan.member_count < clan.capacity_limit`, `cooldown_until == null`
246
+ * (on the `TClans` payload — the cooldown is user-level, not
247
+ * per-clan), and the user's balance for `entry_fee_currency_type_id`
248
+ * being at least `entry_fee_amount` (free clans bypass this check).
249
+ * The SDK forwards the call unconditionally — calling without
250
+ * satisfying these will most likely return one of the error codes
251
+ * below.
252
+ *
253
+ * **Error codes** (in `errCode`, typed as {@link JoinClanErrorCode})
254
+ * - `0` (`JOIN_CLAN_OK`) — success; membership persisted, fee
255
+ * debited, cooldown restarted.
256
+ * - `1000` (`JOIN_CLAN_INVALID_PARAMETERS`) — request body missing
257
+ * `clan_id`. Should not occur via the SDK; treat as a programming
258
+ * error.
259
+ * - `1001` (`JOIN_CLAN_NOT_FOUND`) — clan doesn't exist for this
260
+ * label, OR the clan is archived / in draft state. The server
261
+ * merges "missing" and "archived" into this single code. Refresh
262
+ * `getClans()` and remove the entry from the UI.
263
+ * - `1002` (`JOIN_CLAN_FULL`) — capacity reached between the list
264
+ * fetch and the join click (`member_count >= capacity_limit` at
265
+ * the server's atomic check). Refresh the list — the button will
266
+ * become "Clan is full".
267
+ * - `1003` (`JOIN_CLAN_INSUFFICIENT_FUNDS`) — insufficient balance
268
+ * for the clan's entry fee. A single code covers all three
269
+ * currencies (points / gems / diamonds); read
270
+ * `clan.entry_fee_currency_type_id` to identify which currency
271
+ * the user is short on. Show an insufficient-balance UI naming
272
+ * the deficit.
273
+ * - `1004` (`JOIN_CLAN_SEGMENT_MISMATCH`) — user does not meet the
274
+ * clan's entry segment or numeric conditions. There is no
275
+ * client-side pre-guard for this — surface a gating message.
276
+ * - `1005` (`JOIN_CLAN_USER_IS_NOT_IN_CLAN`) — this method NEVER
277
+ * returns `1005`. The code is shared with the tournament
278
+ * registration error space and fires only on
279
+ * {@link registerInTournament} responses when a clan-based
280
+ * tournament requires the user to be in a clan first.
281
+ * - `1006` (`JOIN_CLAN_COOLDOWN_ACTIVE`) — user is inside the
282
+ * switch-cooldown window from a previous clan join (default
283
+ * 7 days, configurable per label). Surface the
284
+ * `TClans.cooldown_until` expiry in the disabled CTA.
285
+ * - `1007` (`JOIN_CLAN_ARCHIVED`) — defined on the public enum but
286
+ * the server does NOT emit this code in practice (archived clans
287
+ * are reported as `1001`). Handle it as a synonym for `1001`
288
+ * defensively, but do not rely on it.
289
+ * - `1011` (`JOIN_CLAN_JOINED_AFTER_TOURNAMENT_START`) — this
290
+ * method does NOT return `1011` directly. The code fires on
291
+ * {@link registerInTournament} responses when the user joined
292
+ * their current clan after the tournament started AND already
293
+ * has tournament scores.
294
+ * - other non-zero — generic server error. Surface `errMsg` if any.
295
+ *
296
+ * **Idempotency**: NOT safe — and notably dangerous. Calling
297
+ * `joinClan` with the user's CURRENT `clanId` does NOT short-circuit
298
+ * server-side; the call is treated as a clan-switch to the same
299
+ * clan. If the label's cooldown is non-zero (the default), the
300
+ * second call returns `1006`. If the cooldown is configured to
301
+ * zero, the second call will deduct the entry fee AGAIN, deactivate
302
+ * the membership, and re-insert it. The SDK does NOT enforce an
303
+ * in-flight lock. Consumers MUST guard the call site against
304
+ * double-clicks (set a local "joining" flag on click, clear it on
305
+ * response) AND short-circuit when the user is already in the
306
+ * target clan.
307
+ *
308
+ * **Refresh after success (and after failure)**
309
+ * The SDK does NOT automatically refresh the {@link getClans} cache
310
+ * after a join. Manually re-call `getClans()` on success to pick up
311
+ * the new `user_clan_id`, refreshed `member_count`, and the new
312
+ * `cooldown_until` value. Until you do, the cached `TClans` payload
313
+ * is stale.
314
+ *
315
+ * **Side effects** (consumer-observable on success)
316
+ * - Entry-fee currency balance decreases by `entry_fee_amount`
317
+ * (visible on the next {@link getUserProfile} refresh / via the
318
+ * user-properties update channel).
319
+ * - The user's clan membership row is created (or replaced, on a
320
+ * switch). `member_count` on the new clan increments by 1; on a
321
+ * switch, the old clan's `member_count` decrements by 1 in the
322
+ * same transaction.
323
+ * - The user's switch-cooldown restarts at the join time (the
324
+ * `TClans.cooldown_until` field on the next list fetch reflects
325
+ * the new expiry).
326
+ * - Server-side CRM analytics fire (clan-joined event, currency-
327
+ * deducted event for paid clans). These surface only as
328
+ * server-side traces; the SDK consumer observes them indirectly
329
+ * via balance / membership refresh.
330
+ *
331
+ * **UI guidance**: see [UI Guide — `joinClan`](../../docs/ui/clans/UIGuide_joinClan.md).
332
+ *
333
+ * **Visitor mode**: not supported. The server rejects the request
334
+ * for unauthenticated sessions.
335
+ *
336
+ * @param clanId The clan ID from `TClans.clans[i].clan_id` (or
337
+ * `TClanInfo.clan_id`).
338
+ * @returns `{ errCode, errMsg }`; success when `errCode === 0`.
339
+ * Note camelCase keys (see "Result shape note" above).
340
+ *
341
+ * @example
342
+ * ```ts
343
+ * const result = await window._smartico.api.getClans();
344
+ * const target = result.clans.find(c => c.clan_id === clanId);
345
+ *
346
+ * if (!target) {
347
+ * console.log('[smartico] clan not in current list — refresh getClans and retry');
348
+ * return;
349
+ * }
350
+ * if (target.clan_id === result.user_clan_id) {
351
+ * console.log('[smartico] user is already in this clan — short-circuit; do NOT call joinClan again, the server will treat it as a switch and may re-deduct the fee');
352
+ * return;
353
+ * }
354
+ * if (result.cooldown_until) {
355
+ * console.log('[smartico] user is in cooldown — disable Join until', new Date(result.cooldown_until + 'Z').toLocaleString());
356
+ * return;
357
+ * }
358
+ * if (target.member_count >= target.capacity_limit) {
359
+ * console.log('[smartico] clan is full — disable Join');
360
+ * return;
361
+ * }
362
+ *
363
+ * console.log('[smartico] join starting — set in-flight flag, show loading dots on Join button, keep modal open');
364
+ * const r = await window._smartico.api.joinClan(target.clan_id);
365
+ * console.log('[smartico] join response received — clear in-flight flag');
366
+ *
367
+ * if (r.errCode === 0) {
368
+ * console.log('[smartico] joined successfully — refresh getClans to pick up the new user_clan_id, member_count, and cooldown_until');
369
+ * await window._smartico.api.getClans();
370
+ * } else if (r.errCode === 1002) {
371
+ * console.error('[smartico] clan is full — refresh list, hide the Join CTA on the now-full clan');
372
+ * } else if (r.errCode === 1003) {
373
+ * const currencyLabel = ['points', 'gems', 'diamonds'][target.entry_fee_currency_type_id] ?? 'currency';
374
+ * console.error('[smartico] insufficient', currencyLabel, '— need', target.entry_fee_amount);
375
+ * } else if (r.errCode === 1004) {
376
+ * console.error('[smartico] user does not meet segment / entry conditions — show a gating message');
377
+ * } else if (r.errCode === 1006) {
378
+ * console.error('[smartico] cooldown active — surface the cooldown_until from getClans:', result.cooldown_until);
379
+ * } else if (r.errCode === 1001) {
380
+ * console.error('[smartico] clan not found or archived — refresh list and remove from UI');
381
+ * } else {
382
+ * console.error('[smartico] join failed — show a generic error toast with this message:', r.errMsg);
383
+ * }
384
+ * ```
385
+ */
386
+ joinClan(clanId: number): Promise<TClanJoinResult>;
387
+ protected updateClans(): Promise<void>;
388
+ }