@jolibox/implement 1.2.4 → 1.2.5

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 (40) hide show
  1. package/.rush/temp/package-deps_build.json +24 -18
  2. package/dist/common/cache/__tests__/request-cache-service.test.d.ts +1 -0
  3. package/dist/common/cache/request-cache-service.d.ts +111 -0
  4. package/dist/common/report/base-tracker.d.ts +2 -1
  5. package/dist/common/rewards/cached-fetch-reward.d.ts +46 -0
  6. package/dist/common/rewards/cached-reward-service.d.ts +24 -0
  7. package/dist/common/rewards/fetch-reward.d.ts +2 -3
  8. package/dist/common/rewards/index.d.ts +2 -0
  9. package/dist/common/rewards/registers/utils/coins/jolicoin/cached-fetch-balance.d.ts +34 -0
  10. package/dist/common/rewards/registers/utils/coins/jolicoin/fetch-balance.d.ts +2 -1
  11. package/dist/common/rewards/registers/utils/coins/joligem/cached-fetch-gem-balance.d.ts +34 -0
  12. package/dist/common/rewards/registers/utils/coins/joligem/fetch-gem-balance.d.ts +2 -1
  13. package/dist/index.js +9 -9
  14. package/dist/index.native.js +33 -33
  15. package/dist/native/payment/payment-service.d.ts +36 -30
  16. package/implement.build.log +2 -2
  17. package/package.json +5 -5
  18. package/src/common/cache/__tests__/request-cache-service.test.ts +686 -0
  19. package/src/common/cache/request-cache-service.ts +393 -0
  20. package/src/common/report/base-tracker.ts +2 -2
  21. package/src/common/rewards/cached-fetch-reward.ts +241 -0
  22. package/src/common/rewards/cached-reward-service.ts +255 -0
  23. package/src/common/rewards/fetch-reward.ts +17 -93
  24. package/src/common/rewards/index.ts +3 -0
  25. package/src/common/rewards/registers/utils/coins/commands/use-payment.ts +8 -0
  26. package/src/common/rewards/registers/utils/coins/jolicoin/cached-fetch-balance.ts +177 -0
  27. package/src/common/rewards/registers/utils/coins/jolicoin/fetch-balance.ts +13 -1
  28. package/src/common/rewards/registers/utils/coins/jolicoin/jolicoin-handler.ts +2 -0
  29. package/src/common/rewards/registers/utils/coins/joligem/cached-fetch-gem-balance.ts +181 -0
  30. package/src/common/rewards/registers/utils/coins/joligem/fetch-gem-balance.ts +13 -1
  31. package/src/common/rewards/registers/utils/coins/joligem/gem-handler.ts +2 -0
  32. package/src/h5/api/ads.ts +5 -0
  33. package/src/h5/api/storage.ts +2 -2
  34. package/src/h5/http/index.ts +2 -2
  35. package/src/h5/report/event-tracker.ts +2 -2
  36. package/src/native/api/ads.ts +7 -1
  37. package/src/native/api/payment.ts +4 -4
  38. package/src/native/payment/__tests__/payment-service-simple.test.ts +97 -31
  39. package/src/native/payment/payment-service.ts +224 -210
  40. package/src/native/rewards/ui/payment-modal.ts +14 -7
@@ -0,0 +1,255 @@
1
+ import { RequestCacheService, RequestAdapter } from '../cache/request-cache-service';
2
+ import { IHttpClient } from '../http';
3
+ import { StandardResponse, GlobalConfig } from '@jolibox/types';
4
+ import { IJolicoinRewardOption, IUnlockOption, IJoliCoin, IGem } from './type';
5
+ import { IUseModalFrequencyConfig } from './reward-emitter';
6
+
7
+ // 定义请求参数类型
8
+ interface RewardRequest {
9
+ endpoint: string;
10
+ body?: Record<string, unknown>;
11
+ method?: 'GET' | 'POST';
12
+ }
13
+
14
+ interface UnlockOptionsCacheData {
15
+ unlockOptions: IUnlockOption[];
16
+ joliCoin: IJoliCoin;
17
+ joliGem: IGem;
18
+ }
19
+
20
+ interface UnlockOptionsRealTimeData {
21
+ timestamp?: number;
22
+ }
23
+
24
+ // 定义全局配置的缓存数据
25
+ interface GlobalConfigCacheData {
26
+ joliCoinUseAndCharge: IUseModalFrequencyConfig['joliCoinUseAndCharge'];
27
+ loginGuide: IUseModalFrequencyConfig['loginGuide'];
28
+ // 其他全局配置字段
29
+ [key: string]: unknown;
30
+ }
31
+
32
+ // 奖励接口适配器
33
+ class RewardRequestAdapter
34
+ implements
35
+ RequestAdapter<RewardRequest, IJolicoinRewardOption, UnlockOptionsCacheData, UnlockOptionsRealTimeData>
36
+ {
37
+ constructor(private httpClient: IHttpClient) {}
38
+
39
+ async execute(endpoint: string, options?: RewardRequest): Promise<IJolicoinRewardOption> {
40
+ const method = options?.method || 'POST';
41
+ const body = options?.body || {};
42
+
43
+ if (method === 'GET') {
44
+ return await this.httpClient.get<IJolicoinRewardOption>(endpoint, body);
45
+ } else {
46
+ return await this.httpClient.post<IJolicoinRewardOption>(endpoint, body);
47
+ }
48
+ }
49
+
50
+ extractCacheableData(response: IJolicoinRewardOption): UnlockOptionsCacheData {
51
+ return {
52
+ unlockOptions: response.data?.unlockOptions || [],
53
+ joliCoin: response.extra.joliCoin,
54
+ joliGem: response.extra.joliGem || { balance: 0, enableAutoDeduct: false }
55
+ };
56
+ }
57
+
58
+ extractRealTimeData?: undefined;
59
+
60
+ mergeData(cached: UnlockOptionsCacheData, realTime: UnlockOptionsRealTimeData): IJolicoinRewardOption {
61
+ return {
62
+ code: 'SUCCESS',
63
+ message: 'success',
64
+ data: {
65
+ unlockOptions: cached.unlockOptions
66
+ },
67
+ extra: {
68
+ joliCoin: cached.joliCoin,
69
+ joliGem: cached.joliGem
70
+ }
71
+ };
72
+ }
73
+
74
+ processCachedData(cached: UnlockOptionsCacheData): IJolicoinRewardOption {
75
+ return {
76
+ code: 'SUCCESS',
77
+ message: 'success from cache',
78
+ data: {
79
+ unlockOptions: cached.unlockOptions
80
+ },
81
+ extra: {
82
+ joliCoin: cached.joliCoin,
83
+ joliGem: cached.joliGem
84
+ }
85
+ };
86
+ }
87
+ }
88
+
89
+ class GlobalConfigRequestAdapter
90
+ implements
91
+ RequestAdapter<
92
+ RewardRequest,
93
+ StandardResponse<GlobalConfig & IUseModalFrequencyConfig>,
94
+ GlobalConfigCacheData,
95
+ undefined
96
+ >
97
+ {
98
+ constructor(private httpClient: IHttpClient) {}
99
+
100
+ async execute(
101
+ endpoint: string,
102
+ options?: RewardRequest
103
+ ): Promise<StandardResponse<GlobalConfig & IUseModalFrequencyConfig>> {
104
+ const method = options?.method || 'GET';
105
+ const body = options?.body || {};
106
+
107
+ if (method === 'GET') {
108
+ return await this.httpClient.get<StandardResponse<GlobalConfig & IUseModalFrequencyConfig>>(
109
+ endpoint,
110
+ body
111
+ );
112
+ } else {
113
+ return await this.httpClient.post<StandardResponse<GlobalConfig & IUseModalFrequencyConfig>>(
114
+ endpoint,
115
+ body
116
+ );
117
+ }
118
+ }
119
+
120
+ extractCacheableData(
121
+ response: StandardResponse<GlobalConfig & IUseModalFrequencyConfig>
122
+ ): GlobalConfigCacheData {
123
+ const data = response.data;
124
+ return {
125
+ joliCoinUseAndCharge: data?.joliCoinUseAndCharge,
126
+ loginGuide: data?.loginGuide,
127
+ ...data // 包含其他所有配置字段
128
+ } as GlobalConfigCacheData;
129
+ }
130
+
131
+ extractRealTimeData?: undefined;
132
+ mergeData?: undefined;
133
+
134
+ processCachedData(
135
+ cached: GlobalConfigCacheData
136
+ ): StandardResponse<GlobalConfig & IUseModalFrequencyConfig> {
137
+ return {
138
+ code: 'SUCCESS',
139
+ message: 'success from cache',
140
+ data: cached as GlobalConfig & IUseModalFrequencyConfig
141
+ };
142
+ }
143
+ }
144
+
145
+ export class CachedRewardService {
146
+ private unlockOptionsService: RequestCacheService<
147
+ RewardRequest,
148
+ IJolicoinRewardOption,
149
+ UnlockOptionsCacheData,
150
+ UnlockOptionsRealTimeData
151
+ >;
152
+ private globalConfigService: RequestCacheService<
153
+ RewardRequest,
154
+ StandardResponse<GlobalConfig & IUseModalFrequencyConfig>,
155
+ GlobalConfigCacheData,
156
+ undefined
157
+ >;
158
+
159
+ constructor(httpClient: IHttpClient) {
160
+ // 创建 unlock-options 服务,缓存 unlockOptions,实时获取余额
161
+ this.unlockOptionsService = new (RequestCacheService as new (...args: unknown[]) => RequestCacheService<
162
+ RewardRequest,
163
+ IJolicoinRewardOption,
164
+ UnlockOptionsCacheData,
165
+ UnlockOptionsRealTimeData
166
+ >)(new RewardRequestAdapter(httpClient), {
167
+ duration: 30 * 60 * 1000, // 30分钟缓存
168
+ timeout: 1000, // 1s timeout for request
169
+ keyGenerator: (endpoint: string) => endpoint,
170
+ // unlockOptions 结构一致性检查
171
+ consistencyChecker: (cached: UnlockOptionsCacheData, serverData: UnlockOptionsCacheData) => {
172
+ if (cached.unlockOptions.length !== serverData.unlockOptions.length) {
173
+ return false;
174
+ }
175
+ return cached.unlockOptions.every((cachedOption: IUnlockOption, index: number) => {
176
+ const serverOption = serverData.unlockOptions[index];
177
+ return (
178
+ cachedOption.type === serverOption.type &&
179
+ cachedOption.joliGemChoice?.joliGemQuantity === serverOption.joliGemChoice?.joliGemQuantity
180
+ );
181
+ });
182
+ }
183
+ });
184
+
185
+ this.globalConfigService = new (RequestCacheService as new (...args: unknown[]) => RequestCacheService<
186
+ RewardRequest,
187
+ StandardResponse<GlobalConfig & IUseModalFrequencyConfig>,
188
+ GlobalConfigCacheData,
189
+ undefined
190
+ >)(new GlobalConfigRequestAdapter(httpClient), {
191
+ duration: 60 * 60 * 1000, // 60分钟缓存
192
+ timeout: 1000, // 1s timeout for request
193
+ keyGenerator: (endpoint: string) => endpoint
194
+ });
195
+ }
196
+
197
+ async getUnlockOptions(body: Record<string, unknown> = {}): Promise<IJolicoinRewardOption> {
198
+ return await this.unlockOptionsService.request('/api/games/unlock-options', {
199
+ endpoint: '/api/games/unlock-options',
200
+ body,
201
+ method: 'POST'
202
+ });
203
+ }
204
+
205
+ async getGlobalConfig(): Promise<StandardResponse<GlobalConfig & IUseModalFrequencyConfig>> {
206
+ return await this.globalConfigService.request('/api/fe-configs/web-common/global-config', {
207
+ endpoint: '/api/fe-configs/web-common/global-config',
208
+ method: 'GET'
209
+ });
210
+ }
211
+ async refreshUnlockOptions(body: Record<string, unknown> = {}): Promise<IJolicoinRewardOption> {
212
+ return await this.unlockOptionsService.forceRequest('/api/games/unlock-options', {
213
+ endpoint: '/api/games/unlock-options',
214
+ body,
215
+ method: 'POST'
216
+ });
217
+ }
218
+
219
+ async refreshGlobalConfig(): Promise<StandardResponse<GlobalConfig & IUseModalFrequencyConfig>> {
220
+ return await this.globalConfigService.forceRequest('/api/fe-configs/web-common/global-config', {
221
+ endpoint: '/api/fe-configs/web-common/global-config',
222
+ method: 'GET'
223
+ });
224
+ }
225
+
226
+ async warmupCache(): Promise<void> {
227
+ await Promise.all([
228
+ this.unlockOptionsService.warmupCache('/api/games/unlock-options', {
229
+ endpoint: '/api/games/unlock-options',
230
+ method: 'POST'
231
+ }),
232
+ this.globalConfigService.warmupCache('/api/fe-configs/web-common/global-config', {
233
+ endpoint: '/api/fe-configs/web-common/global-config',
234
+ method: 'GET'
235
+ })
236
+ ]);
237
+ }
238
+
239
+ clearAllCache(): void {
240
+ this.unlockOptionsService.clearCache();
241
+ this.globalConfigService.clearCache();
242
+ }
243
+
244
+ getCacheStats() {
245
+ return {
246
+ unlockOptions: this.unlockOptionsService.getCacheStats(),
247
+ globalConfig: this.globalConfigService.getCacheStats()
248
+ };
249
+ }
250
+
251
+ clearExpiredCache(): void {
252
+ this.unlockOptionsService.clearExpiredCache();
253
+ this.globalConfigService.clearExpiredCache();
254
+ }
255
+ }
@@ -1,93 +1,17 @@
1
- import { IHttpClient } from '../http';
2
- import { RewardsHelper, RewardType } from './reward-helper';
3
- import { IJolicoinRewardOption } from './type';
4
- import {
5
- UnlockOptionsEventName,
6
- UseModalFrequencyEventName,
7
- rewardsEmitter,
8
- DefaltJoliCoinUseAndCharge,
9
- DefaltLoginGuide,
10
- IUseModalFrequencyConfig
11
- } from './reward-emitter';
12
- import { StandardResponse, GlobalConfig } from '@jolibox/types';
13
- import { hostEmitter } from '@jolibox/common';
14
-
15
- const priority = () => {
16
- return (a: RewardType, b: RewardType) => {
17
- // Priority order: GEM > JOLI_COIN > ADS
18
- const priorityMap: Record<RewardType, number> = {
19
- JOLI_GEM: 3,
20
- JOLI_GEM_ONLY: 3,
21
- JOLI_COIN: 2,
22
- JOLI_COIN_ONLY: 2,
23
- ADS: 1
24
- };
25
-
26
- return priorityMap[b] - priorityMap[a];
27
- };
28
- };
29
-
30
- const sortRewards = (rewardsTypes: RewardType[]): RewardType[] => {
31
- if (!rewardsTypes.length) return ['ADS'];
32
- if (rewardsTypes.includes('JOLI_GEM') && rewardsTypes.length <= 1) return ['JOLI_GEM_ONLY'];
33
- if (rewardsTypes.includes('JOLI_COIN') && rewardsTypes.length <= 1) return ['JOLI_COIN_ONLY'];
34
-
35
- return rewardsTypes.sort(priority());
36
- };
37
-
38
- export const createRewardFetcher = (rewardsHelper: RewardsHelper) => {
39
- rewardsHelper.registerRewardsFetcher(async (httpClient: IHttpClient) => {
40
- const defaultRewards: RewardType[] = ['ADS'];
41
- try {
42
- const res = await httpClient.post<IJolicoinRewardOption>('/api/games/unlock-options', {});
43
- if (res.code !== 'SUCCESS') {
44
- return defaultRewards;
45
- }
46
-
47
- console.log('-----res fetch reward-----', res);
48
- rewardsEmitter.emit(UnlockOptionsEventName, {
49
- options: res.data?.unlockOptions || [],
50
- userJoliCoin: res.extra?.joliCoin || {
51
- balance: 0,
52
- enableAutoDeduct: false
53
- },
54
- userGem: res.extra?.joliGem || {
55
- balance: 0,
56
- enableAutoDeduct: false
57
- }
58
- });
59
-
60
- const rewardsTypes =
61
- res.data?.unlockOptions?.map((option) => option.type) || Array.from(defaultRewards);
62
- // Sort reward types with JOLI_COIN having higher priority than ADS
63
- return sortRewards(rewardsTypes);
64
- } catch (e) {
65
- console.error('getRewardOptions error:', e);
66
- return defaultRewards;
67
- }
68
- });
69
- };
70
-
71
- export const createRewardFrequencyConfigFetcher = (rewardsHelper: RewardsHelper) => {
72
- rewardsHelper.registerRewardFrequencyConfigFetcher(async (httpClient: IHttpClient) => {
73
- const res = await httpClient.get<StandardResponse<GlobalConfig & IUseModalFrequencyConfig>>(
74
- '/api/fe-configs/web-common/global-config',
75
- {}
76
- );
77
-
78
- rewardsEmitter.emit(UseModalFrequencyEventName, {
79
- joliCoinUseAndCharge: res.data?.joliCoinUseAndCharge || DefaltJoliCoinUseAndCharge,
80
- loginGuide: res.data?.loginGuide || DefaltLoginGuide
81
- });
82
-
83
- res.data &&
84
- hostEmitter.emit('onGlobalConfigChanged', {
85
- globalConfig: res.data
86
- });
87
-
88
- return {
89
- joliCoinUseAndCharge: res.data?.joliCoinUseAndCharge || DefaltJoliCoinUseAndCharge,
90
- loginGuide: res.data?.loginGuide || DefaltLoginGuide
91
- };
92
- });
93
- };
1
+ export {
2
+ createCachedRewardFetcher as createRewardFetcher,
3
+ createCachedRewardFrequencyConfigFetcher as createRewardFrequencyConfigFetcher,
4
+ // cache
5
+ getRewardCacheService,
6
+ refreshRewardCache,
7
+ refreshGlobalConfigCache,
8
+ warmupRewardCache,
9
+ clearRewardCache,
10
+ getRewardCacheStats
11
+ } from './cached-fetch-reward';
12
+
13
+ // original version
14
+ export {
15
+ createRewardFetcher as createRewardFetcherNonCached,
16
+ createRewardFrequencyConfigFetcher as createRewardFrequencyConfigFetcherNonCached
17
+ } from './cached-fetch-reward';
@@ -10,3 +10,6 @@ export * from './registers/use-jolicoin';
10
10
  export * from './registers/use-jolicoin-only';
11
11
  export * from './registers/use-gem';
12
12
  export * from './registers/use-gem-only';
13
+
14
+ export { warmupBalanceCache } from './registers/utils/coins/jolicoin/cached-fetch-balance';
15
+ export { warmupGemBalanceCache } from './registers/utils/coins/joligem/cached-fetch-gem-balance';
@@ -10,6 +10,8 @@ import {
10
10
  InvokePaymentEventName
11
11
  } from '@/common/rewards/reward-emitter';
12
12
  import { CURRENCY_HANDLERS, CurrencyType } from './currency-handlers';
13
+ import { refreshGemBalanceCache } from '../joligem/cached-fetch-gem-balance';
14
+ import { refreshBalanceCache } from '../jolicoin/cached-fetch-balance';
13
15
 
14
16
  export const registerUsePaymentCommand = <T extends IJoliCoin | IGem>(
15
17
  prefix: 'JOLI_COIN' | 'ADS-JOLI_COIN' | 'JOLI_GEM' | 'ADS-JOLI_GEM',
@@ -48,6 +50,12 @@ export const registerUsePaymentCommand = <T extends IJoliCoin | IGem>(
48
50
  currency: currency as T extends IJoliCoin ? 'JOLI_COIN' : 'JOLI_GEM'
49
51
  });
50
52
 
53
+ if (currency === 'JOLI_GEM') {
54
+ refreshGemBalanceCache(httpClient);
55
+ } else {
56
+ refreshBalanceCache(httpClient);
57
+ }
58
+
51
59
  return {
52
60
  result: paymentResult === 'SUCCESS' ? 'SUCCESS' : 'FAILED'
53
61
  };
@@ -0,0 +1,177 @@
1
+ import { RequestCacheService, RequestAdapter } from '@/common/cache/request-cache-service';
2
+ import { IHttpClient } from '@/common/http';
3
+ import { StandardResponse } from '@jolibox/types';
4
+
5
+ interface BalanceRequest {
6
+ endpoint: string;
7
+ query?: Record<string, unknown>;
8
+ method?: 'GET' | 'POST';
9
+ }
10
+
11
+ // 定义余额响应类型
12
+ interface BalanceResponse {
13
+ balance: number;
14
+ }
15
+
16
+ interface BalanceCacheData {
17
+ balance: number;
18
+ timestamp: number;
19
+ }
20
+
21
+ class BalanceRequestAdapter
22
+ implements RequestAdapter<BalanceRequest, StandardResponse<BalanceResponse>, BalanceCacheData, undefined>
23
+ {
24
+ constructor(private httpClient: IHttpClient) {}
25
+
26
+ async execute(endpoint: string, options?: BalanceRequest): Promise<StandardResponse<BalanceResponse>> {
27
+ const method = options?.method || 'GET';
28
+ const query = options?.query || {};
29
+
30
+ if (method === 'GET') {
31
+ return await this.httpClient.get<StandardResponse<BalanceResponse>>(endpoint, {
32
+ query: query as Record<string, string>
33
+ });
34
+ } else {
35
+ return await this.httpClient.post<StandardResponse<BalanceResponse>>(endpoint, {
36
+ query: query as Record<string, string>
37
+ });
38
+ }
39
+ }
40
+
41
+ extractCacheableData(response: StandardResponse<BalanceResponse>): BalanceCacheData {
42
+ return {
43
+ balance: response.data?.balance || 0,
44
+ timestamp: Date.now()
45
+ };
46
+ }
47
+
48
+ // 余额使用纯缓存模式
49
+ extractRealTimeData?: undefined;
50
+ mergeData?: undefined;
51
+
52
+ processCachedData(cached: BalanceCacheData): StandardResponse<BalanceResponse> {
53
+ return {
54
+ code: 'SUCCESS',
55
+ message: 'success from cache',
56
+ data: {
57
+ balance: cached.balance
58
+ }
59
+ };
60
+ }
61
+ }
62
+
63
+ // 缓存余额服务
64
+ export class CachedBalanceService {
65
+ private balanceService: RequestCacheService<
66
+ BalanceRequest,
67
+ StandardResponse<BalanceResponse>,
68
+ BalanceCacheData,
69
+ undefined
70
+ >;
71
+
72
+ constructor(httpClient: IHttpClient) {
73
+ this.balanceService = new (RequestCacheService as new (...args: unknown[]) => RequestCacheService<
74
+ BalanceRequest,
75
+ StandardResponse<BalanceResponse>,
76
+ BalanceCacheData,
77
+ undefined
78
+ >)(new BalanceRequestAdapter(httpClient), {
79
+ duration: 20 * 60 * 1000, // 10min cache, force update every query
80
+ timeout: 1000, // 1s timeout for request
81
+ keyGenerator: (endpoint: string, params?: BalanceRequest) => {
82
+ const queryStr = params?.query ? JSON.stringify(params.query) : '';
83
+ return `${endpoint}:${queryStr}`;
84
+ }
85
+ });
86
+ }
87
+
88
+ async getBalance(type = 'JOLI_COIN'): Promise<BalanceResponse | undefined> {
89
+ const response = await this.balanceService.request('/api/joli-coin/balance', {
90
+ endpoint: '/api/joli-coin/balance',
91
+ query: { type },
92
+ method: 'GET'
93
+ });
94
+ return response.data;
95
+ }
96
+
97
+ async refreshBalance(type = 'JOLI_COIN'): Promise<BalanceResponse | undefined> {
98
+ const response = await this.balanceService.forceRequest('/api/joli-coin/balance', {
99
+ endpoint: '/api/joli-coin/balance',
100
+ query: { type },
101
+ method: 'GET'
102
+ });
103
+ return response.data;
104
+ }
105
+
106
+ async warmupBalance(type = 'JOLI_COIN'): Promise<void> {
107
+ await this.balanceService.warmupCache('/api/joli-coin/balance', {
108
+ endpoint: '/api/joli-coin/balance',
109
+ query: { type },
110
+ method: 'GET'
111
+ });
112
+ }
113
+
114
+ clearBalanceCache(): void {
115
+ this.balanceService.clearCache();
116
+ }
117
+
118
+ getBalanceCacheStats() {
119
+ return this.balanceService.getCacheStats();
120
+ }
121
+
122
+ clearExpiredCache(): void {
123
+ this.balanceService.clearExpiredCache();
124
+ }
125
+ }
126
+
127
+ // create instance
128
+ let cachedBalanceServiceInstance: CachedBalanceService | null = null;
129
+
130
+ function getCachedBalanceService(httpClient: IHttpClient): CachedBalanceService {
131
+ if (!cachedBalanceServiceInstance) {
132
+ cachedBalanceServiceInstance = new CachedBalanceService(httpClient);
133
+ }
134
+ return cachedBalanceServiceInstance;
135
+ }
136
+
137
+ /**
138
+ * 缓存版本的 fetchBalance 函数
139
+ */
140
+ export const fetchBalanceCached = async (httpClient: IHttpClient, type = 'JOLI_COIN') => {
141
+ const cachedBalanceService = getCachedBalanceService(httpClient);
142
+ return await cachedBalanceService.getBalance(type);
143
+ };
144
+
145
+ /**
146
+ * 强制刷新余额缓存
147
+ */
148
+ export const refreshBalanceCache = async (httpClient: IHttpClient, type = 'JOLI_COIN') => {
149
+ const cachedBalanceService = getCachedBalanceService(httpClient);
150
+ const result = await cachedBalanceService.refreshBalance(type);
151
+ console.log(`Balance cache refreshed for type: ${type}`);
152
+ return result;
153
+ };
154
+
155
+ /**
156
+ * 预热余额缓存
157
+ */
158
+ export const warmupBalanceCache = async (httpClient: IHttpClient, type = 'JOLI_COIN') => {
159
+ const cachedBalanceService = getCachedBalanceService(httpClient);
160
+ await cachedBalanceService.warmupBalance(type);
161
+ console.log(`Balance cache warmed up for type: ${type}`);
162
+ };
163
+
164
+ export const clearBalanceCache = (httpClient: IHttpClient) => {
165
+ const cachedBalanceService = getCachedBalanceService(httpClient);
166
+ cachedBalanceService.clearBalanceCache();
167
+ console.log('Balance cache cleared');
168
+ };
169
+
170
+ export const getBalanceCacheStats = (httpClient: IHttpClient) => {
171
+ const cachedBalanceService = getCachedBalanceService(httpClient);
172
+ return cachedBalanceService.getBalanceCacheStats();
173
+ };
174
+
175
+ export const getBalanceCacheService = (httpClient: IHttpClient): CachedBalanceService => {
176
+ return getCachedBalanceService(httpClient);
177
+ };
@@ -1,7 +1,19 @@
1
1
  import { IHttpClient } from '@/common/http';
2
2
  import { StandardResponse } from '@jolibox/types';
3
3
 
4
- export const fetchBalance = async (httpClient: IHttpClient) => {
4
+ // 重新导出缓存版本作为默认实现
5
+ export {
6
+ fetchBalanceCached as fetchBalance,
7
+ // 提供缓存管理功能
8
+ refreshBalanceCache,
9
+ warmupBalanceCache,
10
+ clearBalanceCache,
11
+ getBalanceCacheStats,
12
+ getBalanceCacheService
13
+ } from './cached-fetch-balance';
14
+
15
+ // original version
16
+ export const fetchBalanceNonCached = async (httpClient: IHttpClient) => {
5
17
  const res = await httpClient.get<
6
18
  StandardResponse<{
7
19
  balance: number;
@@ -16,6 +16,7 @@ import {
16
16
  } from '../commands';
17
17
  import { rewardsCommands } from '../rewards-command';
18
18
  import { RewardsCommandType } from '@jolibox/types';
19
+ import { refreshBalanceCache, warmupBalanceCache } from './cached-fetch-balance';
19
20
 
20
21
  interface ICurrencyUnlockRes {
21
22
  code: 'SUCCESS' | 'BALANCE_NOT_ENOUGH' | 'EPISODE_LOCK_JUMP' | 'EPISODE_UNLOCK_ALREADY';
@@ -103,6 +104,7 @@ const createCommonCurrencyRewardHandler = (
103
104
  if ('adViewed' in params) {
104
105
  params.adViewed?.();
105
106
  }
107
+ refreshBalanceCache(httpClient);
106
108
  } catch (e) {
107
109
  console.error('-----unlockWithJolicoin adBreakDone error-----', e);
108
110
  }