Split out of #292, where it was carried for four review rounds and then removed. The code exists in that PR's history (commits 88af4634 through 79356ab0) and can be lifted from there.
Why
#288 made a pushed product available in every region Play prices, which is what the issue asked for and what Play Console's own bulk-pricing flow does. But it means kit decides the footprint. An operator who ships to three countries has no way to say so, and newRegionsConfig additionally opts the product into markets Play launches later at a converted price nobody reviewed.
Product-level regions are gated by the app's own country distribution, so the current default is not "selling in 173 countries" — but it is still kit choosing.
What was already established
Verified against real Play (dev.hyo.petgu.app) while it was in #292:
- Creating with
regions: ["US","KR","JP"] produced exactly 3 configs, each in local currency, with no newRegionsConfig.
- Play refuses to drop a region once a purchase option has it:
Cannot remove region once it has been added: AE. Restricting an existing product means setting the others to NO_LONGER_AVAILABLE, which the API documents as legal only from AVAILABLE.
- An already-enabled
newRegionsConfig has to be actively withdrawn; omitting it carries the old one forward through the purchase-option spread.
What has to be true before it ships
These are the confirmed findings that made it worth splitting out, not a wish list:
- Not a phantom anywhere. ASC prices per territory through a resource the sync does not touch, and Play's subscription update masks
listings only, so a base plan's regional configs are fixed at create. The field must be refused — and hidden in the dashboard — for iOS and for subscriptions, not accepted and ignored.
- The legacy
inappproducts fallback cannot honour a footprint (it prices every region or none). It has to fail on that branch only, carrying the modern failure into the message, and never before the modern attempt.
- Re-enabling must work. A region kit withdrew has to come back when it is added to the list again.
- The degraded path. With no conversion, a footprint that excludes US has nothing legal to write; and
regionsVersion must follow the version the preserved configs came from.
- Reporting must be honest. A requested region Play returns no price for should be named. Withdrawn regions must not be counted as prices left stale, and
availability is absent when a region is available.
- Tests must go through
upsertAndroidOneTimeProduct, not around it. The feature shipped completely dead once with a green suite because every test called the inner function directly.
Suggested shape
regions: v.optional(v.union(v.array(v.string()), v.null())) on products, unset meaning today's sell-everywhere default so nothing changes for anyone who ignores it. Region codes validated as assigned territories rather than any two letters (ZZ, QB, XA are not regions; XK and QA are).
Split out of #292, where it was carried for four review rounds and then removed. The code exists in that PR's history (commits
88af4634through79356ab0) and can be lifted from there.Why
#288 made a pushed product available in every region Play prices, which is what the issue asked for and what Play Console's own bulk-pricing flow does. But it means kit decides the footprint. An operator who ships to three countries has no way to say so, and
newRegionsConfigadditionally opts the product into markets Play launches later at a converted price nobody reviewed.Product-level regions are gated by the app's own country distribution, so the current default is not "selling in 173 countries" — but it is still kit choosing.
What was already established
Verified against real Play (
dev.hyo.petgu.app) while it was in #292:regions: ["US","KR","JP"]produced exactly 3 configs, each in local currency, with nonewRegionsConfig.Cannot remove region once it has been added: AE. Restricting an existing product means setting the others toNO_LONGER_AVAILABLE, which the API documents as legal only fromAVAILABLE.newRegionsConfighas to be actively withdrawn; omitting it carries the old one forward through the purchase-option spread.What has to be true before it ships
These are the confirmed findings that made it worth splitting out, not a wish list:
listingsonly, so a base plan's regional configs are fixed at create. The field must be refused — and hidden in the dashboard — for iOS and for subscriptions, not accepted and ignored.inappproductsfallback cannot honour a footprint (it prices every region or none). It has to fail on that branch only, carrying the modern failure into the message, and never before the modern attempt.regionsVersionmust follow the version the preserved configs came from.availabilityis absent when a region is available.upsertAndroidOneTimeProduct, not around it. The feature shipped completely dead once with a green suite because every test called the inner function directly.Suggested shape
regions: v.optional(v.union(v.array(v.string()), v.null()))onproducts, unset meaning today's sell-everywhere default so nothing changes for anyone who ignores it. Region codes validated as assigned territories rather than any two letters (ZZ,QB,XAare not regions;XKandQAare).