Skip to content

feat(metadata): basic in-app purchase listing#3597

Draft
EvanBacon wants to merge 2 commits intomainfrom
@bacon/metadata-iap-listing
Draft

feat(metadata): basic in-app purchase listing#3597
EvanBacon wants to merge 2 commits intomainfrom
@bacon/metadata-iap-listing

Conversation

@EvanBacon
Copy link
Copy Markdown
Contributor

@EvanBacon EvanBacon commented Apr 9, 2026

Summary

Adds a new InAppPurchasesTask to EAS metadata that round-trips the
basic listing of an app's In-App Purchases (productId, referenceName,
type, plus a read-only state) to/from store.config.json.

This is intentionally a thin first iteration. The goal is to give users a
declarative starting point for the IAP listing without overcommitting to
mutations the underlying API surface doesn't support yet.

Dependency: expo/third-party#148

The third-party repo has a PR (expo/third-party#148) adding:

  • InAppPurchaseV2 model with full CRUD (getAsync, infoAsync, createAsync, updateAsync, deleteAsync)
  • InAppPurchaseLocalization model with CRUD (createAsync, updateAsync, deleteAsync, infoAsync)
  • App.getInAppPurchasesV2Async() for sub-resource listing
  • Convenience methods: getLocalizationsAsync(), createLocalizationAsync()

What works now (v1 read-only)

  • metadata:pull reads existing IAPs via the v1 App#getInAppPurchasesAsync() endpoint
  • metadata:push matches config against ASC by productId and reports diffs (would-create / would-rename) as warnings — no mutations

What's blocked on apple-utils bump

  • Create/update IAPs — requires InAppPurchaseV2.createAsync() / updateAsync() from expo/third-party#148
  • Localized name/description — requires InAppPurchaseLocalization from expo/third-party#148; schema will need an optional localizations array per IAP entry
  • TODOs with specific migration steps are in the task file

Auto-renewable subscriptions: intentionally out of scope

Auto-renewable subscriptions are not part of the v2 IAP resource. They live
on separate subscriptionGroups / subscriptions endpoints. The v2
InAppPurchaseV2Type enum only has CONSUMABLE, NON_CONSUMABLE, and
NON_RENEWING_SUBSCRIPTION.

Legacy v1 auto-renewable entries may still appear on metadata:pull (the v1
enum includes AUTOMATICALLY_RENEWABLE_SUBSCRIPTION), but they cannot be
created or managed via IAP APIs. The type enum preserves these values with
@deprecated markers for backward compatibility.

Scope

In scope:

  • New inAppPurchases block in the metadata schema types
  • New task packages/eas-cli/src/metadata/apple/tasks/in-app-purchases.ts
  • metadata:pull writes the existing IAP listing to store.config.json
  • metadata:push matches by productId against ASC and reports diffs without mutating
  • Registered in the task orchestrator (tasks/index.ts)
  • 10 unit tests covering empty, single create, no-op, rename, multiple, error fallback, round-trip

Explicitly out of scope:

  • Localizations (blocked on apple-utils bump)
  • Pricing / price points / introductory offers
  • Review screenshots / review notes / family sharing / content hosting
  • Auto-renewable subscriptions (separate Apple resource)
  • Deletes — never deletes IAPs in ASC missing from config
  • Actual create/update mutations on push (blocked on apple-utils bump)

Test plan

  • npx jest src/metadata — 16 suites, 194 tests passing (10 new IAP tests)
  • oxlint on changed files — clean
  • Manual: run metadata:pull against an app with IAPs and verify inAppPurchases in store.config.json
  • Manual: run metadata:push after editing referenceName and verify warning lists the diff without mutating ASC

Open questions / follow-ups

  1. Bump apple-utils once expo/third-party#148 is merged and published, then switch to v2 CRUD per the TODO block in the task file.
  2. Localization schema design — add localizations: Record<locale, { name, description }> per IAP entry once InAppPurchaseLocalization is available.
  3. Deletes — should we opt-in delete with a flag or require an explicit deleted: true marker? Apple's flow is non-trivial.
  4. Subscription support — consider a separate subscriptions task for subscriptionGroups/subscriptions resources if there's demand.

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

Pull existing IAPs (productId / referenceName / type) into store.config.json
and warn on push when ASC differs. Push is read-only for now because
@expo/apple-utils only exposes the deprecated v1 inAppPurchases endpoint
without create/update/delete; localization, pricing, deletes, and v2 are
deferred follow-ups.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 9, 2026

Subscribed to pull request

File Patterns Mentions
**/* @douglowder
packages/eas-cli/schema/** @byCedric
packages/eas-cli/src/metadata/** @byCedric

Generated by CodeMention

@EvanBacon EvanBacon marked this pull request as draft April 10, 2026 00:12
…IAP task

Add TODO block referencing expo/third-party#148 for the v2 CRUD migration
(InAppPurchaseV2, InAppPurchaseLocalization). Document that auto-renewable
subscriptions are a separate Apple resource (subscriptionGroups/subscriptions)
and intentionally out of scope. Mark legacy v1-only type enum members as
deprecated. Shorten the upload warning to reference the specific dependency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

❌ It looks like a changelog entry is missing for this PR. Add it manually to CHANGELOG.md.
⏩ If this PR doesn't require a changelog entry, such as if it's an internal change that doesn't affect the user experience, you can add the "no changelog" label to the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant