@nosslabs/iap 7.0.0-next.0 → 7.1.0

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/dist/index.d.cts CHANGED
@@ -844,10 +844,6 @@ interface EventMap<TEntitlement extends EntitlementBase = EntitlementBase> {
844
844
  entitlements: TEntitlement[];
845
845
  previous: TEntitlement[];
846
846
  };
847
- 'price-stale': {
848
- productId: string;
849
- lastFetchedAt: number;
850
- };
851
847
  /**
852
848
  * Recovery classified an `unfinished_transactions` entry as permanently
853
849
  * invalid (per `options.permanentErrorCodes`) and removed it from
@@ -866,9 +862,6 @@ interface EventMap<TEntitlement extends EntitlementBase = EntitlementBase> {
866
862
  error: string;
867
863
  message?: string;
868
864
  };
869
- error: {
870
- error: IAPError;
871
- };
872
865
  }
873
866
  type EventName<TEntitlement extends EntitlementBase = EntitlementBase> = keyof EventMap<TEntitlement>;
874
867
  type EventPayload<K extends EventName<TEntitlement>, TEntitlement extends EntitlementBase = EntitlementBase> = EventMap<TEntitlement>[K];
@@ -957,6 +950,39 @@ interface RestoreResult<TEntitlement extends EntitlementBase = EntitlementBase>
957
950
  entitlements: TEntitlement[];
958
951
  }
959
952
 
953
+ /**
954
+ * The user's App Store / Google Play storefront — i.e. the country their
955
+ * store account is registered to, which is the platform-blessed signal for
956
+ * region-dependent decisions (regional pricing/offers, and gating
957
+ * external-payment links whose eligibility the OS itself keys to storefront
958
+ * country, *not* device locale).
959
+ *
960
+ * `countryCode` is normalized to **ISO 3166-1 alpha-2** across platforms so
961
+ * consumers compare one consistent value (Apple's native code is alpha-3,
962
+ * Google's is alpha-2). The raw native code is preserved in `countryCodeRaw`.
963
+ *
964
+ * Treat the value as a **UX / targeting hint** and read it live (never cache):
965
+ * for compliance- or entitlement-sensitive enforcement, trust the server-side
966
+ * signed storefront (App Store Server API `storefront` / Play Developer API
967
+ * `regionCode`) instead, since the client value can be unreliable (TestFlight
968
+ * historically reports `"USA"`) or empty (EU alternative distribution).
969
+ */
970
+ interface Storefront {
971
+ /**
972
+ * ISO 3166-1 alpha-2 country code (normalized), e.g. `'US'`. In the rare
973
+ * case the native value can't be normalized (an unrecognized code), this
974
+ * falls back to the uppercased raw value — compare against `countryCodeRaw`
975
+ * if you need certainty about the format.
976
+ */
977
+ countryCode: string;
978
+ /** Raw native value (whitespace-trimmed): alpha-3 on iOS (`'USA'`), alpha-2 on Android (`'US'`). */
979
+ countryCodeRaw: string;
980
+ /** Apple-defined storefront identifier (iOS only); `undefined` on Android. */
981
+ storefrontId?: string;
982
+ /** Store the value came from. */
983
+ platform: Platform;
984
+ }
985
+
960
986
  interface IAP<TEntitlement extends EntitlementBase = EntitlementBase> {
961
987
  initialize(): Promise<void>;
962
988
  /**
@@ -1037,6 +1063,25 @@ interface IAP<TEntitlement extends EntitlementBase = EntitlementBase> {
1037
1063
  * yet ingested by the store are silently skipped (no error).
1038
1064
  */
1039
1065
  getProducts(): Promise<Product[]>;
1066
+ /**
1067
+ * Read the current storefront — the country the user's App Store / Google
1068
+ * Play account is registered to. Use it to drive region-dependent UI:
1069
+ * regional offers/pricing, and gating external-payment links whose
1070
+ * eligibility the platform itself keys to storefront country (not device
1071
+ * locale).
1072
+ *
1073
+ * `countryCode` is normalized to ISO 3166-1 alpha-2 across platforms (raw
1074
+ * native code preserved on `countryCodeRaw`). Resolves `null` when no
1075
+ * storefront is available — on web, when the installed
1076
+ * `@capgo/native-purchases` doesn't register the native method, when the
1077
+ * native call fails, or when the store reports an empty country (e.g. EU
1078
+ * alternative distribution).
1079
+ *
1080
+ * Read live — do not cache. Treat the value as a UX/targeting hint; for
1081
+ * compliance- or entitlement-sensitive enforcement, trust the server-side
1082
+ * signed storefront from your backend instead.
1083
+ */
1084
+ getStorefront(): Promise<Storefront | null>;
1040
1085
  hasEntitlement(key: string): boolean;
1041
1086
  /** Returns a defensive shallow copy. Each entitlement is frozen. */
1042
1087
  getEntitlements(): TEntitlement[];
@@ -1221,4 +1266,4 @@ declare class HttpBackendAdapter<TEntitlement extends EntitlementBase = Entitlem
1221
1266
  listProducts(): Promise<ConfiguredProduct[]>;
1222
1267
  }
1223
1268
 
1224
- export { type AppUserId, type BackendAdapter, type BackendConfig, type BackendConfigInput, type ConfiguredProduct, DEFAULT_PERMANENT_ERROR_CODES, type DefaultEntitlement, type EntitlementBase, type EventMap, type EventName, type EventPayload, HttpBackendAdapter, HttpClient, type HttpRequest, type IAP, type IAPConfig, type IAPConfigInput, IAPError, IAPErrorCode, type LogLevel, type Logger, type NativeTransaction, type OptionsConfig, type Platform, type Product, type ProductType, type PurchaseOptions, type PurchaseResult, type RestoreRequest, type RestoreRequestTransaction, type RestoreResponse, type RestoreResult, type StorageConfig, type Unsubscribe, VERSION, type VerifiedTransaction, type VerifyAppleRequest, type VerifyGoogleRequest, type VerifyResponse, createIAP, errorHint, isIAPError };
1269
+ export { type AppUserId, type AppUserIdFetcherContext, type BackendAdapter, type BackendConfig, type BackendConfigInput, type ConfiguredProduct, DEFAULT_PERMANENT_ERROR_CODES, type DefaultEntitlement, type EntitlementBase, type EventMap, type EventName, type EventPayload, HttpBackendAdapter, HttpClient, type HttpRequest, type IAP, type IAPConfig, type IAPConfigInput, IAPError, IAPErrorCode, type LogLevel, type Logger, type NativeTransaction, type OptionsConfig, type Platform, type Product, type ProductType, type PurchaseOptions, type PurchaseResult, type RestoreRequest, type RestoreRequestTransaction, type RestoreResponse, type RestoreResult, type StorageConfig, type Storefront, type Unsubscribe, VERSION, type VerifiedTransaction, type VerifyAppleRequest, type VerifyGoogleRequest, type VerifyResponse, createIAP, errorHint, isIAPError };
package/dist/index.d.ts CHANGED
@@ -844,10 +844,6 @@ interface EventMap<TEntitlement extends EntitlementBase = EntitlementBase> {
844
844
  entitlements: TEntitlement[];
845
845
  previous: TEntitlement[];
846
846
  };
847
- 'price-stale': {
848
- productId: string;
849
- lastFetchedAt: number;
850
- };
851
847
  /**
852
848
  * Recovery classified an `unfinished_transactions` entry as permanently
853
849
  * invalid (per `options.permanentErrorCodes`) and removed it from
@@ -866,9 +862,6 @@ interface EventMap<TEntitlement extends EntitlementBase = EntitlementBase> {
866
862
  error: string;
867
863
  message?: string;
868
864
  };
869
- error: {
870
- error: IAPError;
871
- };
872
865
  }
873
866
  type EventName<TEntitlement extends EntitlementBase = EntitlementBase> = keyof EventMap<TEntitlement>;
874
867
  type EventPayload<K extends EventName<TEntitlement>, TEntitlement extends EntitlementBase = EntitlementBase> = EventMap<TEntitlement>[K];
@@ -957,6 +950,39 @@ interface RestoreResult<TEntitlement extends EntitlementBase = EntitlementBase>
957
950
  entitlements: TEntitlement[];
958
951
  }
959
952
 
953
+ /**
954
+ * The user's App Store / Google Play storefront — i.e. the country their
955
+ * store account is registered to, which is the platform-blessed signal for
956
+ * region-dependent decisions (regional pricing/offers, and gating
957
+ * external-payment links whose eligibility the OS itself keys to storefront
958
+ * country, *not* device locale).
959
+ *
960
+ * `countryCode` is normalized to **ISO 3166-1 alpha-2** across platforms so
961
+ * consumers compare one consistent value (Apple's native code is alpha-3,
962
+ * Google's is alpha-2). The raw native code is preserved in `countryCodeRaw`.
963
+ *
964
+ * Treat the value as a **UX / targeting hint** and read it live (never cache):
965
+ * for compliance- or entitlement-sensitive enforcement, trust the server-side
966
+ * signed storefront (App Store Server API `storefront` / Play Developer API
967
+ * `regionCode`) instead, since the client value can be unreliable (TestFlight
968
+ * historically reports `"USA"`) or empty (EU alternative distribution).
969
+ */
970
+ interface Storefront {
971
+ /**
972
+ * ISO 3166-1 alpha-2 country code (normalized), e.g. `'US'`. In the rare
973
+ * case the native value can't be normalized (an unrecognized code), this
974
+ * falls back to the uppercased raw value — compare against `countryCodeRaw`
975
+ * if you need certainty about the format.
976
+ */
977
+ countryCode: string;
978
+ /** Raw native value (whitespace-trimmed): alpha-3 on iOS (`'USA'`), alpha-2 on Android (`'US'`). */
979
+ countryCodeRaw: string;
980
+ /** Apple-defined storefront identifier (iOS only); `undefined` on Android. */
981
+ storefrontId?: string;
982
+ /** Store the value came from. */
983
+ platform: Platform;
984
+ }
985
+
960
986
  interface IAP<TEntitlement extends EntitlementBase = EntitlementBase> {
961
987
  initialize(): Promise<void>;
962
988
  /**
@@ -1037,6 +1063,25 @@ interface IAP<TEntitlement extends EntitlementBase = EntitlementBase> {
1037
1063
  * yet ingested by the store are silently skipped (no error).
1038
1064
  */
1039
1065
  getProducts(): Promise<Product[]>;
1066
+ /**
1067
+ * Read the current storefront — the country the user's App Store / Google
1068
+ * Play account is registered to. Use it to drive region-dependent UI:
1069
+ * regional offers/pricing, and gating external-payment links whose
1070
+ * eligibility the platform itself keys to storefront country (not device
1071
+ * locale).
1072
+ *
1073
+ * `countryCode` is normalized to ISO 3166-1 alpha-2 across platforms (raw
1074
+ * native code preserved on `countryCodeRaw`). Resolves `null` when no
1075
+ * storefront is available — on web, when the installed
1076
+ * `@capgo/native-purchases` doesn't register the native method, when the
1077
+ * native call fails, or when the store reports an empty country (e.g. EU
1078
+ * alternative distribution).
1079
+ *
1080
+ * Read live — do not cache. Treat the value as a UX/targeting hint; for
1081
+ * compliance- or entitlement-sensitive enforcement, trust the server-side
1082
+ * signed storefront from your backend instead.
1083
+ */
1084
+ getStorefront(): Promise<Storefront | null>;
1040
1085
  hasEntitlement(key: string): boolean;
1041
1086
  /** Returns a defensive shallow copy. Each entitlement is frozen. */
1042
1087
  getEntitlements(): TEntitlement[];
@@ -1221,4 +1266,4 @@ declare class HttpBackendAdapter<TEntitlement extends EntitlementBase = Entitlem
1221
1266
  listProducts(): Promise<ConfiguredProduct[]>;
1222
1267
  }
1223
1268
 
1224
- export { type AppUserId, type BackendAdapter, type BackendConfig, type BackendConfigInput, type ConfiguredProduct, DEFAULT_PERMANENT_ERROR_CODES, type DefaultEntitlement, type EntitlementBase, type EventMap, type EventName, type EventPayload, HttpBackendAdapter, HttpClient, type HttpRequest, type IAP, type IAPConfig, type IAPConfigInput, IAPError, IAPErrorCode, type LogLevel, type Logger, type NativeTransaction, type OptionsConfig, type Platform, type Product, type ProductType, type PurchaseOptions, type PurchaseResult, type RestoreRequest, type RestoreRequestTransaction, type RestoreResponse, type RestoreResult, type StorageConfig, type Unsubscribe, VERSION, type VerifiedTransaction, type VerifyAppleRequest, type VerifyGoogleRequest, type VerifyResponse, createIAP, errorHint, isIAPError };
1269
+ export { type AppUserId, type AppUserIdFetcherContext, type BackendAdapter, type BackendConfig, type BackendConfigInput, type ConfiguredProduct, DEFAULT_PERMANENT_ERROR_CODES, type DefaultEntitlement, type EntitlementBase, type EventMap, type EventName, type EventPayload, HttpBackendAdapter, HttpClient, type HttpRequest, type IAP, type IAPConfig, type IAPConfigInput, IAPError, IAPErrorCode, type LogLevel, type Logger, type NativeTransaction, type OptionsConfig, type Platform, type Product, type ProductType, type PurchaseOptions, type PurchaseResult, type RestoreRequest, type RestoreRequestTransaction, type RestoreResponse, type RestoreResult, type StorageConfig, type Storefront, type Unsubscribe, VERSION, type VerifiedTransaction, type VerifyAppleRequest, type VerifyGoogleRequest, type VerifyResponse, createIAP, errorHint, isIAPError };
package/dist/index.js CHANGED
@@ -137,11 +137,293 @@ var init_platform = __esm({
137
137
  }
138
138
  });
139
139
 
140
+ // src/lib/iso-country.ts
141
+ function toAlpha2(code) {
142
+ if (!code) return null;
143
+ const normalized = code.trim().toUpperCase();
144
+ if (normalized.length === 2) return normalized;
145
+ if (normalized.length === 3) return ALPHA3_TO_ALPHA2[normalized] ?? null;
146
+ return null;
147
+ }
148
+ var ALPHA3_TO_ALPHA2;
149
+ var init_iso_country = __esm({
150
+ "src/lib/iso-country.ts"() {
151
+ ALPHA3_TO_ALPHA2 = {
152
+ ABW: "AW",
153
+ AFG: "AF",
154
+ AGO: "AO",
155
+ AIA: "AI",
156
+ ALA: "AX",
157
+ ALB: "AL",
158
+ AND: "AD",
159
+ ARE: "AE",
160
+ ARG: "AR",
161
+ ARM: "AM",
162
+ ASM: "AS",
163
+ ATA: "AQ",
164
+ ATF: "TF",
165
+ ATG: "AG",
166
+ AUS: "AU",
167
+ AUT: "AT",
168
+ AZE: "AZ",
169
+ BDI: "BI",
170
+ BEL: "BE",
171
+ BEN: "BJ",
172
+ BES: "BQ",
173
+ BFA: "BF",
174
+ BGD: "BD",
175
+ BGR: "BG",
176
+ BHR: "BH",
177
+ BHS: "BS",
178
+ BIH: "BA",
179
+ BLM: "BL",
180
+ BLR: "BY",
181
+ BLZ: "BZ",
182
+ BMU: "BM",
183
+ BOL: "BO",
184
+ BRA: "BR",
185
+ BRB: "BB",
186
+ BRN: "BN",
187
+ BTN: "BT",
188
+ BVT: "BV",
189
+ BWA: "BW",
190
+ CAF: "CF",
191
+ CAN: "CA",
192
+ CCK: "CC",
193
+ CHE: "CH",
194
+ CHL: "CL",
195
+ CHN: "CN",
196
+ CIV: "CI",
197
+ CMR: "CM",
198
+ COD: "CD",
199
+ COG: "CG",
200
+ COK: "CK",
201
+ COL: "CO",
202
+ COM: "KM",
203
+ CPV: "CV",
204
+ CRI: "CR",
205
+ CUB: "CU",
206
+ CUW: "CW",
207
+ CXR: "CX",
208
+ CYM: "KY",
209
+ CYP: "CY",
210
+ CZE: "CZ",
211
+ DEU: "DE",
212
+ DJI: "DJ",
213
+ DMA: "DM",
214
+ DNK: "DK",
215
+ DOM: "DO",
216
+ DZA: "DZ",
217
+ ECU: "EC",
218
+ EGY: "EG",
219
+ ERI: "ER",
220
+ ESH: "EH",
221
+ ESP: "ES",
222
+ EST: "EE",
223
+ ETH: "ET",
224
+ FIN: "FI",
225
+ FJI: "FJ",
226
+ FLK: "FK",
227
+ FRA: "FR",
228
+ FRO: "FO",
229
+ FSM: "FM",
230
+ GAB: "GA",
231
+ GBR: "GB",
232
+ GEO: "GE",
233
+ GGY: "GG",
234
+ GHA: "GH",
235
+ GIB: "GI",
236
+ GIN: "GN",
237
+ GLP: "GP",
238
+ GMB: "GM",
239
+ GNB: "GW",
240
+ GNQ: "GQ",
241
+ GRC: "GR",
242
+ GRD: "GD",
243
+ GRL: "GL",
244
+ GTM: "GT",
245
+ GUF: "GF",
246
+ GUM: "GU",
247
+ GUY: "GY",
248
+ HKG: "HK",
249
+ HMD: "HM",
250
+ HND: "HN",
251
+ HRV: "HR",
252
+ HTI: "HT",
253
+ HUN: "HU",
254
+ IDN: "ID",
255
+ IMN: "IM",
256
+ IND: "IN",
257
+ IOT: "IO",
258
+ IRL: "IE",
259
+ IRN: "IR",
260
+ IRQ: "IQ",
261
+ ISL: "IS",
262
+ ISR: "IL",
263
+ ITA: "IT",
264
+ JAM: "JM",
265
+ JEY: "JE",
266
+ JOR: "JO",
267
+ JPN: "JP",
268
+ KAZ: "KZ",
269
+ KEN: "KE",
270
+ KGZ: "KG",
271
+ KHM: "KH",
272
+ KIR: "KI",
273
+ KNA: "KN",
274
+ KOR: "KR",
275
+ KWT: "KW",
276
+ LAO: "LA",
277
+ LBN: "LB",
278
+ LBR: "LR",
279
+ LBY: "LY",
280
+ LCA: "LC",
281
+ LIE: "LI",
282
+ LKA: "LK",
283
+ LSO: "LS",
284
+ LTU: "LT",
285
+ LUX: "LU",
286
+ LVA: "LV",
287
+ MAC: "MO",
288
+ MAF: "MF",
289
+ MAR: "MA",
290
+ MCO: "MC",
291
+ MDA: "MD",
292
+ MDG: "MG",
293
+ MDV: "MV",
294
+ MEX: "MX",
295
+ MHL: "MH",
296
+ MKD: "MK",
297
+ MLI: "ML",
298
+ MLT: "MT",
299
+ MMR: "MM",
300
+ MNE: "ME",
301
+ MNG: "MN",
302
+ MNP: "MP",
303
+ MOZ: "MZ",
304
+ MRT: "MR",
305
+ MSR: "MS",
306
+ MTQ: "MQ",
307
+ MUS: "MU",
308
+ MWI: "MW",
309
+ MYS: "MY",
310
+ MYT: "YT",
311
+ NAM: "NA",
312
+ NCL: "NC",
313
+ NER: "NE",
314
+ NFK: "NF",
315
+ NGA: "NG",
316
+ NIC: "NI",
317
+ NIU: "NU",
318
+ NLD: "NL",
319
+ NOR: "NO",
320
+ NPL: "NP",
321
+ NRU: "NR",
322
+ NZL: "NZ",
323
+ OMN: "OM",
324
+ PAK: "PK",
325
+ PAN: "PA",
326
+ PCN: "PN",
327
+ PER: "PE",
328
+ PHL: "PH",
329
+ PLW: "PW",
330
+ PNG: "PG",
331
+ POL: "PL",
332
+ PRI: "PR",
333
+ PRK: "KP",
334
+ PRT: "PT",
335
+ PRY: "PY",
336
+ PSE: "PS",
337
+ PYF: "PF",
338
+ QAT: "QA",
339
+ REU: "RE",
340
+ ROU: "RO",
341
+ RUS: "RU",
342
+ RWA: "RW",
343
+ SAU: "SA",
344
+ SDN: "SD",
345
+ SEN: "SN",
346
+ SGP: "SG",
347
+ SGS: "GS",
348
+ SHN: "SH",
349
+ SJM: "SJ",
350
+ SLB: "SB",
351
+ SLE: "SL",
352
+ SLV: "SV",
353
+ SMR: "SM",
354
+ SOM: "SO",
355
+ SPM: "PM",
356
+ SRB: "RS",
357
+ SSD: "SS",
358
+ STP: "ST",
359
+ SUR: "SR",
360
+ SVK: "SK",
361
+ SVN: "SI",
362
+ SWE: "SE",
363
+ SWZ: "SZ",
364
+ SXM: "SX",
365
+ SYC: "SC",
366
+ SYR: "SY",
367
+ TCA: "TC",
368
+ TCD: "TD",
369
+ TGO: "TG",
370
+ THA: "TH",
371
+ TJK: "TJ",
372
+ TKL: "TK",
373
+ TKM: "TM",
374
+ TLS: "TL",
375
+ TON: "TO",
376
+ TTO: "TT",
377
+ TUN: "TN",
378
+ TUR: "TR",
379
+ TUV: "TV",
380
+ TWN: "TW",
381
+ TZA: "TZ",
382
+ UGA: "UG",
383
+ UKR: "UA",
384
+ UMI: "UM",
385
+ URY: "UY",
386
+ USA: "US",
387
+ UZB: "UZ",
388
+ VAT: "VA",
389
+ VCT: "VC",
390
+ VEN: "VE",
391
+ VGB: "VG",
392
+ VIR: "VI",
393
+ VNM: "VN",
394
+ VUT: "VU",
395
+ WLF: "WF",
396
+ WSM: "WS",
397
+ YEM: "YE",
398
+ ZAF: "ZA",
399
+ ZMB: "ZM",
400
+ ZWE: "ZW"
401
+ };
402
+ }
403
+ });
404
+
140
405
  // src/adapters/native/capgo/native-adapter.ts
141
406
  var native_adapter_exports = {};
142
407
  __export(native_adapter_exports, {
143
408
  CapgoNativeAdapter: () => CapgoNativeAdapter
144
409
  });
410
+ function nativeStorefrontRegistered() {
411
+ const headers = Capacitor.PluginHeaders;
412
+ return headers?.find((h) => h.name === "NativePurchases")?.methods?.some((m) => m.name === "getStorefront") ?? false;
413
+ }
414
+ function normalizeStorefront(raw) {
415
+ const code = raw?.countryCode?.trim();
416
+ if (!code) return null;
417
+ const platform = getPlatform() === "android" ? "google" : "apple";
418
+ return {
419
+ // alpha-2 when recognized; otherwise the uppercased raw code as a
420
+ // best-effort fallback (see `Storefront.countryCode`).
421
+ countryCode: toAlpha2(code) ?? code.toUpperCase(),
422
+ countryCodeRaw: code,
423
+ storefrontId: raw.storefrontId,
424
+ platform
425
+ };
426
+ }
145
427
  function normalizeProduct(p, type) {
146
428
  const priceMicros = Math.round(p.price * 1e6).toString();
147
429
  return {
@@ -200,7 +482,7 @@ function mapPurchaseError(error, productId) {
200
482
  cause: error
201
483
  });
202
484
  }
203
- if (lower.includes("product not found")) {
485
+ if (lower.includes("product not found") || lower.includes("cannot find product")) {
204
486
  return new IAPError({
205
487
  code: IAPErrorCode.PRODUCT_NOT_FOUND,
206
488
  message: `Product "${productId}" was not found in the store catalog.`,
@@ -217,6 +499,7 @@ var CapgoNativeAdapter;
217
499
  var init_native_adapter = __esm({
218
500
  "src/adapters/native/capgo/native-adapter.ts"() {
219
501
  init_errors();
502
+ init_iso_country();
220
503
  init_platform();
221
504
  CapgoNativeAdapter = class {
222
505
  async isAvailable() {
@@ -300,6 +583,24 @@ var init_native_adapter = __esm({
300
583
  });
301
584
  }
302
585
  }
586
+ /**
587
+ * Read the current storefront from the native plugin — which is expected to
588
+ * source it from StoreKit 2 `Storefront.current` on iOS (alpha-3) and
589
+ * `getBillingConfigAsync()` on Android (alpha-2) — normalizing `countryCode`
590
+ * to alpha-2. Silent like {@link CapgoNativeAdapter.isAvailable}: any
591
+ * unavailability — older plugin (no native method registered), native
592
+ * rejection, or empty country — resolves to `null` rather than throwing.
593
+ */
594
+ async getStorefront() {
595
+ if (!nativeStorefrontRegistered()) return null;
596
+ const np = NativePurchases;
597
+ try {
598
+ const raw = await np.getStorefront?.();
599
+ return raw ? normalizeStorefront(raw) : null;
600
+ } catch {
601
+ return null;
602
+ }
603
+ }
303
604
  async dispose() {
304
605
  }
305
606
  };
@@ -830,6 +1131,9 @@ var WebStubAdapter = class {
830
1131
  message: "Subscription management is not supported on the web platform."
831
1132
  });
832
1133
  }
1134
+ async getStorefront() {
1135
+ return null;
1136
+ }
833
1137
  };
834
1138
 
835
1139
  // src/adapters/native/index.ts
@@ -1735,6 +2039,24 @@ function createIAP(input) {
1735
2039
  cachedAt: null,
1736
2040
  products: Object.freeze([...config.products ?? []])
1737
2041
  };
2042
+ async function refreshEntitlements() {
2043
+ requireInitialized(state);
2044
+ const previous = state.entitlements;
2045
+ const fetched = await state.backend.getEntitlements();
2046
+ const next = freezeAll(fetched);
2047
+ try {
2048
+ state.cachedAt = await state.cache.save(next);
2049
+ } catch (error) {
2050
+ state.logger.warn(
2051
+ "Failed to persist refreshed entitlements; in-memory state still updated.",
2052
+ error
2053
+ );
2054
+ }
2055
+ state.entitlements = next;
2056
+ if (!entitlementsEqual(previous, next)) {
2057
+ state.emitter.emit("entitlements-changed", { entitlements: next, previous });
2058
+ }
2059
+ }
1738
2060
  return {
1739
2061
  async initialize() {
1740
2062
  if (state.destroyed) {
@@ -1836,7 +2158,7 @@ function createIAP(input) {
1836
2158
  logger: state.logger,
1837
2159
  onResume: async () => {
1838
2160
  try {
1839
- await this.refresh();
2161
+ await refreshEntitlements();
1840
2162
  } catch (error) {
1841
2163
  state.logger.warn("refreshOnResume: refresh() failed.", error);
1842
2164
  }
@@ -1847,7 +2169,7 @@ function createIAP(input) {
1847
2169
  state.logger.debug("Cache exceeds TTL; scheduling background refresh.");
1848
2170
  queueMicrotask(() => {
1849
2171
  if (!state.initialized || state.destroyed) return;
1850
- this.refresh().catch((error) => {
2172
+ refreshEntitlements().catch((error) => {
1851
2173
  state.logger.warn("TTL background refresh failed.", error);
1852
2174
  });
1853
2175
  });
@@ -1855,24 +2177,7 @@ function createIAP(input) {
1855
2177
  state.initialized = true;
1856
2178
  state.emitter.emit("ready", void 0);
1857
2179
  },
1858
- async refresh() {
1859
- requireInitialized(state);
1860
- const previous = state.entitlements;
1861
- const fetched = await state.backend.getEntitlements();
1862
- const next = freezeAll(fetched);
1863
- try {
1864
- state.cachedAt = await state.cache.save(next);
1865
- } catch (error) {
1866
- state.logger.warn(
1867
- "Failed to persist refreshed entitlements; in-memory state still updated.",
1868
- error
1869
- );
1870
- }
1871
- state.entitlements = next;
1872
- if (!entitlementsEqual(previous, next)) {
1873
- state.emitter.emit("entitlements-changed", { entitlements: next, previous });
1874
- }
1875
- },
2180
+ refresh: refreshEntitlements,
1876
2181
  async destroy() {
1877
2182
  if (state.destroyed) return;
1878
2183
  state.destroyed = true;
@@ -1930,6 +2235,10 @@ function createIAP(input) {
1930
2235
  }
1931
2236
  return state.adapter.getProducts(state.products.map((p) => ({ id: p.id, type: p.type })));
1932
2237
  },
2238
+ async getStorefront() {
2239
+ requireInitialized(state);
2240
+ return state.adapter?.getStorefront?.() ?? null;
2241
+ },
1933
2242
  hasEntitlement(key) {
1934
2243
  return state.entitlements.some((e) => e.key === key);
1935
2244
  },