@jolibox/implement 1.2.5-beta.3 → 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 (48) hide show
  1. package/.rush/temp/package-deps_build.json +17 -24
  2. package/dist/common/cache/request-cache-service.d.ts +111 -0
  3. package/dist/common/rewards/cached-fetch-reward.d.ts +2 -2
  4. package/dist/common/rewards/cached-reward-service.d.ts +2 -2
  5. package/dist/common/rewards/index.d.ts +0 -1
  6. package/dist/common/rewards/registers/utils/coins/jolicoin/cached-fetch-balance.d.ts +2 -2
  7. package/dist/common/rewards/registers/utils/coins/joligem/cached-fetch-gem-balance.d.ts +2 -2
  8. package/dist/common/rewards/reward-emitter.d.ts +0 -7
  9. package/dist/common/rewards/reward-helper.d.ts +1 -2
  10. package/dist/common/utils/index.d.ts +0 -18
  11. package/dist/h5/api/platformAdsHandle/JoliboxAdsHandler.d.ts +0 -1
  12. package/dist/index.js +9 -9
  13. package/dist/index.native.js +47 -47
  14. package/dist/native/payment/payment-service.d.ts +1 -1
  15. package/implement.build.log +2 -2
  16. package/package.json +7 -7
  17. package/src/common/cache/__tests__/request-cache-service.test.ts +686 -0
  18. package/src/common/cache/request-cache-service.ts +393 -0
  19. package/src/common/rewards/cached-fetch-reward.ts +2 -19
  20. package/src/common/rewards/cached-reward-service.ts +3 -3
  21. package/src/common/rewards/index.ts +0 -1
  22. package/src/common/rewards/registers/utils/coins/commands/use-payment.ts +8 -0
  23. package/src/common/rewards/registers/utils/coins/jolicoin/cached-fetch-balance.ts +1 -1
  24. package/src/common/rewards/registers/utils/coins/joligem/cached-fetch-gem-balance.ts +1 -1
  25. package/src/common/rewards/reward-emitter.ts +0 -8
  26. package/src/common/rewards/reward-helper.ts +1 -8
  27. package/src/common/utils/index.ts +0 -23
  28. package/src/h5/api/ads.ts +13 -14
  29. package/src/h5/api/platformAdsHandle/JoliboxAdsHandler.ts +1 -25
  30. package/src/h5/bootstrap/index.ts +19 -4
  31. package/src/h5/rewards/index.ts +1 -18
  32. package/src/native/payment/payment-service.ts +1 -1
  33. package/CHANGELOG.json +0 -11
  34. package/CHANGELOG.md +0 -9
  35. package/dist/common/rewards/registers/use-subscription.d.ts +0 -7
  36. package/dist/common/rewards/registers/utils/subscription/commands/index.d.ts +0 -1
  37. package/dist/common/rewards/registers/utils/subscription/commands/use-subscription.d.ts +0 -4
  38. package/dist/common/rewards/registers/utils/subscription/sub-handler.d.ts +0 -13
  39. package/dist/h5/bootstrap/auth/index.d.ts +0 -2
  40. package/dist/h5/bootstrap/auth/sub.d.ts +0 -2
  41. package/src/common/rewards/registers/use-subscription.ts +0 -34
  42. package/src/common/rewards/registers/utils/subscription/commands/index.ts +0 -1
  43. package/src/common/rewards/registers/utils/subscription/commands/use-subscription.ts +0 -29
  44. package/src/common/rewards/registers/utils/subscription/sub-handler.ts +0 -88
  45. package/src/h5/bootstrap/auth/__tests__/auth.test.ts +0 -308
  46. package/src/h5/bootstrap/auth/index.ts +0 -20
  47. package/src/h5/bootstrap/auth/sub.ts +0 -56
  48. /package/dist/{h5/bootstrap/auth/__tests__/auth.test.d.ts → common/cache/__tests__/request-cache-service.test.d.ts} +0 -0
@@ -0,0 +1,393 @@
1
+ /**
2
+ * 通用请求缓存服务基类
3
+ * 支持部分数据缓存,部分数据实时获取的混合模式
4
+ */
5
+
6
+ export interface CacheConfig<TCacheData, TServerData> {
7
+ /** 缓存持续时间,默认10分钟 */
8
+ duration?: number;
9
+ /** 请求超时时间,默认3秒 */
10
+ timeout?: number;
11
+ /** 缓存键生成函数 */
12
+ keyGenerator?: <TRequest>(endpoint: string, params?: TRequest) => string;
13
+ /** 数据一致性校验函数 */
14
+ consistencyChecker?: (cached: TCacheData, serverData: TServerData) => boolean;
15
+ }
16
+
17
+ export interface CacheEntry<T> {
18
+ data: T;
19
+ timestamp: number;
20
+ expiresAt: number;
21
+ key: string;
22
+ sequence: number; // 请求序列号
23
+ metadata?: Record<string, unknown>;
24
+ }
25
+
26
+ export interface CacheStats {
27
+ cacheCount: number;
28
+ validCount: number;
29
+ expiredCount: number;
30
+ }
31
+
32
+ export interface RequestAdapter<TRequest, TResponse, TCacheData, TRealTimeData> {
33
+ /** 执行实际的网络请求 */
34
+ execute(endpoint: string, options?: TRequest): Promise<TResponse>;
35
+ /** 从响应中提取需要缓存的部分(不变数据) */
36
+ extractCacheableData?(response: TResponse): TCacheData;
37
+ /** 从响应中提取实时数据部分(变化数据) */
38
+ extractRealTimeData?(response: TResponse): TRealTimeData;
39
+ /** 合并缓存数据和实时数据 */
40
+ mergeData?(cached: TCacheData, realTime: TRealTimeData): TResponse;
41
+ /** 处理纯缓存场景的数据,当没有新的网络请求时 */
42
+ processCachedData?(cached: TCacheData): TResponse;
43
+ }
44
+
45
+ export abstract class RequestCacheService<TRequest, TResponse, TCacheData, TRealTimeData> {
46
+ private cache = new Map<string, CacheEntry<TCacheData>>();
47
+ private readonly config: {
48
+ duration: number;
49
+ timeout: number;
50
+ keyGenerator: <TReq>(endpoint: string, params?: TReq) => string;
51
+ consistencyChecker: (cached: TCacheData, serverData: TCacheData) => boolean;
52
+ };
53
+
54
+ // 请求去重:每个key只允许同时有一个正在进行的请求
55
+ private pendingRequests = new Map<string, Promise<TResponse>>();
56
+
57
+ // 请求序列号:防止晚到的请求覆盖早发出的请求结果
58
+ private requestSequence = 0;
59
+ private cacheSequences = new Map<string, number>();
60
+
61
+ constructor(
62
+ protected requestAdapter: RequestAdapter<TRequest, TResponse, TCacheData, TRealTimeData>,
63
+ config: Partial<CacheConfig<TCacheData, TCacheData>> = {}
64
+ ) {
65
+ this.config = {
66
+ duration: 10 * 60 * 1000, // 10分钟
67
+ timeout: 3000, // 3秒
68
+ keyGenerator: <TReq>(endpoint: string, _params?: TReq) => endpoint,
69
+ consistencyChecker: () => true,
70
+ ...config
71
+ };
72
+ }
73
+
74
+ /**
75
+ * 带缓存的请求方法 - 缓存优先 + 实时数据混合模式 + 请求去重
76
+ */
77
+ async request(endpoint: string, options?: TRequest): Promise<TResponse> {
78
+ const cacheKey = this.config.keyGenerator(endpoint, options);
79
+
80
+ // 检查是否有正在进行的请求,如果有则等待其完成
81
+ const pendingRequest = this.pendingRequests.get(cacheKey);
82
+ if (pendingRequest) {
83
+ console.log(`[RequestCacheService] Reusing pending request for ${endpoint}`);
84
+ return pendingRequest;
85
+ }
86
+
87
+ // internal request promise for background update
88
+ const internalRequestPromise = this.requestInternal(endpoint, options);
89
+
90
+ // createTimeoutPromise
91
+ const timeoutPromise = this.createTimeoutPromise();
92
+
93
+ // usePromiseRace
94
+ const racedPromise = Promise.race([internalRequestPromise, timeoutPromise]).catch(async (error) => {
95
+ // if timeout error, try to get data from cache as fallback
96
+ if (error.message.includes('timeout')) {
97
+ const cachedData = this.getValidCachedData(cacheKey);
98
+ if (cachedData) {
99
+ console.warn(`[RequestCacheService] Request timeout, falling back to cache for ${endpoint}`);
100
+ return this.requestAdapter.processCachedData
101
+ ? this.requestAdapter.processCachedData(cachedData)
102
+ : (cachedData as TResponse);
103
+ }
104
+ }
105
+ throw error;
106
+ });
107
+
108
+ this.pendingRequests.set(cacheKey, racedPromise);
109
+
110
+ // ensure internal request can be completed in background for cache update
111
+ internalRequestPromise
112
+ .then((result) => {
113
+ // 成功时不需要特殊处理,requestInternal 已经更新了缓存
114
+ console.log(`[RequestCacheService] Background request completed successfully for ${endpoint}`);
115
+ })
116
+ .catch((error) => {
117
+ console.warn(`[RequestCacheService] Background request failed for ${endpoint}:`, error);
118
+ });
119
+
120
+ try {
121
+ const result = await racedPromise;
122
+ return result;
123
+ } finally {
124
+ // 请求完成后清理 pending request
125
+ this.pendingRequests.delete(cacheKey);
126
+ }
127
+ }
128
+
129
+ private async requestInternal(endpoint: string, options?: TRequest): Promise<TResponse> {
130
+ const cacheKey = this.config.keyGenerator(endpoint, options);
131
+ const currentSequence = ++this.requestSequence; // 生成请求序列号
132
+
133
+ const cachedData = this.getValidCachedData(cacheKey);
134
+
135
+ console.log('[RequestCacheService] requestInternal start', endpoint, 'cached:', cachedData);
136
+ if (cachedData) {
137
+ if (this.requestAdapter.extractRealTimeData && this.requestAdapter.mergeData) {
138
+ try {
139
+ const freshResponse = await this.requestAdapter.execute(endpoint, options);
140
+ const realTimeData = this.requestAdapter.extractRealTimeData(freshResponse);
141
+
142
+ const serverCacheableData = this.requestAdapter.extractCacheableData?.(freshResponse);
143
+ if (serverCacheableData && !this.config.consistencyChecker(cachedData, serverCacheableData)) {
144
+ console.log(`[RequestCacheService] Cache invalidated due to data change for ${endpoint}`);
145
+ this.setCachedDataWithSequence(cacheKey, serverCacheableData, currentSequence);
146
+ return freshResponse;
147
+ }
148
+
149
+ return this.requestAdapter.mergeData(cachedData, realTimeData);
150
+ } catch (error) {
151
+ console.warn(
152
+ `[RequestCacheService] Failed to fetch real-time data, using cache only for ${endpoint}:`,
153
+ error
154
+ );
155
+ return this.requestAdapter.processCachedData
156
+ ? this.requestAdapter.processCachedData(cachedData)
157
+ : (cachedData as TResponse);
158
+ }
159
+ }
160
+
161
+ console.log(`[RequestCacheService] use cache for ${endpoint}`);
162
+ return this.requestAdapter.processCachedData
163
+ ? this.requestAdapter.processCachedData(cachedData)
164
+ : (cachedData as TResponse);
165
+ }
166
+
167
+ console.log(
168
+ `[RequestCacheService] Cache miss, fetching fresh data for ${endpoint} (sequence: ${currentSequence})`
169
+ );
170
+ const freshResponse = await this.requestAdapter.execute(endpoint, options);
171
+
172
+ const serverCacheableData = this.requestAdapter.extractCacheableData?.(freshResponse);
173
+ if (serverCacheableData) {
174
+ this.setCachedDataWithSequence(cacheKey, serverCacheableData, currentSequence);
175
+ }
176
+
177
+ return freshResponse;
178
+ }
179
+
180
+ /**
181
+ * timeout
182
+ */
183
+ private createTimeoutPromise(): Promise<never> {
184
+ return new Promise((_, reject) => {
185
+ setTimeout(() => {
186
+ reject(
187
+ new Error(`[RequestCacheService] Request timeout after ${this.config.timeout / 1000} seconds`)
188
+ );
189
+ }, this.config.timeout);
190
+ });
191
+ }
192
+
193
+ /**
194
+ * get valid cached data
195
+ */
196
+ private getValidCachedData(key: string): TCacheData | null {
197
+ const cached = this.cache.get(key);
198
+
199
+ if (!cached) {
200
+ return null;
201
+ }
202
+
203
+ // 检查过期
204
+ if (Date.now() > cached.expiresAt) {
205
+ this.cache.delete(key);
206
+ return null;
207
+ }
208
+
209
+ return cached.data;
210
+ }
211
+
212
+ /**
213
+ * 设置缓存数据 (带序列号检查)
214
+ */
215
+ private setCachedDataWithSequence(
216
+ key: string,
217
+ data: TCacheData,
218
+ sequence: number,
219
+ metadata?: Record<string, unknown>
220
+ ): void {
221
+ const existing = this.cache.get(key);
222
+
223
+ // 如果已有缓存且序列号更新(说明当前请求是过时的),则不更新缓存
224
+ if (existing && existing.sequence > sequence) {
225
+ console.log(
226
+ `[RequestCacheService] Ignoring stale cache update for ${key} (current: ${existing.sequence}, incoming: ${sequence})`
227
+ );
228
+ return;
229
+ }
230
+
231
+ const now = Date.now();
232
+ this.cache.set(key, {
233
+ data: JSON.parse(JSON.stringify(data)), // 深拷贝
234
+ timestamp: now,
235
+ expiresAt: now + this.config.duration,
236
+ key,
237
+ sequence,
238
+ metadata
239
+ });
240
+
241
+ this.cacheSequences.set(key, sequence);
242
+ console.log(`[RequestCacheService] Updated cache for ${key} with sequence ${sequence}`);
243
+ }
244
+
245
+ /**
246
+ * refresh cache
247
+ */
248
+ async refreshCache(endpoint: string, options?: TRequest): Promise<TResponse> {
249
+ const cacheKey = this.config.keyGenerator(endpoint, options);
250
+ this.cache.delete(cacheKey);
251
+
252
+ return this.request(endpoint, options);
253
+ }
254
+
255
+ /**
256
+ * force request and update cache
257
+ */
258
+ async forceRequest(endpoint: string, options?: TRequest): Promise<TResponse> {
259
+ const cacheKey = this.config.keyGenerator(endpoint, options);
260
+ const currentSequence = ++this.requestSequence;
261
+
262
+ console.log(`[RequestCacheService] Force request for ${endpoint} (sequence: ${currentSequence})`);
263
+
264
+ const freshResponse = await this.requestAdapter.execute(endpoint, options);
265
+
266
+ const serverCacheableData = this.requestAdapter.extractCacheableData?.(freshResponse);
267
+
268
+ if (serverCacheableData) {
269
+ this.setCachedDataWithSequence(cacheKey, serverCacheableData, currentSequence);
270
+ console.log(`[RequestCacheService] Force updated cache for ${endpoint}`);
271
+ }
272
+
273
+ return freshResponse;
274
+ }
275
+
276
+ /**
277
+ * warmup cache - 避免与正在进行的请求冲突
278
+ */
279
+ async warmupCache(endpoint: string, options?: TRequest): Promise<void> {
280
+ const cacheKey = this.config.keyGenerator(endpoint, options);
281
+
282
+ // 如果有正在进行的请求,跳过 warmup
283
+ if (this.pendingRequests.has(cacheKey)) {
284
+ console.log(`[RequestCacheService] Skipping warmup for ${endpoint} - request in progress`);
285
+ return;
286
+ }
287
+
288
+ // 如果已有有效缓存,跳过 warmup
289
+ if (this.hasValidCache(cacheKey)) {
290
+ console.log(`[RequestCacheService] Skipping warmup for ${endpoint} - valid cache exists`);
291
+ return;
292
+ }
293
+
294
+ try {
295
+ console.log(`[RequestCacheService] Warming up cache for ${endpoint}`);
296
+ await this.forceRequest(endpoint, options);
297
+ } catch (error) {
298
+ console.warn(`[RequestCacheService] Cache warmup failed for ${endpoint}:`, error);
299
+ }
300
+ }
301
+
302
+ /**
303
+ * clear cache with target key
304
+ */
305
+ clearCache(key?: string): void {
306
+ if (key) {
307
+ this.cache.delete(key);
308
+ this.cacheSequences.delete(key);
309
+ this.pendingRequests.delete(key);
310
+ console.log(`[RequestCacheService] Cleared cache for ${key}`);
311
+ } else {
312
+ this.cache.clear();
313
+ this.cacheSequences.clear();
314
+ this.pendingRequests.clear();
315
+ this.requestSequence = 0; // 重置序列号
316
+ console.log('[RequestCacheService] Cleared all cache');
317
+ }
318
+ }
319
+
320
+ /**
321
+ * clear expired cache
322
+ */
323
+ clearExpiredCache(): void {
324
+ const now = Date.now();
325
+ for (const [key, entry] of this.cache) {
326
+ if (now > entry.expiresAt) {
327
+ this.cache.delete(key);
328
+ this.cacheSequences.delete(key);
329
+ }
330
+ }
331
+ console.log('[RequestCacheService] Cleared expired cache entries');
332
+ }
333
+
334
+ /**
335
+ * get cache stats
336
+ */
337
+ getCacheStats(): CacheStats & { pendingRequestCount: number } {
338
+ const now = Date.now();
339
+ let validCount = 0;
340
+ let expiredCount = 0;
341
+
342
+ for (const entry of this.cache.values()) {
343
+ if (now > entry.expiresAt) {
344
+ expiredCount++;
345
+ } else {
346
+ validCount++;
347
+ }
348
+ }
349
+
350
+ return {
351
+ cacheCount: this.cache.size,
352
+ validCount,
353
+ expiredCount,
354
+ pendingRequestCount: this.pendingRequests.size
355
+ };
356
+ }
357
+
358
+ /**
359
+ * get all cache keys
360
+ */
361
+ getCacheKeys(): string[] {
362
+ return Array.from(this.cache.keys());
363
+ }
364
+
365
+ /**
366
+ * check if the target key has valid cache
367
+ */
368
+ hasValidCache(key: string): boolean {
369
+ const cached = this.cache.get(key);
370
+ return cached ? Date.now() <= cached.expiresAt : false;
371
+ }
372
+
373
+ /**
374
+ * get pending request keys for debugging
375
+ */
376
+ getPendingRequestKeys(): string[] {
377
+ return Array.from(this.pendingRequests.keys());
378
+ }
379
+
380
+ /**
381
+ * check if a request is currently pending
382
+ */
383
+ hasPendingRequest(key: string): boolean {
384
+ return this.pendingRequests.has(key);
385
+ }
386
+
387
+ /**
388
+ * get cache sequence for a specific key
389
+ */
390
+ getCacheSequence(key: string): number | undefined {
391
+ return this.cacheSequences.get(key);
392
+ }
393
+ }
@@ -16,7 +16,6 @@ const priority = () => {
16
16
  return (a: RewardType, b: RewardType) => {
17
17
  // Priority order: GEM > JOLI_COIN > ADS
18
18
  const priorityMap: Record<RewardType, number> = {
19
- SUBSCRIPTION: 4,
20
19
  JOLI_GEM: 3,
21
20
  JOLI_GEM_ONLY: 3,
22
21
  JOLI_COIN: 2,
@@ -30,24 +29,8 @@ const priority = () => {
30
29
 
31
30
  const sortRewards = (rewardsTypes: RewardType[]): RewardType[] => {
32
31
  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
- }
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'];
51
34
 
52
35
  return rewardsTypes.sort(priority());
53
36
  };
@@ -1,4 +1,4 @@
1
- import { RequestCacheService, RequestAdapter } from '@jolibox/common';
1
+ import { RequestCacheService, RequestAdapter } from '../cache/request-cache-service';
2
2
  import { IHttpClient } from '../http';
3
3
  import { StandardResponse, GlobalConfig } from '@jolibox/types';
4
4
  import { IJolicoinRewardOption, IUnlockOption, IJoliCoin, IGem } from './type';
@@ -50,8 +50,8 @@ class RewardRequestAdapter
50
50
  extractCacheableData(response: IJolicoinRewardOption): UnlockOptionsCacheData {
51
51
  return {
52
52
  unlockOptions: response.data?.unlockOptions || [],
53
- joliCoin: response.extra?.joliCoin,
54
- joliGem: response.extra?.joliGem || { balance: 0, enableAutoDeduct: false }
53
+ joliCoin: response.extra.joliCoin,
54
+ joliGem: response.extra.joliGem || { balance: 0, enableAutoDeduct: false }
55
55
  };
56
56
  }
57
57
 
@@ -10,7 +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
- export * from './registers/use-subscription';
14
13
 
15
14
  export { warmupBalanceCache } from './registers/utils/coins/jolicoin/cached-fetch-balance';
16
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
  };
@@ -1,4 +1,4 @@
1
- import { RequestCacheService, RequestAdapter } from '@jolibox/common';
1
+ import { RequestCacheService, RequestAdapter } from '@/common/cache/request-cache-service';
2
2
  import { IHttpClient } from '@/common/http';
3
3
  import { StandardResponse } from '@jolibox/types';
4
4
 
@@ -1,4 +1,4 @@
1
- import { RequestCacheService, RequestAdapter } from '@jolibox/common';
1
+ import { RequestCacheService, RequestAdapter } from '@/common/cache/request-cache-service';
2
2
  import { IHttpClient } from '@/common/http';
3
3
  import { StandardResponse } from '@jolibox/types';
4
4
 
@@ -17,8 +17,6 @@ export const UseModalResultEventName = 'ON_USE_MODAL_RESULT' as const;
17
17
  export const UseModalFrequencyEventName = 'ON_USE_MODAL_FREQUENCY' as const;
18
18
  export const UseUnloginModalResultEventName = 'ON_USE_UNLOGIN_MODAL_EVENT' as const;
19
19
  export const InvokeUnloginModalEventName = 'INVOKE_UNLOGIN_MODAL_EVENT' as const;
20
- export const InvokeSubscriptionEventName = 'INVOKE_SUBSCRIPTION_EVENT' as const;
21
- export const UseSubscriptionResultEventName = 'ON_USE_SUBSCRIPTION_RESULT' as const;
22
20
 
23
21
  type IPaymentResult = 'SUCCESS' | 'FAILED' | 'CANCEL';
24
22
  export interface IPaymentEvent {
@@ -92,10 +90,6 @@ export interface IUseModalFrequencyConfig {
92
90
  };
93
91
  }
94
92
 
95
- export interface IUseSubscriptionResultEvent {
96
- result: 'SUCCESS' | 'CANCEL' | 'FAILED';
97
- }
98
-
99
93
  export interface RewardsEventMap extends Record<string, unknown[]> {
100
94
  [UnlockOptionsEventName]: [IUnlockOptionsEvent];
101
95
  [InvokePaymentEventName]: [
@@ -111,8 +105,6 @@ export interface RewardsEventMap extends Record<string, unknown[]> {
111
105
  IUseUnloginModalEvent
112
106
  ];
113
107
  [UseUnloginModalResultEventName]: [IUseUnloginModalResultEvent];
114
- [InvokeSubscriptionEventName]: ['SUBSCRIPTION'];
115
- [UseSubscriptionResultEventName]: [IUseSubscriptionResultEvent];
116
108
  }
117
109
 
118
110
  export const originalRewardsEmitter = new EventEmitter<RewardsEventMap>();
@@ -1,10 +1,4 @@
1
- export type RewardType =
2
- | 'ADS'
3
- | 'JOLI_COIN'
4
- | 'JOLI_COIN_ONLY'
5
- | 'JOLI_GEM'
6
- | 'JOLI_GEM_ONLY'
7
- | 'SUBSCRIPTION';
1
+ export type RewardType = 'ADS' | 'JOLI_COIN' | 'JOLI_COIN_ONLY' | 'JOLI_GEM' | 'JOLI_GEM_ONLY';
8
2
 
9
3
  import { context } from '../context';
10
4
  import type { AdsRewardsHandler } from './registers/use-ads';
@@ -16,7 +10,6 @@ export interface RewardHandlerMap {
16
10
  JOLI_COIN_ONLY: (params?: unknown) => Promise<boolean>; // coins only
17
11
  JOLI_GEM: (params?: unknown) => Promise<boolean>; // gem + ads
18
12
  JOLI_GEM_ONLY: (params?: unknown) => Promise<boolean>; // gem only
19
- SUBSCRIPTION: (params?: unknown) => Promise<boolean>; // subscription
20
13
  }
21
14
 
22
15
  export type RewardHandler<T extends RewardType> = RewardHandlerMap[T];
@@ -8,11 +8,6 @@ const JOLIBOX_JOLI_COIN_USE_EVENT = 'JOLIBOX_JOLI_COIN_USE_EVENT';
8
8
  const JOLIBOX_JOLI_UNLOGIN_MODAL_EVENT = 'JOLIBOX_JOLI_UNLOGIN_MODAL_EVENT'; // unlogin modal event, triggered when unlogin
9
9
  // unlogin modal result event success.
10
10
 
11
- // subscrition
12
-
13
- const JOLIBOX_GET_USER_SUB_STATUS = 'JOLIBOX_GET_USER_SUB_STATUS';
14
- const JOLIBOX_SUB_EVENT = 'JOLIBOX_SUB_EVENT';
15
-
16
11
  interface JoliboxCustomEvent {
17
12
  [JOLIBOX_CUSTOM_ADS_EVENT_TYPE]: {
18
13
  isAdShowing: boolean;
@@ -46,12 +41,6 @@ interface JoliboxCustomEvent {
46
41
  sequenceId: string;
47
42
  type: 'ADS-JOLI_COIN' | 'JOLI_COIN';
48
43
  };
49
- [JOLIBOX_GET_USER_SUB_STATUS]: {
50
- sequenceId: string;
51
- };
52
- [JOLIBOX_SUB_EVENT]: {
53
- sequenceId: string;
54
- };
55
44
  }
56
45
 
57
46
  const notifyCustomEvent = <T extends keyof JoliboxCustomEvent>(eventName: T, data: JoliboxCustomEvent[T]) => {
@@ -77,10 +66,6 @@ const ON_JOLIBOX_TOPUP_JOLI_COIN_RESULT = 'ON_JOLIBOX_TOPUP_JOLI_COIN_RESULT';
77
66
  const ON_JOLIBOX_JOLI_COIN_USE_RESULT = 'ON_JOLIBOX_JOLI_COIN_USE_RESULT';
78
67
  const ON_JOLIBOX_JOLI_UNLOGIN_MODAL_RESULT_EVENT = 'ON_JOLIBOX_JOLI_UNLOGIN_MODAL_RESULT_EVENT';
79
68
 
80
- // subscription
81
- const ON_GET_USER_SUB_STATUS = 'ON_GET_USER_SUB_STATUS';
82
- const ON_JOLIBOX_SUB_RESULT_EVENT = 'ON_JOLIBOX_SUB_RESULT_EVENT';
83
-
84
69
  interface ReceivedJoliboxCustomEvent {
85
70
  [ON_JOLIBOX_TOPUP_JOLI_COIN_RESULT]: {
86
71
  sequenceId: string;
@@ -108,14 +93,6 @@ interface ReceivedJoliboxCustomEvent {
108
93
  };
109
94
  isFirstLogin?: boolean;
110
95
  };
111
- [ON_GET_USER_SUB_STATUS]: {
112
- sequenceId: string;
113
- isSubUser: boolean;
114
- };
115
- [ON_JOLIBOX_SUB_RESULT_EVENT]: {
116
- sequenceId: string;
117
- result: 'SUCCESS' | 'CANCEL' | 'FAILED';
118
- };
119
96
  }
120
97
 
121
98
  type ReceivedJoliboxCustomEventResult = keyof ReceivedJoliboxCustomEvent;
package/src/h5/api/ads.ts CHANGED
@@ -6,8 +6,7 @@ import {
6
6
  createAdsRewardHandler,
7
7
  rewardsHelper,
8
8
  createJolicoinRewardHandler,
9
- createJolicoinOnlyRewardHandler,
10
- createSubscriptionRewardHandler
9
+ createJolicoinOnlyRewardHandler
11
10
  } from '@/common/rewards';
12
11
  import {
13
12
  JoliboxAdsForGame,
@@ -25,7 +24,7 @@ import GamedistributionAdsHandler from './platformAdsHandle/GamedistributionAdsH
25
24
  import FunmaxAdsHandler from './platformAdsHandle/FunmaxAdsHandler';
26
25
  import JoliboxAdsHandler from './platformAdsHandle/JoliboxAdsHandler';
27
26
  import { warmupRewardCache } from '@/common/rewards/fetch-reward';
28
- import { warmupBalanceCache } from '@/common/rewards';
27
+ import { warmupBalanceCache, warmupGemBalanceCache } from '@/common/rewards';
29
28
 
30
29
  declare global {
31
30
  interface Window {
@@ -130,9 +129,13 @@ const adsContext: IAdsContext<'GAME'> = {
130
129
  }
131
130
  };
132
131
 
133
-
134
- const handleUnlockWithSubscriptionSuccess = () => {
135
- track('subscription_unlock_success', {});
132
+ const handleUnlockSuccess = (params: { quantity: number; balance: number }) => {
133
+ notifyCustomEvent('JOLIBOX_CUSTOM_REWARDS_EVENT', {
134
+ JOLI_COIN: params
135
+ });
136
+ track('jolicoin_unlock_success', {
137
+ quantity: params.quantity
138
+ });
136
139
  };
137
140
 
138
141
  const adsManager = new H5AdsManager(adsContext);
@@ -142,18 +145,14 @@ rewardsHelper.registerRewardHandler('ADS', createAdsRewardHandler(adsHandler.get
142
145
  rewardsHelper.registerRewardHandler(
143
146
  'JOLI_COIN',
144
147
  createJolicoinRewardHandler(httpClient, {
145
- onUnlockSuccess: (params: { quantity: number; balance: number }) => {
146
- notifyCustomEvent('JOLIBOX_CUSTOM_REWARDS_EVENT', {
147
- JOLI_COIN: params
148
- });
149
- }
148
+ onUnlockSuccess: handleUnlockSuccess.bind(this)
150
149
  }) as unknown as (params?: unknown) => Promise<boolean>
151
150
  );
152
151
 
153
152
  rewardsHelper.registerRewardHandler(
154
- 'SUBSCRIPTION',
155
- createSubscriptionRewardHandler(httpClient, {
156
- onSubSuccess: handleUnlockWithSubscriptionSuccess.bind(this)
153
+ 'JOLI_COIN_ONLY',
154
+ createJolicoinOnlyRewardHandler(httpClient, {
155
+ onUnlockSuccess: handleUnlockSuccess.bind(this)
157
156
  }) as unknown as (params?: unknown) => Promise<boolean>
158
157
  );
159
158