@jolibox/implement 1.2.3 → 1.2.4
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 +13 -10
- package/.rush/temp/shrinkwrap-deps.json +2 -1
- package/dist/common/context/index.d.ts +5 -0
- package/dist/index.js +4 -8
- package/dist/index.native.js +32 -36
- package/dist/native/api/index.d.ts +1 -0
- package/dist/native/api/payment.d.ts +1 -0
- package/dist/native/payment/__tests__/payment-service-simple.test.d.ts +1 -0
- package/dist/native/payment/payment-helper.d.ts +8 -5
- package/dist/native/payment/payment-service.d.ts +38 -0
- package/implement.build.log +2 -2
- package/package.json +6 -5
- package/src/common/context/index.ts +12 -0
- package/src/native/api/call-host-method.ts +1 -1
- package/src/native/api/index.ts +1 -0
- package/src/native/api/navigate.ts +10 -1
- package/src/native/api/payment.ts +56 -0
- package/src/native/payment/__tests__/payment-service-simple.test.ts +208 -0
- package/src/native/payment/payment-helper.ts +10 -4
- package/src/native/payment/payment-service.ts +279 -0
- package/src/native/payment/registers/jolicoin-iap.ts +4 -4
- package/src/native/report/index.ts +4 -1
- package/src/native/rewards/ui/payment-modal.ts +11 -58
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
export type PaymentType = 'JOLI_COIN' | 'JOLI_COIN_IAP' | 'JOLI_GEM_IAP';
|
|
2
2
|
import { StandardResponse } from '@jolibox/types';
|
|
3
|
-
type PaymentResult = StandardResponse<
|
|
3
|
+
export type PaymentResult<T> = StandardResponse<T>;
|
|
4
4
|
export interface PaymentHandlerMap {
|
|
5
|
-
JOLI_COIN: (productId: string) => Promise<PaymentResult
|
|
5
|
+
JOLI_COIN: (productId: string) => Promise<PaymentResult<void>>;
|
|
6
6
|
JOLI_COIN_IAP: (params: {
|
|
7
7
|
productId: string;
|
|
8
8
|
appStoreProductId: string;
|
|
9
|
-
}) => Promise<PaymentResult
|
|
9
|
+
}) => Promise<PaymentResult<{
|
|
10
|
+
totalAmount: string;
|
|
11
|
+
}>>;
|
|
10
12
|
JOLI_GEM_IAP: (params: {
|
|
11
13
|
productId: string;
|
|
12
14
|
appStoreProductId: string;
|
|
13
|
-
}) => Promise<PaymentResult
|
|
15
|
+
}) => Promise<PaymentResult<{
|
|
16
|
+
totalAmount: string;
|
|
17
|
+
}>>;
|
|
14
18
|
}
|
|
15
19
|
export type PaymentHandler<T extends PaymentType> = PaymentHandlerMap[T];
|
|
16
20
|
export declare function createPaymentHelper(): {
|
|
@@ -18,4 +22,3 @@ export declare function createPaymentHelper(): {
|
|
|
18
22
|
invokePayment<T extends PaymentType>(type: T, ...args: Parameters<PaymentHandler<T>>): Promise<any>;
|
|
19
23
|
};
|
|
20
24
|
export type PaymentHelper = ReturnType<typeof createPaymentHelper>;
|
|
21
|
-
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { IPaymentChoice } from '@/common/rewards/reward-emitter';
|
|
2
|
+
import type { PaymentResult } from './payment-helper';
|
|
3
|
+
type PaymentPurchaseType = 'JOLI_COIN' | 'JOLI_GEM';
|
|
4
|
+
export interface CachedPaymentChoices {
|
|
5
|
+
choices: IPaymentChoice[];
|
|
6
|
+
timestamp: number;
|
|
7
|
+
expiresAt: number;
|
|
8
|
+
productIds: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare class PaymentService {
|
|
11
|
+
private productInfoCache;
|
|
12
|
+
private static paymentChoicesCache;
|
|
13
|
+
private static readonly PAYMENT_CHOICES_CACHE_DURATION;
|
|
14
|
+
getJolicoinProductsInfo(type: PaymentPurchaseType): Promise<IPaymentChoice[]>;
|
|
15
|
+
purchase(type: PaymentPurchaseType, productId: string): Promise<PaymentResult<{
|
|
16
|
+
totalAmount: string;
|
|
17
|
+
}>>;
|
|
18
|
+
private static mergeResponseData;
|
|
19
|
+
static getProductsInfo(apiEndpoint: string): Promise<{
|
|
20
|
+
balance: number;
|
|
21
|
+
enableAutoDeduct: boolean;
|
|
22
|
+
paymentChoices: IPaymentChoice[];
|
|
23
|
+
} | undefined>;
|
|
24
|
+
private static getProductsInfoInternal;
|
|
25
|
+
private static getPaymentChoicesFromCache;
|
|
26
|
+
private static cachePaymentChoices;
|
|
27
|
+
private static extractProductIds;
|
|
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;
|
|
37
|
+
}
|
|
38
|
+
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.4 clean
|
|
4
4
|
> rimraf ./dist
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
> @jolibox/implement@1.2.
|
|
7
|
+
> @jolibox/implement@1.2.4 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,15 +1,15 @@
|
|
|
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.4",
|
|
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.4",
|
|
10
|
+
"@jolibox/types": "1.2.4",
|
|
11
|
+
"@jolibox/native-bridge": "1.2.4",
|
|
12
|
+
"@jolibox/ads": "1.2.4",
|
|
13
13
|
"localforage": "1.10.0",
|
|
14
14
|
"@jolibox/ui": "1.0.0",
|
|
15
15
|
"web-vitals": "4.2.4"
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"typescript": "5.7.3",
|
|
19
19
|
"@types/jest": "28.1.1",
|
|
20
|
+
"@types/node": "18.0.0",
|
|
20
21
|
"rimraf": "6.0.1",
|
|
21
22
|
"esbuild": "0.24.2",
|
|
22
23
|
"@jolibox/eslint-config": "1.0.0"
|
|
@@ -49,6 +49,11 @@ type Viewport = {
|
|
|
49
49
|
navigationBarHeight: number;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
type MPInfo = {
|
|
53
|
+
mpName: string;
|
|
54
|
+
mpVersion?: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
52
57
|
function hasMetaTag(name: string, content: string): boolean {
|
|
53
58
|
return document?.head.querySelector(`meta[name="${name}"][content="${content}"]`) !== null;
|
|
54
59
|
}
|
|
@@ -165,6 +170,13 @@ const wrapContext = () => {
|
|
|
165
170
|
get abTests(): string[] {
|
|
166
171
|
return env.abValues?.split(',') ?? [];
|
|
167
172
|
},
|
|
173
|
+
get mpInfo(): MPInfo {
|
|
174
|
+
return (
|
|
175
|
+
env.mpInfo ?? {
|
|
176
|
+
mpName: 'unknown'
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
},
|
|
168
180
|
onEnvConfigChanged: (newConfig: Partial<Env>) => {
|
|
169
181
|
mergeWith(env, newConfig, mergeArray);
|
|
170
182
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createAPI, registerCanIUse, t } from './base';
|
|
2
2
|
import { invokeNative } from '@jolibox/native-bridge';
|
|
3
3
|
import { hostEmitter, UserCustomError } from '@jolibox/common';
|
|
4
4
|
import { createCommands } from '@jolibox/common';
|
package/src/native/api/index.ts
CHANGED
|
@@ -56,7 +56,16 @@ const interceptSystemExitSync = createSyncAPI('interceptSystemExitSync', {
|
|
|
56
56
|
|
|
57
57
|
const navigateToNativePage = createSyncAPI('navigateToNativePage', {
|
|
58
58
|
paramsSchema: t.tuple(
|
|
59
|
-
t.enum(
|
|
59
|
+
t.enum(
|
|
60
|
+
'openHistory',
|
|
61
|
+
'openDiscover',
|
|
62
|
+
'openDiscover',
|
|
63
|
+
'openGame',
|
|
64
|
+
'openDrama',
|
|
65
|
+
'openTopup',
|
|
66
|
+
'openFeed',
|
|
67
|
+
'openRewards'
|
|
68
|
+
),
|
|
60
69
|
t.object()
|
|
61
70
|
),
|
|
62
71
|
implement: (path, params) => {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { createCommands } from '@jolibox/common';
|
|
2
|
+
import { createAPI, registerCanIUse, t } from './base';
|
|
3
|
+
import { PaymentService } from '../payment/payment-service';
|
|
4
|
+
import { createAPIError } from '@/common/report/errors';
|
|
5
|
+
import { IPaymentChoice } from '@jolibox/ui/dist/bridge/coin';
|
|
6
|
+
|
|
7
|
+
const commands = createCommands();
|
|
8
|
+
const paymentService = new PaymentService();
|
|
9
|
+
|
|
10
|
+
const purchaseGem = createAPI('purchaseGem', {
|
|
11
|
+
paramsSchema: t.tuple(
|
|
12
|
+
t.object({
|
|
13
|
+
productId: t.string()
|
|
14
|
+
})
|
|
15
|
+
),
|
|
16
|
+
implement: async (params: { productId: string }): Promise<{ totalAmount: string }> => {
|
|
17
|
+
const result = await paymentService.purchase('JOLI_GEM', params.productId);
|
|
18
|
+
|
|
19
|
+
if (result.code !== 'SUCCESS' || !result.data?.totalAmount) {
|
|
20
|
+
throw createAPIError({
|
|
21
|
+
code: -1,
|
|
22
|
+
msg: '[JoliboxSDK]: purchase gem failed: ' + result.message
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
totalAmount: result.data?.totalAmount
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const getGemProducts = createAPI('getGemProducts', {
|
|
33
|
+
paramsSchema: t.tuple(),
|
|
34
|
+
implement: async (): Promise<{ products: IPaymentChoice[] }> => {
|
|
35
|
+
const choices = await paymentService.getJolicoinProductsInfo('JOLI_GEM');
|
|
36
|
+
console.info('choices', choices);
|
|
37
|
+
return {
|
|
38
|
+
products: choices.map((choice) => ({
|
|
39
|
+
productId: choice.productId,
|
|
40
|
+
totalAmountStr: choice.totalAmountStr ?? '',
|
|
41
|
+
quantity: choice.quantity
|
|
42
|
+
}))
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
commands.registerCommand('PaymentSDK.purchaseGem', purchaseGem);
|
|
48
|
+
commands.registerCommand('PaymentSDK.getGemProducts', getGemProducts);
|
|
49
|
+
|
|
50
|
+
registerCanIUse('payment.purchaseGem', {
|
|
51
|
+
version: '1.2.3'
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
registerCanIUse('payment.getGemProducts', {
|
|
55
|
+
version: '1.2.3'
|
|
56
|
+
});
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { PaymentService } from '../payment-service';
|
|
2
|
+
|
|
3
|
+
// Mock dependencies
|
|
4
|
+
jest.mock('@jolibox/native-bridge', () => ({
|
|
5
|
+
applyNative: jest.fn(),
|
|
6
|
+
onNative: jest.fn()
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
jest.mock('@/native/network', () => ({
|
|
10
|
+
innerFetch: jest.fn()
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
14
|
+
const { applyNative } = require('@jolibox/native-bridge');
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
17
|
+
const { innerFetch: fetch } = require('@/native/network');
|
|
18
|
+
|
|
19
|
+
const mockApplyNative = applyNative;
|
|
20
|
+
const mockFetch = fetch;
|
|
21
|
+
|
|
22
|
+
describe('PaymentService - Basic Tests', () => {
|
|
23
|
+
const mockApiEndpoint = '/api/joli-coin/balance-detail';
|
|
24
|
+
|
|
25
|
+
const mockServerData = {
|
|
26
|
+
balance: 100,
|
|
27
|
+
enableAutoDeduct: true,
|
|
28
|
+
paymentChoices: [
|
|
29
|
+
{
|
|
30
|
+
productId: 'coin_100',
|
|
31
|
+
quantity: 100,
|
|
32
|
+
appStoreProductId: 'com.joli.coin.100'
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const mockNativeData = {
|
|
38
|
+
'com.joli.coin.100': { price: '$0.99' }
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
jest.clearAllMocks();
|
|
43
|
+
jest.clearAllTimers();
|
|
44
|
+
jest.useFakeTimers();
|
|
45
|
+
PaymentService.clearPaymentChoicesCache();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
jest.useRealTimers();
|
|
50
|
+
jest.restoreAllMocks();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should fetch and cache payment choices on first call', async () => {
|
|
54
|
+
mockFetch.mockResolvedValue({
|
|
55
|
+
response: {
|
|
56
|
+
data: {
|
|
57
|
+
data: mockServerData
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
mockApplyNative.mockResolvedValue({
|
|
63
|
+
data: mockNativeData
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const result = await PaymentService.getProductsInfo(mockApiEndpoint);
|
|
67
|
+
|
|
68
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
69
|
+
expect(mockApplyNative).toHaveBeenCalledTimes(1);
|
|
70
|
+
expect(result).toEqual({
|
|
71
|
+
balance: 100,
|
|
72
|
+
enableAutoDeduct: true,
|
|
73
|
+
paymentChoices: [
|
|
74
|
+
{
|
|
75
|
+
productId: 'coin_100',
|
|
76
|
+
quantity: 100,
|
|
77
|
+
appStoreProductId: 'com.joli.coin.100',
|
|
78
|
+
totalAmountStr: '$0.99'
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const stats = PaymentService.getPaymentChoicesCacheStats();
|
|
84
|
+
expect(stats.cacheCount).toBe(1);
|
|
85
|
+
expect(stats.validCount).toBe(1);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should use cache on second call', async () => {
|
|
89
|
+
mockFetch.mockResolvedValue({
|
|
90
|
+
response: {
|
|
91
|
+
data: {
|
|
92
|
+
data: mockServerData
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
mockApplyNative.mockResolvedValue({
|
|
98
|
+
data: mockNativeData
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// First call
|
|
102
|
+
await PaymentService.getProductsInfo(mockApiEndpoint);
|
|
103
|
+
|
|
104
|
+
// Second call - should use cache
|
|
105
|
+
const result = await PaymentService.getProductsInfo(mockApiEndpoint);
|
|
106
|
+
|
|
107
|
+
expect(mockFetch).toHaveBeenCalledTimes(2); // Still fetch for real-time data
|
|
108
|
+
expect(mockApplyNative).toHaveBeenCalledTimes(1); // Only called once
|
|
109
|
+
|
|
110
|
+
expect(result).toEqual({
|
|
111
|
+
balance: 100,
|
|
112
|
+
enableAutoDeduct: true,
|
|
113
|
+
paymentChoices: [
|
|
114
|
+
{
|
|
115
|
+
productId: 'coin_100',
|
|
116
|
+
quantity: 100,
|
|
117
|
+
appStoreProductId: 'com.joli.coin.100',
|
|
118
|
+
totalAmountStr: '$0.99'
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should timeout after 3 seconds', async () => {
|
|
125
|
+
// Mock a slow server response
|
|
126
|
+
mockFetch.mockImplementation(() => new Promise((resolve) => setTimeout(resolve, 5000)));
|
|
127
|
+
|
|
128
|
+
const promise = PaymentService.getProductsInfo(mockApiEndpoint);
|
|
129
|
+
|
|
130
|
+
// Fast forward past timeout
|
|
131
|
+
jest.advanceTimersByTime(3000);
|
|
132
|
+
|
|
133
|
+
await expect(promise).rejects.toThrow('[PaymentService] Request timeout after 3 seconds');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should handle cache expiration', async () => {
|
|
137
|
+
mockFetch.mockResolvedValue({
|
|
138
|
+
response: {
|
|
139
|
+
data: {
|
|
140
|
+
data: mockServerData
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
mockApplyNative.mockResolvedValue({
|
|
146
|
+
data: mockNativeData
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// First call
|
|
150
|
+
await PaymentService.getProductsInfo(mockApiEndpoint);
|
|
151
|
+
|
|
152
|
+
// Fast forward time beyond cache duration (10 minutes)
|
|
153
|
+
jest.advanceTimersByTime(11 * 60 * 1000);
|
|
154
|
+
|
|
155
|
+
// Second call - cache should be expired
|
|
156
|
+
await PaymentService.getProductsInfo(mockApiEndpoint);
|
|
157
|
+
|
|
158
|
+
expect(mockApplyNative).toHaveBeenCalledTimes(2); // Called again due to expiration
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should throw error when mockApplyNative fails', async () => {
|
|
162
|
+
mockFetch.mockResolvedValue({
|
|
163
|
+
response: {
|
|
164
|
+
data: {
|
|
165
|
+
data: mockServerData
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Mock applyNative to reject
|
|
171
|
+
mockApplyNative.mockRejectedValue(new Error('Native call failed'));
|
|
172
|
+
|
|
173
|
+
await expect(PaymentService.getProductsInfo(mockApiEndpoint)).rejects.toThrow('Native call failed');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should throw error when mockFetch fails', async () => {
|
|
177
|
+
// Mock fetch to reject
|
|
178
|
+
mockFetch.mockRejectedValue(new Error('Network error'));
|
|
179
|
+
|
|
180
|
+
await expect(PaymentService.getProductsInfo(mockApiEndpoint)).rejects.toThrow('Network error');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should throw error when request exceeds 3 seconds timeout', async () => {
|
|
184
|
+
// Mock a very slow fetch request that never resolves within 3 seconds
|
|
185
|
+
mockFetch.mockImplementation(
|
|
186
|
+
() =>
|
|
187
|
+
new Promise((resolve) => {
|
|
188
|
+
// This will resolve after 5 seconds, but timeout should trigger at 3 seconds
|
|
189
|
+
setTimeout(() => {
|
|
190
|
+
resolve({
|
|
191
|
+
response: {
|
|
192
|
+
data: {
|
|
193
|
+
data: mockServerData
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}, 5000);
|
|
198
|
+
})
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
const promise = PaymentService.getProductsInfo(mockApiEndpoint);
|
|
202
|
+
|
|
203
|
+
// Advance timers to 3 seconds to trigger timeout
|
|
204
|
+
jest.advanceTimersByTime(3000);
|
|
205
|
+
|
|
206
|
+
await expect(promise).rejects.toThrow('[PaymentService] Request timeout after 3 seconds');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
@@ -4,12 +4,18 @@ import { StandardResponse } from '@jolibox/types';
|
|
|
4
4
|
import { reportError } from '@/common/report/errors/report';
|
|
5
5
|
import { BaseError } from '@jolibox/common';
|
|
6
6
|
|
|
7
|
-
type PaymentResult = StandardResponse<
|
|
7
|
+
export type PaymentResult<T> = StandardResponse<T>;
|
|
8
8
|
|
|
9
9
|
export interface PaymentHandlerMap {
|
|
10
|
-
JOLI_COIN: (productId: string) => Promise<PaymentResult
|
|
11
|
-
JOLI_COIN_IAP: (params: {
|
|
12
|
-
|
|
10
|
+
JOLI_COIN: (productId: string) => Promise<PaymentResult<void>>; // jolicoin
|
|
11
|
+
JOLI_COIN_IAP: (params: {
|
|
12
|
+
productId: string;
|
|
13
|
+
appStoreProductId: string;
|
|
14
|
+
}) => Promise<PaymentResult<{ totalAmount: string }>>; // jolicoin iap
|
|
15
|
+
JOLI_GEM_IAP: (params: {
|
|
16
|
+
productId: string;
|
|
17
|
+
appStoreProductId: string;
|
|
18
|
+
}) => Promise<PaymentResult<{ totalAmount: string }>>; // gem iap
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
export type PaymentHandler<T extends PaymentType> = PaymentHandlerMap[T];
|