@nosslabs/iap 8.1.0 → 8.2.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
@@ -1729,6 +1729,11 @@ interface IAP<TEntitlement extends EntitlementBase = EntitlementBase> {
1729
1729
  * A no-op after `destroy()`, rather than an error: a teardown racing a
1730
1730
  * "delete my data" tap is a real sequence, not a programming mistake.
1731
1731
  *
1732
+ * It also throws if the storage backend cannot be reached at all — an
1733
+ * uninstalled `@capacitor/preferences`, say. Individual key failures are
1734
+ * logged and the rest still cleared, but reporting success having erased
1735
+ * nothing is the one outcome a delete-everything control must not have.
1736
+ *
1732
1737
  * It does **not** revoke the purchase. The store still owns it, and a
1733
1738
  * restore will bring the entitlement back — which is correct: the user
1734
1739
  * paid.
package/dist/index.d.ts CHANGED
@@ -1729,6 +1729,11 @@ interface IAP<TEntitlement extends EntitlementBase = EntitlementBase> {
1729
1729
  * A no-op after `destroy()`, rather than an error: a teardown racing a
1730
1730
  * "delete my data" tap is a real sequence, not a programming mistake.
1731
1731
  *
1732
+ * It also throws if the storage backend cannot be reached at all — an
1733
+ * uninstalled `@capacitor/preferences`, say. Individual key failures are
1734
+ * logged and the rest still cleared, but reporting success having erased
1735
+ * nothing is the one outcome a delete-everything control must not have.
1736
+ *
1732
1737
  * It does **not** revoke the purchase. The store still owns it, and a
1733
1738
  * restore will bring the entitlement back — which is correct: the user
1734
1739
  * paid.
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Capacitor } from '@capacitor/core';
2
2
  import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
3
3
  import { z } from 'zod';
4
- import { Preferences } from '@capacitor/preferences';
5
4
 
6
5
  var __defProp = Object.defineProperty;
7
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -1977,39 +1976,122 @@ init_errors();
1977
1976
  var PreferencesAdapter = class {
1978
1977
  prefix;
1979
1978
  knownKeys = /* @__PURE__ */ new Set();
1979
+ /**
1980
+ * Boxed, and that is not incidental — see {@link PreferencesAdapter.preferences}.
1981
+ */
1982
+ plugin = null;
1980
1983
  constructor(namespace) {
1981
1984
  this.prefix = `${namespace}.`;
1982
1985
  }
1986
+ /**
1987
+ * The plugin, inside a box.
1988
+ *
1989
+ * The box is load-bearing. `registerPlugin()` hands back a **Proxy** that
1990
+ * answers any property, `then` included — so resolving a promise *with*
1991
+ * the plugin makes it look like a thenable, and promise assimilation
1992
+ * calls `Preferences.then()`. On web that rejects with
1993
+ * `"Preferences.then()" is not implemented on web`, from inside
1994
+ * `await this.preferences()`, for every storage operation.
1995
+ *
1996
+ * Wrapping it in a plain object means the promise resolves with something
1997
+ * that has no `then`, so nothing is assimilated.
1998
+ */
1999
+ preferences() {
2000
+ this.plugin ??= import('@capacitor/preferences').then((mod) => ({ preferences: mod.Preferences })).catch((cause) => {
2001
+ if (isModuleNotFound(cause)) throw notInstalled(cause);
2002
+ this.plugin = null;
2003
+ throw new IAPError({
2004
+ code: IAPErrorCode.STORAGE_ERROR,
2005
+ message: "Could not load @capacitor/preferences. The package is installed, so this is most likely a chunk that failed to load; it is worth retrying.",
2006
+ cause,
2007
+ recoverable: true
2008
+ });
2009
+ });
2010
+ return this.plugin;
2011
+ }
2012
+ /**
2013
+ * Resolve the plugin now, so a missing one is reported at `initialize()`.
2014
+ *
2015
+ * See the note on lazy loading above for why this is not left to the first
2016
+ * `get()`.
2017
+ */
2018
+ async ensureAvailable() {
2019
+ await this.preferences();
2020
+ }
1983
2021
  async get(key) {
2022
+ const { preferences } = await this.preferences();
1984
2023
  try {
1985
- const result = await Preferences.get({ key: this.prefix + key });
2024
+ const result = await preferences.get({ key: this.prefix + key });
1986
2025
  return result.value;
1987
2026
  } catch (cause) {
1988
2027
  throw wrap(cause, `Preferences.get failed for "${key}".`);
1989
2028
  }
1990
2029
  }
1991
2030
  async set(key, value) {
2031
+ const { preferences } = await this.preferences();
1992
2032
  try {
1993
- await Preferences.set({ key: this.prefix + key, value });
2033
+ await preferences.set({ key: this.prefix + key, value });
1994
2034
  this.knownKeys.add(key);
1995
2035
  } catch (cause) {
1996
2036
  throw wrap(cause, `Preferences.set failed for "${key}".`);
1997
2037
  }
1998
2038
  }
1999
2039
  async remove(key) {
2040
+ const { preferences } = await this.preferences();
2000
2041
  try {
2001
- await Preferences.remove({ key: this.prefix + key });
2042
+ await preferences.remove({ key: this.prefix + key });
2002
2043
  this.knownKeys.delete(key);
2003
2044
  } catch (cause) {
2004
2045
  throw wrap(cause, `Preferences.remove failed for "${key}".`);
2005
2046
  }
2006
2047
  }
2007
2048
  async clear() {
2049
+ const { preferences } = await this.preferences();
2008
2050
  const keys = [...this.knownKeys];
2009
- this.knownKeys.clear();
2010
- await Promise.all(keys.map((k) => Preferences.remove({ key: this.prefix + k })));
2051
+ const failed = [];
2052
+ const errors = [];
2053
+ await Promise.all(
2054
+ keys.map(async (key) => {
2055
+ try {
2056
+ await preferences.remove({ key: this.prefix + key });
2057
+ this.knownKeys.delete(key);
2058
+ } catch (cause) {
2059
+ failed.push(key);
2060
+ errors.push(cause);
2061
+ }
2062
+ })
2063
+ );
2064
+ if (failed.length > 0) {
2065
+ throw wrap(errors[0], `Preferences.clear failed for ${failed.length} key(s).`);
2066
+ }
2011
2067
  }
2012
2068
  };
2069
+ function isModuleNotFound(cause) {
2070
+ let current = cause;
2071
+ for (let depth = 0; depth < 5 && current; depth += 1) {
2072
+ const code = current.code;
2073
+ if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") return true;
2074
+ const message = current instanceof Error ? current.message : String(current);
2075
+ if (/cannot find (module|package)|could not resolve|failed to resolve/i.test(message)) {
2076
+ return true;
2077
+ }
2078
+ const next = current.cause;
2079
+ if (next === current) break;
2080
+ current = next;
2081
+ }
2082
+ return false;
2083
+ }
2084
+ function notInstalled(cause) {
2085
+ return new IAPError({
2086
+ code: IAPErrorCode.INVALID_CONFIG,
2087
+ message: 'storage.type is "preferences" (the default) but @capacitor/preferences is not installed. Install it (npm i @capacitor/preferences && npx cap sync), or choose storage that needs no plugin: storage.type "memory", or "custom" with your own adapter.',
2088
+ // The per-code hint for INVALID_CONFIG sends the reader to check field
2089
+ // paths against the config schema. There are none to check, and no
2090
+ // config change fixes this — the message above already says what to do.
2091
+ includeHint: false,
2092
+ cause
2093
+ });
2094
+ }
2013
2095
  function wrap(cause, message) {
2014
2096
  return new IAPError({
2015
2097
  code: IAPErrorCode.STORAGE_ERROR,
@@ -2110,12 +2192,7 @@ var EntitlementCache = class {
2110
2192
  try {
2111
2193
  await this.storage.set(ENTITLEMENTS_KEY, JSON.stringify(envelope));
2112
2194
  } catch (cause) {
2113
- throw new IAPError({
2114
- code: IAPErrorCode.STORAGE_ERROR,
2115
- message: "Failed to persist entitlement cache.",
2116
- cause,
2117
- recoverable: true
2118
- });
2195
+ throw toIAPError(cause, "Failed to persist entitlement cache.", IAPErrorCode.STORAGE_ERROR);
2119
2196
  }
2120
2197
  return cachedAt;
2121
2198
  }
@@ -3062,6 +3139,7 @@ async function initializeIap(state, refreshEntitlements) {
3062
3139
  state.logger.debug("initialize() called more than once; ignoring.");
3063
3140
  return;
3064
3141
  }
3142
+ await state.storage.ensureAvailable?.();
3065
3143
  const platform = getPlatform();
3066
3144
  if (!isNative()) {
3067
3145
  state.logger.info("Native purchases unavailable on web; entitlement queries still functional.");
@@ -3355,6 +3433,7 @@ async function resetIap(state) {
3355
3433
  recoverable: true
3356
3434
  });
3357
3435
  }
3436
+ await state.storage.ensureAvailable?.();
3358
3437
  const previous = state.entitlements;
3359
3438
  state.entitlements = [];
3360
3439
  state.cachedAt = null;
@@ -3531,12 +3610,11 @@ var UnfinishedTransactionsStore = class {
3531
3610
  try {
3532
3611
  await this.storage.set(STORE_KEY2, JSON.stringify(entries));
3533
3612
  } catch (cause) {
3534
- throw new IAPError({
3535
- code: IAPErrorCode.STORAGE_ERROR,
3536
- message: "Failed to persist unfinished transactions list.",
3613
+ throw toIAPError(
3537
3614
  cause,
3538
- recoverable: true
3539
- });
3615
+ "Failed to persist unfinished transactions list.",
3616
+ IAPErrorCode.STORAGE_ERROR
3617
+ );
3540
3618
  }
3541
3619
  }
3542
3620
  async safeClear() {
@@ -3799,7 +3877,7 @@ function resolveLogger(level, candidate) {
3799
3877
  init_errors();
3800
3878
 
3801
3879
  // src/version.ts
3802
- var VERSION = "8.1.0";
3880
+ var VERSION = "8.2.0";
3803
3881
 
3804
3882
  export { DEFAULT_PERMANENT_ERROR_CODES, HttpBackendAdapter, HttpClient, IAPError, IAPErrorCode, VERSION, createIAP, errorHint, isExpired, isIAPError, verifyPurchaseOnDevice };
3805
3883
  //# sourceMappingURL=index.js.map