Skip to content
This repository was archived by the owner on Apr 26, 2026. It is now read-only.

Commit b903301

Browse files
hyochanclaude
andauthored
feat: sync with openiap v1.3.17 (#3147)
## Summary - Sync with OpenIAP v1.3.17 - Add InstallmentPlanDetailsAndroid type (Billing Library 7.0+) - Add PendingPurchaseUpdateAndroid type (Billing Library 5.0+) - Add purchaseOptionIdAndroid field to DiscountOffer (Billing Library 7.0+) - Add tests for new types - Update llms.txt with new type documentation - Add release blog post ## Related - OpenIAP PR: hyodotdev/openiap#78 - OpenIAP Release Notes: https://www.openiap.dev/docs/updates/notes#gql-1-3-17-google-1-3-28 ## OpenIAP Versions | Package | Version | |---------|---------| | openiap-gql | 1.3.17 | | openiap-google | 1.3.28 | | openiap-apple | 1.3.14 | 🤖 Generated with [Claude Code](https://claude.ai/claude-code) --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 1c14dab commit b903301

6 files changed

Lines changed: 311 additions & 3 deletions

File tree

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
slug: 14.7.10
3+
title: 14.7.10 - OpenIAP 1.3.17 Sync
4+
authors: [hyochan]
5+
tags: [release, openiap, android, billing-library]
6+
date: 2026-02-11
7+
---
8+
9+
# 14.7.10 Release Notes
10+
11+
This release syncs with [OpenIAP v1.3.17](https://www.openiap.dev/docs/updates/notes#gql-1317), adding new types for Google Play Billing Library 5.0+ and 7.0+ features.
12+
13+
<!-- truncate -->
14+
15+
## New Types
16+
17+
### InstallmentPlanDetailsAndroid (Billing Library 7.0+)
18+
19+
Subscription installment plan details for plans that allow users to pay in installments.
20+
21+
```typescript
22+
interface InstallmentPlanDetailsAndroid {
23+
/** Committed payments count after signup (e.g., 12 monthly payments) */
24+
commitmentPaymentsCount: number;
25+
/** Subsequent commitment payments when plan renews (0 if reverts to normal) */
26+
subsequentCommitmentPaymentsCount: number;
27+
}
28+
```
29+
30+
This is available on `ProductSubscriptionAndroidOfferDetails.installmentPlanDetails`.
31+
32+
### PendingPurchaseUpdateAndroid (Billing Library 5.0+)
33+
34+
Details about pending subscription upgrades/downgrades.
35+
36+
```typescript
37+
interface PendingPurchaseUpdateAndroid {
38+
/** Product IDs for the pending purchase update */
39+
products: string[];
40+
/** Purchase token for the pending transaction */
41+
purchaseToken: string;
42+
}
43+
```
44+
45+
This is available on `PurchaseAndroid.pendingPurchaseUpdateAndroid`.
46+
47+
### purchaseOptionIdAndroid (Billing Library 7.0+)
48+
49+
New field on `DiscountOffer` and `ProductAndroidOneTimePurchaseOfferDetail` to identify which purchase option the user selected.
50+
51+
```typescript
52+
// Available on DiscountOffer
53+
discountOffer.purchaseOptionIdAndroid // string | null
54+
```
55+
56+
## OpenIAP Versions
57+
58+
| Package | Version |
59+
|---------|---------|
60+
| openiap-gql | 1.3.17 |
61+
| openiap-google | 1.3.28 |
62+
| openiap-apple | 1.3.14 |
63+
64+
## Installation
65+
66+
```bash
67+
yarn add react-native-iap@14.7.10
68+
```
69+
70+
## Related
71+
72+
- [OpenIAP Release Notes](https://www.openiap.dev/docs/updates/notes#gql-1317)

docs/bun.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/static/llms.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,36 @@ interface DiscountOffer {
212212
offerTokenAndroid?: string;
213213
discountAmountMicrosAndroid?: string;
214214
formattedDiscountAmountAndroid?: string;
215+
purchaseOptionIdAndroid?: string; // v14.7.10+, Billing Library 7.0+
215216
}
216217
```
217218

219+
### InstallmentPlanDetailsAndroid (v14.7.10+, Billing Library 7.0+)
220+
221+
Subscription installment plan details:
222+
223+
```tsx
224+
interface InstallmentPlanDetailsAndroid {
225+
commitmentPaymentsCount: number; // Initial commitment (e.g., 12 months)
226+
subsequentCommitmentPaymentsCount: number; // Renewal commitment (0 if reverts to normal)
227+
}
228+
```
229+
230+
Available on `ProductSubscriptionAndroidOfferDetails.installmentPlanDetails`.
231+
232+
### PendingPurchaseUpdateAndroid (v14.7.10+, Billing Library 5.0+)
233+
234+
Pending subscription upgrade/downgrade details:
235+
236+
```tsx
237+
interface PendingPurchaseUpdateAndroid {
238+
products: string[]; // New products being switched to
239+
purchaseToken: string; // Pending transaction token
240+
}
241+
```
242+
243+
Available on `PurchaseAndroid.pendingPurchaseUpdateAndroid`.
244+
218245
### Purchase
219246

220247
```tsx
@@ -231,6 +258,7 @@ interface Purchase {
231258
autoRenewingAndroid?: boolean;
232259
packageNameAndroid?: string;
233260
isSuspendedAndroid?: boolean; // v14.7.3+, Billing Library 8.1+
261+
pendingPurchaseUpdateAndroid?: PendingPurchaseUpdateAndroid; // v14.7.10+, Billing Library 5.0+
234262
}
235263
```
236264

openiap-versions.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"apple": "1.3.14",
3-
"google": "1.3.27",
4-
"gql": "1.3.16",
5-
"docs": "1.3.16"
3+
"google": "1.3.28",
4+
"gql": "1.3.17",
5+
"docs": "1.3.17"
66
}

src/__tests__/standardized-offer-types.test.ts

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import type {
1717
ProductAndroid,
1818
ProductSubscriptionAndroid,
1919
RequestPurchaseAndroidProps,
20+
InstallmentPlanDetailsAndroid,
21+
PendingPurchaseUpdateAndroid,
22+
PurchaseAndroid,
2023
} from '../types';
2124

2225
describe('Standardized Offer Types', () => {
@@ -466,4 +469,136 @@ describe('Standardized Offer Types', () => {
466469
expect(purchaseRequest.offerToken).toBe('summer_sale_offer_token');
467470
});
468471
});
472+
473+
describe('InstallmentPlanDetailsAndroid', () => {
474+
it('should have correct structure for subscription installment plans', () => {
475+
// Installment plan details are available in Google Play Billing Library 7.0+
476+
const installmentDetails: InstallmentPlanDetailsAndroid = {
477+
commitmentPaymentsCount: 12,
478+
subsequentCommitmentPaymentsCount: 12,
479+
};
480+
481+
expect(installmentDetails.commitmentPaymentsCount).toBe(12);
482+
expect(installmentDetails.subsequentCommitmentPaymentsCount).toBe(12);
483+
});
484+
485+
it('should support zero subsequentCommitmentPaymentsCount for non-recurring installments', () => {
486+
// When subsequentCommitmentPaymentsCount is 0, plan reverts to normal after initial commitment
487+
const nonRecurringInstallment: InstallmentPlanDetailsAndroid = {
488+
commitmentPaymentsCount: 6,
489+
subsequentCommitmentPaymentsCount: 0,
490+
};
491+
492+
expect(nonRecurringInstallment.commitmentPaymentsCount).toBe(6);
493+
expect(nonRecurringInstallment.subsequentCommitmentPaymentsCount).toBe(0);
494+
});
495+
});
496+
497+
describe('PendingPurchaseUpdateAndroid', () => {
498+
it('should have correct structure for pending subscription changes', () => {
499+
// Pending purchase updates are available in Google Play Billing Library 5.0+
500+
const pendingUpdate: PendingPurchaseUpdateAndroid = {
501+
products: ['premium_yearly'],
502+
purchaseToken: 'pending_token_abc123',
503+
};
504+
505+
expect(pendingUpdate.products).toEqual(['premium_yearly']);
506+
expect(pendingUpdate.purchaseToken).toBe('pending_token_abc123');
507+
});
508+
509+
it('should support multiple products in pending update', () => {
510+
// When upgrading to a bundle or combined subscription
511+
const bundlePendingUpdate: PendingPurchaseUpdateAndroid = {
512+
products: ['premium_yearly', 'addon_storage'],
513+
purchaseToken: 'bundle_pending_token_xyz',
514+
};
515+
516+
expect(bundlePendingUpdate.products).toHaveLength(2);
517+
expect(bundlePendingUpdate.products).toContain('premium_yearly');
518+
expect(bundlePendingUpdate.products).toContain('addon_storage');
519+
});
520+
});
521+
522+
describe('purchaseOptionIdAndroid on DiscountOffer', () => {
523+
it('should support purchaseOptionIdAndroid field', () => {
524+
// purchaseOptionIdAndroid is available in Google Play Billing Library 7.0+
525+
const discountOfferWithPurchaseOption: DiscountOffer = {
526+
id: 'limited_offer',
527+
displayPrice: '$3.99',
528+
price: 3.99,
529+
currency: 'USD',
530+
type: 'one-time',
531+
offerTokenAndroid: 'offer_token_123',
532+
purchaseOptionIdAndroid: 'purchase_option_456',
533+
};
534+
535+
expect(discountOfferWithPurchaseOption.purchaseOptionIdAndroid).toBe(
536+
'purchase_option_456',
537+
);
538+
});
539+
540+
it('should allow purchaseOptionIdAndroid to be optional', () => {
541+
const offerWithoutPurchaseOption: DiscountOffer = {
542+
displayPrice: '$4.99',
543+
price: 4.99,
544+
currency: 'USD',
545+
type: 'promotional',
546+
// No purchaseOptionIdAndroid - not all offers have this
547+
};
548+
549+
expect(
550+
offerWithoutPurchaseOption.purchaseOptionIdAndroid,
551+
).toBeUndefined();
552+
});
553+
});
554+
555+
describe('PurchaseAndroid with pendingPurchaseUpdateAndroid', () => {
556+
it('should include pendingPurchaseUpdateAndroid for subscription upgrades', () => {
557+
// When a subscription upgrade/downgrade is pending
558+
const purchaseWithPendingUpdate: PurchaseAndroid = {
559+
id: 'purchase_id_abc',
560+
productId: 'premium_monthly',
561+
platform: 'android',
562+
transactionDate: 1704067200000,
563+
purchaseToken: 'current_token',
564+
purchaseState: 'purchased',
565+
packageNameAndroid: 'com.example.app',
566+
isAutoRenewing: true,
567+
quantity: 1,
568+
store: 'google',
569+
pendingPurchaseUpdateAndroid: {
570+
products: ['premium_yearly'],
571+
purchaseToken: 'pending_upgrade_token',
572+
},
573+
};
574+
575+
expect(
576+
purchaseWithPendingUpdate.pendingPurchaseUpdateAndroid,
577+
).toBeDefined();
578+
expect(
579+
purchaseWithPendingUpdate.pendingPurchaseUpdateAndroid?.products,
580+
).toEqual(['premium_yearly']);
581+
expect(
582+
purchaseWithPendingUpdate.pendingPurchaseUpdateAndroid?.purchaseToken,
583+
).toBe('pending_upgrade_token');
584+
});
585+
586+
it('should allow pendingPurchaseUpdateAndroid to be undefined for regular purchases', () => {
587+
const regularPurchase: PurchaseAndroid = {
588+
id: 'purchase_id_xyz',
589+
productId: 'consumable_coins',
590+
platform: 'android',
591+
transactionDate: 1704067200000,
592+
purchaseToken: 'regular_token',
593+
purchaseState: 'purchased',
594+
packageNameAndroid: 'com.example.app',
595+
isAutoRenewing: false,
596+
quantity: 1,
597+
store: 'google',
598+
// No pending update - this is a regular purchase
599+
};
600+
601+
expect(regularPurchase.pendingPurchaseUpdateAndroid).toBeUndefined();
602+
});
603+
});
469604
});

0 commit comments

Comments
 (0)