stripe-no-webhooks 0.0.8 → 0.0.11

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
@@ -1,152 +1,166 @@
1
1
  # stripe-no-webhooks
2
2
 
3
- Stripe integration without dealing with webhooks. Automatically syncs Stripe data to your PostgreSQL database and provides simple callbacks for subscription events.
3
+ Opinionated library to help you implement payments with Stripe. It syncs Stripe data to your database and gives you useful helpers to implement subscriptions and credits.
4
4
 
5
- ## Installation
5
+ ## Why this library?
6
+
7
+ This library is a wrapper on Stripe SDK (with some bells and whistles). It gives you an opinionated and clear path to implement payments:
8
+
9
+ 1. Define plans in code which sync to Stripe
10
+ 2. No manual webhook setup - the library handles webhooks and syncs Stripe data to your DB
11
+ 3. Simple APIs for subscriptions and credits
12
+ 4. Optional callbacks (`onSubscriptionCreated`, etc.) for custom logic
13
+
14
+ ## Setup
15
+
16
+ ### 1. Install
6
17
 
7
18
  ```bash
8
19
  npm install stripe-no-webhooks stripe
9
20
  ```
10
21
 
11
- ## Setup
22
+ Note: make sure you also have `.env` or `.env.local` in your project so it can save the generated secrets there.
12
23
 
13
- ### 1. Create Stripe schema and tables
24
+ ### 2. Create tables where all Stripe data will be automatically synced
14
25
 
15
- **Option 1:** Run the migration command
26
+ ```bash
27
+ npx stripe-no-webhooks migrate postgresql://[USER]:[PASSWORD]@[DB_URL]/postgres
28
+ ```
29
+
30
+ ### 3. Run `config` to generate files & webhook
16
31
 
17
32
  ```bash
18
- npx stripe-no-webhooks migrate postgresql://postgres.[USER]:[PASSWORD]@[DB_URL]/postgres
33
+ npx stripe-no-webhooks config
19
34
  ```
20
35
 
21
- **Option 2:** Copy `stripe_schema.sql` and run the query manually
36
+ This creates:
22
37
 
23
- ### 2. Set up the webhook handler
38
+ - `lib/billing.ts` - Billing instance (optional, for credits/subscriptions API)
39
+ - `app/api/stripe/[...all]/route.ts` - HTTP handler
40
+ - `billing.config.ts` - Your plans
24
41
 
25
- Create a webhook endpoint in your Next.js app:
42
+ ### 4. Connect your auth
26
43
 
27
- #### App Router (recommended)
44
+ Open `app/api/stripe/[...all]/route.ts` and add your auth:
28
45
 
29
- ```ts
30
- // app/api/stripe/webhook/route.ts
31
- import { createStripeWebhookHandler } from "stripe-no-webhooks";
46
+ ```typescript
47
+ import { billing } from "@/lib/billing";
48
+ import { auth } from "@clerk/nextjs/server"; // or your auth library
32
49
 
33
- const handler = createStripeWebhookHandler({
34
- databaseUrl: process.env.DATABASE_URL!,
35
- stripeSecretKey: process.env.STRIPE_SECRET_KEY!,
36
- stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
37
- callbacks: {
38
- onSubscriptionCreated: async (subscription) => {
39
- // Called when a new subscription is created
40
- console.log("New subscription:", subscription.id);
41
- // e.g., send welcome email, provision resources, etc.
42
- },
43
- onSubscriptionCancelled: async (subscription) => {
44
- // Called when a subscription is cancelled
45
- console.log("Subscription cancelled:", subscription.id);
46
- // e.g., send cancellation email, revoke access, etc.
47
- },
50
+ export const POST = billing.createHandler({
51
+ resolveUser: async () => {
52
+ const { userId } = await auth();
53
+ return userId ? { id: userId } : null;
48
54
  },
49
55
  });
50
-
51
- export const POST = handler;
52
56
  ```
53
57
 
54
- #### Pages Router
58
+ **Simple alternative**: If you don't need credits/subscriptions API, skip `lib/billing.ts`:
55
59
 
56
- ```ts
57
- // pages/api/stripe/webhook.ts
58
- import { createStripeWebhookHandler } from "stripe-no-webhooks";
59
- import type { NextApiRequest, NextApiResponse } from "next";
60
+ ```typescript
61
+ import { createHandler } from "stripe-no-webhooks";
62
+ import billingConfig from "@/billing.config";
60
63
 
61
- const handler = createStripeWebhookHandler({
62
- databaseUrl: process.env.DATABASE_URL!,
63
- stripeSecretKey: process.env.STRIPE_SECRET_KEY!,
64
- stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
65
- callbacks: {
66
- onSubscriptionCreated: async (subscription) => {
67
- console.log("New subscription:", subscription.id);
68
- },
69
- onSubscriptionCancelled: async (subscription) => {
70
- console.log("Subscription cancelled:", subscription.id);
71
- },
64
+ export const POST = createHandler({
65
+ billingConfig,
66
+ resolveUser: async () => {
67
+ const { userId } = await auth();
68
+ return userId ? { id: userId } : null;
72
69
  },
73
70
  });
71
+ ```
74
72
 
75
- // Disable body parsing, we need the raw body for webhook verification
76
- export const config = {
77
- api: {
78
- bodyParser: false,
73
+ ### 5. Create your plans
74
+
75
+ ```javascript
76
+ // billing.config.ts
77
+ import type { BillingConfig } from "stripe-no-webhooks";
78
+
79
+ const billingConfig: BillingConfig = {
80
+ test: {
81
+ plans: [
82
+ {
83
+ name: "Premium",
84
+ description: "Access to all features",
85
+ price: [
86
+ { amount: 1000, currency: "usd", interval: "month" },
87
+ { amount: 10000, currency: "usd", interval: "year" },
88
+ ],
89
+ credits: {
90
+ api_calls: { allocation: 1000 },
91
+ },
92
+ },
93
+ ],
79
94
  },
80
95
  };
96
+ export default billingConfig;
97
+ ```
81
98
 
82
- export default async function webhookHandler(
83
- req: NextApiRequest,
84
- res: NextApiResponse
85
- ) {
86
- if (req.method !== "POST") {
87
- return res.status(405).json({ error: "Method not allowed" });
88
- }
89
-
90
- // Convert NextApiRequest to Request for the handler
91
- const body = await new Promise<string>((resolve) => {
92
- let data = "";
93
- req.on("data", (chunk) => (data += chunk));
94
- req.on("end", () => resolve(data));
95
- });
96
-
97
- const request = new Request(`https://${req.headers.host}${req.url}`, {
98
- method: "POST",
99
- headers: new Headers(req.headers as Record<string, string>),
100
- body,
101
- });
102
-
103
- const response = await handler(request);
104
- res.status(response.status).send(await response.text());
105
- }
99
+ Run sync:
100
+
101
+ ```bash
102
+ npx stripe-no-webhooks sync
106
103
  ```
107
104
 
108
- ### 3. Configure Stripe webhook
105
+ ### 6. (optional) Write custom logic for subscriptions
109
106
 
110
- Run the config command to automatically create a webhook in your Stripe account:
107
+ You probably want something to happen when a new user subscribes or a subscription cancels. Define callbacks when creating the `Billing` instance:
111
108
 
112
- ```bash
113
- npx stripe-no-webhooks config
109
+ ```typescript
110
+ // lib/billing.ts
111
+ import { Billing } from "stripe-no-webhooks";
112
+ import billingConfig from "../billing.config";
113
+ import type { Stripe } from "stripe";
114
+
115
+ export const billing = new Billing({
116
+ billingConfig,
117
+ callbacks: {
118
+ onSubscriptionCreated: async (subscription: Stripe.Subscription) => {
119
+ console.log("New subscription:", subscription.id);
120
+ },
121
+ onSubscriptionCancelled: async (subscription: Stripe.Subscription) => {
122
+ console.log("Subscription cancelled:", subscription.id);
123
+ },
124
+ },
125
+ });
114
126
  ```
115
127
 
116
- This will:
128
+ Supported callbacks:
117
129
 
118
- 1. Ask for your Stripe Secret Key
119
- 2. Ask for your site URL (defaults to `NEXT_PUBLIC_SITE_URL` if set)
120
- 3. Create a webhook endpoint at `https://yoursite.com/api/stripe/webhook` listening to all events
121
- 4. Automatically add `STRIPE_WEBHOOK_SECRET` to your `.env` files (if they exist)
130
+ - `onSubscriptionCreated`
131
+ - `onSubscriptionCancelled`
132
+ - `onSubscriptionRenewed`
133
+ - `onSubscriptionPlanChanged`
134
+ - `onCreditsGranted`
135
+ - `onCreditsRevoked`
136
+ - `onTopUpCompleted`
137
+ - `onAutoTopUpFailed`
138
+ - `onCreditsLow`
122
139
 
123
- ## Environment Variables
140
+ ### 7. (optional) Generate a pricing page
124
141
 
125
- ```env
126
- DATABASE_URL=postgresql://user:pass@host:port/db
127
- STRIPE_SECRET_KEY=sk_test_...
128
- STRIPE_WEBHOOK_SECRET=whsec_... # Output from `npx stripe-no-webhooks config`
142
+ ```bash
143
+ npx stripe-no-webhooks generate pricing-page
129
144
  ```
130
145
 
131
- ## What gets synced?
146
+ This will create a `PricingPage` component in `@/components`. Feel free to edit styling manually or with AI.
132
147
 
133
- All Stripe webhook events are automatically synced to your PostgreSQL database in the `stripe` schema. This includes:
148
+ It is ready-to-use with loading states, error handling, and styling. Import it whenever you want:
134
149
 
135
- - Customers
136
- - Subscriptions
137
- - Products
138
- - Prices
139
- - Invoices
140
- - Payment methods
141
- - And more...
150
+ ```tsx
151
+ import { PricingPage } from "@/components/PricingPage";
152
+ import billingConfig from "@/billing.config";
142
153
 
143
- You can query this data directly from your database without making API calls to Stripe.
154
+ export default function Pricing() {
155
+ const plans = billingConfig.test?.plans || [];
156
+ return <PricingPage plans={plans} currentPlanId="free" />;
157
+ }
158
+ ```
144
159
 
145
- ## Callbacks
160
+ ### 8. (optional) Backfill data
146
161
 
147
- | Callback | Event | Description |
148
- | ------------------------- | --------------------------------------------------------------- | ----------------------------------------- |
149
- | `onSubscriptionCreated` | `customer.subscription.created` | Called when a new subscription is created |
150
- | `onSubscriptionCancelled` | `customer.subscription.deleted` or status changes to `canceled` | Called when a subscription is cancelled |
162
+ If you had data in Stripe before deploying `stripe-no-webhooks`, you can backfill your database by running:
151
163
 
152
- Both callbacks receive the full Stripe `Subscription` object.
164
+ ```bash
165
+ npx stripe-no-webhooks backfill
166
+ ```