diff --git a/.github/pr-previews/july-2026-release-notes.png b/.github/pr-previews/july-2026-release-notes.png new file mode 100644 index 000000000..73eb9c523 Binary files /dev/null and b/.github/pr-previews/july-2026-release-notes.png differ diff --git a/packages/docs/src/pages/docs/updates/releases.tsx b/packages/docs/src/pages/docs/updates/releases.tsx index 8d852a323..db950b72b 100644 --- a/packages/docs/src/pages/docs/updates/releases.tsx +++ b/packages/docs/src/pages/docs/updates/releases.tsx @@ -22,16 +22,16 @@ interface Note { element: React.ReactNode; } -const androidOfferCodePlannedReleases = [ - 'OpenIAP Spec 2.5.0 (docs-2.5.0, planned)', - 'openiap-apple 2.4.2 (planned)', - 'openiap-google 2.5.0 (planned)', - 'react-native-iap 15.6.0 (planned)', - 'expo-iap 4.7.0 (planned)', - 'flutter_inapp_purchase 9.6.0 (planned)', - 'godot-iap 2.6.0 (planned)', - 'kmp-iap 2.7.0 (planned)', - 'OpenIap.Maui 1.4.0 (planned)', +const androidOfferCodeReleases = [ + ['OpenIAP Spec 2.5.0', 'docs-2.5.0'], + ['openiap-apple 2.4.2', '2.4.2'], + ['openiap-google 2.5.0', 'google-2.5.0'], + ['react-native-iap 15.6.0', 'react-native-iap-15.6.0'], + ['expo-iap 4.7.0', 'expo-iap-4.7.0'], + ['flutter_inapp_purchase 9.6.0', 'flutter-iap-9.6.0'], + ['godot-iap 2.6.0', 'godot-iap-2.6.0'], + ['kmp-iap 2.7.0', 'kmp-iap-2.7.0'], + ['OpenIap.Maui 1.4.0', 'maui-iap-1.4.0'], ] as const; const fetchProductsAllFixReleases = [ @@ -86,17 +86,21 @@ function Releases() { useScrollToHash(); const allNotes: Note[] = [ - // July 22, 2026 - Android offer-code redemption across SDKs + // July 23, 2026 - IAPKit webhook deduplication and ASC review automation { - id: 'android-offer-code-redemption-2026-07-22', - date: new Date('2026-07-22'), + id: 'iapkit-webhook-dedup-asc-review-automation-2026-07-23', + date: new Date('2026-07-23'), element: (
- Prepares the stable release train for{' '} + Deploys two hosted IAPKit service updates.{' '} + + PR #245 + {' '} + moves webhook deduplication onto source-aware event identity as + phase 1 of{' '} + + issue #241 + + {', while '} + + PR #246 + {' '} + adds version-based App Store Connect review submissions and + completes{' '} + + issue #242 + + {'. '}These are hosted-service changes and require no SDK package + upgrade. +
+ +webhookEvents identity formed
+ from project, store source, and notification ID. Notifications
+ from different projects or store sources no longer collide when an
+ upstream identifier happens to match.
+ webhookIdempotencyKeys reads, writes, pruning, and
+ deletion cascades remain available for rollback and retained-row
+ compatibility. A later deployment must first stop legacy key
+ writes, wait at least the 30-day WEBHOOK_RETENTION_MS{' '}
+ window, and confirm that the table has zero rows before removing
+ the table, cron work, or cascades. The webhook-event retention
+ cron remains required.
+ en-US localization, execute
+ every upload operation reserved by App Store Connect, commit the
+ MD5 checksum, wait for asset delivery, and submit bounded eligible
+ batches for review. Checksum-committed uploads and Ready rows
+ resume against the exact stored screenshot identity.
+ + See the{' '} + + IAPKit product-sync documentation + {' '} + and the hosted{' '} + + Products guide + {' '} + for the operator workflow and screenshot-reuse policy. +
+
+ Publishes OpenIAP Spec 2.5.0 and coordinated stable package releases
+ for{' '}
openRedeemOfferCodeAndroid
{' '}
@@ -118,10 +282,10 @@ function Releases() {
>
PR #243
- . The additive API opens Google Play's offer or promo-code
- redemption surface without requiring an initialized billing client,
- preserves explicit unsupported-store results, and will carry the
- same contract through every maintained framework SDK.
+ {'. '}The additive Android-only API opens Google Play's offer
+ or promo-code redemption surface without requiring an initialized
+ billing client, preserves explicit unsupported-store results, and
+ carries the same contract through every maintained framework SDK.
openRedeemOfferCodeAndroid mutation
- returning true when the redemption surface launches
- and false when the active store flavor has no
- equivalent flow. Generated Swift, Kotlin, TypeScript, Dart,
- GDScript, and C# resolver contracts stay synchronized with the
- schema.
+ OpenIAP Spec 2.5.0 - adds the Android-only{' '}
+ openRedeemOfferCodeAndroid mutation returning{' '}
+ true when the redemption surface launches and{' '}
+ false when the active store flavor has no equivalent
+ flow. Generated Swift, Kotlin, TypeScript, Dart, GDScript, and C#
+ resolver contracts stay synchronized with the schema.
https://play.google.com/redeem for Google Play builds
while Amazon and Horizon return false instead of
throwing or opening an unrelated external-link flow. The Play
purchase callback also recovers an in-flight{' '}
ITEM_ALREADY_OWNED result by querying owned purchases
- and completing the request with the matching entitlement.
+ and completing the request with the matching entitlement. Play and
+ Horizon purchase callbacks are also bound to the originating
+ client generation, so updates from a disconnected or replaced
+ client are ignored without dropping recovery events from the
+ active connection.
useIAP. Android now retains
+ react-native-iap 15.6.0 - exports the new API
+ directly and from useIAP. Android now retains
purchase updates and errors in bounded FIFO queues while no JS
listener is attached, flushes them after listener registration,
and includes listeners added during a flush only for later
@@ -183,14 +350,16 @@ function Releases() {
of being consumed by an orphaned callback.
useIAP, returns the launch result to the app,
- and reports false on unsupported Vega or Kepler store
- paths. It also declares tvos in Expo module platform
- metadata, so TV-mode prebuilds autolink the existing Apple native
- module and app-delegate subscriber instead of silently omitting
- ExpoIap (
+ expo-iap 4.7.0 - replaces the JavaScript URL stub
+ with the native OpenIAP handler, exposes the mutation from{' '}
+ useIAP, returns the launch result to the app, and
+ reports false on unsupported Vega or Kepler store
+ paths. Native failures such as an unavailable Android activity
+ keep their typed OpenIAP error instead of being replaced by a
+ generic bridge error. It also declares tvos in Expo
+ module platform metadata, so TV-mode prebuilds autolink the
+ existing Apple native module and app-delegate subscriber instead
+ of silently omitting ExpoIap (
false{' '}
for the Android-only capability.
OpenRedeemOfferCodeAndroidAsync to the generated CLR
resolver, binds it to the store-aware Android handler, and keeps
the iOS implementation as an explicit false result.
@@ -276,11 +449,14 @@ function Releases() {
color: 'var(--text-secondary)',
}}
>
- The documentation adds the Android API reference, updates the
+ The documentation publishes the Android API reference, updates the
cross-SDK offer-code guide and examples, and clarifies the macOS
- subscription-management and refund fallbacks. IAPKit has no runtime
- release in this train: its touched files contain test stabilization
- and internal comment cleanup only.
+ subscription-management and refund fallbacks. The separate hosted
+ IAPKit deployments are documented in the{' '}
+
+ July 23 IAPKit entry
+ {' '}
+ and do not have installable package tags.
- These are post-merge release targets, not the versions currently
- stored in this branch. Stable release workflows on{' '}
- main will bump the package metadata from the
- published Spec 2.4.0 and native 2.4.1 baselines. Until each
- release exists, these entries remain unlinked and should not be
- treated as installable versions.
-