@digilogiclabs/saas-factory-payments 0.1.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 DigiLogicLabs
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.
22
+
package/README.md ADDED
@@ -0,0 +1,679 @@
1
+ # @digilogiclabs/saas-factory-payments
2
+
3
+ A comprehensive payments package for SaaS Factory that works seamlessly in both Next.js and React Native environments. Built with TypeScript and designed to be provider-agnostic (currently supporting Stripe with plans for Paddle, LemonSqueezy, and more).
4
+
5
+ ## Features
6
+
7
+ - 🌐 **Hybrid Support**: Works in both Next.js web applications and React Native mobile apps
8
+ - 🔒 **Type-Safe**: Built with TypeScript for better developer experience
9
+ - 🎨 **UI Components**: Pre-built components for checkout, pricing tables, and billing management
10
+ - 🪝 **React Hooks**: Powerful hooks for subscription and customer management
11
+ - 🔧 **Server Utilities**: Complete server-side API and webhook handling
12
+ - 📱 **Mobile-First**: Native mobile payment flows with Stripe React Native
13
+ - 🎯 **Provider-Agnostic**: Extensible architecture for multiple payment providers
14
+ - 🚀 **CLI Integration**: Works seamlessly with create-saas-app
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @digilogiclabs/saas-factory-payments
20
+ # or
21
+ yarn add @digilogiclabs/saas-factory-payments
22
+ # or
23
+ pnpm add @digilogiclabs/saas-factory-payments
24
+ ```
25
+
26
+ ### Peer Dependencies
27
+
28
+ The package requires different peer dependencies based on your platform:
29
+
30
+ **For Web (Next.js):**
31
+ ```bash
32
+ npm install @stripe/stripe-js @stripe/react-stripe-js stripe
33
+ ```
34
+
35
+ **For React Native:**
36
+ ```bash
37
+ npm install @stripe/stripe-react-native stripe
38
+ ```
39
+
40
+ **For Server-side:**
41
+ ```bash
42
+ npm install stripe
43
+ ```
44
+
45
+
46
+
47
+
48
+ ## Quick Start
49
+
50
+ ### 1. Setup Providers
51
+
52
+ First, wrap your app with the PaymentsProvider and platform-specific StripeProvider:
53
+
54
+ **Web (Next.js) - `pages/_app.tsx`:**
55
+ ```tsx
56
+ import { PaymentsProvider } from '@digilogiclabs/saas-factory-payments';
57
+ import { StripeProvider } from '@digilogiclabs/saas-factory-payments/web';
58
+
59
+ export default function App({ Component, pageProps }) {
60
+ return (
61
+ <PaymentsProvider
62
+ config={{
63
+ provider: 'stripe',
64
+ publishableKey: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
65
+ environment: process.env.NODE_ENV as 'development' | 'production',
66
+ }}
67
+ >
68
+ <StripeProvider>
69
+ <Component {...pageProps} />
70
+ </StripeProvider>
71
+ </PaymentsProvider>
72
+ );
73
+ }
74
+ ```
75
+
76
+ **React Native - `App.tsx`:**
77
+ ```tsx
78
+ import { PaymentsProvider } from '@digilogiclabs/saas-factory-payments';
79
+ import { StripeProvider } from '@digilogiclabs/saas-factory-payments/native';
80
+
81
+ export default function App() {
82
+ return (
83
+ <PaymentsProvider
84
+ config={{
85
+ provider: 'stripe',
86
+ publishableKey: process.env.EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
87
+ environment: __DEV__ ? 'development' : 'production',
88
+ }}
89
+ >
90
+ <StripeProvider>
91
+ <MainApp />
92
+ </StripeProvider>
93
+ </PaymentsProvider>
94
+ );
95
+ }
96
+ ```
97
+
98
+ ### 2. Use Components
99
+
100
+ **Checkout Button (Web):**
101
+ ```tsx
102
+ import { CheckoutButton } from '@digilogiclabs/saas-factory-payments/web';
103
+
104
+ export default function PricingPage() {
105
+ return (
106
+ <CheckoutButton
107
+ priceId="price_basic_monthly"
108
+ onSuccess={() => console.log('Payment successful!')}
109
+ onError={(error) => console.error('Payment failed:', error)}
110
+ >
111
+ Subscribe to Basic Plan
112
+ </CheckoutButton>
113
+ );
114
+ }
115
+ ```
116
+
117
+ **Checkout Button (React Native):**
118
+ ```tsx
119
+ import { CheckoutButton } from '@digilogiclabs/saas-factory-payments/native';
120
+
121
+ export default function PricingScreen() {
122
+ return (
123
+ <CheckoutButton
124
+ priceId="price_basic_monthly"
125
+ onSuccess={() => navigation.navigate('Success')}
126
+ onError={(error) => Alert.alert('Error', error)}
127
+ >
128
+ Subscribe to Basic Plan
129
+ </CheckoutButton>
130
+ );
131
+ }
132
+ ```
133
+
134
+ ### 3. Manage Subscriptions
135
+
136
+ ```tsx
137
+ import { useSubscription } from '@digilogiclabs/saas-factory-payments/web'; // or /native
138
+
139
+ function SubscriptionManager({ customerId }) {
140
+ const { subscription, loading, cancel, reactivate } = useSubscription({
141
+ customerId,
142
+ });
143
+
144
+ if (loading) return <div>Loading...</div>;
145
+
146
+ return (
147
+ <div>
148
+ <h3>Current Subscription</h3>
149
+ <p>Status: {subscription?.status}</p>
150
+ <p>Plan: {subscription?.priceId}</p>
151
+
152
+ {subscription?.status === 'active' && (
153
+ <button onClick={() => cancel()}>
154
+ Cancel Subscription
155
+ </button>
156
+ )}
157
+
158
+ {subscription?.cancelAtPeriodEnd && (
159
+ <button onClick={() => reactivate()}>
160
+ Reactivate Subscription
161
+ </button>
162
+ )}
163
+ </div>
164
+ );
165
+ }
166
+ ```
167
+
168
+
169
+ ## API Reference
170
+
171
+ ### Components
172
+
173
+ #### CheckoutButton
174
+
175
+ A button component that handles subscription or one-time payment checkout.
176
+
177
+ **Props:**
178
+ - `priceId` (string): Stripe price ID
179
+ - `customerId?` (string): Existing customer ID
180
+ - `customerEmail?` (string): Customer email for new customers
181
+ - `successUrl?` (string): Redirect URL after successful payment
182
+ - `cancelUrl?` (string): Redirect URL after cancelled payment
183
+ - `onSuccess?` (function): Callback for successful payment
184
+ - `onError?` (function): Callback for payment errors
185
+ - `children` (ReactNode): Button content
186
+
187
+ #### PricingTable
188
+
189
+ A responsive pricing table component with multiple plans.
190
+
191
+ **Props:**
192
+ - `plans` (PricingPlan[]): Array of pricing plans
193
+ - `customerId?` (string): Customer ID for checkout
194
+ - `showFeatures?` (boolean): Whether to show plan features
195
+ - `layout?` ('grid' | 'list' | 'carousel'): Layout style
196
+ - `onPlanSelect?` (function): Callback when plan is selected
197
+
198
+ #### PaymentForm
199
+
200
+ An inline payment form for direct payment processing.
201
+
202
+ **Props:**
203
+ - `clientSecret?` (string): Payment intent client secret
204
+ - `amount?` (number): Payment amount in cents
205
+ - `currency?` (string): Payment currency
206
+ - `onSuccess?` (function): Success callback
207
+ - `onError?` (function): Error callback
208
+
209
+ #### BillingPortal (Web only)
210
+
211
+ A button that opens the Stripe Customer Portal for subscription management.
212
+
213
+ **Props:**
214
+ - `customerId` (string): Customer ID
215
+ - `returnUrl?` (string): Return URL after portal session
216
+ - `onSuccess?` (function): Success callback
217
+ - `onError?` (function): Error callback
218
+
219
+ ### Hooks
220
+
221
+ #### useSubscription
222
+
223
+ Hook for managing customer subscriptions.
224
+
225
+ ```tsx
226
+ const {
227
+ subscription,
228
+ subscriptions,
229
+ loading,
230
+ error,
231
+ refetch,
232
+ cancel,
233
+ reactivate,
234
+ updatePaymentMethod,
235
+ } = useSubscription({ customerId });
236
+ ```
237
+
238
+ #### useCheckout
239
+
240
+ Hook for handling checkout processes.
241
+
242
+ ```tsx
243
+ const {
244
+ loading,
245
+ error,
246
+ createCheckoutSession,
247
+ redirectToCheckout,
248
+ createPaymentIntent,
249
+ } = useCheckout({
250
+ onSuccess: (sessionId) => console.log('Success:', sessionId),
251
+ onError: (error) => console.error('Error:', error),
252
+ });
253
+ ```
254
+
255
+ #### useCustomer
256
+
257
+ Hook for customer management.
258
+
259
+ ```tsx
260
+ const {
261
+ customer,
262
+ paymentMethods,
263
+ loading,
264
+ error,
265
+ createCustomer,
266
+ updateCustomer,
267
+ fetchPaymentMethods,
268
+ } = useCustomer({ customerId });
269
+ ```
270
+
271
+ #### usePayments
272
+
273
+ High-level hook that combines customer and subscription management.
274
+
275
+ ```tsx
276
+ const {
277
+ customer,
278
+ subscriptions,
279
+ activeSubscription,
280
+ loading,
281
+ createCustomer,
282
+ subscribe,
283
+ cancelSubscription,
284
+ hasActiveSubscription,
285
+ isSubscribedToPlan,
286
+ } = usePayments({ customerId });
287
+ ```
288
+
289
+
290
+ ### Server-Side Utilities
291
+
292
+ #### StripeServerAPI
293
+
294
+ Complete server-side Stripe API wrapper.
295
+
296
+ ```tsx
297
+ import { StripeServerAPI } from '@digilogiclabs/saas-factory-payments/server';
298
+
299
+ const stripeAPI = new StripeServerAPI(process.env.STRIPE_SECRET_KEY!);
300
+
301
+ // Create customer
302
+ const customer = await stripeAPI.createCustomer({
303
+ email: 'user@example.com',
304
+ name: 'John Doe',
305
+ });
306
+
307
+ // Create subscription
308
+ const subscription = await stripeAPI.createSubscription({
309
+ customerId: customer.id,
310
+ priceId: 'price_basic_monthly',
311
+ });
312
+
313
+ // Create checkout session
314
+ const session = await stripeAPI.createCheckoutSession({
315
+ priceId: 'price_basic_monthly',
316
+ successUrl: 'https://yourapp.com/success',
317
+ cancelUrl: 'https://yourapp.com/cancel',
318
+ });
319
+ ```
320
+
321
+ #### Webhook Handling
322
+
323
+ Handle Stripe webhooks with built-in event processing.
324
+
325
+ **Next.js API Route (`pages/api/webhooks/stripe.ts`):**
326
+ ```tsx
327
+ import { createNextJSWebhookHandler } from '@digilogiclabs/saas-factory-payments/server';
328
+
329
+ export default createNextJSWebhookHandler(
330
+ process.env.STRIPE_SECRET_KEY!,
331
+ process.env.STRIPE_WEBHOOK_SECRET!,
332
+ {
333
+ onCustomerSubscriptionCreated: async (subscription) => {
334
+ // Handle new subscription
335
+ console.log('New subscription:', subscription.id);
336
+ },
337
+ onInvoicePaymentSucceeded: async (invoice) => {
338
+ // Handle successful payment
339
+ console.log('Payment succeeded:', invoice.id);
340
+ },
341
+ onInvoicePaymentFailed: async (invoice) => {
342
+ // Handle failed payment
343
+ console.log('Payment failed:', invoice.id);
344
+ },
345
+ }
346
+ );
347
+
348
+ export const config = {
349
+ api: {
350
+ bodyParser: {
351
+ sizeLimit: '1mb',
352
+ },
353
+ },
354
+ };
355
+ ```
356
+
357
+ **Express.js:**
358
+ ```tsx
359
+ import express from 'express';
360
+ import { createStripeWebhookMiddleware } from '@digilogiclabs/saas-factory-payments/server';
361
+
362
+ const app = express();
363
+
364
+ app.use('/webhooks/stripe', express.raw({ type: 'application/json' }));
365
+ app.use('/webhooks/stripe', createStripeWebhookMiddleware(
366
+ process.env.STRIPE_SECRET_KEY!,
367
+ process.env.STRIPE_WEBHOOK_SECRET!,
368
+ {
369
+ onCustomerSubscriptionCreated: async (subscription) => {
370
+ // Handle subscription creation
371
+ },
372
+ }
373
+ ));
374
+ ```
375
+
376
+ ## Configuration
377
+
378
+ ### Environment Variables
379
+
380
+ Create a `.env.local` file (Next.js) or configure your environment:
381
+
382
+ ```bash
383
+ # Stripe Configuration
384
+ NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
385
+ STRIPE_SECRET_KEY=sk_test_...
386
+ STRIPE_WEBHOOK_SECRET=whsec_...
387
+
388
+ # For React Native (Expo)
389
+ EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
390
+ ```
391
+
392
+ ### PaymentsProvider Configuration
393
+
394
+ ```tsx
395
+ interface PaymentsConfig {
396
+ provider: 'stripe'; // More providers coming soon
397
+ publishableKey: string;
398
+ secretKey?: string; // Server-side only
399
+ webhookSecret?: string; // Server-side only
400
+ environment: 'development' | 'production';
401
+ }
402
+ ```
403
+
404
+ ### Pricing Plans Configuration
405
+
406
+ ```tsx
407
+ interface PricingPlan {
408
+ id: string;
409
+ name: string;
410
+ description?: string;
411
+ price: number; // In cents
412
+ currency: string;
413
+ interval: 'day' | 'week' | 'month' | 'year';
414
+ stripePriceId: string;
415
+ features: string[];
416
+ popular?: boolean;
417
+ trialPeriodDays?: number;
418
+ }
419
+
420
+ const plans: PricingPlan[] = [
421
+ {
422
+ id: 'basic',
423
+ name: 'Basic Plan',
424
+ description: 'Perfect for getting started',
425
+ price: 999, // $9.99
426
+ currency: 'USD',
427
+ interval: 'month',
428
+ stripePriceId: 'price_basic_monthly',
429
+ features: [
430
+ 'Up to 10 projects',
431
+ 'Basic support',
432
+ '1GB storage',
433
+ ],
434
+ },
435
+ {
436
+ id: 'pro',
437
+ name: 'Pro Plan',
438
+ description: 'For growing businesses',
439
+ price: 1999, // $19.99
440
+ currency: 'USD',
441
+ interval: 'month',
442
+ stripePriceId: 'price_pro_monthly',
443
+ features: [
444
+ 'Unlimited projects',
445
+ 'Priority support',
446
+ '10GB storage',
447
+ 'Advanced analytics',
448
+ ],
449
+ popular: true,
450
+ },
451
+ ];
452
+ ```
453
+
454
+
455
+ ## Examples
456
+
457
+ ### Complete Pricing Page (Web)
458
+
459
+ ```tsx
460
+ import { useState } from 'react';
461
+ import { PricingTable, BillingPortal } from '@digilogiclabs/saas-factory-payments/web';
462
+ import { usePayments } from '@digilogiclabs/saas-factory-payments';
463
+
464
+ const plans = [
465
+ {
466
+ id: 'basic',
467
+ name: 'Basic',
468
+ price: 999,
469
+ currency: 'USD',
470
+ interval: 'month',
471
+ stripePriceId: 'price_basic_monthly',
472
+ features: ['Feature 1', 'Feature 2'],
473
+ },
474
+ {
475
+ id: 'pro',
476
+ name: 'Pro',
477
+ price: 1999,
478
+ currency: 'USD',
479
+ interval: 'month',
480
+ stripePriceId: 'price_pro_monthly',
481
+ features: ['All Basic features', 'Feature 3', 'Feature 4'],
482
+ popular: true,
483
+ },
484
+ ];
485
+
486
+ export default function PricingPage() {
487
+ const [customerId] = useState('cus_example123');
488
+ const { hasActiveSubscription } = usePayments({ customerId });
489
+
490
+ if (hasActiveSubscription()) {
491
+ return (
492
+ <div className="text-center py-8">
493
+ <h2>Manage Your Subscription</h2>
494
+ <BillingPortal customerId={customerId}>
495
+ Manage Billing
496
+ </BillingPortal>
497
+ </div>
498
+ );
499
+ }
500
+
501
+ return (
502
+ <div className="max-w-6xl mx-auto px-4 py-8">
503
+ <h1 className="text-3xl font-bold text-center mb-8">Choose Your Plan</h1>
504
+ <PricingTable
505
+ plans={plans}
506
+ customerId={customerId}
507
+ onCheckoutSuccess={(plan) => {
508
+ console.log(`Successfully subscribed to ${plan.name}`);
509
+ }}
510
+ />
511
+ </div>
512
+ );
513
+ }
514
+ ```
515
+
516
+ ### Mobile Subscription Flow (React Native)
517
+
518
+ ```tsx
519
+ import React from 'react';
520
+ import { View, Text, StyleSheet } from 'react-native';
521
+ import { PricingTable } from '@digilogiclabs/saas-factory-payments/native';
522
+ import { usePayments } from '@digilogiclabs/saas-factory-payments';
523
+
524
+ const plans = [
525
+ // Same plans as above
526
+ ];
527
+
528
+ export default function PricingScreen({ navigation, customerId }) {
529
+ const { hasActiveSubscription } = usePayments({ customerId });
530
+
531
+ if (hasActiveSubscription()) {
532
+ return (
533
+ <View style={styles.container}>
534
+ <Text style={styles.title}>You're all set!</Text>
535
+ <Text style={styles.subtitle}>
536
+ Manage your subscription in the account settings.
537
+ </Text>
538
+ </View>
539
+ );
540
+ }
541
+
542
+ return (
543
+ <View style={styles.container}>
544
+ <Text style={styles.title}>Choose Your Plan</Text>
545
+ <PricingTable
546
+ plans={plans}
547
+ customerId={customerId}
548
+ layout="carousel"
549
+ onCheckoutSuccess={(plan) => {
550
+ navigation.navigate('Success', { plan: plan.name });
551
+ }}
552
+ />
553
+ </View>
554
+ );
555
+ }
556
+
557
+ const styles = StyleSheet.create({
558
+ container: {
559
+ flex: 1,
560
+ padding: 20,
561
+ },
562
+ title: {
563
+ fontSize: 24,
564
+ fontWeight: 'bold',
565
+ textAlign: 'center',
566
+ marginBottom: 20,
567
+ },
568
+ subtitle: {
569
+ fontSize: 16,
570
+ textAlign: 'center',
571
+ color: '#666',
572
+ },
573
+ });
574
+ ```
575
+
576
+ ### Server API Routes (Next.js)
577
+
578
+ ```tsx
579
+ // pages/api/payments/create-checkout-session.ts
580
+ import { NextApiRequest, NextApiResponse } from 'next';
581
+ import { StripeServerAPI } from '@digilogiclabs/saas-factory-payments/server';
582
+
583
+ const stripeAPI = new StripeServerAPI(process.env.STRIPE_SECRET_KEY!);
584
+
585
+ export default async function handler(req: NextApiRequest, res: NextApiResponse) {
586
+ if (req.method !== 'POST') {
587
+ return res.status(405).json({ error: 'Method not allowed' });
588
+ }
589
+
590
+ try {
591
+ const { priceId, customerId, successUrl, cancelUrl } = req.body;
592
+
593
+ const session = await stripeAPI.createCheckoutSession({
594
+ priceId,
595
+ customerId,
596
+ successUrl,
597
+ cancelUrl,
598
+ allowPromotionCodes: true,
599
+ });
600
+
601
+ res.status(200).json({ sessionId: session.id });
602
+ } catch (error) {
603
+ console.error('Checkout session error:', error);
604
+ res.status(500).json({ error: 'Failed to create checkout session' });
605
+ }
606
+ }
607
+ ```
608
+
609
+ ## CLI Integration
610
+
611
+ This package is designed to work seamlessly with `create-saas-app`:
612
+
613
+ ```bash
614
+ npx create-saas-app my-saas-app --payments=stripe
615
+ ```
616
+
617
+ When using the `--payments=stripe` flag, the CLI will:
618
+
619
+ 1. **Install Dependencies**: Automatically install the payments package and required peer dependencies
620
+ 2. **Setup Environment**: Create `.env.example` with Stripe configuration variables
621
+ 3. **Generate API Routes**: Create Next.js API routes for checkout, webhooks, and subscription management
622
+ 4. **Configure Providers**: Set up PaymentsProvider and StripeProvider in your app
623
+ 5. **Add Database Schema**: Include subscription and customer tables for your database
624
+ 6. **Create Example Components**: Generate a basic pricing page with working checkout
625
+
626
+ ### Manual Integration
627
+
628
+ If you're adding payments to an existing project:
629
+
630
+ 1. **Install the package and dependencies**
631
+ 2. **Set up environment variables**
632
+ 3. **Configure providers in your app**
633
+ 4. **Create API routes** (see examples above)
634
+ 5. **Set up webhook endpoints**
635
+ 6. **Add database tables for subscriptions and customers**
636
+
637
+ ## TypeScript Support
638
+
639
+ This package is built with TypeScript and provides full type safety:
640
+
641
+ ```tsx
642
+ import type {
643
+ PricingPlan,
644
+ Subscription,
645
+ Customer,
646
+ PaymentsConfig
647
+ } from '@digilogiclabs/saas-factory-payments';
648
+
649
+ // All components and hooks are fully typed
650
+ const subscription: Subscription = {
651
+ id: 'sub_123',
652
+ customerId: 'cus_123',
653
+ priceId: 'price_123',
654
+ status: 'active',
655
+ currentPeriodStart: new Date(),
656
+ currentPeriodEnd: new Date(),
657
+ cancelAtPeriodEnd: false,
658
+ };
659
+ ```
660
+
661
+ ## Contributing
662
+
663
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
664
+
665
+ ## License
666
+
667
+ MIT License - see [LICENSE](LICENSE) file for details.
668
+
669
+ ## Support
670
+
671
+ - 📧 Email: support@digilogiclabs.com
672
+ - 💬 Discord: [Join our community](https://discord.gg/digilogiclabs)
673
+ - 📖 Documentation: [docs.digilogiclabs.com](https://docs.digilogiclabs.com)
674
+ - 🐛 Issues: [GitHub Issues](https://github.com/DigiLogicLabs/saas-factory-payments/issues)
675
+
676
+ ---
677
+
678
+ Built with ❤️ by [DigiLogicLabs](https://digilogiclabs.com)
679
+