@jolibox/implement 1.2.4 → 1.2.5-beta.3

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 (61) hide show
  1. package/.rush/temp/package-deps_build.json +36 -23
  2. package/CHANGELOG.json +11 -0
  3. package/CHANGELOG.md +9 -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 +3 -0
  9. package/dist/common/rewards/registers/use-subscription.d.ts +7 -0
  10. package/dist/common/rewards/registers/utils/coins/jolicoin/cached-fetch-balance.d.ts +34 -0
  11. package/dist/common/rewards/registers/utils/coins/jolicoin/fetch-balance.d.ts +2 -1
  12. package/dist/common/rewards/registers/utils/coins/joligem/cached-fetch-gem-balance.d.ts +34 -0
  13. package/dist/common/rewards/registers/utils/coins/joligem/fetch-gem-balance.d.ts +2 -1
  14. package/dist/common/rewards/registers/utils/subscription/commands/index.d.ts +1 -0
  15. package/dist/common/rewards/registers/utils/subscription/commands/use-subscription.d.ts +4 -0
  16. package/dist/common/rewards/registers/utils/subscription/sub-handler.d.ts +13 -0
  17. package/dist/common/rewards/reward-emitter.d.ts +7 -0
  18. package/dist/common/rewards/reward-helper.d.ts +2 -1
  19. package/dist/common/utils/index.d.ts +18 -0
  20. package/dist/h5/api/platformAdsHandle/JoliboxAdsHandler.d.ts +1 -0
  21. package/dist/h5/bootstrap/auth/__tests__/auth.test.d.ts +1 -0
  22. package/dist/h5/bootstrap/auth/index.d.ts +2 -0
  23. package/dist/h5/bootstrap/auth/sub.d.ts +2 -0
  24. package/dist/index.js +9 -9
  25. package/dist/index.native.js +49 -49
  26. package/dist/native/payment/payment-service.d.ts +36 -30
  27. package/implement.build.log +2 -2
  28. package/package.json +7 -7
  29. package/src/common/report/base-tracker.ts +2 -2
  30. package/src/common/rewards/cached-fetch-reward.ts +258 -0
  31. package/src/common/rewards/cached-reward-service.ts +255 -0
  32. package/src/common/rewards/fetch-reward.ts +17 -93
  33. package/src/common/rewards/index.ts +4 -0
  34. package/src/common/rewards/registers/use-subscription.ts +34 -0
  35. package/src/common/rewards/registers/utils/coins/jolicoin/cached-fetch-balance.ts +177 -0
  36. package/src/common/rewards/registers/utils/coins/jolicoin/fetch-balance.ts +13 -1
  37. package/src/common/rewards/registers/utils/coins/jolicoin/jolicoin-handler.ts +2 -0
  38. package/src/common/rewards/registers/utils/coins/joligem/cached-fetch-gem-balance.ts +181 -0
  39. package/src/common/rewards/registers/utils/coins/joligem/fetch-gem-balance.ts +13 -1
  40. package/src/common/rewards/registers/utils/coins/joligem/gem-handler.ts +2 -0
  41. package/src/common/rewards/registers/utils/subscription/commands/index.ts +1 -0
  42. package/src/common/rewards/registers/utils/subscription/commands/use-subscription.ts +29 -0
  43. package/src/common/rewards/registers/utils/subscription/sub-handler.ts +88 -0
  44. package/src/common/rewards/reward-emitter.ts +8 -0
  45. package/src/common/rewards/reward-helper.ts +8 -1
  46. package/src/common/utils/index.ts +23 -0
  47. package/src/h5/api/ads.ts +18 -12
  48. package/src/h5/api/platformAdsHandle/JoliboxAdsHandler.ts +25 -1
  49. package/src/h5/api/storage.ts +2 -2
  50. package/src/h5/bootstrap/auth/__tests__/auth.test.ts +308 -0
  51. package/src/h5/bootstrap/auth/index.ts +20 -0
  52. package/src/h5/bootstrap/auth/sub.ts +56 -0
  53. package/src/h5/bootstrap/index.ts +4 -19
  54. package/src/h5/http/index.ts +2 -2
  55. package/src/h5/report/event-tracker.ts +2 -2
  56. package/src/h5/rewards/index.ts +18 -1
  57. package/src/native/api/ads.ts +7 -1
  58. package/src/native/api/payment.ts +4 -4
  59. package/src/native/payment/__tests__/payment-service-simple.test.ts +97 -31
  60. package/src/native/payment/payment-service.ts +224 -210
  61. package/src/native/rewards/ui/payment-modal.ts +14 -7
@@ -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,7 @@ 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
+ export * from './registers/use-subscription';
14
+
15
+ export { warmupBalanceCache } from './registers/utils/coins/jolicoin/cached-fetch-balance';
16
+ export { warmupGemBalanceCache } from './registers/utils/coins/joligem/cached-fetch-gem-balance';
@@ -0,0 +1,34 @@
1
+ import { IHttpClient } from '@/common/http';
2
+ import { IAdBreakParams } from '@/common/ads';
3
+ import { unlockOptionsHandler } from './utils/common';
4
+ import { createCommonSubscriptionHandler } from './utils/subscription/sub-handler';
5
+ import { createShowSubscriptionModal } from './utils/subscription/commands/use-subscription';
6
+
7
+ export type SubscriptionRewardsHandler = (params: IAdBreakParams) => Promise<boolean>;
8
+ export const createSubscriptionRewardHandler = (
9
+ httpClient: IHttpClient,
10
+ {
11
+ onSubSuccess,
12
+ onSubFailed
13
+ }: {
14
+ onSubSuccess?: () => void;
15
+ onSubFailed?: () => void;
16
+ }
17
+ ): SubscriptionRewardsHandler => {
18
+ const handleUnlockFailed = () => {
19
+ onSubFailed?.();
20
+ };
21
+
22
+ const showSubscriptionModal = createShowSubscriptionModal('SUBSCRIPTION');
23
+
24
+ const subscriptionRewardHandler = createCommonSubscriptionHandler('SUBSCRIPTION', httpClient, {
25
+ handlers: {
26
+ handleSubSuccess: onSubSuccess,
27
+ handleSubFailed: handleUnlockFailed,
28
+ unlockOptionsHandler,
29
+ showSubscriptionModal
30
+ }
31
+ });
32
+
33
+ return subscriptionRewardHandler;
34
+ };
@@ -0,0 +1,177 @@
1
+ import { RequestCacheService, RequestAdapter } from '@jolibox/common';
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
  }
@@ -0,0 +1,181 @@
1
+ import { RequestCacheService, RequestAdapter } from '@jolibox/common';
2
+ import { IHttpClient } from '@/common/http';
3
+ import { StandardResponse } from '@jolibox/types';
4
+
5
+ interface GemBalanceRequest {
6
+ endpoint: string;
7
+ query?: Record<string, unknown>;
8
+ method?: 'GET' | 'POST';
9
+ }
10
+
11
+ // 定义宝石余额响应类型
12
+ interface GemBalanceResponse {
13
+ balance: number;
14
+ }
15
+
16
+ interface GemBalanceCacheData {
17
+ balance: number;
18
+ timestamp: number;
19
+ }
20
+
21
+ class GemBalanceRequestAdapter
22
+ implements
23
+ RequestAdapter<GemBalanceRequest, StandardResponse<GemBalanceResponse>, GemBalanceCacheData, undefined>
24
+ {
25
+ constructor(private httpClient: IHttpClient) {}
26
+
27
+ async execute(
28
+ endpoint: string,
29
+ options?: GemBalanceRequest
30
+ ): Promise<StandardResponse<GemBalanceResponse>> {
31
+ const method = options?.method || 'GET';
32
+ const query = options?.query || {};
33
+
34
+ if (method === 'GET') {
35
+ return await this.httpClient.get<StandardResponse<GemBalanceResponse>>(endpoint, {
36
+ query: query as Record<string, string>
37
+ });
38
+ } else {
39
+ return await this.httpClient.post<StandardResponse<GemBalanceResponse>>(endpoint, {
40
+ query: query as Record<string, string>
41
+ });
42
+ }
43
+ }
44
+
45
+ extractCacheableData(response: StandardResponse<GemBalanceResponse>): GemBalanceCacheData {
46
+ return {
47
+ balance: response.data?.balance || 0,
48
+ timestamp: Date.now()
49
+ };
50
+ }
51
+
52
+ // 宝石余额使用纯缓存模式
53
+ extractRealTimeData?: undefined;
54
+ mergeData?: undefined;
55
+
56
+ processCachedData(cached: GemBalanceCacheData): StandardResponse<GemBalanceResponse> {
57
+ return {
58
+ code: 'SUCCESS',
59
+ message: 'success from cache',
60
+ data: {
61
+ balance: cached.balance
62
+ }
63
+ };
64
+ }
65
+ }
66
+
67
+ // 缓存宝石余额服务
68
+ export class CachedGemBalanceService {
69
+ private gemBalanceService: RequestCacheService<
70
+ GemBalanceRequest,
71
+ StandardResponse<GemBalanceResponse>,
72
+ GemBalanceCacheData,
73
+ undefined
74
+ >;
75
+
76
+ constructor(httpClient: IHttpClient) {
77
+ this.gemBalanceService = new (RequestCacheService as new (...args: unknown[]) => RequestCacheService<
78
+ GemBalanceRequest,
79
+ StandardResponse<GemBalanceResponse>,
80
+ GemBalanceCacheData,
81
+ undefined
82
+ >)(new GemBalanceRequestAdapter(httpClient), {
83
+ duration: 20 * 60 * 1000, // 20分钟缓存(宝石余额变化较少)
84
+ timeout: 1000, // 1s timeout for request
85
+ keyGenerator: (endpoint: string, params?: GemBalanceRequest) => {
86
+ const queryStr = params?.query ? JSON.stringify(params.query) : '';
87
+ return `${endpoint}:${queryStr}`;
88
+ }
89
+ });
90
+ }
91
+
92
+ async getGemBalance(type = 'GEM'): Promise<GemBalanceResponse | undefined> {
93
+ const response = await this.gemBalanceService.request('/api/joli-gem/balance', {
94
+ endpoint: '/api/joli-gem/balance',
95
+ query: { type },
96
+ method: 'GET'
97
+ });
98
+ return response.data;
99
+ }
100
+
101
+ async refreshGemBalance(type = 'GEM'): Promise<GemBalanceResponse | undefined> {
102
+ const response = await this.gemBalanceService.forceRequest('/api/joli-gem/balance', {
103
+ endpoint: '/api/joli-gem/balance',
104
+ query: { type },
105
+ method: 'GET'
106
+ });
107
+ return response.data;
108
+ }
109
+
110
+ async warmupGemBalance(type = 'GEM'): Promise<void> {
111
+ await this.gemBalanceService.warmupCache('/api/joli-gem/balance', {
112
+ endpoint: '/api/joli-gem/balance',
113
+ query: { type },
114
+ method: 'GET'
115
+ });
116
+ }
117
+
118
+ clearGemBalanceCache(): void {
119
+ this.gemBalanceService.clearCache();
120
+ }
121
+
122
+ getGemBalanceCacheStats() {
123
+ return this.gemBalanceService.getCacheStats();
124
+ }
125
+
126
+ clearExpiredCache(): void {
127
+ this.gemBalanceService.clearExpiredCache();
128
+ }
129
+ }
130
+
131
+ // create instance
132
+ let cachedGemBalanceServiceInstance: CachedGemBalanceService | null = null;
133
+
134
+ function getCachedGemBalanceService(httpClient: IHttpClient): CachedGemBalanceService {
135
+ if (!cachedGemBalanceServiceInstance) {
136
+ cachedGemBalanceServiceInstance = new CachedGemBalanceService(httpClient);
137
+ }
138
+ return cachedGemBalanceServiceInstance;
139
+ }
140
+
141
+ /**
142
+ * 缓存版本的 fetchGemBalance 函数
143
+ */
144
+ export const fetchGemBalanceCached = async (httpClient: IHttpClient, type = 'GEM') => {
145
+ const cachedGemBalanceService = getCachedGemBalanceService(httpClient);
146
+ return await cachedGemBalanceService.getGemBalance(type);
147
+ };
148
+
149
+ /**
150
+ * 强制刷新宝石余额缓存
151
+ */
152
+ export const refreshGemBalanceCache = async (httpClient: IHttpClient, type = 'GEM') => {
153
+ const cachedGemBalanceService = getCachedGemBalanceService(httpClient);
154
+ const result = await cachedGemBalanceService.refreshGemBalance(type);
155
+ console.log(`Gem balance cache refreshed for type: ${type}`);
156
+ return result;
157
+ };
158
+
159
+ /**
160
+ * 预热宝石余额缓存
161
+ */
162
+ export const warmupGemBalanceCache = async (httpClient: IHttpClient, type = 'GEM') => {
163
+ const cachedGemBalanceService = getCachedGemBalanceService(httpClient);
164
+ await cachedGemBalanceService.warmupGemBalance(type);
165
+ console.log(`Gem balance cache warmed up for type: ${type}`);
166
+ };
167
+
168
+ export const clearGemBalanceCache = (httpClient: IHttpClient) => {
169
+ const cachedGemBalanceService = getCachedGemBalanceService(httpClient);
170
+ cachedGemBalanceService.clearGemBalanceCache();
171
+ console.log('Gem balance cache cleared');
172
+ };
173
+
174
+ export const getGemBalanceCacheStats = (httpClient: IHttpClient) => {
175
+ const cachedGemBalanceService = getCachedGemBalanceService(httpClient);
176
+ return cachedGemBalanceService.getGemBalanceCacheStats();
177
+ };
178
+
179
+ export const getGemBalanceCacheService = (httpClient: IHttpClient): CachedGemBalanceService => {
180
+ return getCachedGemBalanceService(httpClient);
181
+ };
@@ -1,7 +1,19 @@
1
1
  import { IHttpClient } from '@/common/http';
2
2
  import { StandardResponse } from '@jolibox/types';
3
3
 
4
- export const fetchGemBalance = async (httpClient: IHttpClient) => {
4
+ // export cached version as default implementation
5
+ export {
6
+ fetchGemBalanceCached as fetchGemBalance,
7
+ // 提供缓存管理功能
8
+ refreshGemBalanceCache,
9
+ warmupGemBalanceCache,
10
+ clearGemBalanceCache,
11
+ getGemBalanceCacheStats,
12
+ getGemBalanceCacheService
13
+ } from './cached-fetch-gem-balance';
14
+
15
+ // original version
16
+ export const fetchGemBalanceNonCached = async (httpClient: IHttpClient) => {
5
17
  const res = await httpClient.get<
6
18
  StandardResponse<{
7
19
  balance: number;
@@ -15,6 +15,7 @@ import {
15
15
  import { registerUseJolicoinCommand, createShowUnlockWithCurrencyModal } from '../commands/use-jolicoin';
16
16
  import { rewardsCommands } from '../rewards-command';
17
17
  import { RewardsCommandType } from '@jolibox/types';
18
+ import { refreshGemBalanceCache, warmupGemBalanceCache } from './cached-fetch-gem-balance';
18
19
 
19
20
  interface IGemUnlockRes {
20
21
  code: 'SUCCESS' | 'BALANCE_NOT_ENOUGH' | 'EPISODE_LOCK_JUMP' | 'EPISODE_UNLOCK_ALREADY';
@@ -103,6 +104,7 @@ export const createCommonGemRewardHandler = (
103
104
  if ('adViewed' in params) {
104
105
  params.adViewed?.();
105
106
  }
107
+ refreshGemBalanceCache(httpClient);
106
108
  } catch (e) {
107
109
  console.error('-----unlockWithGem adBreakDone error-----', e);
108
110
  }
@@ -0,0 +1 @@
1
+ export * from './use-subscription';
@@ -0,0 +1,29 @@
1
+ import { rewardsCommands } from '../../coins/rewards-command';
2
+ import { createEventPromiseHandler } from '../../event-listener';
3
+ import { IUseSubscriptionResultEvent, UseSubscriptionResultEventName } from '@/common/rewards/reward-emitter';
4
+ import { rewardsEmitter, InvokeSubscriptionEventName } from '@/common/rewards/reward-emitter';
5
+
6
+ export const registerUseSubscriptionCommand = (params: {
7
+ showSubscriptionModal: () => Promise<'SUCCESS' | 'CANCEL' | 'FAILED'>;
8
+ }) => {
9
+ const { showSubscriptionModal } = params;
10
+ rewardsCommands.registerCommand(`Rewards.subscription`, async () => {
11
+ const subscriptionResult = await showSubscriptionModal();
12
+ return {
13
+ result: subscriptionResult === 'SUCCESS' ? 'SUCCESS' : 'FAILED'
14
+ };
15
+ });
16
+ };
17
+
18
+ // EVENTS
19
+ export const createShowSubscriptionModal = (type: 'SUBSCRIPTION') => {
20
+ return async () => {
21
+ const modalHandler = createEventPromiseHandler<
22
+ IUseSubscriptionResultEvent,
23
+ typeof UseSubscriptionResultEventName
24
+ >(rewardsEmitter, UseSubscriptionResultEventName);
25
+ rewardsEmitter.emit(InvokeSubscriptionEventName, type);
26
+ const modalResult = await modalHandler.getFreshData();
27
+ return modalResult.result;
28
+ };
29
+ };