stripe-no-webhooks 0.0.2 → 0.0.4
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/bin/cli.js +531 -51
- package/dist/BillingConfig-BYrAQ7Wx.d.mts +18 -0
- package/dist/BillingConfig-BYrAQ7Wx.d.ts +18 -0
- package/dist/client.d.mts +79 -0
- package/dist/client.d.ts +79 -0
- package/dist/client.js +55 -0
- package/dist/client.mjs +29 -0
- package/dist/index.d.mts +72 -9
- package/dist/index.d.ts +72 -9
- package/dist/index.js +137 -11
- package/dist/index.mjs +136 -10
- package/package.json +13 -6
- package/src/templates/app-router.ts +20 -0
- package/src/templates/billing.config.ts +26 -0
- package/src/templates/pages-router.ts +49 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type PriceInterval = "month" | "year" | "week" | "one_time";
|
|
2
|
+
type Price = {
|
|
3
|
+
id?: string;
|
|
4
|
+
amount: number;
|
|
5
|
+
currency: string;
|
|
6
|
+
interval: PriceInterval;
|
|
7
|
+
};
|
|
8
|
+
type Plan = {
|
|
9
|
+
id?: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
price: Price[];
|
|
13
|
+
};
|
|
14
|
+
type BillingConfig = {
|
|
15
|
+
plans?: Plan[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type { BillingConfig as B, PriceInterval as P, Price as a, Plan as b };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type PriceInterval = "month" | "year" | "week" | "one_time";
|
|
2
|
+
type Price = {
|
|
3
|
+
id?: string;
|
|
4
|
+
amount: number;
|
|
5
|
+
currency: string;
|
|
6
|
+
interval: PriceInterval;
|
|
7
|
+
};
|
|
8
|
+
type Plan = {
|
|
9
|
+
id?: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
price: Price[];
|
|
13
|
+
};
|
|
14
|
+
type BillingConfig = {
|
|
15
|
+
plans?: Plan[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type { BillingConfig as B, PriceInterval as P, Price as a, Plan as b };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { P as PriceInterval } from './BillingConfig-BYrAQ7Wx.mjs';
|
|
2
|
+
|
|
3
|
+
interface CheckoutOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Plan name to checkout (as defined in your billing config)
|
|
6
|
+
*/
|
|
7
|
+
planName?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Plan ID to checkout (as defined in your billing config)
|
|
10
|
+
*/
|
|
11
|
+
planId?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Billing interval (month, year, etc.)
|
|
14
|
+
*/
|
|
15
|
+
interval?: PriceInterval;
|
|
16
|
+
/**
|
|
17
|
+
* Direct Stripe price ID (bypasses billing config lookup)
|
|
18
|
+
*/
|
|
19
|
+
priceId?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Quantity of the item (defaults to 1)
|
|
22
|
+
*/
|
|
23
|
+
quantity?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Customer email for prefilling checkout
|
|
26
|
+
*/
|
|
27
|
+
customerEmail?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Override success URL for this checkout
|
|
30
|
+
*/
|
|
31
|
+
successUrl?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Override cancel URL for this checkout
|
|
34
|
+
*/
|
|
35
|
+
cancelUrl?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Additional metadata to attach to the session
|
|
38
|
+
*/
|
|
39
|
+
metadata?: Record<string, string>;
|
|
40
|
+
}
|
|
41
|
+
interface CheckoutClientConfig {
|
|
42
|
+
/**
|
|
43
|
+
* API endpoint for checkout (defaults to /api/stripe/checkout)
|
|
44
|
+
*/
|
|
45
|
+
checkoutEndpoint?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates a checkout client for initiating Stripe checkouts from the frontend.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { createCheckoutClient } from "stripe-no-webhooks/client";
|
|
53
|
+
*
|
|
54
|
+
* const { checkout } = createCheckoutClient();
|
|
55
|
+
*
|
|
56
|
+
* // In your component:
|
|
57
|
+
* <button onClick={() => checkout({ planName: "pro", interval: "month" })}>
|
|
58
|
+
* Subscribe to Pro
|
|
59
|
+
* </button>
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare function createCheckoutClient(config?: CheckoutClientConfig): {
|
|
63
|
+
checkout: (options: CheckoutOptions) => Promise<void>;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Default checkout client instance using /api/stripe/checkout endpoint.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* import { checkout } from "stripe-no-webhooks/client";
|
|
71
|
+
*
|
|
72
|
+
* <button onClick={() => checkout({ planName: "pro", interval: "month" })}>
|
|
73
|
+
* Subscribe to Pro
|
|
74
|
+
* </button>
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
declare const checkout: (options: CheckoutOptions) => Promise<void>;
|
|
78
|
+
|
|
79
|
+
export { type CheckoutClientConfig, type CheckoutOptions, checkout, createCheckoutClient };
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { P as PriceInterval } from './BillingConfig-BYrAQ7Wx.js';
|
|
2
|
+
|
|
3
|
+
interface CheckoutOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Plan name to checkout (as defined in your billing config)
|
|
6
|
+
*/
|
|
7
|
+
planName?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Plan ID to checkout (as defined in your billing config)
|
|
10
|
+
*/
|
|
11
|
+
planId?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Billing interval (month, year, etc.)
|
|
14
|
+
*/
|
|
15
|
+
interval?: PriceInterval;
|
|
16
|
+
/**
|
|
17
|
+
* Direct Stripe price ID (bypasses billing config lookup)
|
|
18
|
+
*/
|
|
19
|
+
priceId?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Quantity of the item (defaults to 1)
|
|
22
|
+
*/
|
|
23
|
+
quantity?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Customer email for prefilling checkout
|
|
26
|
+
*/
|
|
27
|
+
customerEmail?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Override success URL for this checkout
|
|
30
|
+
*/
|
|
31
|
+
successUrl?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Override cancel URL for this checkout
|
|
34
|
+
*/
|
|
35
|
+
cancelUrl?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Additional metadata to attach to the session
|
|
38
|
+
*/
|
|
39
|
+
metadata?: Record<string, string>;
|
|
40
|
+
}
|
|
41
|
+
interface CheckoutClientConfig {
|
|
42
|
+
/**
|
|
43
|
+
* API endpoint for checkout (defaults to /api/stripe/checkout)
|
|
44
|
+
*/
|
|
45
|
+
checkoutEndpoint?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates a checkout client for initiating Stripe checkouts from the frontend.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { createCheckoutClient } from "stripe-no-webhooks/client";
|
|
53
|
+
*
|
|
54
|
+
* const { checkout } = createCheckoutClient();
|
|
55
|
+
*
|
|
56
|
+
* // In your component:
|
|
57
|
+
* <button onClick={() => checkout({ planName: "pro", interval: "month" })}>
|
|
58
|
+
* Subscribe to Pro
|
|
59
|
+
* </button>
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare function createCheckoutClient(config?: CheckoutClientConfig): {
|
|
63
|
+
checkout: (options: CheckoutOptions) => Promise<void>;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Default checkout client instance using /api/stripe/checkout endpoint.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* import { checkout } from "stripe-no-webhooks/client";
|
|
71
|
+
*
|
|
72
|
+
* <button onClick={() => checkout({ planName: "pro", interval: "month" })}>
|
|
73
|
+
* Subscribe to Pro
|
|
74
|
+
* </button>
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
declare const checkout: (options: CheckoutOptions) => Promise<void>;
|
|
78
|
+
|
|
79
|
+
export { type CheckoutClientConfig, type CheckoutOptions, checkout, createCheckoutClient };
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
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/client.ts
|
|
21
|
+
var client_exports = {};
|
|
22
|
+
__export(client_exports, {
|
|
23
|
+
checkout: () => checkout,
|
|
24
|
+
createCheckoutClient: () => createCheckoutClient
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(client_exports);
|
|
27
|
+
function createCheckoutClient(config = {}) {
|
|
28
|
+
const { checkoutEndpoint = "/api/stripe/checkout" } = config;
|
|
29
|
+
async function checkout2(options) {
|
|
30
|
+
const response = await fetch(checkoutEndpoint, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: {
|
|
33
|
+
"Content-Type": "application/json",
|
|
34
|
+
Accept: "application/json"
|
|
35
|
+
},
|
|
36
|
+
body: JSON.stringify(options)
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
const error = await response.json().catch(() => ({}));
|
|
40
|
+
throw new Error(error.error || `Checkout failed: ${response.status}`);
|
|
41
|
+
}
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
if (!data.url) {
|
|
44
|
+
throw new Error("No checkout URL returned");
|
|
45
|
+
}
|
|
46
|
+
window.location.href = data.url;
|
|
47
|
+
}
|
|
48
|
+
return { checkout: checkout2 };
|
|
49
|
+
}
|
|
50
|
+
var { checkout } = createCheckoutClient();
|
|
51
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
52
|
+
0 && (module.exports = {
|
|
53
|
+
checkout,
|
|
54
|
+
createCheckoutClient
|
|
55
|
+
});
|
package/dist/client.mjs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
function createCheckoutClient(config = {}) {
|
|
3
|
+
const { checkoutEndpoint = "/api/stripe/checkout" } = config;
|
|
4
|
+
async function checkout2(options) {
|
|
5
|
+
const response = await fetch(checkoutEndpoint, {
|
|
6
|
+
method: "POST",
|
|
7
|
+
headers: {
|
|
8
|
+
"Content-Type": "application/json",
|
|
9
|
+
Accept: "application/json"
|
|
10
|
+
},
|
|
11
|
+
body: JSON.stringify(options)
|
|
12
|
+
});
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
const error = await response.json().catch(() => ({}));
|
|
15
|
+
throw new Error(error.error || `Checkout failed: ${response.status}`);
|
|
16
|
+
}
|
|
17
|
+
const data = await response.json();
|
|
18
|
+
if (!data.url) {
|
|
19
|
+
throw new Error("No checkout URL returned");
|
|
20
|
+
}
|
|
21
|
+
window.location.href = data.url;
|
|
22
|
+
}
|
|
23
|
+
return { checkout: checkout2 };
|
|
24
|
+
}
|
|
25
|
+
var { checkout } = createCheckoutClient();
|
|
26
|
+
export {
|
|
27
|
+
checkout,
|
|
28
|
+
createCheckoutClient
|
|
29
|
+
};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import Stripe from 'stripe';
|
|
2
|
+
import { B as BillingConfig, P as PriceInterval } from './BillingConfig-BYrAQ7Wx.mjs';
|
|
3
|
+
export { b as Plan, a as Price } from './BillingConfig-BYrAQ7Wx.mjs';
|
|
2
4
|
|
|
3
5
|
interface StripeWebhookCallbacks {
|
|
4
6
|
/**
|
|
@@ -10,28 +12,89 @@ interface StripeWebhookCallbacks {
|
|
|
10
12
|
*/
|
|
11
13
|
onSubscriptionCancelled?: (subscription: Stripe.Subscription) => void | Promise<void>;
|
|
12
14
|
}
|
|
13
|
-
interface
|
|
14
|
-
/**
|
|
15
|
-
* PostgreSQL connection string for the Stripe sync database
|
|
16
|
-
*/
|
|
17
|
-
databaseUrl: string;
|
|
15
|
+
interface StripeHandlerConfig {
|
|
18
16
|
/**
|
|
19
17
|
* Stripe secret key (sk_test_... or sk_live_...)
|
|
18
|
+
* Falls back to STRIPE_SECRET_KEY environment variable
|
|
20
19
|
*/
|
|
21
|
-
stripeSecretKey
|
|
20
|
+
stripeSecretKey?: string;
|
|
22
21
|
/**
|
|
23
22
|
* Stripe webhook signing secret (whsec_...)
|
|
23
|
+
* Falls back to STRIPE_WEBHOOK_SECRET environment variable
|
|
24
24
|
*/
|
|
25
|
-
stripeWebhookSecret
|
|
25
|
+
stripeWebhookSecret?: string;
|
|
26
|
+
/**
|
|
27
|
+
* PostgreSQL connection string for the Stripe sync database
|
|
28
|
+
* Falls back to DATABASE_URL environment variable
|
|
29
|
+
*/
|
|
30
|
+
databaseUrl?: string;
|
|
26
31
|
/**
|
|
27
32
|
* Database schema name (defaults to 'stripe')
|
|
28
33
|
*/
|
|
29
34
|
schema?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Billing configuration containing plans and prices
|
|
37
|
+
*/
|
|
38
|
+
billingConfig?: BillingConfig;
|
|
39
|
+
/**
|
|
40
|
+
* Default success URL (can be overridden per request)
|
|
41
|
+
*/
|
|
42
|
+
successUrl?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Default cancel URL (can be overridden per request)
|
|
45
|
+
*/
|
|
46
|
+
cancelUrl?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Enable automatic tax calculation (defaults to true)
|
|
49
|
+
*/
|
|
50
|
+
automaticTax?: boolean;
|
|
30
51
|
/**
|
|
31
52
|
* Callbacks for subscription events
|
|
32
53
|
*/
|
|
33
54
|
callbacks?: StripeWebhookCallbacks;
|
|
34
55
|
}
|
|
35
|
-
|
|
56
|
+
interface CheckoutRequestBody {
|
|
57
|
+
/**
|
|
58
|
+
* Plan name to look up in billingConfig (use with interval)
|
|
59
|
+
*/
|
|
60
|
+
planName?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Plan ID to look up in billingConfig (use with interval)
|
|
63
|
+
*/
|
|
64
|
+
planId?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Price interval for plan lookup
|
|
67
|
+
*/
|
|
68
|
+
interval?: PriceInterval;
|
|
69
|
+
/**
|
|
70
|
+
* Direct Stripe price ID (bypasses billingConfig lookup)
|
|
71
|
+
*/
|
|
72
|
+
priceId?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Override the success URL for this checkout
|
|
75
|
+
*/
|
|
76
|
+
successUrl?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Override the cancel URL for this checkout
|
|
79
|
+
*/
|
|
80
|
+
cancelUrl?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Quantity of the item (defaults to 1)
|
|
83
|
+
*/
|
|
84
|
+
quantity?: number;
|
|
85
|
+
/**
|
|
86
|
+
* Customer email for prefilling checkout
|
|
87
|
+
*/
|
|
88
|
+
customerEmail?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Existing Stripe customer ID
|
|
91
|
+
*/
|
|
92
|
+
customerId?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Additional metadata to attach to the session
|
|
95
|
+
*/
|
|
96
|
+
metadata?: Record<string, string>;
|
|
97
|
+
}
|
|
98
|
+
declare function createStripeHandler(config?: StripeHandlerConfig): (request: Request) => Promise<Response>;
|
|
36
99
|
|
|
37
|
-
export { type
|
|
100
|
+
export { BillingConfig, type CheckoutRequestBody, PriceInterval, type StripeHandlerConfig, type StripeWebhookCallbacks, createStripeHandler };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import Stripe from 'stripe';
|
|
2
|
+
import { B as BillingConfig, P as PriceInterval } from './BillingConfig-BYrAQ7Wx.js';
|
|
3
|
+
export { b as Plan, a as Price } from './BillingConfig-BYrAQ7Wx.js';
|
|
2
4
|
|
|
3
5
|
interface StripeWebhookCallbacks {
|
|
4
6
|
/**
|
|
@@ -10,28 +12,89 @@ interface StripeWebhookCallbacks {
|
|
|
10
12
|
*/
|
|
11
13
|
onSubscriptionCancelled?: (subscription: Stripe.Subscription) => void | Promise<void>;
|
|
12
14
|
}
|
|
13
|
-
interface
|
|
14
|
-
/**
|
|
15
|
-
* PostgreSQL connection string for the Stripe sync database
|
|
16
|
-
*/
|
|
17
|
-
databaseUrl: string;
|
|
15
|
+
interface StripeHandlerConfig {
|
|
18
16
|
/**
|
|
19
17
|
* Stripe secret key (sk_test_... or sk_live_...)
|
|
18
|
+
* Falls back to STRIPE_SECRET_KEY environment variable
|
|
20
19
|
*/
|
|
21
|
-
stripeSecretKey
|
|
20
|
+
stripeSecretKey?: string;
|
|
22
21
|
/**
|
|
23
22
|
* Stripe webhook signing secret (whsec_...)
|
|
23
|
+
* Falls back to STRIPE_WEBHOOK_SECRET environment variable
|
|
24
24
|
*/
|
|
25
|
-
stripeWebhookSecret
|
|
25
|
+
stripeWebhookSecret?: string;
|
|
26
|
+
/**
|
|
27
|
+
* PostgreSQL connection string for the Stripe sync database
|
|
28
|
+
* Falls back to DATABASE_URL environment variable
|
|
29
|
+
*/
|
|
30
|
+
databaseUrl?: string;
|
|
26
31
|
/**
|
|
27
32
|
* Database schema name (defaults to 'stripe')
|
|
28
33
|
*/
|
|
29
34
|
schema?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Billing configuration containing plans and prices
|
|
37
|
+
*/
|
|
38
|
+
billingConfig?: BillingConfig;
|
|
39
|
+
/**
|
|
40
|
+
* Default success URL (can be overridden per request)
|
|
41
|
+
*/
|
|
42
|
+
successUrl?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Default cancel URL (can be overridden per request)
|
|
45
|
+
*/
|
|
46
|
+
cancelUrl?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Enable automatic tax calculation (defaults to true)
|
|
49
|
+
*/
|
|
50
|
+
automaticTax?: boolean;
|
|
30
51
|
/**
|
|
31
52
|
* Callbacks for subscription events
|
|
32
53
|
*/
|
|
33
54
|
callbacks?: StripeWebhookCallbacks;
|
|
34
55
|
}
|
|
35
|
-
|
|
56
|
+
interface CheckoutRequestBody {
|
|
57
|
+
/**
|
|
58
|
+
* Plan name to look up in billingConfig (use with interval)
|
|
59
|
+
*/
|
|
60
|
+
planName?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Plan ID to look up in billingConfig (use with interval)
|
|
63
|
+
*/
|
|
64
|
+
planId?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Price interval for plan lookup
|
|
67
|
+
*/
|
|
68
|
+
interval?: PriceInterval;
|
|
69
|
+
/**
|
|
70
|
+
* Direct Stripe price ID (bypasses billingConfig lookup)
|
|
71
|
+
*/
|
|
72
|
+
priceId?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Override the success URL for this checkout
|
|
75
|
+
*/
|
|
76
|
+
successUrl?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Override the cancel URL for this checkout
|
|
79
|
+
*/
|
|
80
|
+
cancelUrl?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Quantity of the item (defaults to 1)
|
|
83
|
+
*/
|
|
84
|
+
quantity?: number;
|
|
85
|
+
/**
|
|
86
|
+
* Customer email for prefilling checkout
|
|
87
|
+
*/
|
|
88
|
+
customerEmail?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Existing Stripe customer ID
|
|
91
|
+
*/
|
|
92
|
+
customerId?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Additional metadata to attach to the session
|
|
95
|
+
*/
|
|
96
|
+
metadata?: Record<string, string>;
|
|
97
|
+
}
|
|
98
|
+
declare function createStripeHandler(config?: StripeHandlerConfig): (request: Request) => Promise<Response>;
|
|
36
99
|
|
|
37
|
-
export { type
|
|
100
|
+
export { BillingConfig, type CheckoutRequestBody, PriceInterval, type StripeHandlerConfig, type StripeWebhookCallbacks, createStripeHandler };
|
package/dist/index.js
CHANGED
|
@@ -30,31 +30,131 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
|
|
33
|
+
createStripeHandler: () => createStripeHandler
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
37
|
// src/handler.ts
|
|
38
38
|
var import_stripe_sync_engine = require("@supabase/stripe-sync-engine");
|
|
39
39
|
var import_stripe = __toESM(require("stripe"));
|
|
40
|
-
function
|
|
40
|
+
function createStripeHandler(config = {}) {
|
|
41
41
|
const {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
stripeSecretKey = process.env.STRIPE_SECRET_KEY,
|
|
43
|
+
stripeWebhookSecret = process.env.STRIPE_WEBHOOK_SECRET,
|
|
44
|
+
databaseUrl = process.env.DATABASE_URL,
|
|
45
45
|
schema = "stripe",
|
|
46
|
+
billingConfig,
|
|
47
|
+
successUrl: defaultSuccessUrl,
|
|
48
|
+
cancelUrl: defaultCancelUrl,
|
|
49
|
+
automaticTax = true,
|
|
46
50
|
callbacks
|
|
47
51
|
} = config;
|
|
48
|
-
const
|
|
52
|
+
const stripe = new import_stripe.default(stripeSecretKey);
|
|
53
|
+
const sync = databaseUrl ? new import_stripe_sync_engine.StripeSync({
|
|
49
54
|
poolConfig: {
|
|
50
55
|
connectionString: databaseUrl
|
|
51
56
|
},
|
|
52
57
|
schema,
|
|
53
58
|
stripeSecretKey,
|
|
54
59
|
stripeWebhookSecret
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
}) : null;
|
|
61
|
+
function resolvePriceId(body) {
|
|
62
|
+
if (body.priceId) {
|
|
63
|
+
return body.priceId;
|
|
64
|
+
}
|
|
65
|
+
if (!body.interval) {
|
|
66
|
+
throw new Error("interval is required when using planName or planId");
|
|
67
|
+
}
|
|
68
|
+
if (!billingConfig?.plans) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
"billingConfig with plans is required when using planName or planId"
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
const plan = body.planName ? billingConfig.plans.find((p) => p.name === body.planName) : body.planId ? billingConfig.plans.find((p) => p.id === body.planId) : null;
|
|
74
|
+
if (!plan) {
|
|
75
|
+
const identifier = body.planName || body.planId;
|
|
76
|
+
throw new Error(`Plan not found: ${identifier}`);
|
|
77
|
+
}
|
|
78
|
+
const price = plan.price.find((p) => p.interval === body.interval);
|
|
79
|
+
if (!price) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Price with interval "${body.interval}" not found for plan "${plan.name}"`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
if (!price.id) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Price ID not set for plan "${plan.name}" with interval "${body.interval}". Run stripe-sync to sync price IDs.`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return price.id;
|
|
90
|
+
}
|
|
91
|
+
async function getPriceMode(priceId) {
|
|
92
|
+
const price = await stripe.prices.retrieve(priceId);
|
|
93
|
+
return price.type === "recurring" ? "subscription" : "payment";
|
|
94
|
+
}
|
|
95
|
+
async function handleCheckout(request) {
|
|
96
|
+
try {
|
|
97
|
+
const body = await request.json();
|
|
98
|
+
if (!body.priceId && !body.planName && !body.planId) {
|
|
99
|
+
return new Response(
|
|
100
|
+
JSON.stringify({
|
|
101
|
+
error: "Provide either priceId, planName+interval, or planId+interval"
|
|
102
|
+
}),
|
|
103
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
const origin = request.headers.get("origin") || "";
|
|
107
|
+
const successUrl = body.successUrl || defaultSuccessUrl || `${origin}/success?session_id={CHECKOUT_SESSION_ID}`;
|
|
108
|
+
const cancelUrl = body.cancelUrl || defaultCancelUrl || `${origin}/`;
|
|
109
|
+
const priceId = resolvePriceId(body);
|
|
110
|
+
const mode = await getPriceMode(priceId);
|
|
111
|
+
const sessionParams = {
|
|
112
|
+
line_items: [
|
|
113
|
+
{
|
|
114
|
+
price: priceId,
|
|
115
|
+
quantity: body.quantity ?? 1
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
mode,
|
|
119
|
+
success_url: successUrl,
|
|
120
|
+
cancel_url: cancelUrl,
|
|
121
|
+
automatic_tax: { enabled: automaticTax }
|
|
122
|
+
};
|
|
123
|
+
if (body.customerEmail) {
|
|
124
|
+
sessionParams.customer_email = body.customerEmail;
|
|
125
|
+
}
|
|
126
|
+
if (body.customerId) {
|
|
127
|
+
sessionParams.customer = body.customerId;
|
|
128
|
+
}
|
|
129
|
+
if (body.metadata) {
|
|
130
|
+
sessionParams.metadata = body.metadata;
|
|
131
|
+
}
|
|
132
|
+
const session = await stripe.checkout.sessions.create(sessionParams);
|
|
133
|
+
if (!session.url) {
|
|
134
|
+
return new Response(
|
|
135
|
+
JSON.stringify({ error: "Failed to create checkout session" }),
|
|
136
|
+
{ status: 500, headers: { "Content-Type": "application/json" } }
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const acceptHeader = request.headers.get("accept") || "";
|
|
140
|
+
if (acceptHeader.includes("application/json")) {
|
|
141
|
+
return new Response(JSON.stringify({ url: session.url }), {
|
|
142
|
+
status: 200,
|
|
143
|
+
headers: { "Content-Type": "application/json" }
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return Response.redirect(session.url, 303);
|
|
147
|
+
} catch (err) {
|
|
148
|
+
console.error("Checkout error:", err);
|
|
149
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
150
|
+
const status = err && typeof err === "object" && "statusCode" in err ? err.statusCode : 500;
|
|
151
|
+
return new Response(JSON.stringify({ error: message }), {
|
|
152
|
+
status,
|
|
153
|
+
headers: { "Content-Type": "application/json" }
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function handleWebhook(request) {
|
|
58
158
|
try {
|
|
59
159
|
const body = await request.text();
|
|
60
160
|
const signature = request.headers.get("stripe-signature");
|
|
@@ -75,7 +175,9 @@ function createStripeWebhookHandler(config) {
|
|
|
75
175
|
{ status: 400 }
|
|
76
176
|
);
|
|
77
177
|
}
|
|
78
|
-
|
|
178
|
+
if (sync) {
|
|
179
|
+
await sync.processWebhook(body, signature);
|
|
180
|
+
}
|
|
79
181
|
if (callbacks) {
|
|
80
182
|
await handleCallbacks(event, callbacks);
|
|
81
183
|
}
|
|
@@ -88,6 +190,30 @@ function createStripeWebhookHandler(config) {
|
|
|
88
190
|
const message = error instanceof Error ? error.message : "Internal server error";
|
|
89
191
|
return new Response(message, { status: 500 });
|
|
90
192
|
}
|
|
193
|
+
}
|
|
194
|
+
return async function handler(request) {
|
|
195
|
+
const url = new URL(request.url);
|
|
196
|
+
const pathSegments = url.pathname.split("/").filter(Boolean);
|
|
197
|
+
const action = pathSegments[pathSegments.length - 1];
|
|
198
|
+
if (request.method !== "POST") {
|
|
199
|
+
return new Response(JSON.stringify({ error: "Method not allowed" }), {
|
|
200
|
+
status: 405,
|
|
201
|
+
headers: { "Content-Type": "application/json" }
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
switch (action) {
|
|
205
|
+
case "checkout":
|
|
206
|
+
return handleCheckout(request);
|
|
207
|
+
case "webhook":
|
|
208
|
+
return handleWebhook(request);
|
|
209
|
+
default:
|
|
210
|
+
return new Response(
|
|
211
|
+
JSON.stringify({
|
|
212
|
+
error: `Unknown action: ${action}. Supported: checkout, webhook`
|
|
213
|
+
}),
|
|
214
|
+
{ status: 404, headers: { "Content-Type": "application/json" } }
|
|
215
|
+
);
|
|
216
|
+
}
|
|
91
217
|
};
|
|
92
218
|
}
|
|
93
219
|
async function handleCallbacks(event, callbacks) {
|
|
@@ -114,5 +240,5 @@ async function handleCallbacks(event, callbacks) {
|
|
|
114
240
|
}
|
|
115
241
|
// Annotate the CommonJS export names for ESM import in node:
|
|
116
242
|
0 && (module.exports = {
|
|
117
|
-
|
|
243
|
+
createStripeHandler
|
|
118
244
|
});
|