@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.
- package/.rush/temp/package-deps_build.json +36 -23
- package/CHANGELOG.json +11 -0
- package/CHANGELOG.md +9 -0
- package/dist/common/report/base-tracker.d.ts +2 -1
- package/dist/common/rewards/cached-fetch-reward.d.ts +46 -0
- package/dist/common/rewards/cached-reward-service.d.ts +24 -0
- package/dist/common/rewards/fetch-reward.d.ts +2 -3
- package/dist/common/rewards/index.d.ts +3 -0
- package/dist/common/rewards/registers/use-subscription.d.ts +7 -0
- package/dist/common/rewards/registers/utils/coins/jolicoin/cached-fetch-balance.d.ts +34 -0
- package/dist/common/rewards/registers/utils/coins/jolicoin/fetch-balance.d.ts +2 -1
- package/dist/common/rewards/registers/utils/coins/joligem/cached-fetch-gem-balance.d.ts +34 -0
- package/dist/common/rewards/registers/utils/coins/joligem/fetch-gem-balance.d.ts +2 -1
- package/dist/common/rewards/registers/utils/subscription/commands/index.d.ts +1 -0
- package/dist/common/rewards/registers/utils/subscription/commands/use-subscription.d.ts +4 -0
- package/dist/common/rewards/registers/utils/subscription/sub-handler.d.ts +13 -0
- package/dist/common/rewards/reward-emitter.d.ts +7 -0
- package/dist/common/rewards/reward-helper.d.ts +2 -1
- package/dist/common/utils/index.d.ts +18 -0
- package/dist/h5/api/platformAdsHandle/JoliboxAdsHandler.d.ts +1 -0
- package/dist/h5/bootstrap/auth/__tests__/auth.test.d.ts +1 -0
- package/dist/h5/bootstrap/auth/index.d.ts +2 -0
- package/dist/h5/bootstrap/auth/sub.d.ts +2 -0
- package/dist/index.js +9 -9
- package/dist/index.native.js +49 -49
- package/dist/native/payment/payment-service.d.ts +36 -30
- package/implement.build.log +2 -2
- package/package.json +7 -7
- package/src/common/report/base-tracker.ts +2 -2
- package/src/common/rewards/cached-fetch-reward.ts +258 -0
- package/src/common/rewards/cached-reward-service.ts +255 -0
- package/src/common/rewards/fetch-reward.ts +17 -93
- package/src/common/rewards/index.ts +4 -0
- package/src/common/rewards/registers/use-subscription.ts +34 -0
- package/src/common/rewards/registers/utils/coins/jolicoin/cached-fetch-balance.ts +177 -0
- package/src/common/rewards/registers/utils/coins/jolicoin/fetch-balance.ts +13 -1
- package/src/common/rewards/registers/utils/coins/jolicoin/jolicoin-handler.ts +2 -0
- package/src/common/rewards/registers/utils/coins/joligem/cached-fetch-gem-balance.ts +181 -0
- package/src/common/rewards/registers/utils/coins/joligem/fetch-gem-balance.ts +13 -1
- package/src/common/rewards/registers/utils/coins/joligem/gem-handler.ts +2 -0
- package/src/common/rewards/registers/utils/subscription/commands/index.ts +1 -0
- package/src/common/rewards/registers/utils/subscription/commands/use-subscription.ts +29 -0
- package/src/common/rewards/registers/utils/subscription/sub-handler.ts +88 -0
- package/src/common/rewards/reward-emitter.ts +8 -0
- package/src/common/rewards/reward-helper.ts +8 -1
- package/src/common/utils/index.ts +23 -0
- package/src/h5/api/ads.ts +18 -12
- package/src/h5/api/platformAdsHandle/JoliboxAdsHandler.ts +25 -1
- package/src/h5/api/storage.ts +2 -2
- package/src/h5/bootstrap/auth/__tests__/auth.test.ts +308 -0
- package/src/h5/bootstrap/auth/index.ts +20 -0
- package/src/h5/bootstrap/auth/sub.ts +56 -0
- package/src/h5/bootstrap/index.ts +4 -19
- package/src/h5/http/index.ts +2 -2
- package/src/h5/report/event-tracker.ts +2 -2
- package/src/h5/rewards/index.ts +18 -1
- package/src/native/api/ads.ts +7 -1
- package/src/native/api/payment.ts +4 -4
- package/src/native/payment/__tests__/payment-service-simple.test.ts +97 -31
- package/src/native/payment/payment-service.ts +224 -210
- package/src/native/rewards/ui/payment-modal.ts +14 -7
|
@@ -1,38 +1,44 @@
|
|
|
1
1
|
import { IPaymentChoice } from '@/common/rewards/reward-emitter';
|
|
2
2
|
import type { PaymentResult } from './payment-helper';
|
|
3
|
+
import { RequestCacheService } from '@jolibox/common';
|
|
3
4
|
type PaymentPurchaseType = 'JOLI_COIN' | 'JOLI_GEM';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
type PaymentRequest = Record<string, never>;
|
|
6
|
+
interface PaymentResponse {
|
|
7
|
+
balance: number;
|
|
8
|
+
enableAutoDeduct: boolean;
|
|
9
|
+
paymentChoices: IPaymentChoice[];
|
|
9
10
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
interface PaymentCacheData {
|
|
12
|
+
paymentChoices: IPaymentChoice[];
|
|
13
|
+
}
|
|
14
|
+
interface PaymentRealTimeData {
|
|
15
|
+
balance: number;
|
|
16
|
+
enableAutoDeduct: boolean;
|
|
17
|
+
}
|
|
18
|
+
declare class BasePaymentService extends RequestCacheService<PaymentRequest, PaymentResponse, PaymentCacheData, PaymentRealTimeData> {
|
|
19
|
+
private apiEndpoint;
|
|
20
|
+
private paymentType;
|
|
21
|
+
private static failureCounters;
|
|
22
|
+
private static readonly MAX_FAILURE_COUNT;
|
|
23
|
+
constructor(apiEndpoint: string, paymentType: PaymentPurchaseType);
|
|
24
|
+
getProductsInfo(): Promise<PaymentResponse | undefined>;
|
|
25
|
+
purchase(productId: string): Promise<PaymentResult<{
|
|
16
26
|
totalAmount: string;
|
|
17
27
|
}>>;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
private static arraysEqual;
|
|
29
|
-
private static updateChoicesWithServerData;
|
|
30
|
-
static clearPaymentChoicesCache(apiEndpoint?: string): void;
|
|
31
|
-
static getPaymentChoicesCacheStats(): {
|
|
32
|
-
cacheCount: number;
|
|
33
|
-
validCount: number;
|
|
34
|
-
expiredCount: number;
|
|
35
|
-
};
|
|
36
|
-
static clearExpiredPaymentChoicesCache(): void;
|
|
28
|
+
getProductsInfoWithBalance(): Promise<PaymentResponse | undefined>;
|
|
29
|
+
refreshProductsInfo(): Promise<PaymentResponse | undefined>;
|
|
30
|
+
static resetFailureCounters(): void;
|
|
31
|
+
static getFailureCount(endpoint: string): number;
|
|
32
|
+
}
|
|
33
|
+
export declare class JoliCoinPaymentService extends BasePaymentService {
|
|
34
|
+
constructor();
|
|
35
|
+
}
|
|
36
|
+
export declare class JoliGemPaymentService extends BasePaymentService {
|
|
37
|
+
constructor();
|
|
37
38
|
}
|
|
39
|
+
export declare const createJoliCoinPaymentService: () => JoliCoinPaymentService;
|
|
40
|
+
export declare const createJoliGemPaymentService: () => JoliGemPaymentService;
|
|
41
|
+
export declare const clearNativePriceCache: () => void;
|
|
42
|
+
export declare const resetFailureCounters: () => void;
|
|
43
|
+
export declare const getFailureCount: (endpoint: string) => number;
|
|
38
44
|
export {};
|
package/implement.build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Invoking: npm run clean && npm run build:esm && tsc
|
|
2
2
|
|
|
3
|
-
> @jolibox/implement@1.2.
|
|
3
|
+
> @jolibox/implement@1.2.5-beta.3 clean
|
|
4
4
|
> rimraf ./dist
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
> @jolibox/implement@1.2.
|
|
7
|
+
> @jolibox/implement@1.2.5-beta.3 build:esm
|
|
8
8
|
> BUILD_VERSION=$(node -p "require('./package.json').version") node esbuild.config.js --format=esm
|
|
9
9
|
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jolibox/implement",
|
|
3
3
|
"description": "This project is Jolibox JS-SDk implement for Native && H5",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.5-beta.3",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@jolibox/common": "1.2.
|
|
10
|
-
"@jolibox/types": "1.2.
|
|
11
|
-
"@jolibox/native-bridge": "1.2.
|
|
12
|
-
"@jolibox/ads": "1.2.
|
|
9
|
+
"@jolibox/common": "1.2.5-beta.3",
|
|
10
|
+
"@jolibox/types": "1.2.5-beta.3",
|
|
11
|
+
"@jolibox/native-bridge": "1.2.5-beta.3",
|
|
12
|
+
"@jolibox/ads": "1.2.5-beta.3",
|
|
13
13
|
"localforage": "1.10.0",
|
|
14
|
-
"@jolibox/ui": "1.
|
|
14
|
+
"@jolibox/ui": "1.2.5-beta.3",
|
|
15
15
|
"web-vitals": "4.2.4"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@types/node": "18.0.0",
|
|
21
21
|
"rimraf": "6.0.1",
|
|
22
22
|
"esbuild": "0.24.2",
|
|
23
|
-
"@jolibox/eslint-config": "1.0.
|
|
23
|
+
"@jolibox/eslint-config": "1.0.1-beta.11"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"clean": "rimraf ./dist",
|
|
@@ -22,12 +22,12 @@ export abstract class EventTracker {
|
|
|
22
22
|
|
|
23
23
|
private samplesConfig: ISamplesConfig | null = null;
|
|
24
24
|
|
|
25
|
-
constructor() {
|
|
25
|
+
constructor(readonly apiHost: string) {
|
|
26
26
|
this.fetchSamplesConfig();
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
private async fetchSamplesConfig() {
|
|
30
|
-
const host =
|
|
30
|
+
const host = this.apiHost;
|
|
31
31
|
const path = `${host}/api/fe-configs/js-sdk/samples-config`;
|
|
32
32
|
const samplesConfig = (await (await fetch(path)).json()) as ISamplesConfig;
|
|
33
33
|
this.samplesConfig = samplesConfig;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { IHttpClient } from '../http';
|
|
2
|
+
import { RewardsHelper, RewardType } from './reward-helper';
|
|
3
|
+
import { CachedRewardService } from './cached-reward-service';
|
|
4
|
+
import { IUnlockOption } from './type';
|
|
5
|
+
import {
|
|
6
|
+
UnlockOptionsEventName,
|
|
7
|
+
UseModalFrequencyEventName,
|
|
8
|
+
rewardsEmitter,
|
|
9
|
+
DefaltJoliCoinUseAndCharge,
|
|
10
|
+
DefaltLoginGuide
|
|
11
|
+
} from './reward-emitter';
|
|
12
|
+
import { hostEmitter } from '@jolibox/common';
|
|
13
|
+
import { StandardResponse, GlobalConfig } from '@jolibox/types';
|
|
14
|
+
|
|
15
|
+
const priority = () => {
|
|
16
|
+
return (a: RewardType, b: RewardType) => {
|
|
17
|
+
// Priority order: GEM > JOLI_COIN > ADS
|
|
18
|
+
const priorityMap: Record<RewardType, number> = {
|
|
19
|
+
SUBSCRIPTION: 4,
|
|
20
|
+
JOLI_GEM: 3,
|
|
21
|
+
JOLI_GEM_ONLY: 3,
|
|
22
|
+
JOLI_COIN: 2,
|
|
23
|
+
JOLI_COIN_ONLY: 2,
|
|
24
|
+
ADS: 1
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return priorityMap[b] - priorityMap[a];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const sortRewards = (rewardsTypes: RewardType[]): RewardType[] => {
|
|
32
|
+
if (!rewardsTypes.length) return ['ADS'];
|
|
33
|
+
|
|
34
|
+
// Handle JOLI_GEM cases
|
|
35
|
+
if (rewardsTypes.includes('JOLI_GEM')) {
|
|
36
|
+
if (rewardsTypes.length === 1) {
|
|
37
|
+
return ['JOLI_GEM_ONLY'];
|
|
38
|
+
} else if (rewardsTypes.includes('SUBSCRIPTION') && rewardsTypes.length === 2) {
|
|
39
|
+
return ['SUBSCRIPTION', 'JOLI_GEM_ONLY'];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Handle JOLI_COIN cases
|
|
44
|
+
if (rewardsTypes.includes('JOLI_COIN')) {
|
|
45
|
+
if (rewardsTypes.length === 1) {
|
|
46
|
+
return ['JOLI_COIN_ONLY'];
|
|
47
|
+
} else if (rewardsTypes.includes('SUBSCRIPTION') && rewardsTypes.length === 2) {
|
|
48
|
+
return ['SUBSCRIPTION', 'JOLI_COIN_ONLY'];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return rewardsTypes.sort(priority());
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// 创建缓存奖励服务的单例
|
|
56
|
+
let cachedRewardServiceInstance: CachedRewardService | null = null;
|
|
57
|
+
|
|
58
|
+
function getCachedRewardService(httpClient: IHttpClient): CachedRewardService {
|
|
59
|
+
if (!cachedRewardServiceInstance) {
|
|
60
|
+
cachedRewardServiceInstance = new CachedRewardService(httpClient);
|
|
61
|
+
}
|
|
62
|
+
return cachedRewardServiceInstance;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 使用缓存的奖励获取器
|
|
67
|
+
* 优化版本:unlockOptions 使用缓存,余额信息实时获取
|
|
68
|
+
*/
|
|
69
|
+
export const createCachedRewardFetcher = (rewardsHelper: RewardsHelper) => {
|
|
70
|
+
rewardsHelper.registerRewardsFetcher(async (httpClient: IHttpClient) => {
|
|
71
|
+
const defaultRewards: RewardType[] = ['ADS'];
|
|
72
|
+
const cachedRewardService = getCachedRewardService(httpClient);
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const res = await cachedRewardService.getUnlockOptions({});
|
|
76
|
+
|
|
77
|
+
if (res.code !== 'SUCCESS') {
|
|
78
|
+
return defaultRewards;
|
|
79
|
+
}
|
|
80
|
+
// 发送事件通知
|
|
81
|
+
rewardsEmitter.emit(UnlockOptionsEventName, {
|
|
82
|
+
options: res.data?.unlockOptions || [],
|
|
83
|
+
userJoliCoin: res.extra?.joliCoin || {
|
|
84
|
+
balance: 0,
|
|
85
|
+
enableAutoDeduct: false
|
|
86
|
+
},
|
|
87
|
+
userGem: res.extra?.joliGem || {
|
|
88
|
+
balance: 0,
|
|
89
|
+
enableAutoDeduct: false
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const rewardsTypes =
|
|
94
|
+
res.data?.unlockOptions?.map((option: IUnlockOption) => option.type) || Array.from(defaultRewards);
|
|
95
|
+
|
|
96
|
+
return sortRewards(rewardsTypes);
|
|
97
|
+
} catch (e) {
|
|
98
|
+
console.error('getRewardOptions error (cached):', e);
|
|
99
|
+
return defaultRewards;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 使用缓存的频率配置获取器
|
|
106
|
+
* 优化版本:全局配置使用纯缓存
|
|
107
|
+
*/
|
|
108
|
+
export const createCachedRewardFrequencyConfigFetcher = (rewardsHelper: RewardsHelper) => {
|
|
109
|
+
rewardsHelper.registerRewardFrequencyConfigFetcher(async (httpClient: IHttpClient) => {
|
|
110
|
+
const cachedRewardService = getCachedRewardService(httpClient);
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const res = await cachedRewardService.getGlobalConfig();
|
|
114
|
+
|
|
115
|
+
// 发送事件通知
|
|
116
|
+
rewardsEmitter.emit(UseModalFrequencyEventName, {
|
|
117
|
+
joliCoinUseAndCharge: res.data?.joliCoinUseAndCharge || DefaltJoliCoinUseAndCharge,
|
|
118
|
+
loginGuide: res.data?.loginGuide || DefaltLoginGuide
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
res.data &&
|
|
122
|
+
hostEmitter.emit('onGlobalConfigChanged', {
|
|
123
|
+
globalConfig: res.data
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
joliCoinUseAndCharge: res.data?.joliCoinUseAndCharge || DefaltJoliCoinUseAndCharge,
|
|
128
|
+
loginGuide: res.data?.loginGuide || DefaltLoginGuide
|
|
129
|
+
};
|
|
130
|
+
} catch (e) {
|
|
131
|
+
console.error('getGlobalConfig error (cached):', e);
|
|
132
|
+
// 发送兜底事件通知
|
|
133
|
+
rewardsEmitter.emit(UseModalFrequencyEventName, {
|
|
134
|
+
joliCoinUseAndCharge: DefaltJoliCoinUseAndCharge,
|
|
135
|
+
loginGuide: DefaltLoginGuide
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
hostEmitter.emit('onGlobalConfigChanged', {
|
|
139
|
+
globalConfig: {
|
|
140
|
+
joliCoinUseAndCharge: DefaltJoliCoinUseAndCharge,
|
|
141
|
+
loginGuide: DefaltLoginGuide
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
joliCoinUseAndCharge: DefaltJoliCoinUseAndCharge,
|
|
146
|
+
loginGuide: DefaltLoginGuide
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* 获取缓存服务实例(用于手动管理缓存)
|
|
154
|
+
*/
|
|
155
|
+
export const getRewardCacheService = (httpClient: IHttpClient): CachedRewardService => {
|
|
156
|
+
return getCachedRewardService(httpClient);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 强制刷新奖励数据缓存
|
|
161
|
+
*/
|
|
162
|
+
export const refreshRewardCache = async (httpClient: IHttpClient) => {
|
|
163
|
+
const cachedRewardService = getCachedRewardService(httpClient);
|
|
164
|
+
await cachedRewardService.refreshUnlockOptions({});
|
|
165
|
+
console.log('Reward cache refreshed');
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 强制刷新全局配置缓存
|
|
170
|
+
*/
|
|
171
|
+
export const refreshGlobalConfigCache = async (httpClient: IHttpClient) => {
|
|
172
|
+
const cachedRewardService = getCachedRewardService(httpClient);
|
|
173
|
+
await cachedRewardService.refreshGlobalConfig();
|
|
174
|
+
console.log('Global config cache refreshed');
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 预热所有缓存
|
|
179
|
+
*/
|
|
180
|
+
export const warmupRewardCache = async (httpClient: IHttpClient) => {
|
|
181
|
+
const cachedRewardService = getCachedRewardService(httpClient);
|
|
182
|
+
await cachedRewardService.warmupCache();
|
|
183
|
+
console.log('Reward cache warmed up');
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* 清除所有奖励相关缓存
|
|
188
|
+
*/
|
|
189
|
+
export const clearRewardCache = (httpClient: IHttpClient) => {
|
|
190
|
+
const cachedRewardService = getCachedRewardService(httpClient);
|
|
191
|
+
cachedRewardService.clearAllCache();
|
|
192
|
+
console.log('All reward cache cleared');
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 获取缓存统计信息
|
|
197
|
+
*/
|
|
198
|
+
export const getRewardCacheStats = (httpClient: IHttpClient) => {
|
|
199
|
+
const cachedRewardService = getCachedRewardService(httpClient);
|
|
200
|
+
return cachedRewardService.getCacheStats();
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// 保持原有的创建器以便向后兼容
|
|
204
|
+
export const createRewardFetcher = (rewardsHelper: RewardsHelper) => {
|
|
205
|
+
rewardsHelper.registerRewardsFetcher(async (httpClient: IHttpClient) => {
|
|
206
|
+
const defaultRewards: RewardType[] = ['ADS'];
|
|
207
|
+
try {
|
|
208
|
+
const res = await httpClient.post('/api/games/unlock-options', {});
|
|
209
|
+
if (res.code !== 'SUCCESS') {
|
|
210
|
+
return defaultRewards;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
console.log('-----res fetch reward-----', res);
|
|
214
|
+
rewardsEmitter.emit(UnlockOptionsEventName, {
|
|
215
|
+
options: res.data?.unlockOptions || [],
|
|
216
|
+
userJoliCoin: res.extra?.joliCoin || {
|
|
217
|
+
balance: 0,
|
|
218
|
+
enableAutoDeduct: false
|
|
219
|
+
},
|
|
220
|
+
userGem: res.extra?.joliGem || {
|
|
221
|
+
balance: 0,
|
|
222
|
+
enableAutoDeduct: false
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const rewardsTypes =
|
|
227
|
+
res.data?.unlockOptions?.map((option: IUnlockOption) => option.type) || Array.from(defaultRewards);
|
|
228
|
+
return sortRewards(rewardsTypes);
|
|
229
|
+
} catch (e) {
|
|
230
|
+
console.error('getRewardOptions error:', e);
|
|
231
|
+
return defaultRewards;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export const createRewardFrequencyConfigFetcher = (rewardsHelper: RewardsHelper) => {
|
|
237
|
+
rewardsHelper.registerRewardFrequencyConfigFetcher(async (httpClient: IHttpClient) => {
|
|
238
|
+
const res: StandardResponse<GlobalConfig> = await httpClient.get(
|
|
239
|
+
'/api/fe-configs/web-common/global-config',
|
|
240
|
+
{}
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
rewardsEmitter.emit(UseModalFrequencyEventName, {
|
|
244
|
+
joliCoinUseAndCharge: res.data?.joliCoinUseAndCharge || DefaltJoliCoinUseAndCharge,
|
|
245
|
+
loginGuide: res.data?.loginGuide || DefaltLoginGuide
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
res.data &&
|
|
249
|
+
hostEmitter.emit('onGlobalConfigChanged', {
|
|
250
|
+
globalConfig: res.data
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
joliCoinUseAndCharge: res.data?.joliCoinUseAndCharge || DefaltJoliCoinUseAndCharge,
|
|
255
|
+
loginGuide: res.data?.loginGuide || DefaltLoginGuide
|
|
256
|
+
};
|
|
257
|
+
});
|
|
258
|
+
};
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { RequestCacheService, RequestAdapter } from '@jolibox/common';
|
|
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
|
+
}
|