expo-iap 5.2.2 → 5.2.4

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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  <div align="center">
4
4
  <img src="https://openiap.dev/frameworks/expo.svg" alt="Expo IAP Logo" width="150" />
5
5
 
6
- [![Version](http://img.shields.io/npm/v/expo-iap.svg?style=flat-square)](https://npmjs.org/package/expo-iap) [![Download](http://img.shields.io/npm/dm/expo-iap.svg?style=flat-square)](https://npmjs.org/package/expo-iap) [![OpenIAP](https://img.shields.io/badge/OpenIAP-Compliant-green?style=flat-square)](https://openiap.dev) [![CI](https://github.com/hyodotdev/openiap/actions/workflows/ci.yml/badge.svg)](https://github.com/hyodotdev/openiap/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/hyodotdev/openiap/graph/badge.svg?token=47VMTY5NyM)](https://codecov.io/gh/hyodotdev/openiap) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fhyochan%2Fexpo-iap.svg?type=shield&issueType=license)](https://app.fossa.com/projects/git%2Bgithub.com%2Fhyochan%2Fexpo-iap?ref=badge_shield&issueType=license)
6
+ [![Version](http://img.shields.io/npm/v/expo-iap.svg?style=flat-square)](https://npmjs.org/package/expo-iap) [![Download](http://img.shields.io/npm/dm/expo-iap.svg?style=flat-square)](https://npmjs.org/package/expo-iap) [![OpenIAP](https://img.shields.io/badge/OpenIAP-Compliant-green?style=flat-square)](https://openiap.dev) [![CI](https://github.com/hyodotdev/openiap/actions/workflows/ci-expo-iap.yml/badge.svg?branch=main)](https://github.com/hyodotdev/openiap/actions/workflows/ci-expo-iap.yml?query=branch%3Amain) [![codecov](https://codecov.io/gh/hyodotdev/openiap/branch/main/graph/badge.svg?component=expo-iap)](https://app.codecov.io/gh/hyodotdev/openiap/tree/main/libraries/expo-iap) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fhyochan%2Fexpo-iap.svg?type=shield&issueType=license)](https://app.fossa.com/projects/git%2Bgithub.com%2Fhyochan%2Fexpo-iap?ref=badge_shield&issueType=license)
7
7
 
8
8
  Expo IAP is a powerful in-app purchase solution for Expo and React Native applications that conforms to the Open IAP specification. It provides a unified API for handling in-app purchases across iOS and Android platforms with comprehensive error handling and modern TypeScript support.
9
9
 
@@ -1 +1 @@
1
- {"version":3,"file":"kit-api.d.ts","sourceRoot":"","sources":["../src/kit-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kit-api.d.ts","sourceRoot":"","sources":["../src/kit-api.ts"],"names":[],"mappings":"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"}
package/build/kit-api.js CHANGED
@@ -4,15 +4,11 @@
4
4
  // reachable from both LLM tools and end-user apps without each
5
5
  // duplicating the URL layout.
6
6
  const DEFAULT_BASE_URL = "https://kit.openiap.dev";
7
- // Merge caller-supplied headers with kit defaults (`accept`,
8
- // optionally `content-type`). When the runtime exposes a global
9
- // `Headers` constructor we use it directly so callers passing a
10
- // `Headers` instance (a `HeadersInit`) keep that exact instance's
11
- // values. When `Headers` is missing — older React Native builds where
12
- // the operator wires up `fetchImpl` without a `Headers` polyfill —
13
- // we fall back to a case-insensitive merge into a plain record so
14
- // the request still goes through. Either way, caller-set values take
15
- // precedence over kit defaults.
7
+ // Merge the request's internal headers with kit defaults (`accept`,
8
+ // optionally `content-type`). When `Headers` is missing — older React
9
+ // Native builds where the operator wires up `fetchImpl` without a
10
+ // `Headers` polyfill — the internal request sites use plain records,
11
+ // so a small case-insensitive merge is sufficient.
16
12
  function mergeHeaders(callerHeaders, hasBody) {
17
13
  if (typeof Headers === "function") {
18
14
  const merged = new Headers(callerHeaders);
@@ -23,37 +19,17 @@ function mergeHeaders(callerHeaders, hasBody) {
23
19
  }
24
20
  return merged;
25
21
  }
26
- // Plain-object fallback path. Build a case-insensitive name map
27
- // from whatever the caller passed (Headers-shaped, array-of-pairs,
28
- // or plain record) and re-emit as a record `fetchImpl` accepts.
22
+ // Plain-object fallback path. Build a case-insensitive name map and
23
+ // re-emit it as a record `fetchImpl` accepts.
29
24
  const lower = new Map();
30
25
  const setIfAbsent = (name, value) => {
31
26
  const key = name.toLowerCase();
32
27
  if (!lower.has(key))
33
28
  lower.set(key, { name, value });
34
29
  };
35
- const setForce = (name, value) => {
36
- const key = name.toLowerCase();
37
- lower.set(key, { name, value });
38
- };
39
30
  if (callerHeaders) {
40
- if (Array.isArray(callerHeaders)) {
41
- for (const [name, value] of callerHeaders)
42
- setForce(name, value);
43
- }
44
- else if (typeof callerHeaders.forEach === "function") {
45
- // `Headers`-like (without being our `typeof Headers === "function"`
46
- // global). RN polyfills sometimes attach `Headers` only to
47
- // request/response instances rather than the global scope.
48
- // Standard signature is `forEach((value, key, parent))`; we
49
- // bind the first two positionally so a polyfill that omits
50
- // the third argument still works. `key` is the header name.
51
- callerHeaders.forEach((value, key) => setForce(key, value));
52
- }
53
- else {
54
- for (const [name, value] of Object.entries(callerHeaders)) {
55
- setForce(name, value);
56
- }
31
+ for (const [name, value] of Object.entries(callerHeaders)) {
32
+ lower.set(name.toLowerCase(), { name, value });
57
33
  }
58
34
  }
59
35
  setIfAbsent("accept", "application/json");
@@ -89,11 +65,10 @@ export function kitApi(options) {
89
65
  // constructor: older React Native runtimes ship `fetch` (or a
90
66
  // polyfill via `fetchImpl`) without exposing `Headers` globally.
91
67
  // The prior implementation crashed before the first request on
92
- // those runtimes. We use `new Headers()` when available (preserves
93
- // caller-supplied `Headers` instances exactly), and otherwise fall
94
- // back to a small case-insensitive merge into a plain record.
95
- // Either way, kit defaults only apply when the caller hasn't set
96
- // the same name.
68
+ // those runtimes. We use `new Headers()` when available and
69
+ // otherwise fall back to a small case-insensitive merge into a
70
+ // plain record. Either way, kit defaults only apply when the
71
+ // internal request hasn't set the same name.
97
72
  const headers = mergeHeaders(init?.headers, init?.body != null);
98
73
  // Prepend a leading slash if `path` is missing one. Today's
99
74
  // call sites all hard-code the leading "/", but normalizing here
@@ -1 +1 @@
1
- {"version":3,"file":"kit-api.js","sourceRoot":"","sources":["../src/kit-api.ts"],"names":[],"mappings":"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","sourcesContent":["// Tiny fetch wrapper around kit's `/v1` HTTP surface for use by the JS\n// SDK consumers (react-native-iap + expo-iap). Mirrors the shape of\n// `packages/mcp-server/src/kit-client.ts` so the same operations are\n// reachable from both LLM tools and end-user apps without each\n// duplicating the URL layout.\n\nexport type KitApiOptions = {\n apiKey: string;\n baseUrl?: string;\n // Optional fetch override for runtimes without a global (older RN\n // builds) or for injection in tests.\n fetchImpl?: (input: string, init?: RequestInit) => Promise<Response>;\n /** Optional AsyncStorage-compatible persistent cache for direct client\n * payload reads. Cache failures never change a successful API result. */\n clientPayloadCache?: KitClientPayloadCache;\n};\n\nexport type KitClientPayloadCache = {\n getItem: (key: string) => Promise<string | null> | string | null;\n setItem: (key: string, value: string) => Promise<void> | void;\n removeItem?: (key: string) => Promise<void> | void;\n};\n\nexport type KitClientPayloadOptions = {\n /** Revalidate a cached payload with its scoped ETag. Without this flag,\n * a valid persistent entry is returned without a network request. */\n refresh?: boolean;\n};\n\nexport type KitSubscription = {\n id: string;\n productId: string;\n platform: \"IOS\" | \"Android\";\n state: string;\n expiresAt?: number;\n renewsAt?: number;\n willRenew?: boolean;\n cancellationReason?: string;\n currency?: string;\n priceAmountMicros?: number;\n startedAt: number;\n updatedAt: number;\n purchaseToken: string;\n userId?: string;\n};\n\nexport type EntitlementsResponse = {\n userId: string;\n productIds: string[];\n subscriptions: KitSubscription[];\n};\n\nexport type StatusResponse = {\n active: boolean;\n subscription: KitSubscription | null;\n};\n\nexport type KitProductPlatform = \"IOS\" | \"Android\";\n\nexport type KitProductClientPayload = {\n format: \"toml\" | \"json\" | \"text\";\n body: string;\n version: number;\n updatedAt: number;\n};\n\nexport type KitProductOffer = {\n id: string;\n kind:\n | \"FreeTrial\"\n | \"IntroPayUpFront\"\n | \"IntroPayAsYouGo\"\n | \"PromotionalOffer\"\n | \"BasePlan\";\n duration?: string;\n numberOfPeriods?: number;\n priceAmountMicros?: number;\n currency?: string;\n};\n\nexport type KitProduct = {\n productId: string;\n platform: KitProductPlatform;\n type: \"Subscription\" | \"NonConsumable\" | \"Consumable\";\n title: string;\n description?: string;\n priceAmountMicros?: number;\n currency?: string;\n state: \"Draft\" | \"Ready\" | \"Active\" | \"Removed\";\n storeRef?: string;\n subscriptionGroupId?: string;\n subscriptionGroupName?: string;\n billingPeriod?: \"P1W\" | \"P1M\" | \"P2M\" | \"P3M\" | \"P6M\" | \"P1Y\";\n offers?: KitProductOffer[];\n updatedAt: number;\n clientPayload?: KitProductClientPayload;\n};\n\nexport type KitProductsOptions = {\n platform?: KitProductPlatform;\n /** Include public client payload bodies in a bounded platform page. */\n includeClientPayload?: boolean;\n /** Page size for every catalog read (default 25, maximum 50). */\n limit?: number;\n /** Opaque cursor returned as `nextCursor` by the previous page. */\n cursor?: string;\n};\n\nexport type KitProductsResponse = {\n products: KitProduct[];\n hasMore: boolean;\n /** Present when a catalog page has another page. */\n nextCursor?: string;\n};\n\nexport type KitClientPayloadResponse = {\n clientPayload: KitProductClientPayload;\n};\n\ntype CachedClientPayload = KitClientPayloadResponse & {\n etag?: string;\n};\n\nconst DEFAULT_BASE_URL = \"https://kit.openiap.dev\";\n\n// Merge caller-supplied headers with kit defaults (`accept`,\n// optionally `content-type`). When the runtime exposes a global\n// `Headers` constructor we use it directly so callers passing a\n// `Headers` instance (a `HeadersInit`) keep that exact instance's\n// values. When `Headers` is missing — older React Native builds where\n// the operator wires up `fetchImpl` without a `Headers` polyfill —\n// we fall back to a case-insensitive merge into a plain record so\n// the request still goes through. Either way, caller-set values take\n// precedence over kit defaults.\nfunction mergeHeaders(\n callerHeaders: HeadersInit | undefined,\n hasBody: boolean,\n): HeadersInit {\n if (typeof Headers === \"function\") {\n const merged = new Headers(callerHeaders);\n if (!merged.has(\"accept\")) merged.set(\"accept\", \"application/json\");\n if (hasBody && !merged.has(\"content-type\")) {\n merged.set(\"content-type\", \"application/json\");\n }\n return merged;\n }\n // Plain-object fallback path. Build a case-insensitive name map\n // from whatever the caller passed (Headers-shaped, array-of-pairs,\n // or plain record) and re-emit as a record `fetchImpl` accepts.\n const lower = new Map<string, { name: string; value: string }>();\n const setIfAbsent = (name: string, value: string) => {\n const key = name.toLowerCase();\n if (!lower.has(key)) lower.set(key, { name, value });\n };\n const setForce = (name: string, value: string) => {\n const key = name.toLowerCase();\n lower.set(key, { name, value });\n };\n if (callerHeaders) {\n if (Array.isArray(callerHeaders)) {\n for (const [name, value] of callerHeaders) setForce(name, value);\n } else if (\n typeof (callerHeaders as { forEach?: unknown }).forEach === \"function\"\n ) {\n // `Headers`-like (without being our `typeof Headers === \"function\"`\n // global). RN polyfills sometimes attach `Headers` only to\n // request/response instances rather than the global scope.\n // Standard signature is `forEach((value, key, parent))`; we\n // bind the first two positionally so a polyfill that omits\n // the third argument still works. `key` is the header name.\n (\n callerHeaders as {\n forEach: (cb: (value: string, key: string) => void) => void;\n }\n ).forEach((value, key) => setForce(key, value));\n } else {\n for (const [name, value] of Object.entries(\n callerHeaders as Record<string, string>,\n )) {\n setForce(name, value);\n }\n }\n }\n setIfAbsent(\"accept\", \"application/json\");\n if (hasBody) setIfAbsent(\"content-type\", \"application/json\");\n const out: Record<string, string> = {};\n for (const { name, value } of lower.values()) out[name] = value;\n return out;\n}\n\nexport class KitApiError extends Error {\n constructor(\n readonly status: number,\n readonly body: unknown,\n message: string,\n ) {\n super(message);\n this.name = \"KitApiError\";\n }\n}\n\nexport function kitApi(options: KitApiOptions) {\n const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n const fetchImpl: (input: string, init?: RequestInit) => Promise<Response> =\n (() => {\n if (options.fetchImpl) return options.fetchImpl;\n if (typeof fetch === \"function\") {\n return (input: string, init?: RequestInit) => fetch(input, init);\n }\n throw new Error(\n \"kitApi requires a fetch implementation. Pass `fetchImpl` for runtimes without a global fetch.\",\n );\n })();\n\n async function request(path: string, init?: RequestInit): Promise<Response> {\n // Normalize headers without depending on a global `Headers`\n // constructor: older React Native runtimes ship `fetch` (or a\n // polyfill via `fetchImpl`) without exposing `Headers` globally.\n // The prior implementation crashed before the first request on\n // those runtimes. We use `new Headers()` when available (preserves\n // caller-supplied `Headers` instances exactly), and otherwise fall\n // back to a small case-insensitive merge into a plain record.\n // Either way, kit defaults only apply when the caller hasn't set\n // the same name.\n const headers = mergeHeaders(init?.headers, init?.body != null);\n // Prepend a leading slash if `path` is missing one. Today's\n // call sites all hard-code the leading \"/\", but normalizing here\n // makes the helper safe for future additions and matches the\n // already-stripped `baseUrl` (PR #124\n // (https://github.com/hyodotdev/openiap/pull/124) review).\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n return fetchImpl(`${baseUrl}${normalizedPath}`, {\n ...init,\n headers,\n });\n }\n\n async function parseResponse<T>(\n response: Response,\n path: string,\n ): Promise<T> {\n const text = await response.text();\n // Empty body normalizes to null so callers expecting JSON\n // (status / entitlements / list*) don't get a truthy \"\"\n // and crash on property access.\n let parsed: unknown = null;\n let parseError: unknown = null;\n if (text) {\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n // Non-JSON body (a misconfigured proxy returning HTML, a\n // CDN-injected error page, etc.) on a 2xx response would\n // otherwise reach the caller as `parsed = text` and crash\n // on property access via `parsed as T`. Throw a structured\n // KitApiError instead so callers see a typed failure.\n parseError = error;\n }\n }\n if (!response.ok) {\n // Surface the raw body (text or parsed) on the error path so\n // operators can read the upstream error message verbatim.\n throw new KitApiError(\n response.status,\n parsed ?? text,\n `kit ${path} returned ${response.status}`,\n );\n }\n if (parseError) {\n throw new KitApiError(\n response.status,\n text,\n `kit ${path} returned a non-JSON ${response.status} body (${\n parseError instanceof Error ? parseError.message : String(parseError)\n })`,\n );\n }\n return parsed as T;\n }\n\n async function call<T>(path: string, init?: RequestInit): Promise<T> {\n return parseResponse<T>(await request(path, init), path);\n }\n\n function clientPayloadCacheKey(\n productId: string,\n platform: KitProductPlatform,\n ): string {\n return [\n \"iapkit-client-payload-v1\",\n baseUrl,\n options.apiKey,\n platform,\n productId,\n ]\n .map(encodeURIComponent)\n .join(\":\");\n }\n\n async function readCachedClientPayload(\n cacheKey: string,\n ): Promise<CachedClientPayload | null> {\n if (!options.clientPayloadCache) return null;\n try {\n const raw = await options.clientPayloadCache.getItem(cacheKey);\n if (!raw) return null;\n const candidate = JSON.parse(raw) as Partial<CachedClientPayload>;\n const payload = candidate.clientPayload;\n if (\n !payload ||\n ![\"toml\", \"json\", \"text\"].includes(payload.format) ||\n typeof payload.body !== \"string\" ||\n !Number.isSafeInteger(payload.version) ||\n payload.version < 1 ||\n typeof payload.updatedAt !== \"number\" ||\n (candidate.etag !== undefined && typeof candidate.etag !== \"string\")\n ) {\n await options.clientPayloadCache.removeItem?.(cacheKey);\n return null;\n }\n return candidate as CachedClientPayload;\n } catch {\n return null;\n }\n }\n\n async function writeCachedClientPayload(\n cacheKey: string,\n value: CachedClientPayload,\n ): Promise<void> {\n try {\n await options.clientPayloadCache?.setItem(\n cacheKey,\n JSON.stringify(value),\n );\n } catch {\n // Persistence is an optimization. A device storage failure must not\n // turn a successful IAPKit read into an application error.\n }\n }\n\n async function removeCachedClientPayload(cacheKey: string): Promise<void> {\n try {\n await options.clientPayloadCache?.removeItem?.(cacheKey);\n } catch {\n // See writeCachedClientPayload: cache maintenance is best effort.\n }\n }\n\n return {\n apiKey: options.apiKey,\n baseUrl,\n\n /** GET /v1/subscriptions/status — the `active` boolean is the\n * fastest gate for \"is this user paying?\". */\n status: (userId: string) =>\n call<StatusResponse>(\n `/v1/subscriptions/status/${encodeURIComponent(options.apiKey)}?userId=${encodeURIComponent(userId)}`,\n ),\n\n /** GET /v1/subscriptions/entitlements — every productId the user\n * is entitled to. Use this when feature gating depends on which\n * specific tier the user owns. */\n entitlements: (userId: string) =>\n call<EntitlementsResponse>(\n `/v1/subscriptions/entitlements/${encodeURIComponent(options.apiKey)}?userId=${encodeURIComponent(userId)}`,\n ),\n\n /** GET /v1/products — read the store-synced catalog. Client payloads\n * are excluded unless explicitly requested because they may add up to\n * 16 KiB per product. */\n products: (productOptions: KitProductsOptions = {}) => {\n if (\n productOptions.includeClientPayload === true &&\n !productOptions.platform\n ) {\n throw new Error(\n \"kitApi.products requires platform when includeClientPayload is true\",\n );\n }\n const query = new URLSearchParams();\n if (productOptions.platform) {\n query.set(\"platform\", productOptions.platform);\n }\n if (productOptions.includeClientPayload !== undefined) {\n query.set(\n \"includeClientPayload\",\n String(productOptions.includeClientPayload),\n );\n }\n if (productOptions.limit !== undefined) {\n query.set(\"limit\", String(productOptions.limit));\n }\n if (productOptions.cursor !== undefined) {\n query.set(\"cursor\", productOptions.cursor);\n }\n const encodedQuery = query.toString();\n const suffix = encodedQuery ? `?${encodedQuery}` : \"\";\n return call<KitProductsResponse>(\n `/v1/products/${encodeURIComponent(options.apiKey)}${suffix}`,\n );\n },\n\n /** GET one public client payload by its store-specific natural key.\n * Payloads are app-facing data; never store secrets in them. */\n clientPayload: async (\n productId: string,\n platform: KitProductPlatform,\n payloadOptions: KitClientPayloadOptions = {},\n ) => {\n const path = `/v1/products/${encodeURIComponent(options.apiKey)}/${encodeURIComponent(productId)}/client-payload?platform=${encodeURIComponent(platform)}`;\n const cacheKey = clientPayloadCacheKey(productId, platform);\n const cached = await readCachedClientPayload(cacheKey);\n if (cached && payloadOptions.refresh !== true) {\n return { clientPayload: cached.clientPayload };\n }\n const response = await request(path, {\n ...(cached?.etag ? { headers: { \"If-None-Match\": cached.etag } } : {}),\n });\n if (response.status === 304 && cached) {\n return { clientPayload: cached.clientPayload };\n }\n try {\n const result = await parseResponse<KitClientPayloadResponse>(\n response,\n path,\n );\n await writeCachedClientPayload(cacheKey, {\n ...result,\n ...(response.headers.get(\"etag\")\n ? { etag: response.headers.get(\"etag\")! }\n : {}),\n });\n return result;\n } catch (error) {\n if (error instanceof KitApiError && error.status === 404) {\n await removeCachedClientPayload(cacheKey);\n }\n throw error;\n }\n },\n\n /** POST /v1/subscriptions/bind-user — call after a successful\n * verifyReceipt so kit knows which userId owns the verified\n * `purchaseToken`. Idempotent. */\n bindUser: (purchaseToken: string, userId: string) =>\n call<{ ok: boolean; bound: boolean }>(\n `/v1/subscriptions/bind-user/${encodeURIComponent(options.apiKey)}`,\n {\n method: \"POST\",\n body: JSON.stringify({ purchaseToken, userId }),\n },\n ),\n };\n}\n"]}
1
+ {"version":3,"file":"kit-api.js","sourceRoot":"","sources":["../src/kit-api.ts"],"names":[],"mappings":"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","sourcesContent":["// Tiny fetch wrapper around kit's `/v1` HTTP surface for use by the JS\n// SDK consumers (react-native-iap + expo-iap). Mirrors the shape of\n// `packages/mcp-server/src/kit-client.ts` so the same operations are\n// reachable from both LLM tools and end-user apps without each\n// duplicating the URL layout.\n\nexport type KitApiOptions = {\n apiKey: string;\n baseUrl?: string;\n // Optional fetch override for runtimes without a global (older RN\n // builds) or for injection in tests.\n fetchImpl?: (input: string, init?: RequestInit) => Promise<Response>;\n /** Optional AsyncStorage-compatible persistent cache for direct client\n * payload reads. Cache failures never change a successful API result. */\n clientPayloadCache?: KitClientPayloadCache;\n};\n\nexport type KitClientPayloadCache = {\n getItem: (key: string) => Promise<string | null> | string | null;\n setItem: (key: string, value: string) => Promise<void> | void;\n removeItem?: (key: string) => Promise<void> | void;\n};\n\nexport type KitClientPayloadOptions = {\n /** Revalidate a cached payload with its scoped ETag. Without this flag,\n * a valid persistent entry is returned without a network request. */\n refresh?: boolean;\n};\n\nexport type KitSubscription = {\n id: string;\n productId: string;\n platform: \"IOS\" | \"Android\";\n state: string;\n expiresAt?: number;\n renewsAt?: number;\n willRenew?: boolean;\n cancellationReason?: string;\n currency?: string;\n priceAmountMicros?: number;\n startedAt: number;\n updatedAt: number;\n purchaseToken: string;\n userId?: string;\n};\n\nexport type EntitlementsResponse = {\n userId: string;\n productIds: string[];\n subscriptions: KitSubscription[];\n};\n\nexport type StatusResponse = {\n active: boolean;\n subscription: KitSubscription | null;\n};\n\nexport type KitProductPlatform = \"IOS\" | \"Android\";\n\nexport type KitProductClientPayload = {\n format: \"toml\" | \"json\" | \"text\";\n body: string;\n version: number;\n updatedAt: number;\n};\n\nexport type KitProductOffer = {\n id: string;\n kind:\n | \"FreeTrial\"\n | \"IntroPayUpFront\"\n | \"IntroPayAsYouGo\"\n | \"PromotionalOffer\"\n | \"BasePlan\";\n duration?: string;\n numberOfPeriods?: number;\n priceAmountMicros?: number;\n currency?: string;\n};\n\nexport type KitProduct = {\n productId: string;\n platform: KitProductPlatform;\n type: \"Subscription\" | \"NonConsumable\" | \"Consumable\";\n title: string;\n description?: string;\n priceAmountMicros?: number;\n currency?: string;\n state: \"Draft\" | \"Ready\" | \"Active\" | \"Removed\";\n storeRef?: string;\n subscriptionGroupId?: string;\n subscriptionGroupName?: string;\n billingPeriod?: \"P1W\" | \"P1M\" | \"P2M\" | \"P3M\" | \"P6M\" | \"P1Y\";\n offers?: KitProductOffer[];\n updatedAt: number;\n clientPayload?: KitProductClientPayload;\n};\n\nexport type KitProductsOptions = {\n platform?: KitProductPlatform;\n /** Include public client payload bodies in a bounded platform page. */\n includeClientPayload?: boolean;\n /** Page size for every catalog read (default 25, maximum 50). */\n limit?: number;\n /** Opaque cursor returned as `nextCursor` by the previous page. */\n cursor?: string;\n};\n\nexport type KitProductsResponse = {\n products: KitProduct[];\n hasMore: boolean;\n /** Present when a catalog page has another page. */\n nextCursor?: string;\n};\n\nexport type KitClientPayloadResponse = {\n clientPayload: KitProductClientPayload;\n};\n\ntype CachedClientPayload = KitClientPayloadResponse & {\n etag?: string;\n};\n\ntype InternalRequestInit = Omit<RequestInit, \"headers\"> & {\n headers?: Record<string, string>;\n};\n\nconst DEFAULT_BASE_URL = \"https://kit.openiap.dev\";\n\n// Merge the request's internal headers with kit defaults (`accept`,\n// optionally `content-type`). When `Headers` is missing — older React\n// Native builds where the operator wires up `fetchImpl` without a\n// `Headers` polyfill — the internal request sites use plain records,\n// so a small case-insensitive merge is sufficient.\nfunction mergeHeaders(\n callerHeaders: Record<string, string> | undefined,\n hasBody: boolean,\n): HeadersInit {\n if (typeof Headers === \"function\") {\n const merged = new Headers(callerHeaders);\n if (!merged.has(\"accept\")) merged.set(\"accept\", \"application/json\");\n if (hasBody && !merged.has(\"content-type\")) {\n merged.set(\"content-type\", \"application/json\");\n }\n return merged;\n }\n // Plain-object fallback path. Build a case-insensitive name map and\n // re-emit it as a record `fetchImpl` accepts.\n const lower = new Map<string, { name: string; value: string }>();\n const setIfAbsent = (name: string, value: string) => {\n const key = name.toLowerCase();\n if (!lower.has(key)) lower.set(key, { name, value });\n };\n if (callerHeaders) {\n for (const [name, value] of Object.entries(callerHeaders)) {\n lower.set(name.toLowerCase(), { name, value });\n }\n }\n setIfAbsent(\"accept\", \"application/json\");\n if (hasBody) setIfAbsent(\"content-type\", \"application/json\");\n const out: Record<string, string> = {};\n for (const { name, value } of lower.values()) out[name] = value;\n return out;\n}\n\nexport class KitApiError extends Error {\n constructor(\n readonly status: number,\n readonly body: unknown,\n message: string,\n ) {\n super(message);\n this.name = \"KitApiError\";\n }\n}\n\nexport function kitApi(options: KitApiOptions) {\n const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n const fetchImpl: (input: string, init?: RequestInit) => Promise<Response> =\n (() => {\n if (options.fetchImpl) return options.fetchImpl;\n if (typeof fetch === \"function\") {\n return (input: string, init?: RequestInit) => fetch(input, init);\n }\n throw new Error(\n \"kitApi requires a fetch implementation. Pass `fetchImpl` for runtimes without a global fetch.\",\n );\n })();\n\n async function request(\n path: string,\n init?: InternalRequestInit,\n ): Promise<Response> {\n // Normalize headers without depending on a global `Headers`\n // constructor: older React Native runtimes ship `fetch` (or a\n // polyfill via `fetchImpl`) without exposing `Headers` globally.\n // The prior implementation crashed before the first request on\n // those runtimes. We use `new Headers()` when available and\n // otherwise fall back to a small case-insensitive merge into a\n // plain record. Either way, kit defaults only apply when the\n // internal request hasn't set the same name.\n const headers = mergeHeaders(init?.headers, init?.body != null);\n // Prepend a leading slash if `path` is missing one. Today's\n // call sites all hard-code the leading \"/\", but normalizing here\n // makes the helper safe for future additions and matches the\n // already-stripped `baseUrl` (PR #124\n // (https://github.com/hyodotdev/openiap/pull/124) review).\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n return fetchImpl(`${baseUrl}${normalizedPath}`, {\n ...init,\n headers,\n });\n }\n\n async function parseResponse<T>(\n response: Response,\n path: string,\n ): Promise<T> {\n const text = await response.text();\n // Empty body normalizes to null so callers expecting JSON\n // (status / entitlements / list*) don't get a truthy \"\"\n // and crash on property access.\n let parsed: unknown = null;\n let parseError: unknown = null;\n if (text) {\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n // Non-JSON body (a misconfigured proxy returning HTML, a\n // CDN-injected error page, etc.) on a 2xx response would\n // otherwise reach the caller as `parsed = text` and crash\n // on property access via `parsed as T`. Throw a structured\n // KitApiError instead so callers see a typed failure.\n parseError = error;\n }\n }\n if (!response.ok) {\n // Surface the raw body (text or parsed) on the error path so\n // operators can read the upstream error message verbatim.\n throw new KitApiError(\n response.status,\n parsed ?? text,\n `kit ${path} returned ${response.status}`,\n );\n }\n if (parseError) {\n throw new KitApiError(\n response.status,\n text,\n `kit ${path} returned a non-JSON ${response.status} body (${\n parseError instanceof Error ? parseError.message : String(parseError)\n })`,\n );\n }\n return parsed as T;\n }\n\n async function call<T>(path: string, init?: InternalRequestInit): Promise<T> {\n return parseResponse<T>(await request(path, init), path);\n }\n\n function clientPayloadCacheKey(\n productId: string,\n platform: KitProductPlatform,\n ): string {\n return [\n \"iapkit-client-payload-v1\",\n baseUrl,\n options.apiKey,\n platform,\n productId,\n ]\n .map(encodeURIComponent)\n .join(\":\");\n }\n\n async function readCachedClientPayload(\n cacheKey: string,\n ): Promise<CachedClientPayload | null> {\n if (!options.clientPayloadCache) return null;\n try {\n const raw = await options.clientPayloadCache.getItem(cacheKey);\n if (!raw) return null;\n const candidate = JSON.parse(raw) as Partial<CachedClientPayload>;\n const payload = candidate.clientPayload;\n if (\n !payload ||\n ![\"toml\", \"json\", \"text\"].includes(payload.format) ||\n typeof payload.body !== \"string\" ||\n !Number.isSafeInteger(payload.version) ||\n payload.version < 1 ||\n typeof payload.updatedAt !== \"number\" ||\n (candidate.etag !== undefined && typeof candidate.etag !== \"string\")\n ) {\n await options.clientPayloadCache.removeItem?.(cacheKey);\n return null;\n }\n return candidate as CachedClientPayload;\n } catch {\n return null;\n }\n }\n\n async function writeCachedClientPayload(\n cacheKey: string,\n value: CachedClientPayload,\n ): Promise<void> {\n try {\n await options.clientPayloadCache?.setItem(\n cacheKey,\n JSON.stringify(value),\n );\n } catch {\n // Persistence is an optimization. A device storage failure must not\n // turn a successful IAPKit read into an application error.\n }\n }\n\n async function removeCachedClientPayload(cacheKey: string): Promise<void> {\n try {\n await options.clientPayloadCache?.removeItem?.(cacheKey);\n } catch {\n // See writeCachedClientPayload: cache maintenance is best effort.\n }\n }\n\n return {\n apiKey: options.apiKey,\n baseUrl,\n\n /** GET /v1/subscriptions/status — the `active` boolean is the\n * fastest gate for \"is this user paying?\". */\n status: (userId: string) =>\n call<StatusResponse>(\n `/v1/subscriptions/status/${encodeURIComponent(options.apiKey)}?userId=${encodeURIComponent(userId)}`,\n ),\n\n /** GET /v1/subscriptions/entitlements — every productId the user\n * is entitled to. Use this when feature gating depends on which\n * specific tier the user owns. */\n entitlements: (userId: string) =>\n call<EntitlementsResponse>(\n `/v1/subscriptions/entitlements/${encodeURIComponent(options.apiKey)}?userId=${encodeURIComponent(userId)}`,\n ),\n\n /** GET /v1/products — read the store-synced catalog. Client payloads\n * are excluded unless explicitly requested because they may add up to\n * 16 KiB per product. */\n products: (productOptions: KitProductsOptions = {}) => {\n if (\n productOptions.includeClientPayload === true &&\n !productOptions.platform\n ) {\n throw new Error(\n \"kitApi.products requires platform when includeClientPayload is true\",\n );\n }\n const query = new URLSearchParams();\n if (productOptions.platform) {\n query.set(\"platform\", productOptions.platform);\n }\n if (productOptions.includeClientPayload !== undefined) {\n query.set(\n \"includeClientPayload\",\n String(productOptions.includeClientPayload),\n );\n }\n if (productOptions.limit !== undefined) {\n query.set(\"limit\", String(productOptions.limit));\n }\n if (productOptions.cursor !== undefined) {\n query.set(\"cursor\", productOptions.cursor);\n }\n const encodedQuery = query.toString();\n const suffix = encodedQuery ? `?${encodedQuery}` : \"\";\n return call<KitProductsResponse>(\n `/v1/products/${encodeURIComponent(options.apiKey)}${suffix}`,\n );\n },\n\n /** GET one public client payload by its store-specific natural key.\n * Payloads are app-facing data; never store secrets in them. */\n clientPayload: async (\n productId: string,\n platform: KitProductPlatform,\n payloadOptions: KitClientPayloadOptions = {},\n ) => {\n const path = `/v1/products/${encodeURIComponent(options.apiKey)}/${encodeURIComponent(productId)}/client-payload?platform=${encodeURIComponent(platform)}`;\n const cacheKey = clientPayloadCacheKey(productId, platform);\n const cached = await readCachedClientPayload(cacheKey);\n if (cached && payloadOptions.refresh !== true) {\n return { clientPayload: cached.clientPayload };\n }\n const response = await request(path, {\n ...(cached?.etag ? { headers: { \"If-None-Match\": cached.etag } } : {}),\n });\n if (response.status === 304 && cached) {\n return { clientPayload: cached.clientPayload };\n }\n try {\n const result = await parseResponse<KitClientPayloadResponse>(\n response,\n path,\n );\n await writeCachedClientPayload(cacheKey, {\n ...result,\n ...(response.headers.get(\"etag\")\n ? { etag: response.headers.get(\"etag\")! }\n : {}),\n });\n return result;\n } catch (error) {\n if (error instanceof KitApiError && error.status === 404) {\n await removeCachedClientPayload(cacheKey);\n }\n throw error;\n }\n },\n\n /** POST /v1/subscriptions/bind-user — call after a successful\n * verifyReceipt so kit knows which userId owns the verified\n * `purchaseToken`. Idempotent. */\n bindUser: (purchaseToken: string, userId: string) =>\n call<{ ok: boolean; bound: boolean }>(\n `/v1/subscriptions/bind-user/${encodeURIComponent(options.apiKey)}`,\n {\n method: \"POST\",\n body: JSON.stringify({ purchaseToken, userId }),\n },\n ),\n };\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "spec": "3.1.1",
3
- "google": "3.2.2",
3
+ "google": "3.2.3",
4
4
  "apple": "3.1.1"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-iap",
3
- "version": "5.2.2",
3
+ "version": "5.2.4",
4
4
  "description": "In App Purchase module in Expo",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
package/src/kit-api.ts CHANGED
@@ -121,19 +121,19 @@ type CachedClientPayload = KitClientPayloadResponse & {
121
121
  etag?: string;
122
122
  };
123
123
 
124
+ type InternalRequestInit = Omit<RequestInit, "headers"> & {
125
+ headers?: Record<string, string>;
126
+ };
127
+
124
128
  const DEFAULT_BASE_URL = "https://kit.openiap.dev";
125
129
 
126
- // Merge caller-supplied headers with kit defaults (`accept`,
127
- // optionally `content-type`). When the runtime exposes a global
128
- // `Headers` constructor we use it directly so callers passing a
129
- // `Headers` instance (a `HeadersInit`) keep that exact instance's
130
- // values. When `Headers` is missing — older React Native builds where
131
- // the operator wires up `fetchImpl` without a `Headers` polyfill —
132
- // we fall back to a case-insensitive merge into a plain record so
133
- // the request still goes through. Either way, caller-set values take
134
- // precedence over kit defaults.
130
+ // Merge the request's internal headers with kit defaults (`accept`,
131
+ // optionally `content-type`). When `Headers` is missing — older React
132
+ // Native builds where the operator wires up `fetchImpl` without a
133
+ // `Headers` polyfill — the internal request sites use plain records,
134
+ // so a small case-insensitive merge is sufficient.
135
135
  function mergeHeaders(
136
- callerHeaders: HeadersInit | undefined,
136
+ callerHeaders: Record<string, string> | undefined,
137
137
  hasBody: boolean,
138
138
  ): HeadersInit {
139
139
  if (typeof Headers === "function") {
@@ -144,41 +144,16 @@ function mergeHeaders(
144
144
  }
145
145
  return merged;
146
146
  }
147
- // Plain-object fallback path. Build a case-insensitive name map
148
- // from whatever the caller passed (Headers-shaped, array-of-pairs,
149
- // or plain record) and re-emit as a record `fetchImpl` accepts.
147
+ // Plain-object fallback path. Build a case-insensitive name map and
148
+ // re-emit it as a record `fetchImpl` accepts.
150
149
  const lower = new Map<string, { name: string; value: string }>();
151
150
  const setIfAbsent = (name: string, value: string) => {
152
151
  const key = name.toLowerCase();
153
152
  if (!lower.has(key)) lower.set(key, { name, value });
154
153
  };
155
- const setForce = (name: string, value: string) => {
156
- const key = name.toLowerCase();
157
- lower.set(key, { name, value });
158
- };
159
154
  if (callerHeaders) {
160
- if (Array.isArray(callerHeaders)) {
161
- for (const [name, value] of callerHeaders) setForce(name, value);
162
- } else if (
163
- typeof (callerHeaders as { forEach?: unknown }).forEach === "function"
164
- ) {
165
- // `Headers`-like (without being our `typeof Headers === "function"`
166
- // global). RN polyfills sometimes attach `Headers` only to
167
- // request/response instances rather than the global scope.
168
- // Standard signature is `forEach((value, key, parent))`; we
169
- // bind the first two positionally so a polyfill that omits
170
- // the third argument still works. `key` is the header name.
171
- (
172
- callerHeaders as {
173
- forEach: (cb: (value: string, key: string) => void) => void;
174
- }
175
- ).forEach((value, key) => setForce(key, value));
176
- } else {
177
- for (const [name, value] of Object.entries(
178
- callerHeaders as Record<string, string>,
179
- )) {
180
- setForce(name, value);
181
- }
155
+ for (const [name, value] of Object.entries(callerHeaders)) {
156
+ lower.set(name.toLowerCase(), { name, value });
182
157
  }
183
158
  }
184
159
  setIfAbsent("accept", "application/json");
@@ -212,16 +187,18 @@ export function kitApi(options: KitApiOptions) {
212
187
  );
213
188
  })();
214
189
 
215
- async function request(path: string, init?: RequestInit): Promise<Response> {
190
+ async function request(
191
+ path: string,
192
+ init?: InternalRequestInit,
193
+ ): Promise<Response> {
216
194
  // Normalize headers without depending on a global `Headers`
217
195
  // constructor: older React Native runtimes ship `fetch` (or a
218
196
  // polyfill via `fetchImpl`) without exposing `Headers` globally.
219
197
  // The prior implementation crashed before the first request on
220
- // those runtimes. We use `new Headers()` when available (preserves
221
- // caller-supplied `Headers` instances exactly), and otherwise fall
222
- // back to a small case-insensitive merge into a plain record.
223
- // Either way, kit defaults only apply when the caller hasn't set
224
- // the same name.
198
+ // those runtimes. We use `new Headers()` when available and
199
+ // otherwise fall back to a small case-insensitive merge into a
200
+ // plain record. Either way, kit defaults only apply when the
201
+ // internal request hasn't set the same name.
225
202
  const headers = mergeHeaders(init?.headers, init?.body != null);
226
203
  // Prepend a leading slash if `path` is missing one. Today's
227
204
  // call sites all hard-code the leading "/", but normalizing here
@@ -278,7 +255,7 @@ export function kitApi(options: KitApiOptions) {
278
255
  return parsed as T;
279
256
  }
280
257
 
281
- async function call<T>(path: string, init?: RequestInit): Promise<T> {
258
+ async function call<T>(path: string, init?: InternalRequestInit): Promise<T> {
282
259
  return parseResponse<T>(await request(path, init), path);
283
260
  }
284
261
 
package/codecov.yml DELETED
@@ -1,69 +0,0 @@
1
- codecov:
2
- require_ci_to_pass: true
3
- notify:
4
- wait_for_ci: true
5
-
6
- coverage:
7
- precision: 2
8
- round: down
9
- range: '50...100'
10
-
11
- status:
12
- project:
13
- default:
14
- target: 60%
15
- threshold: 5%
16
- base: auto
17
- flags:
18
- - unittests
19
- paths:
20
- - src
21
-
22
- example:
23
- target: 40%
24
- threshold: 10%
25
- base: auto
26
- flags:
27
- - example
28
- paths:
29
- - example
30
-
31
- patch:
32
- default:
33
- target: 60%
34
- threshold: 5%
35
- base: auto
36
-
37
- parsers:
38
- gcov:
39
- branch_detection:
40
- conditional: yes
41
- loop: yes
42
- method: no
43
- macro: no
44
-
45
- comment:
46
- layout: 'reach,diff,flags,files,footer'
47
- behavior: default
48
- require_changes: false
49
- require_base: false
50
- require_head: true
51
-
52
- flags:
53
- unittests:
54
- paths:
55
- - src/
56
- carryforward: false
57
-
58
- ignore:
59
- - '**/__tests__/**'
60
- - '**/*.test.ts'
61
- - '**/*.test.tsx'
62
- - '**/node_modules/**'
63
- - 'build/**'
64
- - 'android/**'
65
- - 'ios/**'
66
- - 'docs/**'
67
- - 'plugin/**'
68
- - '*.config.js'
69
- - '*.setup.js'