stripe-no-webhooks 0.0.1

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 ADDED
@@ -0,0 +1,152 @@
1
+ # stripe-no-webhooks
2
+
3
+ Stripe integration without dealing with webhooks. Automatically syncs Stripe data to your PostgreSQL database and provides simple callbacks for subscription events.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install stripe-no-webhooks stripe
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ### 1. Create Stripe schema and tables
14
+
15
+ **Option 1:** Run the migration command
16
+
17
+ ```bash
18
+ npx stripe-no-webhooks migrate postgresql://postgres.[USER]:[PASSWORD]@[DB_URL]/postgres
19
+ ```
20
+
21
+ **Option 2:** Copy `stripe_schema.sql` and run the query manually
22
+
23
+ ### 2. Set up the webhook handler
24
+
25
+ Create a webhook endpoint in your Next.js app:
26
+
27
+ #### App Router (recommended)
28
+
29
+ ```ts
30
+ // app/api/stripe/webhook/route.ts
31
+ import { createStripeWebhookHandler } from "stripe-no-webhooks";
32
+
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
+ },
48
+ },
49
+ });
50
+
51
+ export const POST = handler;
52
+ ```
53
+
54
+ #### Pages Router
55
+
56
+ ```ts
57
+ // pages/api/stripe/webhook.ts
58
+ import { createStripeWebhookHandler } from "stripe-no-webhooks";
59
+ import type { NextApiRequest, NextApiResponse } from "next";
60
+
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
+ },
72
+ },
73
+ });
74
+
75
+ // Disable body parsing, we need the raw body for webhook verification
76
+ export const config = {
77
+ api: {
78
+ bodyParser: false,
79
+ },
80
+ };
81
+
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
+ }
106
+ ```
107
+
108
+ ### 3. Configure Stripe webhook
109
+
110
+ Run the config command to automatically create a webhook in your Stripe account:
111
+
112
+ ```bash
113
+ npx stripe-no-webhooks config
114
+ ```
115
+
116
+ This will:
117
+
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)
122
+
123
+ ## Environment Variables
124
+
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`
129
+ ```
130
+
131
+ ## What gets synced?
132
+
133
+ All Stripe webhook events are automatically synced to your PostgreSQL database in the `stripe` schema. This includes:
134
+
135
+ - Customers
136
+ - Subscriptions
137
+ - Products
138
+ - Prices
139
+ - Invoices
140
+ - Payment methods
141
+ - And more...
142
+
143
+ You can query this data directly from your database without making API calls to Stripe.
144
+
145
+ ## Callbacks
146
+
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 |
151
+
152
+ Both callbacks receive the full Stripe `Subscription` object.
package/bin/cli.js ADDED
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { runMigrations } = require("@supabase/stripe-sync-engine");
4
+ const readline = require("readline");
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+
8
+ const args = process.argv.slice(2);
9
+ const command = args[0];
10
+ const databaseUrl = args[1];
11
+
12
+ function createPrompt() {
13
+ return readline.createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout,
16
+ });
17
+ }
18
+
19
+ function question(rl, query, defaultValue = "") {
20
+ return new Promise((resolve) => {
21
+ const prompt = defaultValue ? `${query} (${defaultValue}): ` : `${query}: `;
22
+ rl.question(prompt, (answer) => {
23
+ resolve(answer || defaultValue);
24
+ });
25
+ });
26
+ }
27
+
28
+ function questionHidden(rl, query) {
29
+ return new Promise((resolve) => {
30
+ const stdin = process.stdin;
31
+ const stdout = process.stdout;
32
+
33
+ stdout.write(`${query}: `);
34
+
35
+ stdin.setRawMode(true);
36
+ stdin.resume();
37
+ stdin.setEncoding("utf8");
38
+
39
+ let input = "";
40
+ const onData = (char) => {
41
+ if (char === "\n" || char === "\r" || char === "\u0004") {
42
+ stdin.setRawMode(false);
43
+ stdin.pause();
44
+ stdin.removeListener("data", onData);
45
+ stdout.write("\n");
46
+ resolve(input);
47
+ } else if (char === "\u0003") {
48
+ // Ctrl+C
49
+ process.exit();
50
+ } else if (char === "\u007F" || char === "\b") {
51
+ // Backspace
52
+ if (input.length > 0) {
53
+ input = input.slice(0, -1);
54
+ stdout.write("\b \b"); // Erase character from display
55
+ }
56
+ } else {
57
+ input += char;
58
+ stdout.write("**************"); // Show asterisk for each character
59
+ }
60
+ };
61
+
62
+ stdin.on("data", onData);
63
+ });
64
+ }
65
+
66
+ async function migrate(databaseUrl) {
67
+ if (!databaseUrl) {
68
+ console.error("❌ Missing database URL.\n");
69
+ console.log(
70
+ "Usage:\n npx stripe-no-webhooks migrate <postgres_connection_string>"
71
+ );
72
+ process.exit(1);
73
+ }
74
+
75
+ console.log("🚀 Running Stripe migrations...");
76
+ try {
77
+ await runMigrations({
78
+ databaseUrl,
79
+ schema: "stripe",
80
+ logger: console,
81
+ });
82
+ console.log("✅ Migrations completed successfully!");
83
+ } catch (error) {
84
+ console.error("❌ Migration failed:");
85
+ console.error(error);
86
+ process.exit(1);
87
+ }
88
+ }
89
+
90
+ async function config() {
91
+ let Stripe;
92
+ try {
93
+ Stripe = require("stripe").default || require("stripe");
94
+ } catch (e) {
95
+ console.error("❌ Stripe package not found.");
96
+ console.log("Please install it first: npm install stripe");
97
+ process.exit(1);
98
+ }
99
+
100
+ const rl = createPrompt();
101
+
102
+ console.log("\n🔧 Stripe Webhook Configuration\n");
103
+
104
+ // Get Stripe API key (hidden input)
105
+ rl.close(); // Close readline for hidden input
106
+ const stripeSecretKey = await questionHidden(
107
+ null,
108
+ "Enter your Stripe Secret Key (sk_...)"
109
+ );
110
+
111
+ if (!stripeSecretKey || !stripeSecretKey.startsWith("sk_")) {
112
+ console.error("❌ Invalid Stripe Secret Key. It should start with 'sk_'");
113
+ process.exit(1);
114
+ }
115
+
116
+ // Reopen readline for remaining questions
117
+ const rl2 = createPrompt();
118
+
119
+ // Get site URL with default from env
120
+ const defaultSiteUrl = process.env.NEXT_PUBLIC_SITE_URL || "";
121
+ const siteUrl = await question(rl2, "Enter your site URL", defaultSiteUrl);
122
+
123
+ if (!siteUrl) {
124
+ console.error("❌ Site URL is required");
125
+ rl2.close();
126
+ process.exit(1);
127
+ }
128
+
129
+ // Validate URL
130
+ let webhookUrl;
131
+ try {
132
+ const url = new URL(siteUrl);
133
+ webhookUrl = `${url.origin}/api/stripe/webhook`;
134
+ } catch (e) {
135
+ console.error("❌ Invalid URL format");
136
+ rl2.close();
137
+ process.exit(1);
138
+ }
139
+
140
+ rl2.close();
141
+
142
+ console.log(`\n📡 Creating webhook endpoint: ${webhookUrl}\n`);
143
+
144
+ const stripe = new Stripe(stripeSecretKey);
145
+
146
+ try {
147
+ // Get all available event types
148
+ const webhook = await stripe.webhookEndpoints.create({
149
+ url: webhookUrl,
150
+ enabled_events: ["*"], // Listen to all events
151
+ description: "Created by stripe-no-webhooks CLI",
152
+ });
153
+
154
+ console.log("✅ Webhook created successfully!\n");
155
+
156
+ // Try to add webhook secret to env files
157
+ const envFiles = [
158
+ ".env",
159
+ ".env.local",
160
+ ".env.development",
161
+ ".env.production",
162
+ ];
163
+ const cwd = process.cwd();
164
+ const updatedFiles = [];
165
+
166
+ for (const envFile of envFiles) {
167
+ const envPath = path.join(cwd, envFile);
168
+ if (fs.existsSync(envPath)) {
169
+ let content = fs.readFileSync(envPath, "utf8");
170
+ const secretLine = `STRIPE_WEBHOOK_SECRET=${webhook.secret}`;
171
+
172
+ if (content.includes("STRIPE_WEBHOOK_SECRET=")) {
173
+ // Replace existing value
174
+ content = content.replace(/STRIPE_WEBHOOK_SECRET=.*/, secretLine);
175
+ } else {
176
+ // Append to file
177
+ const newline = content.endsWith("\n") ? "" : "\n";
178
+ content = content + newline + secretLine + "\n";
179
+ }
180
+
181
+ fs.writeFileSync(envPath, content);
182
+ updatedFiles.push(envFile);
183
+ }
184
+ }
185
+
186
+ if (updatedFiles.length > 0) {
187
+ console.log(
188
+ `📝 Updated ${updatedFiles.join(
189
+ ", "
190
+ )} with STRIPE_WEBHOOK_SECRET\nREMEMBER: Update the enviroment variable in Vercel too\nSTRIPE_WEBHOOK_SECRET=${
191
+ webhook.secret
192
+ }`
193
+ );
194
+ } else {
195
+ console.log("Add this to your environment variables:\n");
196
+ console.log(`STRIPE_WEBHOOK_SECRET=${webhook.secret}\n`);
197
+ }
198
+
199
+ console.log("─".repeat(50));
200
+ console.log("Webhook ID:", webhook.id);
201
+ console.log("Webhook URL:", webhook.url);
202
+ console.log("Events: All events (*)");
203
+ if (updatedFiles.length === 0) {
204
+ console.log("Secret:", webhook.secret);
205
+ }
206
+ console.log("─".repeat(50));
207
+ } catch (error) {
208
+ if (error.type === "StripeAuthenticationError") {
209
+ console.error("❌ Authentication failed. Check your Stripe Secret Key.");
210
+ } else if (error.type === "StripeInvalidRequestError") {
211
+ console.error("❌ Invalid request:", error.message);
212
+ } else {
213
+ console.error("❌ Failed to create webhook:");
214
+ console.error(error.message);
215
+ }
216
+ process.exit(1);
217
+ }
218
+ }
219
+
220
+ async function main() {
221
+ switch (command) {
222
+ case "migrate":
223
+ await migrate(databaseUrl);
224
+ break;
225
+
226
+ case "config":
227
+ await config();
228
+ break;
229
+
230
+ default:
231
+ console.log("Usage:");
232
+ console.log(" npx stripe-no-webhooks migrate <connection_string>");
233
+ console.log(" npx stripe-no-webhooks config");
234
+ process.exit(1);
235
+ }
236
+ }
237
+
238
+ main();
@@ -0,0 +1,37 @@
1
+ import Stripe from 'stripe';
2
+
3
+ interface StripeWebhookCallbacks {
4
+ /**
5
+ * Called when a new subscription is created
6
+ */
7
+ onSubscriptionCreated?: (subscription: Stripe.Subscription) => void | Promise<void>;
8
+ /**
9
+ * Called when a subscription is cancelled
10
+ */
11
+ onSubscriptionCancelled?: (subscription: Stripe.Subscription) => void | Promise<void>;
12
+ }
13
+ interface StripeWebhookConfig {
14
+ /**
15
+ * PostgreSQL connection string for the Stripe sync database
16
+ */
17
+ databaseUrl: string;
18
+ /**
19
+ * Stripe secret key (sk_test_... or sk_live_...)
20
+ */
21
+ stripeSecretKey: string;
22
+ /**
23
+ * Stripe webhook signing secret (whsec_...)
24
+ */
25
+ stripeWebhookSecret: string;
26
+ /**
27
+ * Database schema name (defaults to 'stripe')
28
+ */
29
+ schema?: string;
30
+ /**
31
+ * Callbacks for subscription events
32
+ */
33
+ callbacks?: StripeWebhookCallbacks;
34
+ }
35
+ declare function createStripeWebhookHandler(config: StripeWebhookConfig): (request: Request) => Promise<Response>;
36
+
37
+ export { type StripeWebhookCallbacks, type StripeWebhookConfig, createStripeWebhookHandler };
@@ -0,0 +1,37 @@
1
+ import Stripe from 'stripe';
2
+
3
+ interface StripeWebhookCallbacks {
4
+ /**
5
+ * Called when a new subscription is created
6
+ */
7
+ onSubscriptionCreated?: (subscription: Stripe.Subscription) => void | Promise<void>;
8
+ /**
9
+ * Called when a subscription is cancelled
10
+ */
11
+ onSubscriptionCancelled?: (subscription: Stripe.Subscription) => void | Promise<void>;
12
+ }
13
+ interface StripeWebhookConfig {
14
+ /**
15
+ * PostgreSQL connection string for the Stripe sync database
16
+ */
17
+ databaseUrl: string;
18
+ /**
19
+ * Stripe secret key (sk_test_... or sk_live_...)
20
+ */
21
+ stripeSecretKey: string;
22
+ /**
23
+ * Stripe webhook signing secret (whsec_...)
24
+ */
25
+ stripeWebhookSecret: string;
26
+ /**
27
+ * Database schema name (defaults to 'stripe')
28
+ */
29
+ schema?: string;
30
+ /**
31
+ * Callbacks for subscription events
32
+ */
33
+ callbacks?: StripeWebhookCallbacks;
34
+ }
35
+ declare function createStripeWebhookHandler(config: StripeWebhookConfig): (request: Request) => Promise<Response>;
36
+
37
+ export { type StripeWebhookCallbacks, type StripeWebhookConfig, createStripeWebhookHandler };
package/dist/index.js ADDED
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ createStripeWebhookHandler: () => createStripeWebhookHandler
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/handler.ts
38
+ var import_stripe_sync_engine = require("@supabase/stripe-sync-engine");
39
+ var import_stripe = __toESM(require("stripe"));
40
+ function createStripeWebhookHandler(config) {
41
+ const {
42
+ databaseUrl,
43
+ stripeSecretKey,
44
+ stripeWebhookSecret,
45
+ schema = "stripe",
46
+ callbacks
47
+ } = config;
48
+ const sync = new import_stripe_sync_engine.StripeSync({
49
+ poolConfig: {
50
+ connectionString: databaseUrl
51
+ },
52
+ schema,
53
+ stripeSecretKey,
54
+ stripeWebhookSecret
55
+ });
56
+ const stripe = new import_stripe.default(stripeSecretKey);
57
+ return async function handler(request) {
58
+ try {
59
+ const body = await request.text();
60
+ const signature = request.headers.get("stripe-signature");
61
+ if (!signature) {
62
+ return new Response("Missing stripe-signature header", { status: 400 });
63
+ }
64
+ let event;
65
+ try {
66
+ event = stripe.webhooks.constructEvent(
67
+ body,
68
+ signature,
69
+ stripeWebhookSecret
70
+ );
71
+ } catch (err) {
72
+ const message = err instanceof Error ? err.message : "Unknown error";
73
+ return new Response(
74
+ `Webhook signature verification failed: ${message}`,
75
+ { status: 400 }
76
+ );
77
+ }
78
+ await sync.processWebhook(body, signature);
79
+ if (callbacks) {
80
+ await handleCallbacks(event, callbacks);
81
+ }
82
+ return new Response(JSON.stringify({ received: true }), {
83
+ status: 200,
84
+ headers: { "Content-Type": "application/json" }
85
+ });
86
+ } catch (error) {
87
+ console.error("Stripe webhook error:", error);
88
+ const message = error instanceof Error ? error.message : "Internal server error";
89
+ return new Response(message, { status: 500 });
90
+ }
91
+ };
92
+ }
93
+ async function handleCallbacks(event, callbacks) {
94
+ const { onSubscriptionCreated, onSubscriptionCancelled } = callbacks;
95
+ switch (event.type) {
96
+ case "customer.subscription.created":
97
+ if (onSubscriptionCreated) {
98
+ await onSubscriptionCreated(event.data.object);
99
+ }
100
+ break;
101
+ case "customer.subscription.deleted":
102
+ if (onSubscriptionCancelled) {
103
+ await onSubscriptionCancelled(event.data.object);
104
+ }
105
+ break;
106
+ case "customer.subscription.updated":
107
+ const subscription = event.data.object;
108
+ const previousAttributes = event.data.previous_attributes;
109
+ if (onSubscriptionCancelled && subscription.status === "canceled" && previousAttributes?.status && previousAttributes.status !== "canceled") {
110
+ await onSubscriptionCancelled(subscription);
111
+ }
112
+ break;
113
+ }
114
+ }
115
+ // Annotate the CommonJS export names for ESM import in node:
116
+ 0 && (module.exports = {
117
+ createStripeWebhookHandler
118
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,81 @@
1
+ // src/handler.ts
2
+ import { StripeSync } from "@supabase/stripe-sync-engine";
3
+ import Stripe from "stripe";
4
+ function createStripeWebhookHandler(config) {
5
+ const {
6
+ databaseUrl,
7
+ stripeSecretKey,
8
+ stripeWebhookSecret,
9
+ schema = "stripe",
10
+ callbacks
11
+ } = config;
12
+ const sync = new StripeSync({
13
+ poolConfig: {
14
+ connectionString: databaseUrl
15
+ },
16
+ schema,
17
+ stripeSecretKey,
18
+ stripeWebhookSecret
19
+ });
20
+ const stripe = new Stripe(stripeSecretKey);
21
+ return async function handler(request) {
22
+ try {
23
+ const body = await request.text();
24
+ const signature = request.headers.get("stripe-signature");
25
+ if (!signature) {
26
+ return new Response("Missing stripe-signature header", { status: 400 });
27
+ }
28
+ let event;
29
+ try {
30
+ event = stripe.webhooks.constructEvent(
31
+ body,
32
+ signature,
33
+ stripeWebhookSecret
34
+ );
35
+ } catch (err) {
36
+ const message = err instanceof Error ? err.message : "Unknown error";
37
+ return new Response(
38
+ `Webhook signature verification failed: ${message}`,
39
+ { status: 400 }
40
+ );
41
+ }
42
+ await sync.processWebhook(body, signature);
43
+ if (callbacks) {
44
+ await handleCallbacks(event, callbacks);
45
+ }
46
+ return new Response(JSON.stringify({ received: true }), {
47
+ status: 200,
48
+ headers: { "Content-Type": "application/json" }
49
+ });
50
+ } catch (error) {
51
+ console.error("Stripe webhook error:", error);
52
+ const message = error instanceof Error ? error.message : "Internal server error";
53
+ return new Response(message, { status: 500 });
54
+ }
55
+ };
56
+ }
57
+ async function handleCallbacks(event, callbacks) {
58
+ const { onSubscriptionCreated, onSubscriptionCancelled } = callbacks;
59
+ switch (event.type) {
60
+ case "customer.subscription.created":
61
+ if (onSubscriptionCreated) {
62
+ await onSubscriptionCreated(event.data.object);
63
+ }
64
+ break;
65
+ case "customer.subscription.deleted":
66
+ if (onSubscriptionCancelled) {
67
+ await onSubscriptionCancelled(event.data.object);
68
+ }
69
+ break;
70
+ case "customer.subscription.updated":
71
+ const subscription = event.data.object;
72
+ const previousAttributes = event.data.previous_attributes;
73
+ if (onSubscriptionCancelled && subscription.status === "canceled" && previousAttributes?.status && previousAttributes.status !== "canceled") {
74
+ await onSubscriptionCancelled(subscription);
75
+ }
76
+ break;
77
+ }
78
+ }
79
+ export {
80
+ createStripeWebhookHandler
81
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "stripe-no-webhooks",
3
+ "version": "0.0.1",
4
+ "author": "Ramon Garate",
5
+ "description": "Stripe integration without dealing with webhooks",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.js"
14
+ }
15
+ },
16
+ "bin": {
17
+ "stripe-no-webhooks": "./bin/cli.js"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "bin"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsup src/index.ts --format cjs,esm --dts",
25
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
26
+ "prepublishOnly": "npm run build",
27
+ "publish": "npm version patch && npm publish"
28
+ },
29
+ "dependencies": {
30
+ "@supabase/stripe-sync-engine": "^0.47.0"
31
+ },
32
+ "peerDependencies": {
33
+ "stripe": ">=14.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^22.10.2",
37
+ "stripe": "^17.4.0",
38
+ "tsup": "^8.3.5",
39
+ "typescript": "^5.7.2"
40
+ },
41
+ "keywords": [
42
+ "stripe",
43
+ "webhooks",
44
+ "nextjs",
45
+ "supabase",
46
+ "sync"
47
+ ],
48
+ "license": "MIT"
49
+ }