@nosslabs/iap 0.3.0 → 0.3.1

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
@@ -822,6 +822,24 @@ type EventName<TEntitlement extends EntitlementBase = EntitlementBase> = keyof E
822
822
  type EventPayload<K extends EventName<TEntitlement>, TEntitlement extends EntitlementBase = EntitlementBase> = EventMap<TEntitlement>[K];
823
823
  type Unsubscribe = () => void;
824
824
 
825
+ /**
826
+ * Convenience context the library passes to a function-form
827
+ * {@link AppUserId} fetcher. `authHeaders` is the result of awaiting
828
+ * `backend.getAuthHeaders()` — the same headers the library will use
829
+ * for its own backend requests. Resolved fresh per purchase so token
830
+ * refresh keeps working.
831
+ *
832
+ * It's a convenience, not a contract: fetchers may legitimately ignore
833
+ * the parameter. Use it when your UUID-minting endpoint shares auth
834
+ * with your IAP backend; ignore it (and close over your own auth
835
+ * state) when it doesn't.
836
+ *
837
+ * For consumers using a custom `BackendAdapter` (no `getAuthHeaders`
838
+ * configured), `authHeaders` is `{}`.
839
+ */
840
+ interface AppUserIdFetcherContext {
841
+ authHeaders: Record<string, string>;
842
+ }
825
843
  /**
826
844
  * Value supplied to `iap.purchase({ appUserId })`. Either a UUID v4
827
845
  * string the caller already has (e.g. from local cache / app state) or
@@ -830,9 +848,14 @@ type Unsubscribe = () => void;
830
848
  * persists on first call, returns the existing UUID on later calls).
831
849
  *
832
850
  * The fetcher is invoked **fresh on every purchase** — iap caches
833
- * nothing. The backend owns the mint-or-lookup idempotency. The
834
- * fetcher closes over whatever auth state the caller needs (session
835
- * token, JWT, cookie); iap passes no implicit context.
851
+ * nothing. The backend owns the mint-or-lookup idempotency.
852
+ *
853
+ * Two fetcher shapes are supported:
854
+ * - `() => Promise<string>` — closes over its own auth state.
855
+ * - `(ctx) => Promise<string>` — receives `ctx.authHeaders` populated
856
+ * from `backend.getAuthHeaders()` so the auth wired up for IAP
857
+ * requests can be reused without redefining a helper. See
858
+ * {@link AppUserIdFetcherContext}.
836
859
  *
837
860
  * Either form is validated as UUID v4 before being forwarded to
838
861
  * StoreKit's `appAccountToken` (iOS) / Play Billing's
@@ -840,7 +863,7 @@ type Unsubscribe = () => void;
840
863
  * `IAPError(INVALID_APP_USER_ID)`. A throwing/rejecting fetcher
841
864
  * surfaces as `IAPError(APP_USER_ID_FETCH_FAILED, cause: <original>)`.
842
865
  */
843
- type AppUserId = string | (() => Promise<string>);
866
+ type AppUserId = string | (() => Promise<string>) | ((ctx: AppUserIdFetcherContext) => Promise<string>);
844
867
  /**
845
868
  * Options accepted by `iap.purchase(...)`. `productId` is required;
846
869
  * `appUserId` is optional — when omitted, no `applicationUsername` is
package/dist/index.d.ts CHANGED
@@ -822,6 +822,24 @@ type EventName<TEntitlement extends EntitlementBase = EntitlementBase> = keyof E
822
822
  type EventPayload<K extends EventName<TEntitlement>, TEntitlement extends EntitlementBase = EntitlementBase> = EventMap<TEntitlement>[K];
823
823
  type Unsubscribe = () => void;
824
824
 
825
+ /**
826
+ * Convenience context the library passes to a function-form
827
+ * {@link AppUserId} fetcher. `authHeaders` is the result of awaiting
828
+ * `backend.getAuthHeaders()` — the same headers the library will use
829
+ * for its own backend requests. Resolved fresh per purchase so token
830
+ * refresh keeps working.
831
+ *
832
+ * It's a convenience, not a contract: fetchers may legitimately ignore
833
+ * the parameter. Use it when your UUID-minting endpoint shares auth
834
+ * with your IAP backend; ignore it (and close over your own auth
835
+ * state) when it doesn't.
836
+ *
837
+ * For consumers using a custom `BackendAdapter` (no `getAuthHeaders`
838
+ * configured), `authHeaders` is `{}`.
839
+ */
840
+ interface AppUserIdFetcherContext {
841
+ authHeaders: Record<string, string>;
842
+ }
825
843
  /**
826
844
  * Value supplied to `iap.purchase({ appUserId })`. Either a UUID v4
827
845
  * string the caller already has (e.g. from local cache / app state) or
@@ -830,9 +848,14 @@ type Unsubscribe = () => void;
830
848
  * persists on first call, returns the existing UUID on later calls).
831
849
  *
832
850
  * The fetcher is invoked **fresh on every purchase** — iap caches
833
- * nothing. The backend owns the mint-or-lookup idempotency. The
834
- * fetcher closes over whatever auth state the caller needs (session
835
- * token, JWT, cookie); iap passes no implicit context.
851
+ * nothing. The backend owns the mint-or-lookup idempotency.
852
+ *
853
+ * Two fetcher shapes are supported:
854
+ * - `() => Promise<string>` — closes over its own auth state.
855
+ * - `(ctx) => Promise<string>` — receives `ctx.authHeaders` populated
856
+ * from `backend.getAuthHeaders()` so the auth wired up for IAP
857
+ * requests can be reused without redefining a helper. See
858
+ * {@link AppUserIdFetcherContext}.
836
859
  *
837
860
  * Either form is validated as UUID v4 before being forwarded to
838
861
  * StoreKit's `appAccountToken` (iOS) / Play Billing's
@@ -840,7 +863,7 @@ type Unsubscribe = () => void;
840
863
  * `IAPError(INVALID_APP_USER_ID)`. A throwing/rejecting fetcher
841
864
  * surfaces as `IAPError(APP_USER_ID_FETCH_FAILED, cause: <original>)`.
842
865
  */
843
- type AppUserId = string | (() => Promise<string>);
866
+ type AppUserId = string | (() => Promise<string>) | ((ctx: AppUserIdFetcherContext) => Promise<string>);
844
867
  /**
845
868
  * Options accepted by `iap.purchase(...)`. `productId` is required;
846
869
  * `appUserId` is optional — when omitted, no `applicationUsername` is
package/dist/index.js CHANGED
@@ -1230,7 +1230,11 @@ var PurchaseOrchestrator = class {
1230
1230
  message: `Product "${productId}" is not in the configured catalog.`
1231
1231
  });
1232
1232
  }
1233
- const resolvedAppUserId = appUserId !== void 0 ? await resolveAppUserId(appUserId) : void 0;
1233
+ let resolvedAppUserId;
1234
+ if (appUserId !== void 0) {
1235
+ const ctx = typeof appUserId === "function" ? { authHeaders: await this.deps.getAuthHeaders() } : { authHeaders: {} };
1236
+ resolvedAppUserId = await resolveAppUserId(appUserId, ctx);
1237
+ }
1234
1238
  this.inFlight.add(productId);
1235
1239
  this.deps.emitter.emit("purchase-started", { productId });
1236
1240
  try {
@@ -1347,11 +1351,11 @@ var PurchaseOrchestrator = class {
1347
1351
  return { status: "verification_failed", productId, error: iapError };
1348
1352
  }
1349
1353
  };
1350
- async function resolveAppUserId(supply) {
1354
+ async function resolveAppUserId(supply, ctx) {
1351
1355
  let resolved;
1352
1356
  if (typeof supply === "function") {
1353
1357
  try {
1354
- resolved = await supply();
1358
+ resolved = await supply(ctx);
1355
1359
  } catch (cause) {
1356
1360
  throw new IAPError({
1357
1361
  code: IAPErrorCode.APP_USER_ID_FETCH_FAILED,
@@ -1849,6 +1853,8 @@ function createIAP(input) {
1849
1853
  state.logger.debug(`Resolved ${validated.data.length} product(s) from backend manifest.`);
1850
1854
  }
1851
1855
  state.adapter = await selectNativeAdapter({ products: state.products });
1856
+ const configGetAuthHeaders = state.config.backend.getAuthHeaders;
1857
+ const getAuthHeaders = configGetAuthHeaders ? async () => configGetAuthHeaders() : async () => ({});
1852
1858
  const sharedDeps = {
1853
1859
  nativeAdapter: state.adapter,
1854
1860
  backend: state.backend,
@@ -1862,7 +1868,8 @@ function createIAP(input) {
1862
1868
  },
1863
1869
  setCachePersisted: (cachedAt) => {
1864
1870
  state.cachedAt = cachedAt;
1865
- }
1871
+ },
1872
+ getAuthHeaders
1866
1873
  };
1867
1874
  state.orchestrator = new PurchaseOrchestrator({
1868
1875
  ...sharedDeps,