@solvapay/react 1.0.0-preview.2 → 1.0.0-preview.20

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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 SolvaPay Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,34 +1,324 @@
1
1
  # @solvapay/react
2
2
 
3
- Payment components for SolvaPay with Stripe integration.
3
+ Headless React components and hooks for SolvaPay payment integration with Stripe.
4
4
 
5
5
  ## Install
6
+
6
7
  ```bash
7
8
  pnpm add @solvapay/react
8
9
  ```
9
10
 
10
- ## Usage
11
+ ## Peer Dependencies
12
+
13
+ - `react` ^18.2.0 || ^19.0.0
14
+ - `react-dom` ^18.2.0 || ^19.0.0
15
+
16
+ ## Quick Start
17
+
18
+ ### Zero-Config Usage (Recommended)
19
+
20
+ ```tsx
21
+ import { SolvaPayProvider, PaymentForm, usePurchase } from '@solvapay/react'
22
+
23
+ export default function App() {
24
+ return (
25
+ <SolvaPayProvider>
26
+ <CheckoutPage />
27
+ </SolvaPayProvider>
28
+ )
29
+ }
30
+ ```
31
+
32
+ By default, `SolvaPayProvider` uses:
33
+
34
+ - `/api/check-purchase` for purchase checks
35
+ - `/api/create-payment-intent` for payment creation
36
+ - `/api/process-payment` for payment processing
37
+
38
+ ### Custom API Routes
39
+
40
+ ```tsx
41
+ import { SolvaPayProvider, PaymentForm } from '@solvapay/react'
42
+
43
+ export default function App() {
44
+ return (
45
+ <SolvaPayProvider
46
+ config={{
47
+ api: {
48
+ checkPurchase: '/api/custom/purchase',
49
+ createPayment: '/api/custom/payment',
50
+ processPayment: '/api/custom/process',
51
+ },
52
+ }}
53
+ >
54
+ <CheckoutPage />
55
+ </SolvaPayProvider>
56
+ )
57
+ }
58
+ ```
59
+
60
+ ### With Supabase Authentication
61
+
62
+ ```tsx
63
+ import { SolvaPayProvider } from '@solvapay/react'
64
+ import { createSupabaseAuthAdapter } from '@solvapay/react-supabase'
65
+
66
+ export default function App() {
67
+ const adapter = createSupabaseAuthAdapter({
68
+ supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
69
+ supabaseAnonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
70
+ })
71
+
72
+ return (
73
+ <SolvaPayProvider config={{ auth: { adapter } }}>
74
+ <CheckoutPage />
75
+ </SolvaPayProvider>
76
+ )
77
+ }
78
+ ```
79
+
80
+ ### Fully Custom Implementation
81
+
11
82
  ```tsx
12
- import { SolvaPayProvider, PaymentForm } from '@solvapay/react';
83
+ import { SolvaPayProvider } from '@solvapay/react'
13
84
 
14
- export default function CheckoutPage() {
85
+ export default function App() {
15
86
  return (
16
87
  <SolvaPayProvider
17
- amount={999}
18
- currency="USD"
19
- planRef="pln_abc123"
88
+ createPayment={async ({ planRef, agentRef }) => {
89
+ const res = await fetch('/api/custom/payment', {
90
+ method: 'POST',
91
+ body: JSON.stringify({ planRef, agentRef }),
92
+ })
93
+ if (!res.ok) throw new Error('Failed to create payment')
94
+ return res.json()
95
+ }}
96
+ checkPurchase={async customerRef => {
97
+ const res = await fetch(`/api/custom/purchase?customerRef=${customerRef}`)
98
+ if (!res.ok) throw new Error('Failed to check purchase')
99
+ return res.json()
100
+ }}
20
101
  >
21
- <PaymentForm
22
- returnUrl="/checkout/success"
23
- onSuccess={(paymentIntent) => {
24
- console.log('Payment successful!', paymentIntent);
25
- }}
26
- />
102
+ <CheckoutPage />
27
103
  </SolvaPayProvider>
28
- );
104
+ )
105
+ }
106
+ ```
107
+
108
+ ## Components
109
+
110
+ ### SolvaPayProvider
111
+
112
+ Headless context provider that manages purchase state, payment methods, and customer references.
113
+
114
+ **Features:**
115
+
116
+ - Zero-config with sensible defaults
117
+ - Auto-fetches purchases on mount
118
+ - Built-in localStorage caching with user validation
119
+ - Supports auth adapters for extracting user IDs and tokens
120
+ - Customizable API routes via config
121
+
122
+ **Props:**
123
+
124
+ - `config?: SolvaPayConfig` - Configuration object (optional)
125
+ - `config.api?` - Custom API route paths
126
+ - `config.auth?` - Auth adapter configuration
127
+ - `createPayment?: (params: { planRef: string; agentRef?: string }) => Promise<PaymentIntentResult>` - Custom payment creation function (optional, overrides config)
128
+ - `checkPurchase?: (customerRef: string) => Promise<CustomerPurchaseData>` - Custom purchase check function (optional, overrides config)
129
+ - `processPayment?: (params: { paymentIntentId: string; agentRef: string; planRef?: string }) => Promise<ProcessPaymentResult>` - Custom payment processing function (optional)
130
+ - `children: React.ReactNode` - Child components
131
+
132
+ **Config Options:**
133
+
134
+ ```tsx
135
+ interface SolvaPayConfig {
136
+ api?: {
137
+ checkPurchase?: string // Default: '/api/check-purchase'
138
+ createPayment?: string // Default: '/api/create-payment-intent'
139
+ processPayment?: string // Default: '/api/process-payment'
140
+ }
141
+ auth?: {
142
+ adapter?: AuthAdapter // Auth adapter for extracting user ID/token
143
+ getToken?: () => Promise<string | null> // Deprecated: use adapter
144
+ getUserId?: () => Promise<string | null> // Deprecated: use adapter
145
+ }
146
+ }
147
+ ```
148
+
149
+ ### PlanSelector
150
+
151
+ Component for selecting and displaying available plans.
152
+
153
+ **Props:**
154
+
155
+ - `agentRef?: string` - Agent reference to filter plans
156
+ - `fetcher?: (agentRef: string) => Promise<Plan[]>` - Custom plan fetcher function
157
+ - `onPlanSelect?: (plan: Plan) => void` - Callback when plan is selected
158
+ - `renderPlan?: (plan: Plan) => React.ReactNode` - Custom plan renderer
159
+ - `className?: string` - Container className
160
+
161
+ **Example:**
162
+
163
+ ```tsx
164
+ import { PlanSelector, usePlans } from '@solvapay/react'
165
+
166
+ function PlansPage() {
167
+ const { plans, loading } = usePlans({ agentRef: 'my-agent' })
168
+
169
+ return (
170
+ <div>
171
+ {loading ? 'Loading...' : plans.map(plan => <div key={plan.reference}>{plan.name}</div>)}
172
+ </div>
173
+ )
29
174
  }
30
175
  ```
31
176
 
32
- Peer deps: react, react-dom
177
+ ### PaymentForm
178
+
179
+ Payment form component using Stripe PaymentElement. Automatically handles Stripe Elements provider setup.
180
+
181
+ **Props:**
182
+
183
+ - `planRef: string` - Plan reference for the payment
184
+ - `agentRef?: string` - Optional agent reference
185
+ - `onSuccess?: (paymentIntent: PaymentIntent) => void` - Callback on successful payment
186
+ - `onError?: (error: Error) => void` - Callback on payment error
187
+ - `returnUrl?: string` - Return URL after payment
188
+ - `submitButtonText?: string` - Submit button text (default: "Pay Now")
189
+ - `formClassName?: string` - Form element className
190
+ - `messageClassName?: string` - Message container className
191
+ - `buttonClassName?: string` - Submit button className
192
+
193
+ **Example:**
194
+
195
+ ```tsx
196
+ import { PaymentForm } from '@solvapay/react'
197
+
198
+ function CheckoutPage() {
199
+ return (
200
+ <PaymentForm
201
+ planRef="pln_YOUR_PLAN"
202
+ agentRef="agt_YOUR_AGENT"
203
+ onSuccess={() => console.log('Payment successful!')}
204
+ />
205
+ )
206
+ }
207
+ ```
208
+
209
+ ### PlanBadge
210
+
211
+ Displays current purchase plan with render props or className pattern.
212
+
213
+ **Props:**
214
+
215
+ - `children?: (props) => React.ReactNode` - Render prop function
216
+ - `as?: React.ElementType` - Component to render (default: "div")
217
+ - `className?: string | ((props) => string)` - ClassName or function
218
+
219
+ **Example:**
220
+
221
+ ```tsx
222
+ <PlanBadge className="badge badge-primary" />
223
+ ```
224
+
225
+ ### PurchaseGate
226
+
227
+ Controls access to content based on purchase status.
228
+
229
+ **Props:**
230
+
231
+ - `requirePlan?: string` - Optional plan name to require
232
+ - `children: (props) => React.ReactNode` - Render prop function
233
+
234
+ **Example:**
235
+
236
+ ```tsx
237
+ <PurchaseGate requirePlan="Pro Plan">
238
+ {({ hasAccess, loading, purchases }) => {
239
+ if (loading) return <Loading />
240
+ if (!hasAccess) return <Paywall />
241
+ return <PremiumContent />
242
+ }}
243
+ </PurchaseGate>
244
+ ```
245
+
246
+ ## Hooks
247
+
248
+ ### usePurchase
249
+
250
+ Access purchase status, active purchases, and helper functions.
251
+
252
+ ```tsx
253
+ const {
254
+ purchases, // Array of all purchases
255
+ loading, // Loading state
256
+ hasPaidPurchase, // Boolean: has any paid purchase
257
+ activePurchase, // Most recent active purchase
258
+ refetch, // Function to refetch purchases
259
+ } = usePurchase()
260
+ ```
261
+
262
+ ### usePlans
263
+
264
+ Fetch and manage available plans.
265
+
266
+ ```tsx
267
+ const {
268
+ plans, // Array of available plans
269
+ loading, // Loading state
270
+ error, // Error object if fetch failed
271
+ refetch, // Function to refetch plans
272
+ } = usePlans({
273
+ agentRef: 'my-agent', // Optional agent reference
274
+ fetcher: customFetcher, // Optional custom fetcher function
275
+ })
276
+ ```
277
+
278
+ ### usePurchaseStatus
279
+
280
+ Advanced purchase status helpers.
281
+
282
+ ```tsx
283
+ const {
284
+ cancelledPurchase, // Most recent cancelled purchase
285
+ shouldShowCancelledNotice, // Boolean: should show cancellation notice
286
+ formatDate, // Helper to format dates
287
+ getDaysUntilExpiration, // Helper to get days until expiration
288
+ } = usePurchaseStatus()
289
+ ```
290
+
291
+ ### useCheckout
292
+
293
+ Manage checkout flow for a specific plan.
294
+
295
+ ```tsx
296
+ const { loading, error, startCheckout, reset } = useCheckout('plan_ref')
297
+ ```
298
+
299
+ ### useSolvaPay
300
+
301
+ Access SolvaPay context directly.
302
+
303
+ ```tsx
304
+ const {
305
+ purchaseData, // Full purchase data
306
+ loading, // Loading state
307
+ createPayment, // Payment creation function
308
+ processPayment, // Payment processing function
309
+ customerRef, // Current customer reference
310
+ updateCustomerRef, // Function to update customer reference
311
+ } = useSolvaPay()
312
+ ```
313
+
314
+ ## TypeScript
315
+
316
+ All components and hooks are fully typed. Import types as needed:
317
+
318
+ ```tsx
319
+ import type { PaymentFormProps, PurchaseStatus, PaymentIntentResult } from '@solvapay/react'
320
+ ```
321
+
322
+ ## More Information
33
323
 
34
- More: docs/architecture.md
324
+ See [`docs/guides/architecture.md`](../../docs/guides/architecture.md) for detailed architecture documentation.
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/adapters/auth.ts
21
+ var auth_exports = {};
22
+ __export(auth_exports, {
23
+ defaultAuthAdapter: () => defaultAuthAdapter
24
+ });
25
+ module.exports = __toCommonJS(auth_exports);
26
+ var defaultAuthAdapter = {
27
+ async getToken() {
28
+ if (typeof window === "undefined") return null;
29
+ const token = localStorage.getItem("auth_token");
30
+ return token || null;
31
+ },
32
+ async getUserId() {
33
+ const token = await this.getToken();
34
+ if (!token) return null;
35
+ try {
36
+ const parts = token.split(".");
37
+ if (parts.length === 3) {
38
+ const payload = JSON.parse(atob(parts[1]));
39
+ return payload.sub || payload.user_id || null;
40
+ }
41
+ } catch {
42
+ }
43
+ return null;
44
+ }
45
+ };
46
+ // Annotate the CommonJS export names for ESM import in node:
47
+ 0 && (module.exports = {
48
+ defaultAuthAdapter
49
+ });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Auth Adapter Interface for Client-Side Authentication
3
+ *
4
+ * Defines the contract for authentication adapters used by SolvaPayProvider.
5
+ * Adapters handle token retrieval and user ID extraction in the browser.
6
+ */
7
+ /**
8
+ * Auth adapter interface for client-side authentication
9
+ *
10
+ * Used by SolvaPayProvider to get auth tokens and user IDs.
11
+ * Adapters should handle their own error cases and return null when
12
+ * authentication is not available or fails.
13
+ */
14
+ interface AuthAdapter {
15
+ /**
16
+ * Get the authentication token
17
+ *
18
+ * @returns The auth token string if available, null otherwise
19
+ *
20
+ * @remarks
21
+ * This method should never throw. If authentication fails or is missing,
22
+ * return null and let the caller decide how to handle unauthenticated requests.
23
+ */
24
+ getToken: () => Promise<string | null>;
25
+ /**
26
+ * Get the authenticated user ID
27
+ *
28
+ * @returns The user ID string if authenticated, null otherwise
29
+ *
30
+ * @remarks
31
+ * This method should never throw. If authentication fails or is missing,
32
+ * return null and let the caller decide how to handle unauthenticated requests.
33
+ */
34
+ getUserId: () => Promise<string | null>;
35
+ }
36
+ /**
37
+ * Default auth adapter that only checks localStorage
38
+ *
39
+ * This is a fallback adapter that doesn't depend on any specific auth provider.
40
+ * It checks for a token in localStorage under the 'auth_token' key.
41
+ */
42
+ declare const defaultAuthAdapter: AuthAdapter;
43
+
44
+ export { type AuthAdapter, defaultAuthAdapter };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Auth Adapter Interface for Client-Side Authentication
3
+ *
4
+ * Defines the contract for authentication adapters used by SolvaPayProvider.
5
+ * Adapters handle token retrieval and user ID extraction in the browser.
6
+ */
7
+ /**
8
+ * Auth adapter interface for client-side authentication
9
+ *
10
+ * Used by SolvaPayProvider to get auth tokens and user IDs.
11
+ * Adapters should handle their own error cases and return null when
12
+ * authentication is not available or fails.
13
+ */
14
+ interface AuthAdapter {
15
+ /**
16
+ * Get the authentication token
17
+ *
18
+ * @returns The auth token string if available, null otherwise
19
+ *
20
+ * @remarks
21
+ * This method should never throw. If authentication fails or is missing,
22
+ * return null and let the caller decide how to handle unauthenticated requests.
23
+ */
24
+ getToken: () => Promise<string | null>;
25
+ /**
26
+ * Get the authenticated user ID
27
+ *
28
+ * @returns The user ID string if authenticated, null otherwise
29
+ *
30
+ * @remarks
31
+ * This method should never throw. If authentication fails or is missing,
32
+ * return null and let the caller decide how to handle unauthenticated requests.
33
+ */
34
+ getUserId: () => Promise<string | null>;
35
+ }
36
+ /**
37
+ * Default auth adapter that only checks localStorage
38
+ *
39
+ * This is a fallback adapter that doesn't depend on any specific auth provider.
40
+ * It checks for a token in localStorage under the 'auth_token' key.
41
+ */
42
+ declare const defaultAuthAdapter: AuthAdapter;
43
+
44
+ export { type AuthAdapter, defaultAuthAdapter };
@@ -0,0 +1,6 @@
1
+ import {
2
+ defaultAuthAdapter
3
+ } from "../chunk-OUSEQRCT.js";
4
+ export {
5
+ defaultAuthAdapter
6
+ };
@@ -0,0 +1,25 @@
1
+ // src/adapters/auth.ts
2
+ var defaultAuthAdapter = {
3
+ async getToken() {
4
+ if (typeof window === "undefined") return null;
5
+ const token = localStorage.getItem("auth_token");
6
+ return token || null;
7
+ },
8
+ async getUserId() {
9
+ const token = await this.getToken();
10
+ if (!token) return null;
11
+ try {
12
+ const parts = token.split(".");
13
+ if (parts.length === 3) {
14
+ const payload = JSON.parse(atob(parts[1]));
15
+ return payload.sub || payload.user_id || null;
16
+ }
17
+ } catch {
18
+ }
19
+ return null;
20
+ }
21
+ };
22
+
23
+ export {
24
+ defaultAuthAdapter
25
+ };