capacitor-plugin-cdv-purchase 13.15.3 → 13.16.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.js CHANGED
@@ -661,10 +661,16 @@ var CdvPurchase;
661
661
  const body = yield (adapter === null || adapter === void 0 ? void 0 : adapter.receiptValidationBody(receipt));
662
662
  if (!body)
663
663
  return;
664
- // Add the applicationUsername
665
- body.additionalData = Object.assign(Object.assign({}, (_a = body.additionalData) !== null && _a !== void 0 ? _a : {}), { applicationUsername: this.controller.getApplicationUsername() });
664
+ // Add the applicationUsername and its obfuscated form
665
+ const rawUsername = this.controller.getApplicationUsername();
666
+ body.additionalData = Object.assign(Object.assign({}, (_a = body.additionalData) !== null && _a !== void 0 ? _a : {}), { applicationUsername: rawUsername });
666
667
  if (!body.additionalData.applicationUsername)
667
668
  delete body.additionalData.applicationUsername;
669
+ if (rawUsername) {
670
+ const obfuscated = this.controller.obfuscateUsername(rawUsername, receipt.platform);
671
+ if (obfuscated)
672
+ body.additionalData.obfuscatedUsername = obfuscated;
673
+ }
668
674
  // Add device information
669
675
  body.device = Object.assign(Object.assign({}, (_b = body.device) !== null && _b !== void 0 ? _b : {}), CdvPurchase.Validator.Internal.getDeviceInfo(this.controller));
670
676
  // Add legacy pricing information
@@ -782,13 +788,32 @@ var CdvPurchase;
782
788
  Internal.Validator = Validator;
783
789
  /**
784
790
  * Check if a payload looks like a valid validator response.
791
+ *
792
+ * When `ok` is `true`, validates that `data` exists and contains the
793
+ * fields the rest of the pipeline reads unconditionally: `id` (used to
794
+ * key the verified-receipt cache) and `transaction` (stored as the
795
+ * native transaction). Optional fields like `latest_receipt`,
796
+ * `collection`, `warning`, `date` are not required — a validator that
797
+ * omits them produces a usable VerifiedReceipt all the same.
798
+ *
799
+ * When `ok` is `false`, the `data` field is optional per ErrorPayload.
785
800
  */
786
801
  function isValidatorResponsePayload(payload) {
787
- // TODO: could be made more robust.
788
- return (!!payload)
789
- && (typeof payload === 'object')
790
- && ('ok' in payload)
791
- && (typeof payload.ok === 'boolean');
802
+ if (!payload || typeof payload !== 'object')
803
+ return false;
804
+ const p = payload;
805
+ if (typeof p.ok !== 'boolean')
806
+ return false;
807
+ if (p.ok === true) {
808
+ const data = p.data;
809
+ if (!data || typeof data !== 'object')
810
+ return false;
811
+ if (typeof data.id !== 'string')
812
+ return false;
813
+ if (!data.transaction || typeof data.transaction !== 'object')
814
+ return false;
815
+ }
816
+ return true;
792
817
  }
793
818
  })(CdvPurchase.Internal || (CdvPurchase.Internal = {}));
794
819
  })(CdvPurchase || (CdvPurchase = {}));
@@ -1598,6 +1623,37 @@ var CdvPurchase;
1598
1623
  Internal.ExpiryMonitor = ExpiryMonitor;
1599
1624
  })(CdvPurchase.Internal || (CdvPurchase.Internal = {}));
1600
1625
  })(CdvPurchase || (CdvPurchase = {}));
1626
+ var CdvPurchase;
1627
+ (function (CdvPurchase) {
1628
+ (function (Utils) {
1629
+ /**
1630
+ * Convert a string to a UUIDv3-like format using MD5 hashing.
1631
+ *
1632
+ * Takes an input string, computes its MD5 hash, then formats the 32 hex
1633
+ * characters as a UUID with version nibble set to '3' (MD5) and variant
1634
+ * nibble set to '8' (RFC 4122).
1635
+ *
1636
+ * This produces a deterministic, valid UUID suitable for Apple's SK2
1637
+ * `appAccountToken` and Google Play's `obfuscatedAccountId`.
1638
+ *
1639
+ * @param str - The input string to hash and format
1640
+ * @returns A UUIDv3-like string (36 chars with dashes), or empty string if input is empty
1641
+ */
1642
+ function md5toUUID(str) {
1643
+ if (!str)
1644
+ return '';
1645
+ const hash = Utils.md5(str);
1646
+ // UUID format: xxxxxxxx-xxxx-3xxx-8xxx-xxxxxxxxxxxx
1647
+ // Position 12: version '3' (MD5), Position 16: variant '8' (RFC 4122)
1648
+ return hash.substring(0, 8) + '-'
1649
+ + hash.substring(8, 12) + '-'
1650
+ + '3' + hash.substring(13, 16) + '-'
1651
+ + '8' + hash.substring(17, 20) + '-'
1652
+ + hash.substring(20, 32);
1653
+ }
1654
+ Utils.md5toUUID = md5toUUID;
1655
+ })(CdvPurchase.Utils || (CdvPurchase.Utils = {}));
1656
+ })(CdvPurchase || (CdvPurchase = {}));
1601
1657
  /// <reference path="types.ts" />
1602
1658
  /// <reference path="utils/compatibility.ts" />
1603
1659
  /// <reference path="utils/platform-name.ts" />
@@ -1612,6 +1668,7 @@ var CdvPurchase;
1612
1668
  /// <reference path="internal/transaction-monitor.ts" />
1613
1669
  /// <reference path="internal/receipts-monitor.ts" />
1614
1670
  /// <reference path="internal/expiry-monitor.ts" />
1671
+ /// <reference path="utils/to-uuid.ts" />
1615
1672
  /**
1616
1673
  * Namespace for the cordova-plugin-purchase plugin.
1617
1674
  *
@@ -1645,7 +1702,7 @@ var CdvPurchase;
1645
1702
  /**
1646
1703
  * Current release number of the plugin.
1647
1704
  */
1648
- CdvPurchase.PLUGIN_VERSION = '13.15.3';
1705
+ CdvPurchase.PLUGIN_VERSION = '13.16.0';
1649
1706
  /**
1650
1707
  * Entry class of the plugin.
1651
1708
  */
@@ -1677,6 +1734,8 @@ var CdvPurchase;
1677
1734
  * @see {@link LogLevel}
1678
1735
  */
1679
1736
  this.verbosity = CdvPurchase.LogLevel.ERROR;
1737
+ /** @internal Tracks whether the info notice for 'legacy' has been emitted */
1738
+ this._legacyObfuscatorNoticeEmitted = false;
1680
1739
  /** List of callbacks for the "ready" events */
1681
1740
  this._readyCallbacks = new CdvPurchase.Internal.ReadyCallbacks(this.log);
1682
1741
  /** Callbacks when a product definition was updated */
@@ -1736,6 +1795,7 @@ var CdvPurchase;
1736
1795
  this._validator = new CdvPurchase.Internal.Validator({
1737
1796
  adapters: this.adapters,
1738
1797
  getApplicationUsername: this.getApplicationUsername.bind(this),
1798
+ obfuscateUsername: this.obfuscateUsername.bind(this),
1739
1799
  get localReceipts() { return store.localReceipts; },
1740
1800
  get validator() { return store.validator; },
1741
1801
  get validator_privacy_policy() { return store.validator_privacy_policy; },
@@ -1793,6 +1853,40 @@ var CdvPurchase;
1793
1853
  return this.applicationUsername();
1794
1854
  return this.applicationUsername;
1795
1855
  }
1856
+ /**
1857
+ * Obfuscate the application username according to the configured obfuscation strategy.
1858
+ *
1859
+ * See {@link Obfuscator} for the per-mode output format.
1860
+ *
1861
+ * @internal
1862
+ */
1863
+ obfuscateUsername(applicationUsername, platform) {
1864
+ var _a;
1865
+ if (!applicationUsername)
1866
+ return undefined;
1867
+ const obfuscator = (_a = this.obfuscator) !== null && _a !== void 0 ? _a : 'legacy';
1868
+ if (typeof obfuscator === 'function') {
1869
+ return obfuscator(applicationUsername, platform);
1870
+ }
1871
+ switch (obfuscator) {
1872
+ case 'disabled':
1873
+ return applicationUsername;
1874
+ case 'uuid':
1875
+ return CdvPurchase.Utils.md5toUUID(applicationUsername);
1876
+ case 'legacy':
1877
+ default:
1878
+ if (!this._legacyObfuscatorNoticeEmitted) {
1879
+ this._legacyObfuscatorNoticeEmitted = true;
1880
+ this.log.info('store.obfuscator defaults to "legacy" for backward compatibility. New integrations should set store.obfuscator = "uuid". See https://github.com/j3k0/cordova-plugin-purchase/issues/1665');
1881
+ }
1882
+ if (platform === CdvPurchase.Platform.GOOGLE_PLAY) {
1883
+ // Backward-compatible: raw MD5 hash (32 hex chars, no dashes)
1884
+ return CdvPurchase.Utils.md5(applicationUsername);
1885
+ }
1886
+ // UUIDv3 format — valid for Apple appAccountToken (SK1 + SK2) and any other platform
1887
+ return CdvPurchase.Utils.md5toUUID(applicationUsername);
1888
+ }
1889
+ }
1796
1890
  /**
1797
1891
  * Register a product.
1798
1892
  *
@@ -1851,6 +1945,8 @@ var CdvPurchase;
1851
1945
  error: this.triggerError.bind(this),
1852
1946
  get verbosity() { return store.verbosity; },
1853
1947
  getApplicationUsername() { return store.getApplicationUsername(); },
1948
+ obfuscateUsername: (username, platform) => store.obfuscateUsername(username, platform),
1949
+ get obfuscator() { return store.obfuscator; },
1854
1950
  get listener() { return store.listener; },
1855
1951
  get log() { return store.log; },
1856
1952
  get registeredProducts() { return store.registeredProducts; },
@@ -3070,6 +3166,24 @@ var CdvPurchase;
3070
3166
  }, 300);
3071
3167
  }
3072
3168
  get products() { return this._products; }
3169
+ /**
3170
+ * Resolve the username string passed to the native bridge for a
3171
+ * purchase. SK1 + 'legacy' keeps the raw username for backward
3172
+ * compatibility; every other mode obfuscates through the
3173
+ * configured strategy. 'disabled' always returns the raw value.
3174
+ */
3175
+ resolveBridgeUsername() {
3176
+ var _a;
3177
+ const raw = this.context.getApplicationUsername();
3178
+ if (!raw)
3179
+ return undefined;
3180
+ const obfuscator = (_a = this.context.obfuscator) !== null && _a !== void 0 ? _a : 'legacy';
3181
+ if (obfuscator === 'disabled')
3182
+ return raw;
3183
+ if (obfuscator === 'legacy' && !this.useSK2)
3184
+ return raw;
3185
+ return this.context.obfuscateUsername(raw, CdvPurchase.Platform.APPLE_APPSTORE);
3186
+ }
3073
3187
  /** Find a given product from ID */
3074
3188
  getProduct(id) { return this._products.find(p => p.id === id); }
3075
3189
  get receipts() {
@@ -3427,46 +3541,39 @@ var CdvPurchase;
3427
3541
  loadEligibility(validProducts) {
3428
3542
  return __awaiter(this, void 0, void 0, function* () {
3429
3543
  this.log.debug('load eligibility: ' + JSON.stringify(validProducts));
3430
- if (!this.discountEligibilityDeterminer) {
3431
- this.log.debug('No discount eligibility determiner, skipping...');
3544
+ // Collect eligibility requests alongside native-provided answers (from
3545
+ // StoreKit 2's isEligibleForIntroOffer, when available).
3546
+ const { requests, nativeAnswers } = AppleAppStore.Internal.collectEligibilityRequests(validProducts);
3547
+ if (requests.length === 0) {
3432
3548
  return new AppleAppStore.Internal.DiscountEligibilities([], []);
3433
3549
  }
3434
- const eligibilityRequests = [];
3435
- validProducts.forEach(valid => {
3436
- var _a, _b, _c;
3437
- (_a = valid.discounts) === null || _a === void 0 ? void 0 : _a.forEach(discount => {
3438
- eligibilityRequests.push({
3439
- productId: valid.id,
3440
- discountId: discount.id,
3441
- discountType: discount.type,
3442
- });
3443
- });
3444
- if (((_c = (_b = valid.discounts) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) === 0 && valid.introPrice) {
3445
- // sometime apple returns the discounts in the deprecated "introductory" info
3446
- // we create a special "discount" with the id "intro" to check for eligibility.
3447
- eligibilityRequests.push({
3448
- productId: valid.id,
3449
- discountId: 'intro',
3450
- discountType: 'Introductory',
3451
- });
3452
- }
3453
- });
3454
- if (eligibilityRequests.length > 0) {
3455
- const applicationReceipt = yield this.loadAppStoreReceipt();
3456
- if (!applicationReceipt || !applicationReceipt.appStoreReceipt) {
3457
- this.log.debug('no receipt, assuming introductory price are available.');
3458
- return new AppleAppStore.Internal.DiscountEligibilities(eligibilityRequests, eligibilityRequests.map(r => r.discountType === "Introductory"));
3459
- }
3460
- else {
3461
- this.log.debug('calling discount eligibility determiner.');
3462
- const response = yield this.callDiscountEligibilityDeterminer(applicationReceipt, eligibilityRequests);
3463
- this.log.debug('response: ' + JSON.stringify(response));
3464
- return new AppleAppStore.Internal.DiscountEligibilities(eligibilityRequests, response);
3465
- }
3550
+ // Fast path — if every eligibility answer came from native, we can skip
3551
+ // the receipt fetch and the determiner entirely. This is the common case
3552
+ // for StoreKit 2 where the app store receipt is always empty.
3553
+ const allNative = nativeAnswers.every(a => a !== undefined);
3554
+ if (allNative) {
3555
+ this.log.debug('native eligibility answers cover all requests, skipping determiner.');
3556
+ return new AppleAppStore.Internal.DiscountEligibilities(requests, nativeAnswers);
3557
+ }
3558
+ // Otherwise fall back to the receipt + determiner path, then overlay any
3559
+ // native answers we do have (native wins on conflict — it's authoritative).
3560
+ if (!this.discountEligibilityDeterminer) {
3561
+ this.log.debug('No discount eligibility determiner; using native answers only where available.');
3562
+ const defaultForMissing = requests.map(r => r.discountType === 'Introductory');
3563
+ return new AppleAppStore.Internal.DiscountEligibilities(requests, AppleAppStore.Internal.mergeNativeEligibility(defaultForMissing, nativeAnswers));
3564
+ }
3565
+ const applicationReceipt = yield this.loadAppStoreReceipt();
3566
+ let response;
3567
+ if (!applicationReceipt || !applicationReceipt.appStoreReceipt) {
3568
+ this.log.debug('no receipt, assuming introductory price are available.');
3569
+ response = requests.map(r => r.discountType === 'Introductory');
3466
3570
  }
3467
3571
  else {
3468
- return new AppleAppStore.Internal.DiscountEligibilities([], []);
3572
+ this.log.debug('calling discount eligibility determiner.');
3573
+ response = yield this.callDiscountEligibilityDeterminer(applicationReceipt, requests);
3574
+ this.log.debug('response: ' + JSON.stringify(response));
3469
3575
  }
3576
+ return new AppleAppStore.Internal.DiscountEligibilities(requests, AppleAppStore.Internal.mergeNativeEligibility(response, nativeAnswers));
3470
3577
  });
3471
3578
  }
3472
3579
  callDiscountEligibilityDeterminer(applicationReceipt, eligibilityRequests) {
@@ -3572,7 +3679,9 @@ var CdvPurchase;
3572
3679
  // When we switch AppStore user, the cached receipt isn't from the new user.
3573
3680
  // so after a purchase, we want to make sure we're using the receipt from the logged in user.
3574
3681
  this.forceReceiptReload = true;
3575
- this.bridge.purchase(offer.productId, quantity, this.context.getApplicationUsername(), discount, success, error);
3682
+ warnIfDeprecatedAdditionalUsername(this.log, additionalData);
3683
+ const username = this.resolveBridgeUsername();
3684
+ this.bridge.purchase(offer.productId, quantity, username, discount, success, error);
3576
3685
  });
3577
3686
  });
3578
3687
  }
@@ -3829,6 +3938,16 @@ var CdvPurchase;
3829
3938
  function appStoreError(code, message, productId) {
3830
3939
  return CdvPurchase.storeError(code, message, CdvPurchase.Platform.APPLE_APPSTORE, productId);
3831
3940
  }
3941
+ let deprecatedAdditionalUsernameNoticed = false;
3942
+ function warnIfDeprecatedAdditionalUsername(log, additionalData) {
3943
+ // Bracket access avoids the @deprecated read warning on the field.
3944
+ if (!additionalData || !additionalData['applicationUsername'])
3945
+ return;
3946
+ if (deprecatedAdditionalUsernameNoticed)
3947
+ return;
3948
+ deprecatedAdditionalUsernameNoticed = true;
3949
+ log.warn('additionalData.applicationUsername is deprecated and ignored. Set store.applicationUsername instead.');
3950
+ }
3832
3951
  })(CdvPurchase.AppleAppStore || (CdvPurchase.AppleAppStore = {}));
3833
3952
  })(CdvPurchase || (CdvPurchase = {}));
3834
3953
  var CdvPurchase;
@@ -4795,6 +4914,52 @@ var CdvPurchase;
4795
4914
  }
4796
4915
  }
4797
4916
  Internal.DiscountEligibilities = DiscountEligibilities;
4917
+ /**
4918
+ * Build the pair of (requests, native-provided answers) for every valid product.
4919
+ *
4920
+ * The two arrays are parallel: for each request, the matching `nativeAnswers` entry
4921
+ * is either the native eligibility (from StoreKit 2's `isEligibleForIntroOffer`)
4922
+ * or `undefined` if native did not provide one (SK1 / older native plugin).
4923
+ *
4924
+ * Only Introductory requests can carry a native answer — SK2 does not answer
4925
+ * promotional offer eligibility at the adapter level.
4926
+ */
4927
+ function collectEligibilityRequests(validProducts) {
4928
+ const requests = [];
4929
+ const nativeAnswers = [];
4930
+ validProducts.forEach(valid => {
4931
+ var _a, _b, _c;
4932
+ (_a = valid.discounts) === null || _a === void 0 ? void 0 : _a.forEach(discount => {
4933
+ requests.push({
4934
+ productId: valid.id,
4935
+ discountId: discount.id,
4936
+ discountType: discount.type,
4937
+ });
4938
+ nativeAnswers.push(discount.type === 'Introductory' ? valid.introPriceEligible : undefined);
4939
+ });
4940
+ if (((_c = (_b = valid.discounts) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) === 0 && valid.introPrice) {
4941
+ requests.push({
4942
+ productId: valid.id,
4943
+ discountId: 'intro',
4944
+ discountType: 'Introductory',
4945
+ });
4946
+ nativeAnswers.push(valid.introPriceEligible);
4947
+ }
4948
+ });
4949
+ return { requests, nativeAnswers };
4950
+ }
4951
+ Internal.collectEligibilityRequests = collectEligibilityRequests;
4952
+ /**
4953
+ * Overlay native-provided eligibility answers on top of a determiner response.
4954
+ *
4955
+ * Native wins on conflict — it's the authoritative source for StoreKit 2.
4956
+ * Determiner response is used where native did not provide an answer (SK1
4957
+ * or older native builds).
4958
+ */
4959
+ function mergeNativeEligibility(determinerResponse, nativeAnswers) {
4960
+ return determinerResponse.map((r, i) => nativeAnswers[i] !== undefined ? nativeAnswers[i] : r);
4961
+ }
4962
+ Internal.mergeNativeEligibility = mergeNativeEligibility;
4798
4963
  })(AppleAppStore.Internal || (AppleAppStore.Internal = {}));
4799
4964
  })(CdvPurchase.AppleAppStore || (CdvPurchase.AppleAppStore = {}));
4800
4965
  })(CdvPurchase || (CdvPurchase = {}));
@@ -6179,6 +6344,8 @@ var CdvPurchase;
6179
6344
  /** @inheritDoc */
6180
6345
  order(offer, additionalData) {
6181
6346
  return __awaiter(this, void 0, void 0, function* () {
6347
+ warnIfDeprecatedAdditionalUsername(this.log, additionalData);
6348
+ additionalData = withObfuscatedAccountId(additionalData, this.context);
6182
6349
  return new Promise(resolve => {
6183
6350
  this.log.info("Order - " + JSON.stringify(offer));
6184
6351
  const buySuccess = () => resolve(undefined);
@@ -6326,6 +6493,33 @@ var CdvPurchase;
6326
6493
  PRODUCTION: 7 * 24 * 60 * 60 * 1000 + 10 * 60 * 1000, // 7 days + 10 minutes for production
6327
6494
  };
6328
6495
  GooglePlay.Adapter = Adapter;
6496
+ let deprecatedAdditionalUsernameNoticed = false;
6497
+ function warnIfDeprecatedAdditionalUsername(log, additionalData) {
6498
+ // Bracket access avoids the @deprecated read warning on the field.
6499
+ if (!additionalData || !additionalData['applicationUsername'])
6500
+ return;
6501
+ if (deprecatedAdditionalUsernameNoticed)
6502
+ return;
6503
+ deprecatedAdditionalUsernameNoticed = true;
6504
+ log.warn('additionalData.applicationUsername is deprecated and ignored. Set store.applicationUsername instead.');
6505
+ }
6506
+ /**
6507
+ * Return a copy of `additionalData` with `googlePlay.accountId` populated
6508
+ * from `store.applicationUsername` (via the configured obfuscator) when
6509
+ * not already provided by the caller. Never mutates the input.
6510
+ */
6511
+ function withObfuscatedAccountId(additionalData, context) {
6512
+ var _a;
6513
+ const next = Object.assign({}, (additionalData !== null && additionalData !== void 0 ? additionalData : {}));
6514
+ next.googlePlay = Object.assign({}, ((_a = additionalData === null || additionalData === void 0 ? void 0 : additionalData.googlePlay) !== null && _a !== void 0 ? _a : {}));
6515
+ if (!next.googlePlay.accountId) {
6516
+ const username = context.getApplicationUsername();
6517
+ if (username) {
6518
+ next.googlePlay.accountId = context.obfuscateUsername(username, CdvPurchase.Platform.GOOGLE_PLAY);
6519
+ }
6520
+ }
6521
+ return next;
6522
+ }
6329
6523
  function playStoreError(code, message, productId) {
6330
6524
  return CdvPurchase.storeError(code, message, CdvPurchase.Platform.GOOGLE_PLAY, productId);
6331
6525
  }
@@ -6489,11 +6683,7 @@ var CdvPurchase;
6489
6683
  return !!obj && obj.constructor === Object ? obj : {};
6490
6684
  }
6491
6685
  function extendAdditionalData(ad) {
6492
- const additionalData = ensureObject(ad === null || ad === void 0 ? void 0 : ad.googlePlay);
6493
- if (!additionalData.accountId && (ad === null || ad === void 0 ? void 0 : ad.applicationUsername)) {
6494
- additionalData.accountId = CdvPurchase.Utils.md5(ad.applicationUsername);
6495
- }
6496
- return additionalData;
6686
+ return ensureObject(ad === null || ad === void 0 ? void 0 : ad.googlePlay);
6497
6687
  }
6498
6688
  })(GooglePlay.Bridge || (GooglePlay.Bridge = {}));
6499
6689
  })(CdvPurchase.GooglePlay || (CdvPurchase.GooglePlay = {}));
@@ -6712,11 +6902,7 @@ var CdvPurchase;
6712
6902
  return !!obj && obj.constructor === Object ? obj : {};
6713
6903
  }
6714
6904
  function extendAdditionalData(ad) {
6715
- const additionalData = ensureObject(ad === null || ad === void 0 ? void 0 : ad.googlePlay);
6716
- if (!additionalData.accountId && (ad === null || ad === void 0 ? void 0 : ad.applicationUsername)) {
6717
- additionalData.accountId = CdvPurchase.Utils.md5(ad.applicationUsername);
6718
- }
6719
- return additionalData;
6905
+ return ensureObject(ad === null || ad === void 0 ? void 0 : ad.googlePlay);
6720
6906
  }
6721
6907
  })(GooglePlay.Bridge || (GooglePlay.Bridge = {}));
6722
6908
  })(CdvPurchase.GooglePlay || (CdvPurchase.GooglePlay = {}));
@@ -7561,11 +7747,12 @@ var CdvPurchase;
7561
7747
  });
7562
7748
  }
7563
7749
  handleReceiptValidationResponse(receipt, response) {
7750
+ var _a, _b;
7564
7751
  return __awaiter(this, void 0, void 0, function* () {
7565
7752
  this.log.info('handleReceiptValidationResponse for IapticJS');
7566
7753
  if (response.ok) {
7567
- response.data.transaction;
7568
- const collection = response.data.collection;
7754
+ (_a = response.data) === null || _a === void 0 ? void 0 : _a.transaction;
7755
+ const collection = (_b = response.data) === null || _b === void 0 ? void 0 : _b.collection;
7569
7756
  // Update receipt based on validated collection
7570
7757
  if (collection) {
7571
7758
  const purchases = collection.map((vp) => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["esm/index.js","../build/entry.mjs"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\n// Set the marker so the shared store.js knows Capacitor native bridges are available\nif (typeof window !== 'undefined') {\n window.CdvPurchaseCapacitor = { installed: true };\n}\nconst PurchasePlugin = registerPlugin('PurchasePlugin');\nexport { PurchasePlugin };\n","// Capacitor bridge — sets CdvPurchaseCapacitor marker and registers native plugin\nexport { PurchasePlugin } from '../dist/esm/index.js';\n\n// Store runtime — executes the IIFE, creates window.CdvPurchase\nimport { CdvPurchase } from 'virtual:store-js';\n\n// Re-export the full namespace\nexport { CdvPurchase };\n\n// Convenience named exports\nexport const store = CdvPurchase.store;\nexport const Store = CdvPurchase.Store;\nexport const ProductType = CdvPurchase.ProductType;\nexport const Platform = CdvPurchase.Platform;\nexport const LogLevel = CdvPurchase.LogLevel;\nexport const ErrorCode = CdvPurchase.ErrorCode;\nexport const Logger = CdvPurchase.Logger;\nexport const Iaptic = CdvPurchase.Iaptic;\n"],"names":[],"mappings":";;AACA;AACA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;AACnC,IAAI,MAAM,CAAC,oBAAoB,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE;AACrD;AACK,MAAC,cAAc,GAAG,cAAc,CAAC,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLtD;;AASA;AACY,MAAC,KAAK,GAAG,WAAW,CAAC;AACrB,MAAC,KAAK,GAAG,WAAW,CAAC;AACrB,MAAC,WAAW,GAAG,WAAW,CAAC;AAC3B,MAAC,QAAQ,GAAG,WAAW,CAAC;AACxB,MAAC,QAAQ,GAAG,WAAW,CAAC;AACxB,MAAC,SAAS,GAAG,WAAW,CAAC;AACzB,MAAC,MAAM,GAAG,WAAW,CAAC;AACtB,MAAC,MAAM,GAAG,WAAW,CAAC;;;;"}
1
+ {"version":3,"file":"index.js","sources":["esm/index.js","../build/entry.mjs"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\n// Set the marker so the shared store.js knows Capacitor native bridges are available\nif (typeof window !== 'undefined') {\n window.CdvPurchaseCapacitor = { installed: true };\n}\nconst PurchasePlugin = registerPlugin('PurchasePlugin');\nexport { PurchasePlugin };\n","// Capacitor bridge — sets CdvPurchaseCapacitor marker and registers native plugin\nexport { PurchasePlugin } from '../dist/esm/index.js';\n\n// Store runtime — executes the IIFE, creates window.CdvPurchase\nimport { CdvPurchase } from 'virtual:store-js';\n\n// Re-export the full namespace\nexport { CdvPurchase };\n\n// Convenience named exports\nexport const store = CdvPurchase.store;\nexport const Store = CdvPurchase.Store;\nexport const ProductType = CdvPurchase.ProductType;\nexport const Platform = CdvPurchase.Platform;\nexport const LogLevel = CdvPurchase.LogLevel;\nexport const ErrorCode = CdvPurchase.ErrorCode;\nexport const Logger = CdvPurchase.Logger;\nexport const Iaptic = CdvPurchase.Iaptic;\n"],"names":[],"mappings":";;AACA;AACA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;AACnC,IAAI,MAAM,CAAC,oBAAoB,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE;AACrD;AACK,MAAC,cAAc,GAAG,cAAc,CAAC,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLtD;;AASA;AACY,MAAC,KAAK,GAAG,WAAW,CAAC;AACrB,MAAC,KAAK,GAAG,WAAW,CAAC;AACrB,MAAC,WAAW,GAAG,WAAW,CAAC;AAC3B,MAAC,QAAQ,GAAG,WAAW,CAAC;AACxB,MAAC,QAAQ,GAAG,WAAW,CAAC;AACxB,MAAC,SAAS,GAAG,WAAW,CAAC;AACzB,MAAC,MAAM,GAAG,WAAW,CAAC;AACtB,MAAC,MAAM,GAAG,WAAW,CAAC;;;;"}
@@ -150,7 +150,7 @@ public class PurchasePlugin: CAPPlugin, CAPBridgedPlugin {
150
150
 
151
151
  for product in storeProducts {
152
152
  sk2.products[product.id] = product
153
- validProducts.append(productToDict(product))
153
+ validProducts.append(await productToDict(product))
154
154
  validIds.insert(product.id)
155
155
  }
156
156
 
@@ -186,9 +186,12 @@ public class PurchasePlugin: CAPPlugin, CAPBridgedPlugin {
186
186
  Task {
187
187
  do {
188
188
  var options: Set<Product.PurchaseOption> = []
189
- if let username = call.getString("applicationUsername") {
190
- options.insert(.appAccountToken(
191
- UUID(uuidString: username) ?? UUID()))
189
+ if let username = call.getString("applicationUsername"), !username.isEmpty {
190
+ if let uuid = UUID(uuidString: username) {
191
+ options.insert(.appAccountToken(uuid))
192
+ } else {
193
+ debugLog("applicationUsername is not a valid UUID, appAccountToken will not be set: \(username)")
194
+ }
192
195
  }
193
196
  if quantity > 1 {
194
197
  options.insert(.quantity(quantity))
@@ -445,7 +448,7 @@ public class PurchasePlugin: CAPPlugin, CAPBridgedPlugin {
445
448
  }
446
449
 
447
450
  @available(iOS 15.0, *)
448
- private func productToDict(_ product: Product) -> [String: Any] {
451
+ private func productToDict(_ product: Product) async -> [String: Any] {
449
452
  var dict: [String: Any] = [
450
453
  "id": product.id,
451
454
  "title": product.displayName,
@@ -478,6 +481,10 @@ public class PurchasePlugin: CAPPlugin, CAPBridgedPlugin {
478
481
  dict["introPricePeriod"] = intro.period.value
479
482
  dict["introPricePeriodUnit"] = periodUnitToString(intro.period.unit)
480
483
  dict["introPricePaymentMode"] = paymentModeToString(intro.paymentMode)
484
+ // StoreKit 2 eligibility — honors the user's prior subscription/trial history.
485
+ // Only meaningful when an intro offer exists; omitted otherwise so older TS
486
+ // builds that don't know about this field keep their SK1-era behavior.
487
+ dict["introPriceEligible"] = await subscription.isEligibleForIntroOffer
481
488
  }
482
489
 
483
490
  // Promotional offers (discounts)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-plugin-cdv-purchase",
3
- "version": "13.15.3",
3
+ "version": "13.16.0",
4
4
  "description": "In-App Purchases for Capacitor — iOS (StoreKit 2) and Android (Google Play Billing)",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -10,7 +10,8 @@
10
10
  "types": "./types/index.d.ts",
11
11
  "import": "./dist/index.js",
12
12
  "default": "./dist/index.js"
13
- }
13
+ },
14
+ "./package.json": "./package.json"
14
15
  },
15
16
  "capacitor": {
16
17
  "ios": { "src": "ios" },
package/www/store.d.ts CHANGED
@@ -348,6 +348,7 @@ declare namespace CdvPurchase {
348
348
  adapters: Adapters;
349
349
  validator_privacy_policy: PrivacyPolicyItem | PrivacyPolicyItem[] | undefined;
350
350
  getApplicationUsername(): string | undefined;
351
+ obfuscateUsername: (applicationUsername: string, platform: CdvPurchase.Platform) => string | undefined;
351
352
  verifiedCallbacks: Callbacks<VerifiedReceipt>;
352
353
  unverifiedCallbacks: Callbacks<UnverifiedReceipt>;
353
354
  finish(receipt: VerifiedReceipt): Promise<void>;
@@ -443,6 +444,10 @@ declare namespace CdvPurchase {
443
444
  listener: AdapterListener;
444
445
  /** Retrieves the application username */
445
446
  getApplicationUsername: () => string | undefined;
447
+ /** Obfuscate the application username for the given platform */
448
+ obfuscateUsername: (applicationUsername: string, platform: CdvPurchase.Platform) => string | undefined;
449
+ /** The obfuscation strategy */
450
+ obfuscator?: CdvPurchase.Obfuscator;
446
451
  /** Functions used to decorate the API */
447
452
  apiDecorators: ProductDecorator & TransactionDecorator & OfferDecorator & ReceiptDecorator;
448
453
  /** Collection of per-platform storefront values. */
@@ -854,6 +859,24 @@ declare namespace CdvPurchase {
854
859
  }
855
860
  }
856
861
  }
862
+ declare namespace CdvPurchase {
863
+ namespace Utils {
864
+ /**
865
+ * Convert a string to a UUIDv3-like format using MD5 hashing.
866
+ *
867
+ * Takes an input string, computes its MD5 hash, then formats the 32 hex
868
+ * characters as a UUID with version nibble set to '3' (MD5) and variant
869
+ * nibble set to '8' (RFC 4122).
870
+ *
871
+ * This produces a deterministic, valid UUID suitable for Apple's SK2
872
+ * `appAccountToken` and Google Play's `obfuscatedAccountId`.
873
+ *
874
+ * @param str - The input string to hash and format
875
+ * @returns A UUIDv3-like string (36 chars with dashes), or empty string if input is empty
876
+ */
877
+ function md5toUUID(str: string): string;
878
+ }
879
+ }
857
880
  /**
858
881
  * Namespace for the cordova-plugin-purchase plugin.
859
882
  *
@@ -886,7 +909,7 @@ declare namespace CdvPurchase {
886
909
  /**
887
910
  * Current release number of the plugin.
888
911
  */
889
- const PLUGIN_VERSION = "13.15.3";
912
+ const PLUGIN_VERSION = "13.16.0";
890
913
  /**
891
914
  * Entry class of the plugin.
892
915
  */
@@ -928,14 +951,44 @@ declare namespace CdvPurchase {
928
951
  /**
929
952
  * Return the identifier of the user for your application.
930
953
  *
931
- * **Note:** Apple AppStore requires an UUIDv4 if you want it to appear as the "appAccountToken" in
932
- * the transaction data.
954
+ * This value is obfuscated according to {@link Store.obfuscator} before being
955
+ * sent to the native platform API. The default obfuscator (`'legacy'`) hashes
956
+ * or formats the value so the original username is never transmitted in cleartext.
957
+ *
958
+ * For Apple's App Store, the obfuscated value is used as `appAccountToken`
959
+ * (which must be a valid UUID when using StoreKit 2).
960
+ *
961
+ * You can also pass it per-transaction via `additionalData.applicationUsername`
962
+ * in `store.order()` or `store.requestPayment()`, which takes priority.
933
963
  */
934
964
  applicationUsername?: string | (() => string | undefined);
935
965
  /**
936
966
  * Get the application username as a string by either calling or returning {@link Store.applicationUsername}
937
967
  */
938
968
  getApplicationUsername(): string | undefined;
969
+ /**
970
+ * Obfuscation strategy for the application username.
971
+ *
972
+ * Controls how `applicationUsername` is transformed before being sent
973
+ * to each platform's native API. `'uuid'` is the recommended setting
974
+ * for new integrations; the default `'legacy'` exists only for
975
+ * backward compatibility with server-side modules that already
976
+ * correlate against the raw 32-hex MD5 value.
977
+ *
978
+ * @default 'legacy'
979
+ * @see {@link Obfuscator}
980
+ */
981
+ obfuscator?: CdvPurchase.Obfuscator;
982
+ /** @internal Tracks whether the info notice for 'legacy' has been emitted */
983
+ private _legacyObfuscatorNoticeEmitted;
984
+ /**
985
+ * Obfuscate the application username according to the configured obfuscation strategy.
986
+ *
987
+ * See {@link Obfuscator} for the per-mode output format.
988
+ *
989
+ * @internal
990
+ */
991
+ obfuscateUsername(applicationUsername: string, platform: CdvPurchase.Platform): string | undefined;
939
992
  /**
940
993
  * URL or implementation of the receipt validation service
941
994
  *
@@ -1512,7 +1565,16 @@ declare namespace CdvPurchase {
1512
1565
  * @see {@link Store.requestPayment}
1513
1566
  */
1514
1567
  interface AdditionalData {
1515
- /** The application's user identifier, will be obfuscated with md5 to fill `accountId` if necessary */
1568
+ /**
1569
+ * The application's user identifier.
1570
+ *
1571
+ * @deprecated Set {@link Store.applicationUsername} instead. The
1572
+ * per-transaction value is ignored — adapters always read the
1573
+ * store-level username so receipt validation later (which doesn't
1574
+ * have access to the original additionalData) sees the same value
1575
+ * that was sent to the native API at purchase time. Passing this
1576
+ * field logs a one-shot notice.
1577
+ */
1516
1578
  applicationUsername?: string;
1517
1579
  /**
1518
1580
  * Quantity of items to purchase.
@@ -1530,6 +1592,38 @@ declare namespace CdvPurchase {
1530
1592
  /** Apple AppStore specific additional data */
1531
1593
  appStore?: AppleAppStore.AdditionalData;
1532
1594
  }
1595
+ /**
1596
+ * Obfuscation strategy for the application username.
1597
+ *
1598
+ * Controls how `applicationUsername` is transformed before being sent to
1599
+ * each platform's native API.
1600
+ *
1601
+ * - `'uuid'` — **Recommended.** MD5 hash formatted as UUIDv3 on all
1602
+ * platforms. Deterministic, valid UUID, works as Apple's
1603
+ * `appAccountToken` (SK1 + SK2) and Google Play's
1604
+ * `obfuscatedAccountId`.
1605
+ *
1606
+ * - `'legacy'` (default) — Only use this when an existing server-side
1607
+ * integration already correlates against the original 32-hex MD5 value
1608
+ * sent on Google Play. New integrations should pick `'uuid'`.
1609
+ * - Google Play: raw MD5 hash (32 hex chars)
1610
+ * - Apple AppStore (SK2): MD5 hash formatted as UUIDv3
1611
+ * - Apple AppStore (SK1, deprecated): raw username, unchanged
1612
+ * - Other platforms: MD5 hash formatted as UUIDv3
1613
+ *
1614
+ * - `'disabled'` — No obfuscation. The raw `applicationUsername` is
1615
+ * passed through to all platforms. For Apple SK2, the value must be a
1616
+ * valid UUID string or `appAccountToken` will not be set.
1617
+ *
1618
+ * - Custom function — `(username: string, platform: Platform) => string`.
1619
+ * Receives the raw username and platform, returns the obfuscated value.
1620
+ * For Apple (both SK1 and SK2), the function must return a valid UUID
1621
+ * string.
1622
+ *
1623
+ * @see {@link Store.obfuscator}
1624
+ * @see {@link https://github.com/j3k0/cordova-plugin-purchase/issues/1665}
1625
+ */
1626
+ type Obfuscator = 'legacy' | 'uuid' | 'disabled' | ((applicationUsername: string, platform: Platform) => string);
1533
1627
  /**
1534
1628
  * Purchase platforms supported by the plugin
1535
1629
  */
@@ -2700,6 +2794,13 @@ declare namespace CdvPurchase {
2700
2794
  /** List of products loaded from AppStore */
2701
2795
  _products: SKProduct[];
2702
2796
  get products(): Product[];
2797
+ /**
2798
+ * Resolve the username string passed to the native bridge for a
2799
+ * purchase. SK1 + 'legacy' keeps the raw username for backward
2800
+ * compatibility; every other mode obfuscates through the
2801
+ * configured strategy. 'disabled' always returns the raw value.
2802
+ */
2803
+ private resolveBridgeUsername;
2703
2804
  /** Find a given product from ID */
2704
2805
  getProduct(id: string): SKProduct | undefined;
2705
2806
  /** The application receipt, contains all transactions */
@@ -2970,6 +3071,15 @@ declare namespace CdvPurchase {
2970
3071
  introPricePeriodUnit?: IPeriodUnit;
2971
3072
  /** Payment mode for introductory price */
2972
3073
  introPricePaymentMode?: PaymentMode;
3074
+ /**
3075
+ * Whether the user is eligible for the introductory price.
3076
+ *
3077
+ * Populated from StoreKit 2's `Product.SubscriptionInfo.isEligibleForIntroOffer`
3078
+ * when running on SK2 (iOS 15+). Absent on SK1 and on older native builds that
3079
+ * don't surface it — in which case the discount eligibility determiner is used
3080
+ * as before.
3081
+ */
3082
+ introPriceEligible?: boolean;
2973
3083
  /** Available discount offers */
2974
3084
  discounts?: Discount[];
2975
3085
  /** Group this product is member of */
@@ -3170,6 +3280,28 @@ declare namespace CdvPurchase {
3170
3280
  constructor(request: DiscountEligibilityRequest[], response: boolean[]);
3171
3281
  isEligible(productId: string, discountType: DiscountType, discountId: string): boolean;
3172
3282
  }
3283
+ /**
3284
+ * Build the pair of (requests, native-provided answers) for every valid product.
3285
+ *
3286
+ * The two arrays are parallel: for each request, the matching `nativeAnswers` entry
3287
+ * is either the native eligibility (from StoreKit 2's `isEligibleForIntroOffer`)
3288
+ * or `undefined` if native did not provide one (SK1 / older native plugin).
3289
+ *
3290
+ * Only Introductory requests can carry a native answer — SK2 does not answer
3291
+ * promotional offer eligibility at the adapter level.
3292
+ */
3293
+ function collectEligibilityRequests(validProducts: Bridge.ValidProduct[]): {
3294
+ requests: DiscountEligibilityRequest[];
3295
+ nativeAnswers: (boolean | undefined)[];
3296
+ };
3297
+ /**
3298
+ * Overlay native-provided eligibility answers on top of a determiner response.
3299
+ *
3300
+ * Native wins on conflict — it's the authoritative source for StoreKit 2.
3301
+ * Determiner response is used where native did not provide an answer (SK1
3302
+ * or older native builds).
3303
+ */
3304
+ function mergeNativeEligibility(determinerResponse: boolean[], nativeAnswers: (boolean | undefined)[]): boolean[];
3173
3305
  }
3174
3306
  }
3175
3307
  }
@@ -4848,7 +4980,9 @@ declare namespace CdvPurchase {
4848
4980
  /**
4849
4981
  * Obfuscated user account identifier
4850
4982
  *
4851
- * Default to md5(store.applicationUsername)
4983
+ * Populated by the adapter using `store.obfuscateUsername()`.
4984
+ * Format depends on `store.obfuscator` setting.
4985
+ * @see {@link CdvPurchase.Store.obfuscator}
4852
4986
  */
4853
4987
  accountId?: string;
4854
4988
  /**
@@ -4920,7 +5054,7 @@ declare namespace CdvPurchase {
4920
5054
  signature: string;
4921
5055
  /** String in JSON format that contains details about the purchase order. */
4922
5056
  receipt: string;
4923
- /** Obfuscated account id specified at purchase - by default md5(applicationUsername) */
5057
+ /** Obfuscated account id specified at purchase. Format depends on `store.obfuscator`. */
4924
5058
  accountId: string;
4925
5059
  /** Obfuscated profile id specified at purchase - used when a single user can have multiple profiles */
4926
5060
  profileId: string;
@@ -6157,6 +6291,14 @@ declare namespace CdvPurchase {
6157
6291
  *
6158
6292
  * @optional */
6159
6293
  applicationUsername?: string | number;
6294
+ /**
6295
+ * The obfuscated form of `applicationUsername`, derived by applying
6296
+ * `store.obfuscator`. The server can use this to correlate obfuscated
6297
+ * IDs from Apple/Google server notifications (e.g. `appAccountToken`,
6298
+ * `obfuscatedExternalAccountId`) with the original user.
6299
+ *
6300
+ * @optional */
6301
+ obfuscatedUsername?: string;
6160
6302
  };
6161
6303
  /** Microsoft license information */
6162
6304
  license?: {
package/www/store.js CHANGED
@@ -666,10 +666,16 @@ var CdvPurchase;
666
666
  const body = yield (adapter === null || adapter === void 0 ? void 0 : adapter.receiptValidationBody(receipt));
667
667
  if (!body)
668
668
  return;
669
- // Add the applicationUsername
670
- body.additionalData = Object.assign(Object.assign({}, (_a = body.additionalData) !== null && _a !== void 0 ? _a : {}), { applicationUsername: this.controller.getApplicationUsername() });
669
+ // Add the applicationUsername and its obfuscated form
670
+ const rawUsername = this.controller.getApplicationUsername();
671
+ body.additionalData = Object.assign(Object.assign({}, (_a = body.additionalData) !== null && _a !== void 0 ? _a : {}), { applicationUsername: rawUsername });
671
672
  if (!body.additionalData.applicationUsername)
672
673
  delete body.additionalData.applicationUsername;
674
+ if (rawUsername) {
675
+ const obfuscated = this.controller.obfuscateUsername(rawUsername, receipt.platform);
676
+ if (obfuscated)
677
+ body.additionalData.obfuscatedUsername = obfuscated;
678
+ }
673
679
  // Add device information
674
680
  body.device = Object.assign(Object.assign({}, (_b = body.device) !== null && _b !== void 0 ? _b : {}), CdvPurchase.Validator.Internal.getDeviceInfo(this.controller));
675
681
  // Add legacy pricing information
@@ -787,13 +793,32 @@ var CdvPurchase;
787
793
  Internal.Validator = Validator;
788
794
  /**
789
795
  * Check if a payload looks like a valid validator response.
796
+ *
797
+ * When `ok` is `true`, validates that `data` exists and contains the
798
+ * fields the rest of the pipeline reads unconditionally: `id` (used to
799
+ * key the verified-receipt cache) and `transaction` (stored as the
800
+ * native transaction). Optional fields like `latest_receipt`,
801
+ * `collection`, `warning`, `date` are not required — a validator that
802
+ * omits them produces a usable VerifiedReceipt all the same.
803
+ *
804
+ * When `ok` is `false`, the `data` field is optional per ErrorPayload.
790
805
  */
791
806
  function isValidatorResponsePayload(payload) {
792
- // TODO: could be made more robust.
793
- return (!!payload)
794
- && (typeof payload === 'object')
795
- && ('ok' in payload)
796
- && (typeof payload.ok === 'boolean');
807
+ if (!payload || typeof payload !== 'object')
808
+ return false;
809
+ const p = payload;
810
+ if (typeof p.ok !== 'boolean')
811
+ return false;
812
+ if (p.ok === true) {
813
+ const data = p.data;
814
+ if (!data || typeof data !== 'object')
815
+ return false;
816
+ if (typeof data.id !== 'string')
817
+ return false;
818
+ if (!data.transaction || typeof data.transaction !== 'object')
819
+ return false;
820
+ }
821
+ return true;
797
822
  }
798
823
  })(Internal = CdvPurchase.Internal || (CdvPurchase.Internal = {}));
799
824
  })(CdvPurchase || (CdvPurchase = {}));
@@ -1615,6 +1640,38 @@ var CdvPurchase;
1615
1640
  Internal.ExpiryMonitor = ExpiryMonitor;
1616
1641
  })(Internal = CdvPurchase.Internal || (CdvPurchase.Internal = {}));
1617
1642
  })(CdvPurchase || (CdvPurchase = {}));
1643
+ var CdvPurchase;
1644
+ (function (CdvPurchase) {
1645
+ let Utils;
1646
+ (function (Utils) {
1647
+ /**
1648
+ * Convert a string to a UUIDv3-like format using MD5 hashing.
1649
+ *
1650
+ * Takes an input string, computes its MD5 hash, then formats the 32 hex
1651
+ * characters as a UUID with version nibble set to '3' (MD5) and variant
1652
+ * nibble set to '8' (RFC 4122).
1653
+ *
1654
+ * This produces a deterministic, valid UUID suitable for Apple's SK2
1655
+ * `appAccountToken` and Google Play's `obfuscatedAccountId`.
1656
+ *
1657
+ * @param str - The input string to hash and format
1658
+ * @returns A UUIDv3-like string (36 chars with dashes), or empty string if input is empty
1659
+ */
1660
+ function md5toUUID(str) {
1661
+ if (!str)
1662
+ return '';
1663
+ const hash = Utils.md5(str);
1664
+ // UUID format: xxxxxxxx-xxxx-3xxx-8xxx-xxxxxxxxxxxx
1665
+ // Position 12: version '3' (MD5), Position 16: variant '8' (RFC 4122)
1666
+ return hash.substring(0, 8) + '-'
1667
+ + hash.substring(8, 12) + '-'
1668
+ + '3' + hash.substring(13, 16) + '-'
1669
+ + '8' + hash.substring(17, 20) + '-'
1670
+ + hash.substring(20, 32);
1671
+ }
1672
+ Utils.md5toUUID = md5toUUID;
1673
+ })(Utils = CdvPurchase.Utils || (CdvPurchase.Utils = {}));
1674
+ })(CdvPurchase || (CdvPurchase = {}));
1618
1675
  /// <reference path="types.ts" />
1619
1676
  /// <reference path="utils/compatibility.ts" />
1620
1677
  /// <reference path="utils/platform-name.ts" />
@@ -1629,6 +1686,7 @@ var CdvPurchase;
1629
1686
  /// <reference path="internal/transaction-monitor.ts" />
1630
1687
  /// <reference path="internal/receipts-monitor.ts" />
1631
1688
  /// <reference path="internal/expiry-monitor.ts" />
1689
+ /// <reference path="utils/to-uuid.ts" />
1632
1690
  /**
1633
1691
  * Namespace for the cordova-plugin-purchase plugin.
1634
1692
  *
@@ -1662,7 +1720,7 @@ var CdvPurchase;
1662
1720
  /**
1663
1721
  * Current release number of the plugin.
1664
1722
  */
1665
- CdvPurchase.PLUGIN_VERSION = '13.15.3';
1723
+ CdvPurchase.PLUGIN_VERSION = '13.16.0';
1666
1724
  /**
1667
1725
  * Entry class of the plugin.
1668
1726
  */
@@ -1694,6 +1752,8 @@ var CdvPurchase;
1694
1752
  * @see {@link LogLevel}
1695
1753
  */
1696
1754
  this.verbosity = CdvPurchase.LogLevel.ERROR;
1755
+ /** @internal Tracks whether the info notice for 'legacy' has been emitted */
1756
+ this._legacyObfuscatorNoticeEmitted = false;
1697
1757
  /** List of callbacks for the "ready" events */
1698
1758
  this._readyCallbacks = new CdvPurchase.Internal.ReadyCallbacks(this.log);
1699
1759
  /** Callbacks when a product definition was updated */
@@ -1753,6 +1813,7 @@ var CdvPurchase;
1753
1813
  this._validator = new CdvPurchase.Internal.Validator({
1754
1814
  adapters: this.adapters,
1755
1815
  getApplicationUsername: this.getApplicationUsername.bind(this),
1816
+ obfuscateUsername: this.obfuscateUsername.bind(this),
1756
1817
  get localReceipts() { return store.localReceipts; },
1757
1818
  get validator() { return store.validator; },
1758
1819
  get validator_privacy_policy() { return store.validator_privacy_policy; },
@@ -1810,6 +1871,40 @@ var CdvPurchase;
1810
1871
  return this.applicationUsername();
1811
1872
  return this.applicationUsername;
1812
1873
  }
1874
+ /**
1875
+ * Obfuscate the application username according to the configured obfuscation strategy.
1876
+ *
1877
+ * See {@link Obfuscator} for the per-mode output format.
1878
+ *
1879
+ * @internal
1880
+ */
1881
+ obfuscateUsername(applicationUsername, platform) {
1882
+ var _a;
1883
+ if (!applicationUsername)
1884
+ return undefined;
1885
+ const obfuscator = (_a = this.obfuscator) !== null && _a !== void 0 ? _a : 'legacy';
1886
+ if (typeof obfuscator === 'function') {
1887
+ return obfuscator(applicationUsername, platform);
1888
+ }
1889
+ switch (obfuscator) {
1890
+ case 'disabled':
1891
+ return applicationUsername;
1892
+ case 'uuid':
1893
+ return CdvPurchase.Utils.md5toUUID(applicationUsername);
1894
+ case 'legacy':
1895
+ default:
1896
+ if (!this._legacyObfuscatorNoticeEmitted) {
1897
+ this._legacyObfuscatorNoticeEmitted = true;
1898
+ this.log.info('store.obfuscator defaults to "legacy" for backward compatibility. New integrations should set store.obfuscator = "uuid". See https://github.com/j3k0/cordova-plugin-purchase/issues/1665');
1899
+ }
1900
+ if (platform === CdvPurchase.Platform.GOOGLE_PLAY) {
1901
+ // Backward-compatible: raw MD5 hash (32 hex chars, no dashes)
1902
+ return CdvPurchase.Utils.md5(applicationUsername);
1903
+ }
1904
+ // UUIDv3 format — valid for Apple appAccountToken (SK1 + SK2) and any other platform
1905
+ return CdvPurchase.Utils.md5toUUID(applicationUsername);
1906
+ }
1907
+ }
1813
1908
  /**
1814
1909
  * Register a product.
1815
1910
  *
@@ -1868,6 +1963,8 @@ var CdvPurchase;
1868
1963
  error: this.triggerError.bind(this),
1869
1964
  get verbosity() { return store.verbosity; },
1870
1965
  getApplicationUsername() { return store.getApplicationUsername(); },
1966
+ obfuscateUsername: (username, platform) => store.obfuscateUsername(username, platform),
1967
+ get obfuscator() { return store.obfuscator; },
1871
1968
  get listener() { return store.listener; },
1872
1969
  get log() { return store.log; },
1873
1970
  get registeredProducts() { return store.registeredProducts; },
@@ -3143,6 +3240,24 @@ var CdvPurchase;
3143
3240
  }, 300);
3144
3241
  }
3145
3242
  get products() { return this._products; }
3243
+ /**
3244
+ * Resolve the username string passed to the native bridge for a
3245
+ * purchase. SK1 + 'legacy' keeps the raw username for backward
3246
+ * compatibility; every other mode obfuscates through the
3247
+ * configured strategy. 'disabled' always returns the raw value.
3248
+ */
3249
+ resolveBridgeUsername() {
3250
+ var _a;
3251
+ const raw = this.context.getApplicationUsername();
3252
+ if (!raw)
3253
+ return undefined;
3254
+ const obfuscator = (_a = this.context.obfuscator) !== null && _a !== void 0 ? _a : 'legacy';
3255
+ if (obfuscator === 'disabled')
3256
+ return raw;
3257
+ if (obfuscator === 'legacy' && !this.useSK2)
3258
+ return raw;
3259
+ return this.context.obfuscateUsername(raw, CdvPurchase.Platform.APPLE_APPSTORE);
3260
+ }
3146
3261
  /** Find a given product from ID */
3147
3262
  getProduct(id) { return this._products.find(p => p.id === id); }
3148
3263
  get receipts() {
@@ -3500,46 +3615,39 @@ var CdvPurchase;
3500
3615
  loadEligibility(validProducts) {
3501
3616
  return __awaiter(this, void 0, void 0, function* () {
3502
3617
  this.log.debug('load eligibility: ' + JSON.stringify(validProducts));
3503
- if (!this.discountEligibilityDeterminer) {
3504
- this.log.debug('No discount eligibility determiner, skipping...');
3618
+ // Collect eligibility requests alongside native-provided answers (from
3619
+ // StoreKit 2's isEligibleForIntroOffer, when available).
3620
+ const { requests, nativeAnswers } = AppleAppStore.Internal.collectEligibilityRequests(validProducts);
3621
+ if (requests.length === 0) {
3505
3622
  return new AppleAppStore.Internal.DiscountEligibilities([], []);
3506
3623
  }
3507
- const eligibilityRequests = [];
3508
- validProducts.forEach(valid => {
3509
- var _a, _b, _c;
3510
- (_a = valid.discounts) === null || _a === void 0 ? void 0 : _a.forEach(discount => {
3511
- eligibilityRequests.push({
3512
- productId: valid.id,
3513
- discountId: discount.id,
3514
- discountType: discount.type,
3515
- });
3516
- });
3517
- if (((_c = (_b = valid.discounts) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) === 0 && valid.introPrice) {
3518
- // sometime apple returns the discounts in the deprecated "introductory" info
3519
- // we create a special "discount" with the id "intro" to check for eligibility.
3520
- eligibilityRequests.push({
3521
- productId: valid.id,
3522
- discountId: 'intro',
3523
- discountType: 'Introductory',
3524
- });
3525
- }
3526
- });
3527
- if (eligibilityRequests.length > 0) {
3528
- const applicationReceipt = yield this.loadAppStoreReceipt();
3529
- if (!applicationReceipt || !applicationReceipt.appStoreReceipt) {
3530
- this.log.debug('no receipt, assuming introductory price are available.');
3531
- return new AppleAppStore.Internal.DiscountEligibilities(eligibilityRequests, eligibilityRequests.map(r => r.discountType === "Introductory"));
3532
- }
3533
- else {
3534
- this.log.debug('calling discount eligibility determiner.');
3535
- const response = yield this.callDiscountEligibilityDeterminer(applicationReceipt, eligibilityRequests);
3536
- this.log.debug('response: ' + JSON.stringify(response));
3537
- return new AppleAppStore.Internal.DiscountEligibilities(eligibilityRequests, response);
3538
- }
3624
+ // Fast path — if every eligibility answer came from native, we can skip
3625
+ // the receipt fetch and the determiner entirely. This is the common case
3626
+ // for StoreKit 2 where the app store receipt is always empty.
3627
+ const allNative = nativeAnswers.every(a => a !== undefined);
3628
+ if (allNative) {
3629
+ this.log.debug('native eligibility answers cover all requests, skipping determiner.');
3630
+ return new AppleAppStore.Internal.DiscountEligibilities(requests, nativeAnswers);
3631
+ }
3632
+ // Otherwise fall back to the receipt + determiner path, then overlay any
3633
+ // native answers we do have (native wins on conflict — it's authoritative).
3634
+ if (!this.discountEligibilityDeterminer) {
3635
+ this.log.debug('No discount eligibility determiner; using native answers only where available.');
3636
+ const defaultForMissing = requests.map(r => r.discountType === 'Introductory');
3637
+ return new AppleAppStore.Internal.DiscountEligibilities(requests, AppleAppStore.Internal.mergeNativeEligibility(defaultForMissing, nativeAnswers));
3638
+ }
3639
+ const applicationReceipt = yield this.loadAppStoreReceipt();
3640
+ let response;
3641
+ if (!applicationReceipt || !applicationReceipt.appStoreReceipt) {
3642
+ this.log.debug('no receipt, assuming introductory price are available.');
3643
+ response = requests.map(r => r.discountType === 'Introductory');
3539
3644
  }
3540
3645
  else {
3541
- return new AppleAppStore.Internal.DiscountEligibilities([], []);
3646
+ this.log.debug('calling discount eligibility determiner.');
3647
+ response = yield this.callDiscountEligibilityDeterminer(applicationReceipt, requests);
3648
+ this.log.debug('response: ' + JSON.stringify(response));
3542
3649
  }
3650
+ return new AppleAppStore.Internal.DiscountEligibilities(requests, AppleAppStore.Internal.mergeNativeEligibility(response, nativeAnswers));
3543
3651
  });
3544
3652
  }
3545
3653
  callDiscountEligibilityDeterminer(applicationReceipt, eligibilityRequests) {
@@ -3645,7 +3753,9 @@ var CdvPurchase;
3645
3753
  // When we switch AppStore user, the cached receipt isn't from the new user.
3646
3754
  // so after a purchase, we want to make sure we're using the receipt from the logged in user.
3647
3755
  this.forceReceiptReload = true;
3648
- this.bridge.purchase(offer.productId, quantity, this.context.getApplicationUsername(), discount, success, error);
3756
+ warnIfDeprecatedAdditionalUsername(this.log, additionalData);
3757
+ const username = this.resolveBridgeUsername();
3758
+ this.bridge.purchase(offer.productId, quantity, username, discount, success, error);
3649
3759
  });
3650
3760
  });
3651
3761
  }
@@ -3902,6 +4012,16 @@ var CdvPurchase;
3902
4012
  function appStoreError(code, message, productId) {
3903
4013
  return CdvPurchase.storeError(code, message, CdvPurchase.Platform.APPLE_APPSTORE, productId);
3904
4014
  }
4015
+ let deprecatedAdditionalUsernameNoticed = false;
4016
+ function warnIfDeprecatedAdditionalUsername(log, additionalData) {
4017
+ // Bracket access avoids the @deprecated read warning on the field.
4018
+ if (!additionalData || !additionalData['applicationUsername'])
4019
+ return;
4020
+ if (deprecatedAdditionalUsernameNoticed)
4021
+ return;
4022
+ deprecatedAdditionalUsernameNoticed = true;
4023
+ log.warn('additionalData.applicationUsername is deprecated and ignored. Set store.applicationUsername instead.');
4024
+ }
3905
4025
  })(AppleAppStore = CdvPurchase.AppleAppStore || (CdvPurchase.AppleAppStore = {}));
3906
4026
  })(CdvPurchase || (CdvPurchase = {}));
3907
4027
  var CdvPurchase;
@@ -4882,6 +5002,52 @@ var CdvPurchase;
4882
5002
  }
4883
5003
  }
4884
5004
  Internal.DiscountEligibilities = DiscountEligibilities;
5005
+ /**
5006
+ * Build the pair of (requests, native-provided answers) for every valid product.
5007
+ *
5008
+ * The two arrays are parallel: for each request, the matching `nativeAnswers` entry
5009
+ * is either the native eligibility (from StoreKit 2's `isEligibleForIntroOffer`)
5010
+ * or `undefined` if native did not provide one (SK1 / older native plugin).
5011
+ *
5012
+ * Only Introductory requests can carry a native answer — SK2 does not answer
5013
+ * promotional offer eligibility at the adapter level.
5014
+ */
5015
+ function collectEligibilityRequests(validProducts) {
5016
+ const requests = [];
5017
+ const nativeAnswers = [];
5018
+ validProducts.forEach(valid => {
5019
+ var _a, _b, _c;
5020
+ (_a = valid.discounts) === null || _a === void 0 ? void 0 : _a.forEach(discount => {
5021
+ requests.push({
5022
+ productId: valid.id,
5023
+ discountId: discount.id,
5024
+ discountType: discount.type,
5025
+ });
5026
+ nativeAnswers.push(discount.type === 'Introductory' ? valid.introPriceEligible : undefined);
5027
+ });
5028
+ if (((_c = (_b = valid.discounts) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) === 0 && valid.introPrice) {
5029
+ requests.push({
5030
+ productId: valid.id,
5031
+ discountId: 'intro',
5032
+ discountType: 'Introductory',
5033
+ });
5034
+ nativeAnswers.push(valid.introPriceEligible);
5035
+ }
5036
+ });
5037
+ return { requests, nativeAnswers };
5038
+ }
5039
+ Internal.collectEligibilityRequests = collectEligibilityRequests;
5040
+ /**
5041
+ * Overlay native-provided eligibility answers on top of a determiner response.
5042
+ *
5043
+ * Native wins on conflict — it's the authoritative source for StoreKit 2.
5044
+ * Determiner response is used where native did not provide an answer (SK1
5045
+ * or older native builds).
5046
+ */
5047
+ function mergeNativeEligibility(determinerResponse, nativeAnswers) {
5048
+ return determinerResponse.map((r, i) => nativeAnswers[i] !== undefined ? nativeAnswers[i] : r);
5049
+ }
5050
+ Internal.mergeNativeEligibility = mergeNativeEligibility;
4885
5051
  })(Internal = AppleAppStore.Internal || (AppleAppStore.Internal = {}));
4886
5052
  })(AppleAppStore = CdvPurchase.AppleAppStore || (CdvPurchase.AppleAppStore = {}));
4887
5053
  })(CdvPurchase || (CdvPurchase = {}));
@@ -6320,6 +6486,8 @@ var CdvPurchase;
6320
6486
  /** @inheritDoc */
6321
6487
  order(offer, additionalData) {
6322
6488
  return __awaiter(this, void 0, void 0, function* () {
6489
+ warnIfDeprecatedAdditionalUsername(this.log, additionalData);
6490
+ additionalData = withObfuscatedAccountId(additionalData, this.context);
6323
6491
  return new Promise(resolve => {
6324
6492
  this.log.info("Order - " + JSON.stringify(offer));
6325
6493
  const buySuccess = () => resolve(undefined);
@@ -6477,6 +6645,33 @@ var CdvPurchase;
6477
6645
  PRODUCTION: 7 * 24 * 60 * 60 * 1000 + 10 * 60 * 1000, // 7 days + 10 minutes for production
6478
6646
  };
6479
6647
  GooglePlay.Adapter = Adapter;
6648
+ let deprecatedAdditionalUsernameNoticed = false;
6649
+ function warnIfDeprecatedAdditionalUsername(log, additionalData) {
6650
+ // Bracket access avoids the @deprecated read warning on the field.
6651
+ if (!additionalData || !additionalData['applicationUsername'])
6652
+ return;
6653
+ if (deprecatedAdditionalUsernameNoticed)
6654
+ return;
6655
+ deprecatedAdditionalUsernameNoticed = true;
6656
+ log.warn('additionalData.applicationUsername is deprecated and ignored. Set store.applicationUsername instead.');
6657
+ }
6658
+ /**
6659
+ * Return a copy of `additionalData` with `googlePlay.accountId` populated
6660
+ * from `store.applicationUsername` (via the configured obfuscator) when
6661
+ * not already provided by the caller. Never mutates the input.
6662
+ */
6663
+ function withObfuscatedAccountId(additionalData, context) {
6664
+ var _a;
6665
+ const next = Object.assign({}, (additionalData !== null && additionalData !== void 0 ? additionalData : {}));
6666
+ next.googlePlay = Object.assign({}, ((_a = additionalData === null || additionalData === void 0 ? void 0 : additionalData.googlePlay) !== null && _a !== void 0 ? _a : {}));
6667
+ if (!next.googlePlay.accountId) {
6668
+ const username = context.getApplicationUsername();
6669
+ if (username) {
6670
+ next.googlePlay.accountId = context.obfuscateUsername(username, CdvPurchase.Platform.GOOGLE_PLAY);
6671
+ }
6672
+ }
6673
+ return next;
6674
+ }
6480
6675
  function playStoreError(code, message, productId) {
6481
6676
  return CdvPurchase.storeError(code, message, CdvPurchase.Platform.GOOGLE_PLAY, productId);
6482
6677
  }
@@ -6642,11 +6837,7 @@ var CdvPurchase;
6642
6837
  return !!obj && obj.constructor === Object ? obj : {};
6643
6838
  }
6644
6839
  function extendAdditionalData(ad) {
6645
- const additionalData = ensureObject(ad === null || ad === void 0 ? void 0 : ad.googlePlay);
6646
- if (!additionalData.accountId && (ad === null || ad === void 0 ? void 0 : ad.applicationUsername)) {
6647
- additionalData.accountId = CdvPurchase.Utils.md5(ad.applicationUsername);
6648
- }
6649
- return additionalData;
6840
+ return ensureObject(ad === null || ad === void 0 ? void 0 : ad.googlePlay);
6650
6841
  }
6651
6842
  })(Bridge = GooglePlay.Bridge || (GooglePlay.Bridge = {}));
6652
6843
  })(GooglePlay = CdvPurchase.GooglePlay || (CdvPurchase.GooglePlay = {}));
@@ -6910,11 +7101,7 @@ var CdvPurchase;
6910
7101
  return !!obj && obj.constructor === Object ? obj : {};
6911
7102
  }
6912
7103
  function extendAdditionalData(ad) {
6913
- const additionalData = ensureObject(ad === null || ad === void 0 ? void 0 : ad.googlePlay);
6914
- if (!additionalData.accountId && (ad === null || ad === void 0 ? void 0 : ad.applicationUsername)) {
6915
- additionalData.accountId = CdvPurchase.Utils.md5(ad.applicationUsername);
6916
- }
6917
- return additionalData;
7104
+ return ensureObject(ad === null || ad === void 0 ? void 0 : ad.googlePlay);
6918
7105
  }
6919
7106
  })(Bridge = GooglePlay.Bridge || (GooglePlay.Bridge = {}));
6920
7107
  })(GooglePlay = CdvPurchase.GooglePlay || (CdvPurchase.GooglePlay = {}));
@@ -7774,11 +7961,12 @@ var CdvPurchase;
7774
7961
  });
7775
7962
  }
7776
7963
  handleReceiptValidationResponse(receipt, response) {
7964
+ var _a, _b;
7777
7965
  return __awaiter(this, void 0, void 0, function* () {
7778
7966
  this.log.info('handleReceiptValidationResponse for IapticJS');
7779
7967
  if (response.ok) {
7780
- const validatedData = response.data.transaction;
7781
- const collection = response.data.collection;
7968
+ const validatedData = (_a = response.data) === null || _a === void 0 ? void 0 : _a.transaction;
7969
+ const collection = (_b = response.data) === null || _b === void 0 ? void 0 : _b.collection;
7782
7970
  // Update receipt based on validated collection
7783
7971
  if (collection) {
7784
7972
  const purchases = collection.map((vp) => {