@idealyst/payments 1.2.108 → 1.2.109

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.
@@ -1,91 +1,70 @@
1
1
  // ============================================================================
2
- // Web Payment Stub
2
+ // Web IAP Stub
3
3
  //
4
- // Native payment sheets (Apple Pay, Google Pay) are mobile-only concepts.
5
- // On web, use Stripe Elements (@stripe/react-stripe-js) or Stripe Checkout.
6
- //
7
- // This stub initializes and reports availability so the hook works,
8
- // but payment operations throw descriptive errors with guidance.
4
+ // In-App Purchases are a native-only concept (StoreKit / Google Play Billing).
5
+ // This stub allows the hook and types to be imported on web without errors,
6
+ // but all operations throw descriptive errors.
9
7
  // ============================================================================
10
8
 
11
9
  import type {
12
- PaymentConfig,
13
- PaymentProviderStatus,
14
- PaymentMethodAvailability,
15
- PaymentSheetRequest,
16
- PaymentResult,
10
+ IAPConfig,
11
+ IAPProviderStatus,
12
+ IAPProduct,
13
+ IAPSubscription,
14
+ IAPPurchase,
17
15
  } from './types';
18
16
  import { INITIAL_PROVIDER_STATUS } from './constants';
19
- import { createPaymentError } from './errors';
20
-
21
- const WEB_NOT_SUPPORTED_MESSAGE =
22
- '@idealyst/payments does not provide a web payment UI. ' +
23
- 'Use Stripe Elements (@stripe/react-stripe-js) or Stripe Checkout for web payments.';
17
+ import { createIAPError } from './errors';
24
18
 
25
- const WEB_UNAVAILABLE_METHODS: PaymentMethodAvailability[] = [
26
- {
27
- type: 'apple_pay',
28
- isAvailable: false,
29
- unavailableReason: 'Apple Pay requires native iOS integration',
30
- },
31
- {
32
- type: 'google_pay',
33
- isAvailable: false,
34
- unavailableReason: 'Google Pay requires native Android integration',
35
- },
36
- {
37
- type: 'card',
38
- isAvailable: false,
39
- unavailableReason:
40
- 'Use Stripe Elements (@stripe/react-stripe-js) for web card payments',
41
- },
42
- ];
19
+ const NOT_SUPPORTED_MESSAGE =
20
+ 'In-App Purchases are only available on native iOS and Android platforms. ' +
21
+ 'For web payments, use a payment processor like Stripe directly.';
43
22
 
44
- let _status: PaymentProviderStatus = { ...INITIAL_PROVIDER_STATUS };
23
+ let _status: IAPProviderStatus = { ...INITIAL_PROVIDER_STATUS };
45
24
 
46
- /**
47
- * Get the current payment provider status.
48
- */
49
- export function getPaymentStatus(): PaymentProviderStatus {
25
+ export function getIAPStatus(): IAPProviderStatus {
50
26
  return { ..._status };
51
27
  }
52
28
 
53
- /**
54
- * Initialize — succeeds on web but reports all methods as unavailable.
55
- */
56
- export async function initializePayments(
57
- _config: PaymentConfig,
58
- ): Promise<void> {
29
+ export async function initializeIAP(_config?: IAPConfig): Promise<void> {
59
30
  _status = {
60
31
  state: 'ready',
61
- availablePaymentMethods: WEB_UNAVAILABLE_METHODS,
62
- isPaymentAvailable: false,
32
+ isStoreAvailable: false,
63
33
  };
64
34
  }
65
35
 
66
- /**
67
- * Check availability — all methods are unavailable on web.
68
- */
69
- export async function checkPaymentAvailability(): Promise<
70
- PaymentMethodAvailability[]
71
- > {
72
- return WEB_UNAVAILABLE_METHODS;
36
+ export async function getProducts(_skus: string[]): Promise<IAPProduct[]> {
37
+ return [];
38
+ }
39
+
40
+ export async function getSubscriptions(
41
+ _skus: string[],
42
+ ): Promise<IAPSubscription[]> {
43
+ return [];
44
+ }
45
+
46
+ export async function purchaseProduct(_sku: string): Promise<IAPPurchase> {
47
+ throw createIAPError('not_supported', NOT_SUPPORTED_MESSAGE);
48
+ }
49
+
50
+ export async function purchaseSubscription(
51
+ _sku: string,
52
+ _offerToken?: string,
53
+ ): Promise<IAPPurchase> {
54
+ throw createIAPError('not_supported', NOT_SUPPORTED_MESSAGE);
55
+ }
56
+
57
+ export async function finishTransaction(
58
+ _purchase: IAPPurchase,
59
+ _isConsumable?: boolean,
60
+ ): Promise<void> {
61
+ throw createIAPError('not_supported', NOT_SUPPORTED_MESSAGE);
73
62
  }
74
63
 
75
- /**
76
- * Not supported on web — throws with guidance to use Stripe Elements.
77
- */
78
- export async function confirmPayment(
79
- _request: PaymentSheetRequest,
80
- ): Promise<PaymentResult> {
81
- throw createPaymentError('not_supported', WEB_NOT_SUPPORTED_MESSAGE);
64
+ export async function restorePurchases(): Promise<IAPPurchase[]> {
65
+ return [];
82
66
  }
83
67
 
84
- /**
85
- * Not supported on web — throws with guidance to use Stripe Elements.
86
- */
87
- export async function createPaymentMethod(
88
- _request: PaymentSheetRequest,
89
- ): Promise<PaymentResult> {
90
- throw createPaymentError('not_supported', WEB_NOT_SUPPORTED_MESSAGE);
68
+ export async function endConnection(): Promise<void> {
69
+ _status = { ...INITIAL_PROVIDER_STATUS };
91
70
  }
package/src/types.ts CHANGED
@@ -1,179 +1,193 @@
1
1
  // ============================================================================
2
- // Payment Method Types
2
+ // Product Types
3
3
  // ============================================================================
4
4
 
5
- export type PaymentMethodType = 'apple_pay' | 'google_pay' | 'card';
6
-
7
- export interface PaymentMethodAvailability {
8
- /** The payment method type. */
9
- type: PaymentMethodType;
10
- /** Whether this method is available on the current device. */
11
- isAvailable: boolean;
12
- /** Reason if unavailable. */
13
- unavailableReason?: string;
5
+ export type ProductType = 'iap' | 'sub';
6
+
7
+ export type ProductPlatform = 'ios' | 'android';
8
+
9
+ export interface IAPProduct {
10
+ /** Store-specific product identifier (SKU). */
11
+ sku: string;
12
+ /** Product title from the store. */
13
+ title: string;
14
+ /** Product description from the store. */
15
+ description: string;
16
+ /** Price as a number (e.g., 4.99). */
17
+ price: number;
18
+ /** Localized price string (e.g., "$4.99"). */
19
+ priceFormatted: string;
20
+ /** ISO 4217 currency code (e.g., "USD"). */
21
+ currency: string;
22
+ /** Product type: one-time purchase or subscription. */
23
+ type: ProductType;
24
+ /** Platform this product was fetched from. */
25
+ platform: ProductPlatform;
14
26
  }
15
27
 
16
28
  // ============================================================================
17
- // Configuration
29
+ // Subscription Types
18
30
  // ============================================================================
19
31
 
20
- export interface PaymentConfig {
21
- /** Stripe publishable key (pk_test_xxx or pk_live_xxx). */
22
- publishableKey: string;
23
-
24
- /**
25
- * Apple Pay merchant identifier (e.g., "merchant.com.yourapp").
26
- * Required for Apple Pay on iOS.
27
- */
28
- merchantIdentifier?: string;
29
-
30
- /** Merchant display name shown on the payment sheet. */
31
- merchantName: string;
32
+ export type SubscriptionPeriodUnit = 'day' | 'week' | 'month' | 'year';
32
33
 
33
- /** ISO 3166-1 alpha-2 country code (e.g., "US", "GB"). */
34
- merchantCountryCode: string;
34
+ export interface SubscriptionPeriod {
35
+ /** Time unit. */
36
+ unit: SubscriptionPeriodUnit;
37
+ /** Number of units per period (e.g., 1 month, 3 months). */
38
+ numberOfUnits: number;
39
+ }
35
40
 
36
- /**
37
- * URL scheme for 3D Secure redirects (e.g., "com.yourapp").
38
- * Required on native for 3D Secure / bank redirect flows.
39
- */
40
- urlScheme?: string;
41
+ export type DiscountPaymentMode = 'freeTrial' | 'payAsYouGo' | 'payUpFront';
42
+ export type DiscountType = 'introductory' | 'promotional';
43
+
44
+ export interface SubscriptionDiscount {
45
+ /** Discount identifier (promotional only). */
46
+ identifier?: string;
47
+ /** Discounted price as a number. */
48
+ price: number;
49
+ /** Localized discounted price string. */
50
+ priceFormatted: string;
51
+ /** Discount billing period. */
52
+ period: SubscriptionPeriod;
53
+ /** How the discount is applied. */
54
+ paymentMode: DiscountPaymentMode;
55
+ /** Whether this is introductory or promotional. */
56
+ type: DiscountType;
57
+ }
41
58
 
42
- /** Use test environment for Google Pay. Default: false. */
43
- testEnvironment?: boolean;
59
+ export interface IAPSubscription extends IAPProduct {
60
+ /** Subscription billing period. */
61
+ subscriptionPeriod: SubscriptionPeriod;
62
+ /** Introductory offer, if any. */
63
+ introductoryPrice?: SubscriptionDiscount;
64
+ /** Promotional discounts (iOS). */
65
+ discounts?: SubscriptionDiscount[];
44
66
  }
45
67
 
46
68
  // ============================================================================
47
- // Payment Request
69
+ // Purchase Types
48
70
  // ============================================================================
49
71
 
50
- export interface PaymentAmount {
51
- /** Amount in the smallest currency unit (e.g., cents for USD). */
52
- amount: number;
53
- /** ISO 4217 currency code (e.g., "usd", "eur"). */
54
- currencyCode: string;
72
+ export type PurchaseState = 'purchased' | 'pending' | 'restored';
73
+
74
+ export interface IAPPurchase {
75
+ /** Product SKU. */
76
+ sku: string;
77
+ /** Store transaction ID. */
78
+ transactionId: string;
79
+ /** Transaction timestamp (ms since epoch). */
80
+ transactionDate: number;
81
+ /** Receipt data (base64 on iOS, JSON string on Android). */
82
+ transactionReceipt: string;
83
+ /** Google Play purchase token (Android only). */
84
+ purchaseToken?: string;
85
+ /** Whether the purchase has been acknowledged (Android only). */
86
+ isAcknowledged?: boolean;
87
+ /** Current purchase state. */
88
+ purchaseState: PurchaseState;
55
89
  }
56
90
 
57
- export interface PaymentLineItem {
58
- /** Label displayed on the payment sheet (e.g., "Subtotal", "Tax"). */
59
- label: string;
60
- /** Amount in the smallest currency unit. */
61
- amount: number;
62
- }
63
-
64
- export interface BillingAddressConfig {
65
- /** Whether billing address is required. */
66
- isRequired?: boolean;
67
- /** Whether phone number is required. */
68
- isPhoneNumberRequired?: boolean;
69
- /** Address format: 'MIN' for name+postal, 'FULL' for complete address. */
70
- format?: 'MIN' | 'FULL';
71
- }
91
+ // ============================================================================
92
+ // Configuration
93
+ // ============================================================================
72
94
 
73
- export interface PaymentSheetRequest {
95
+ export interface IAPConfig {
74
96
  /**
75
- * PaymentIntent client secret from your server.
76
- * Required for confirmPayment(), not needed for createPaymentMethod().
97
+ * If true, transactions are automatically finished after purchase.
98
+ * Default: false.
99
+ *
100
+ * WARNING: Set to false in production so you can validate receipts
101
+ * on your server before finishing transactions.
77
102
  */
78
- clientSecret?: string;
79
-
80
- /** Total payment amount. Used for display and for createPaymentMethod flow. */
81
- amount: PaymentAmount;
82
-
83
- /** Line items displayed on the payment sheet. */
84
- lineItems?: PaymentLineItem[];
85
-
86
- /** Billing address requirements. */
87
- billingAddress?: BillingAddressConfig;
88
-
89
- /** Preferred payment methods. If empty, all available methods are shown. */
90
- allowedPaymentMethods?: PaymentMethodType[];
103
+ autoFinishTransactions?: boolean;
91
104
  }
92
105
 
93
106
  // ============================================================================
94
- // Payment Result
107
+ // Provider State
95
108
  // ============================================================================
96
109
 
97
- export interface PaymentResult {
98
- /** The payment method type that was used. */
99
- paymentMethodType: PaymentMethodType;
100
-
101
- /** Stripe payment method ID (pm_xxx). Present for createPaymentMethod flow. */
102
- paymentMethodId?: string;
103
-
104
- /** Stripe PaymentIntent ID (pi_xxx). Present for confirmPayment flow. */
105
- paymentIntentId?: string;
110
+ export type IAPProviderState =
111
+ | 'uninitialized'
112
+ | 'initializing'
113
+ | 'ready'
114
+ | 'error';
106
115
 
107
- /** PaymentIntent status (e.g., 'succeeded', 'requires_capture'). */
108
- status?: string;
116
+ export interface IAPProviderStatus {
117
+ /** Current state of the IAP connection. */
118
+ state: IAPProviderState;
119
+ /** Whether the native store is available and connected. */
120
+ isStoreAvailable: boolean;
121
+ /** Error if state is 'error'. */
122
+ error?: IAPError;
109
123
  }
110
124
 
111
125
  // ============================================================================
112
126
  // Error Types
113
127
  // ============================================================================
114
128
 
115
- export type PaymentErrorCode =
129
+ export type IAPErrorCode =
116
130
  | 'not_initialized'
117
131
  | 'not_available'
118
132
  | 'not_supported'
119
133
  | 'user_cancelled'
120
- | 'payment_failed'
134
+ | 'already_owned'
135
+ | 'purchase_pending'
136
+ | 'item_unavailable'
121
137
  | 'network_error'
122
- | 'invalid_config'
123
- | 'invalid_request'
124
- | 'provider_error'
138
+ | 'store_error'
125
139
  | 'unknown';
126
140
 
127
- export interface PaymentError {
128
- code: PaymentErrorCode;
141
+ export interface IAPError {
142
+ code: IAPErrorCode;
129
143
  message: string;
130
- /** Original error from the underlying provider. */
144
+ /** Original error from react-native-iap. */
131
145
  originalError?: unknown;
132
146
  }
133
147
 
134
- // ============================================================================
135
- // Provider State
136
- // ============================================================================
137
-
138
- export type PaymentProviderState =
139
- | 'uninitialized'
140
- | 'initializing'
141
- | 'ready'
142
- | 'error';
143
-
144
- export interface PaymentProviderStatus {
145
- state: PaymentProviderState;
146
- availablePaymentMethods: PaymentMethodAvailability[];
147
- isPaymentAvailable: boolean;
148
- error?: PaymentError;
149
- }
150
-
151
148
  // ============================================================================
152
149
  // Hook Types
153
150
  // ============================================================================
154
151
 
155
- export interface UsePaymentsOptions {
156
- /** If provided, auto-initializes the payment provider. */
157
- config?: PaymentConfig;
158
- /** Automatically check availability after init. Default: true. */
159
- autoCheckAvailability?: boolean;
152
+ export interface UseIAPOptions {
153
+ /** If provided, auto-initializes the IAP connection. */
154
+ config?: IAPConfig;
155
+ /** Product SKUs to auto-fetch after initialization. */
156
+ productSkus?: string[];
157
+ /** Subscription SKUs to auto-fetch after initialization. */
158
+ subscriptionSkus?: string[];
160
159
  }
161
160
 
162
- export interface UsePaymentsResult {
161
+ export interface UseIAPResult {
163
162
  // State
164
- status: PaymentProviderStatus;
163
+ /** Whether the IAP connection is ready. */
165
164
  isReady: boolean;
165
+ /** Whether a purchase or fetch is in progress. */
166
166
  isProcessing: boolean;
167
- availablePaymentMethods: PaymentMethodAvailability[];
168
- isApplePayAvailable: boolean;
169
- isGooglePayAvailable: boolean;
170
- isPaymentAvailable: boolean;
171
- error: PaymentError | null;
167
+ /** Current error, if any. */
168
+ error: IAPError | null;
169
+ /** Fetched products. */
170
+ products: IAPProduct[];
171
+ /** Fetched subscriptions. */
172
+ subscriptions: IAPSubscription[];
173
+ /** The most recent purchase (useful for handling post-purchase flows). */
174
+ currentPurchase: IAPPurchase | null;
172
175
 
173
176
  // Actions
174
- initialize: (config: PaymentConfig) => Promise<void>;
175
- checkAvailability: () => Promise<PaymentMethodAvailability[]>;
176
- confirmPayment: (request: PaymentSheetRequest) => Promise<PaymentResult>;
177
- createPaymentMethod: (request: PaymentSheetRequest) => Promise<PaymentResult>;
177
+ /** Initialize the IAP connection. */
178
+ initialize: (config?: IAPConfig) => Promise<void>;
179
+ /** Fetch products by SKU. */
180
+ getProducts: (skus: string[]) => Promise<IAPProduct[]>;
181
+ /** Fetch subscriptions by SKU. */
182
+ getSubscriptions: (skus: string[]) => Promise<IAPSubscription[]>;
183
+ /** Purchase a one-time product. */
184
+ purchaseProduct: (sku: string) => Promise<IAPPurchase>;
185
+ /** Purchase a subscription. */
186
+ purchaseSubscription: (sku: string, offerToken?: string) => Promise<IAPPurchase>;
187
+ /** Finish a transaction (call after server-side validation). */
188
+ finishTransaction: (purchase: IAPPurchase, isConsumable?: boolean) => Promise<void>;
189
+ /** Restore previous purchases. */
190
+ restorePurchases: () => Promise<IAPPurchase[]>;
191
+ /** Clear the current error. */
178
192
  clearError: () => void;
179
193
  }