expo-iap 2.6.0 → 2.6.2
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/.copilot-instructions.md +321 -0
- package/.cursorrules +303 -0
- package/CONTRIBUTING.md +378 -0
- package/README.md +10 -0
- package/build/index.d.ts +18 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +27 -3
- package/build/index.js.map +1 -1
- package/build/modules/android.d.ts.map +1 -1
- package/build/modules/android.js +2 -0
- package/build/modules/android.js.map +1 -1
- package/build/modules/ios.d.ts +127 -21
- package/build/modules/ios.d.ts.map +1 -1
- package/build/modules/ios.js +200 -27
- package/build/modules/ios.js.map +1 -1
- package/build/types/ExpoIapIos.types.d.ts +9 -1
- package/build/types/ExpoIapIos.types.d.ts.map +1 -1
- package/build/types/ExpoIapIos.types.js.map +1 -1
- package/build/useIap.d.ts.map +1 -1
- package/build/useIap.js +7 -5
- package/build/useIap.js.map +1 -1
- package/codecov.yml +74 -0
- package/ios/ExpoIapModule.swift +22 -8
- package/package.json +5 -6
- package/scripts/test-coverage.sh +15 -0
- package/src/index.ts +36 -6
- package/src/modules/android.ts +6 -1
- package/src/modules/ios.ts +289 -35
- package/src/types/ExpoIapIos.types.ts +9 -1
- package/src/useIap.ts +11 -6
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# GitHub Copilot Instructions for expo-iap
|
|
2
|
+
|
|
3
|
+
## Package Manager
|
|
4
|
+
|
|
5
|
+
**IMPORTANT: This project uses Bun exclusively. Do not suggest npm, yarn, or pnpm commands.**
|
|
6
|
+
|
|
7
|
+
- Install dependencies: `bun install`
|
|
8
|
+
- Run scripts: `bun run <script>`
|
|
9
|
+
- Run tests: `bun test`
|
|
10
|
+
- Add packages: `bun add <package>`
|
|
11
|
+
- Add dev dependencies: `bun add -d <package>`
|
|
12
|
+
|
|
13
|
+
**NEVER suggest creating package-lock.json or yarn.lock files. Only bun.lock should exist.**
|
|
14
|
+
|
|
15
|
+
## Platform-Specific Function Naming
|
|
16
|
+
|
|
17
|
+
When suggesting code for expo-iap, follow these naming conventions:
|
|
18
|
+
|
|
19
|
+
### Platform-Specific Functions
|
|
20
|
+
|
|
21
|
+
Functions that only work on one platform MUST have platform suffixes:
|
|
22
|
+
|
|
23
|
+
- iOS: `functionNameIos()`
|
|
24
|
+
- Android: `functionNameAndroid()`
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// Correct examples:
|
|
28
|
+
export const getStorefrontIos = async (): Promise<string> => { ... }
|
|
29
|
+
export const consumeProductAndroid = async (token: string): Promise<void> => { ... }
|
|
30
|
+
export const getAppTransactionIos = async (): Promise<AppTransactionIOS | null> => { ... }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Cross-Platform Functions
|
|
34
|
+
|
|
35
|
+
Functions that abstract platform differences don't need suffixes:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// Correct cross-platform example:
|
|
39
|
+
export const getProducts = async (skus: string[]): Promise<Product[]> => {
|
|
40
|
+
return Platform.select({
|
|
41
|
+
ios: async () => {
|
|
42
|
+
/* iOS implementation */
|
|
43
|
+
},
|
|
44
|
+
android: async () => {
|
|
45
|
+
/* Android implementation */
|
|
46
|
+
},
|
|
47
|
+
})();
|
|
48
|
+
};
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Project Overview
|
|
52
|
+
|
|
53
|
+
This is the **expo-iap** library - a modern React Native/Expo module for handling in-app purchases across iOS and Android platforms. The library provides a unified, TypeScript-first API with automatic type inference and platform abstraction.
|
|
54
|
+
|
|
55
|
+
## Key Principles
|
|
56
|
+
|
|
57
|
+
### 🎯 Modern TypeScript-First API
|
|
58
|
+
|
|
59
|
+
- **Automatic Type Inference**: No manual type casting required
|
|
60
|
+
- **Unified Platform API**: Single API that works across iOS and Android
|
|
61
|
+
- **Consistent Results**: Unified data structure regardless of platform
|
|
62
|
+
- **Clean Error Handling**: Result pattern with detailed error information
|
|
63
|
+
|
|
64
|
+
### 🚀 Primary API Pattern
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const result = await requestPurchase({
|
|
68
|
+
request: {sku: 'product.id'},
|
|
69
|
+
type: 'inapp',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (result.success) {
|
|
73
|
+
console.log('Purchase successful:', result.transactionId);
|
|
74
|
+
} else {
|
|
75
|
+
console.error('Purchase failed:', result.error.message);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 🏗️ Code Style Guidelines
|
|
80
|
+
|
|
81
|
+
#### TypeScript Best Practices
|
|
82
|
+
|
|
83
|
+
- **Explicit Type Definitions**: Always define types explicitly for public APIs
|
|
84
|
+
- **Function Overloads**: Provide multiple signatures for better IntelliSense
|
|
85
|
+
- **Discriminated Unions**: Use for platform-specific types and conditional returns
|
|
86
|
+
- **Strict Type Safety**: No `any` types in production code
|
|
87
|
+
|
|
88
|
+
#### Naming Conventions
|
|
89
|
+
|
|
90
|
+
- **PascalCase**: Interfaces, types, enums, classes
|
|
91
|
+
- **camelCase**: Functions, variables, methods, properties
|
|
92
|
+
- **kebab-case**: File names (except for React components)
|
|
93
|
+
- **Descriptive Names**: Avoid abbreviations, use clear intent-revealing names
|
|
94
|
+
|
|
95
|
+
#### Error Handling Pattern
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
type PurchaseResult<T = unknown> =
|
|
99
|
+
| {success: true; data: T; platform: 'ios' | 'android'}
|
|
100
|
+
| {success: false; error: PurchaseError; platform: 'ios' | 'android'};
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## API Implementation Patterns
|
|
104
|
+
|
|
105
|
+
### Core Purchase Functions
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
export function requestPurchase(params: {
|
|
109
|
+
readonly request: {sku: string; quantity?: number};
|
|
110
|
+
readonly type: 'inapp';
|
|
111
|
+
}): Promise<ProductPurchase | ProductPurchase[]>;
|
|
112
|
+
|
|
113
|
+
export function requestSubscription(params: {
|
|
114
|
+
readonly request: {sku: string};
|
|
115
|
+
}): Promise<SubscriptionPurchase | SubscriptionPurchase[]>;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Platform Abstraction
|
|
119
|
+
|
|
120
|
+
The library automatically handles platform differences:
|
|
121
|
+
|
|
122
|
+
- **iOS**: Uses `sku` directly with StoreKit
|
|
123
|
+
- **Android**: Converts to Google Play Billing format
|
|
124
|
+
- **Unified Properties**: Both platforms return consistent data
|
|
125
|
+
|
|
126
|
+
### Type Guards for Advanced Usage
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
export const isPurchaseResult = (
|
|
130
|
+
result: unknown,
|
|
131
|
+
): result is ProductPurchase | SubscriptionPurchase => {
|
|
132
|
+
return (
|
|
133
|
+
result !== null &&
|
|
134
|
+
typeof result === 'object' &&
|
|
135
|
+
'transactionId' in result &&
|
|
136
|
+
'productId' in result
|
|
137
|
+
);
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## File Organization
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
src/
|
|
145
|
+
├── index.ts # Main exports
|
|
146
|
+
├── ExpoIap.types.ts # Core type definitions
|
|
147
|
+
├── ExpoIapModule.ts # Native module interface
|
|
148
|
+
├── useIap.ts # React hook (legacy support)
|
|
149
|
+
├── modules/
|
|
150
|
+
│ ├── android.ts # Android-specific utilities
|
|
151
|
+
│ └── ios.ts # iOS-specific utilities
|
|
152
|
+
└── types/
|
|
153
|
+
├── ExpoIapAndroid.types.ts # Android type definitions
|
|
154
|
+
└── ExpoIapIos.types.ts # iOS type definitions
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Usage Examples
|
|
158
|
+
|
|
159
|
+
### Simple Product Purchase
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import {requestPurchase} from 'expo-iap';
|
|
163
|
+
|
|
164
|
+
const handlePurchase = async (productId: string) => {
|
|
165
|
+
const result = await requestPurchase({
|
|
166
|
+
request: {sku: productId},
|
|
167
|
+
type: 'inapp',
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (result.success) {
|
|
171
|
+
console.log('Purchase successful:', result.data);
|
|
172
|
+
} else {
|
|
173
|
+
console.error('Purchase failed:', result.error.message);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Subscription Purchase
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import {requestSubscription} from 'expo-iap';
|
|
182
|
+
|
|
183
|
+
const handleSubscription = async (subscriptionId: string) => {
|
|
184
|
+
const result = await requestSubscription({
|
|
185
|
+
request: {sku: subscriptionId},
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (result.success) {
|
|
189
|
+
console.log('Subscription activated:', result.data);
|
|
190
|
+
} else {
|
|
191
|
+
console.error('Subscription failed:', result.error.message);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Type Naming
|
|
197
|
+
|
|
198
|
+
- Platform-specific types: `ProductIos`, `ProductAndroid`, `PurchaseErrorIos`
|
|
199
|
+
- Cross-platform types: `Product`, `Purchase`, `PurchaseError`
|
|
200
|
+
|
|
201
|
+
## Code Suggestions
|
|
202
|
+
|
|
203
|
+
When generating code:
|
|
204
|
+
|
|
205
|
+
1. Check if the function is platform-specific
|
|
206
|
+
2. Add appropriate suffix if it only works on one platform
|
|
207
|
+
3. Use Platform.select() for cross-platform implementations
|
|
208
|
+
4. Always use TypeScript
|
|
209
|
+
5. Include proper error handling
|
|
210
|
+
6. Add JSDoc comments for public APIs
|
|
211
|
+
|
|
212
|
+
## Testing
|
|
213
|
+
|
|
214
|
+
Suggest tests that:
|
|
215
|
+
|
|
216
|
+
- Cover both iOS and Android paths
|
|
217
|
+
- Use `bun test` commands
|
|
218
|
+
- Include platform mocking when needed
|
|
219
|
+
- Test error scenarios
|
|
220
|
+
|
|
221
|
+
## Common Patterns
|
|
222
|
+
|
|
223
|
+
### Platform Selection
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
Platform.select({
|
|
227
|
+
ios: () => {
|
|
228
|
+
/* iOS code */
|
|
229
|
+
},
|
|
230
|
+
android: () => {
|
|
231
|
+
/* Android code */
|
|
232
|
+
},
|
|
233
|
+
default: () => {
|
|
234
|
+
/* Fallback */
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Receipt Validation (Platform-specific parameters)
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// iOS only needs SKU
|
|
243
|
+
await validateReceiptIos(sku);
|
|
244
|
+
|
|
245
|
+
// Android needs additional parameters
|
|
246
|
+
await validateReceiptAndroid({
|
|
247
|
+
packageName,
|
|
248
|
+
productToken,
|
|
249
|
+
accessToken,
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Documentation Standards
|
|
254
|
+
|
|
255
|
+
### Code Comments
|
|
256
|
+
|
|
257
|
+
- **Document the "why"**, not just the "what"
|
|
258
|
+
- **Explain platform differences** and how they're handled
|
|
259
|
+
- **Provide usage examples** for complex APIs
|
|
260
|
+
- **Use JSDoc format** for all public APIs
|
|
261
|
+
|
|
262
|
+
### Example Documentation Pattern
|
|
263
|
+
|
|
264
|
+
````typescript
|
|
265
|
+
/**
|
|
266
|
+
* Enhanced requestPurchase with unified API support
|
|
267
|
+
*
|
|
268
|
+
* This function automatically handles platform differences:
|
|
269
|
+
* - iOS: Uses `sku` directly with StoreKit
|
|
270
|
+
* - Android: Converts to Google Play Billing format
|
|
271
|
+
*
|
|
272
|
+
* @param params - Purchase request parameters
|
|
273
|
+
* @param params.request - Request object with product details
|
|
274
|
+
* @param params.type - Purchase type: 'inapp' for products
|
|
275
|
+
*
|
|
276
|
+
* @returns Promise resolving to purchase result
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```typescript
|
|
280
|
+
* const result = await requestPurchase({
|
|
281
|
+
* request: { sku: 'com.example.premium' },
|
|
282
|
+
* type: 'inapp'
|
|
283
|
+
* });
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
````
|
|
287
|
+
|
|
288
|
+
## Development Philosophy
|
|
289
|
+
|
|
290
|
+
The expo-iap library provides a **world-class developer experience**:
|
|
291
|
+
|
|
292
|
+
### ✅ Core Achievements
|
|
293
|
+
|
|
294
|
+
- **🎯 Zero Manual Casting**: Automatic type inference
|
|
295
|
+
- **🌍 Unified API**: Single codebase for iOS and Android
|
|
296
|
+
- **⚡ Enhanced DX**: Better IntelliSense and error messages
|
|
297
|
+
- **🛡️ Full Backward Compatibility**: Existing code continues to work
|
|
298
|
+
- **📚 Modern Patterns**: TypeScript-first, result pattern error handling
|
|
299
|
+
|
|
300
|
+
### 🎯 When Contributing, Always Consider:
|
|
301
|
+
|
|
302
|
+
1. **Developer Experience First** - Eliminate manual work and reduce cognitive load
|
|
303
|
+
2. **Platform Differences** - Handle iOS/Android disparities transparently
|
|
304
|
+
3. **Type Safety** - Provide automatic inference with compile-time guarantees
|
|
305
|
+
4. **Documentation Excellence** - Explain the "why" behind solutions
|
|
306
|
+
5. **Backward Compatibility** - Never break existing code
|
|
307
|
+
6. **Performance** - Optimize for common use cases
|
|
308
|
+
7. **Testing** - Comprehensive coverage across platforms and scenarios
|
|
309
|
+
|
|
310
|
+
### 🚀 Ultimate Goal
|
|
311
|
+
|
|
312
|
+
Transform in-app purchases from a complex, error-prone process into something as simple as:
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
const result = await requestPurchase({
|
|
316
|
+
request: {sku: 'premium.product'},
|
|
317
|
+
type: 'inapp',
|
|
318
|
+
});
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
While maintaining full power and flexibility for advanced enterprise use cases.
|
package/.cursorrules
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# GitHub Copilot and Cursor Rules for expo-iap
|
|
2
|
+
|
|
3
|
+
## Package Manager
|
|
4
|
+
**IMPORTANT: This project uses Bun exclusively. Do not suggest npm, yarn, or pnpm commands.**
|
|
5
|
+
|
|
6
|
+
- Install dependencies: `bun install`
|
|
7
|
+
- Run scripts: `bun run <script>`
|
|
8
|
+
- Run tests: `bun test`
|
|
9
|
+
- Add packages: `bun add <package>`
|
|
10
|
+
- Add dev dependencies: `bun add -d <package>`
|
|
11
|
+
|
|
12
|
+
**NEVER suggest creating package-lock.json or yarn.lock files. Only bun.lock should exist.**
|
|
13
|
+
|
|
14
|
+
## Platform-Specific Function Naming
|
|
15
|
+
|
|
16
|
+
When suggesting code for expo-iap, follow these naming conventions:
|
|
17
|
+
|
|
18
|
+
### Platform-Specific Functions
|
|
19
|
+
Functions that only work on one platform MUST have platform suffixes:
|
|
20
|
+
- iOS: `functionNameIos()`
|
|
21
|
+
- Android: `functionNameAndroid()`
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// Correct examples:
|
|
25
|
+
export const getStorefrontIos = async (): Promise<string> => { ... }
|
|
26
|
+
export const consumeProductAndroid = async (token: string): Promise<void> => { ... }
|
|
27
|
+
export const getAppTransactionIos = async (): Promise<AppTransactionIOS | null> => { ... }
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Cross-Platform Functions
|
|
31
|
+
Functions that abstract platform differences don't need suffixes:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// Correct cross-platform example:
|
|
35
|
+
export const getProducts = async (skus: string[]): Promise<Product[]> => {
|
|
36
|
+
return Platform.select({
|
|
37
|
+
ios: async () => { /* iOS implementation */ },
|
|
38
|
+
android: async () => { /* Android implementation */ },
|
|
39
|
+
})();
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Project Overview
|
|
44
|
+
|
|
45
|
+
This is the **expo-iap** library - a modern React Native/Expo module for handling in-app purchases across iOS and Android platforms. The library provides a unified, TypeScript-first API with automatic type inference and platform abstraction.
|
|
46
|
+
|
|
47
|
+
## Key Principles
|
|
48
|
+
|
|
49
|
+
### 🎯 Modern TypeScript-First API
|
|
50
|
+
|
|
51
|
+
- **Automatic Type Inference**: No manual type casting required
|
|
52
|
+
- **Unified Platform API**: Single API that works across iOS and Android
|
|
53
|
+
- **Consistent Results**: Unified data structure regardless of platform
|
|
54
|
+
- **Clean Error Handling**: Result pattern with detailed error information
|
|
55
|
+
|
|
56
|
+
### 🚀 Primary API Pattern
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const result = await requestPurchase({
|
|
60
|
+
request: {sku: 'product.id'},
|
|
61
|
+
type: 'inapp',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (result.success) {
|
|
65
|
+
console.log('Purchase successful:', result.transactionId);
|
|
66
|
+
} else {
|
|
67
|
+
console.error('Purchase failed:', result.error.message);
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 🏗️ Code Style Guidelines
|
|
72
|
+
|
|
73
|
+
#### TypeScript Best Practices
|
|
74
|
+
|
|
75
|
+
- **Explicit Type Definitions**: Always define types explicitly for public APIs
|
|
76
|
+
- **Function Overloads**: Provide multiple signatures for better IntelliSense
|
|
77
|
+
- **Discriminated Unions**: Use for platform-specific types and conditional returns
|
|
78
|
+
- **Strict Type Safety**: No `any` types in production code
|
|
79
|
+
|
|
80
|
+
#### Naming Conventions
|
|
81
|
+
|
|
82
|
+
- **PascalCase**: Interfaces, types, enums, classes
|
|
83
|
+
- **camelCase**: Functions, variables, methods, properties
|
|
84
|
+
- **kebab-case**: File names (except for React components)
|
|
85
|
+
- **Descriptive Names**: Avoid abbreviations, use clear intent-revealing names
|
|
86
|
+
|
|
87
|
+
#### Error Handling Pattern
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
type PurchaseResult<T = unknown> =
|
|
91
|
+
| {success: true; data: T; platform: 'ios' | 'android'}
|
|
92
|
+
| {success: false; error: PurchaseError; platform: 'ios' | 'android'};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## API Implementation Patterns
|
|
96
|
+
|
|
97
|
+
### Core Purchase Functions
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
export function requestPurchase(params: {
|
|
101
|
+
readonly request: {sku: string; quantity?: number};
|
|
102
|
+
readonly type: 'inapp';
|
|
103
|
+
}): Promise<ProductPurchase | ProductPurchase[]>;
|
|
104
|
+
|
|
105
|
+
export function requestSubscription(params: {
|
|
106
|
+
readonly request: {sku: string};
|
|
107
|
+
}): Promise<SubscriptionPurchase | SubscriptionPurchase[]>;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Platform Abstraction
|
|
111
|
+
|
|
112
|
+
The library automatically handles platform differences:
|
|
113
|
+
|
|
114
|
+
- **iOS**: Uses `sku` directly with StoreKit
|
|
115
|
+
- **Android**: Converts to Google Play Billing format
|
|
116
|
+
- **Unified Properties**: Both platforms return consistent data
|
|
117
|
+
|
|
118
|
+
### Type Guards for Advanced Usage
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
export const isPurchaseResult = (
|
|
122
|
+
result: unknown,
|
|
123
|
+
): result is ProductPurchase | SubscriptionPurchase => {
|
|
124
|
+
return (
|
|
125
|
+
result !== null &&
|
|
126
|
+
typeof result === 'object' &&
|
|
127
|
+
'transactionId' in result &&
|
|
128
|
+
'productId' in result
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## File Organization
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
src/
|
|
137
|
+
├── index.ts # Main exports
|
|
138
|
+
├── ExpoIap.types.ts # Core type definitions
|
|
139
|
+
├── ExpoIapModule.ts # Native module interface
|
|
140
|
+
├── useIap.ts # React hook (legacy support)
|
|
141
|
+
├── modules/
|
|
142
|
+
│ ├── android.ts # Android-specific utilities
|
|
143
|
+
│ └── ios.ts # iOS-specific utilities
|
|
144
|
+
└── types/
|
|
145
|
+
├── ExpoIapAndroid.types.ts # Android type definitions
|
|
146
|
+
└── ExpoIapIos.types.ts # iOS type definitions
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Usage Examples
|
|
150
|
+
|
|
151
|
+
### Simple Product Purchase
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import {requestPurchase} from 'expo-iap';
|
|
155
|
+
|
|
156
|
+
const handlePurchase = async (productId: string) => {
|
|
157
|
+
const result = await requestPurchase({
|
|
158
|
+
request: {sku: productId},
|
|
159
|
+
type: 'inapp',
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (result.success) {
|
|
163
|
+
console.log('Purchase successful:', result.data);
|
|
164
|
+
} else {
|
|
165
|
+
console.error('Purchase failed:', result.error.message);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Subscription Purchase
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import {requestSubscription} from 'expo-iap';
|
|
174
|
+
|
|
175
|
+
const handleSubscription = async (subscriptionId: string) => {
|
|
176
|
+
const result = await requestSubscription({
|
|
177
|
+
request: {sku: subscriptionId},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
if (result.success) {
|
|
181
|
+
console.log('Subscription activated:', result.data);
|
|
182
|
+
} else {
|
|
183
|
+
console.error('Subscription failed:', result.error.message);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Type Naming
|
|
189
|
+
|
|
190
|
+
- Platform-specific types: `ProductIos`, `ProductAndroid`, `PurchaseErrorIos`
|
|
191
|
+
- Cross-platform types: `Product`, `Purchase`, `PurchaseError`
|
|
192
|
+
|
|
193
|
+
## Code Suggestions
|
|
194
|
+
|
|
195
|
+
When generating code:
|
|
196
|
+
1. Check if the function is platform-specific
|
|
197
|
+
2. Add appropriate suffix if it only works on one platform
|
|
198
|
+
3. Use Platform.select() for cross-platform implementations
|
|
199
|
+
4. Always use TypeScript
|
|
200
|
+
5. Include proper error handling
|
|
201
|
+
6. Add JSDoc comments for public APIs
|
|
202
|
+
|
|
203
|
+
## Testing
|
|
204
|
+
Suggest tests that:
|
|
205
|
+
- Cover both iOS and Android paths
|
|
206
|
+
- Use `bun test` commands
|
|
207
|
+
- Include platform mocking when needed
|
|
208
|
+
- Test error scenarios
|
|
209
|
+
|
|
210
|
+
## Common Patterns
|
|
211
|
+
|
|
212
|
+
### Platform Selection
|
|
213
|
+
```typescript
|
|
214
|
+
Platform.select({
|
|
215
|
+
ios: () => { /* iOS code */ },
|
|
216
|
+
android: () => { /* Android code */ },
|
|
217
|
+
default: () => { /* Fallback */ },
|
|
218
|
+
})
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Receipt Validation (Platform-specific parameters)
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// iOS only needs SKU
|
|
225
|
+
await validateReceiptIos(sku);
|
|
226
|
+
|
|
227
|
+
// Android needs additional parameters
|
|
228
|
+
await validateReceiptAndroid({
|
|
229
|
+
packageName,
|
|
230
|
+
productToken,
|
|
231
|
+
accessToken,
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Documentation Standards
|
|
236
|
+
|
|
237
|
+
### Code Comments
|
|
238
|
+
|
|
239
|
+
- **Document the "why"**, not just the "what"
|
|
240
|
+
- **Explain platform differences** and how they're handled
|
|
241
|
+
- **Provide usage examples** for complex APIs
|
|
242
|
+
- **Use JSDoc format** for all public APIs
|
|
243
|
+
|
|
244
|
+
### Example Documentation Pattern
|
|
245
|
+
|
|
246
|
+
````typescript
|
|
247
|
+
/**
|
|
248
|
+
* Enhanced requestPurchase with unified API support
|
|
249
|
+
*
|
|
250
|
+
* This function automatically handles platform differences:
|
|
251
|
+
* - iOS: Uses `sku` directly with StoreKit
|
|
252
|
+
* - Android: Converts to Google Play Billing format
|
|
253
|
+
*
|
|
254
|
+
* @param params - Purchase request parameters
|
|
255
|
+
* @param params.request - Request object with product details
|
|
256
|
+
* @param params.type - Purchase type: 'inapp' for products
|
|
257
|
+
*
|
|
258
|
+
* @returns Promise resolving to purchase result
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```typescript
|
|
262
|
+
* const result = await requestPurchase({
|
|
263
|
+
* request: { sku: 'com.example.premium' },
|
|
264
|
+
* type: 'inapp'
|
|
265
|
+
* });
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
````
|
|
269
|
+
|
|
270
|
+
## Development Philosophy
|
|
271
|
+
|
|
272
|
+
The expo-iap library provides a **world-class developer experience**:
|
|
273
|
+
|
|
274
|
+
### ✅ Core Achievements
|
|
275
|
+
|
|
276
|
+
- **🎯 Zero Manual Casting**: Automatic type inference
|
|
277
|
+
- **🌍 Unified API**: Single codebase for iOS and Android
|
|
278
|
+
- **⚡ Enhanced DX**: Better IntelliSense and error messages
|
|
279
|
+
- **🛡️ Full Backward Compatibility**: Existing code continues to work
|
|
280
|
+
- **📚 Modern Patterns**: TypeScript-first, result pattern error handling
|
|
281
|
+
|
|
282
|
+
### 🎯 When Contributing, Always Consider:
|
|
283
|
+
|
|
284
|
+
1. **Developer Experience First** - Eliminate manual work and reduce cognitive load
|
|
285
|
+
2. **Platform Differences** - Handle iOS/Android disparities transparently
|
|
286
|
+
3. **Type Safety** - Provide automatic inference with compile-time guarantees
|
|
287
|
+
4. **Documentation Excellence** - Explain the "why" behind solutions
|
|
288
|
+
5. **Backward Compatibility** - Never break existing code
|
|
289
|
+
6. **Performance** - Optimize for common use cases
|
|
290
|
+
7. **Testing** - Comprehensive coverage across platforms and scenarios
|
|
291
|
+
|
|
292
|
+
### 🚀 Ultimate Goal
|
|
293
|
+
|
|
294
|
+
Transform in-app purchases from a complex, error-prone process into something as simple as:
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
const result = await requestPurchase({
|
|
298
|
+
request: {sku: 'premium.product'},
|
|
299
|
+
type: 'inapp',
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
While maintaining full power and flexibility for advanced enterprise use cases.
|