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.
@@ -0,0 +1,54 @@
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 OnDemandTopUp = {
9
+ mode: "on_demand";
10
+ pricePerCreditCents: number;
11
+ minPerPurchase?: number;
12
+ maxPerPurchase?: number;
13
+ };
14
+ type AutoTopUp = {
15
+ mode: "auto";
16
+ pricePerCreditCents: number;
17
+ balanceThreshold: number;
18
+ purchaseAmount: number;
19
+ maxPerMonth?: number;
20
+ };
21
+ type CreditConfig = {
22
+ allocation: number;
23
+ displayName?: string;
24
+ /**
25
+ * What happens on renewal (default: 'reset')
26
+ * - 'reset': Set balance to allocation (unused credits expire)
27
+ * - 'add': Add allocation to current balance (credits accumulate)
28
+ */
29
+ onRenewal?: "reset" | "add";
30
+ topUp?: OnDemandTopUp | AutoTopUp;
31
+ };
32
+ type Plan = {
33
+ id?: string;
34
+ name: string;
35
+ description?: string;
36
+ price: Price[];
37
+ credits?: Record<string, CreditConfig>;
38
+ /**
39
+ * Enable per-seat billing for this plan.
40
+ * When true, addSeat/removeSeat will update Stripe subscription quantity.
41
+ * Stripe automatically prorates charges when quantity changes.
42
+ */
43
+ perSeat?: boolean;
44
+ };
45
+ type BillingConfig = {
46
+ test?: {
47
+ plans?: Plan[];
48
+ };
49
+ production?: {
50
+ plans?: Plan[];
51
+ };
52
+ };
53
+
54
+ export type { AutoTopUp as A, BillingConfig as B, CreditConfig as C, OnDemandTopUp as O, PriceInterval as P, Price as a, Plan as b };
@@ -0,0 +1,54 @@
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 OnDemandTopUp = {
9
+ mode: "on_demand";
10
+ pricePerCreditCents: number;
11
+ minPerPurchase?: number;
12
+ maxPerPurchase?: number;
13
+ };
14
+ type AutoTopUp = {
15
+ mode: "auto";
16
+ pricePerCreditCents: number;
17
+ balanceThreshold: number;
18
+ purchaseAmount: number;
19
+ maxPerMonth?: number;
20
+ };
21
+ type CreditConfig = {
22
+ allocation: number;
23
+ displayName?: string;
24
+ /**
25
+ * What happens on renewal (default: 'reset')
26
+ * - 'reset': Set balance to allocation (unused credits expire)
27
+ * - 'add': Add allocation to current balance (credits accumulate)
28
+ */
29
+ onRenewal?: "reset" | "add";
30
+ topUp?: OnDemandTopUp | AutoTopUp;
31
+ };
32
+ type Plan = {
33
+ id?: string;
34
+ name: string;
35
+ description?: string;
36
+ price: Price[];
37
+ credits?: Record<string, CreditConfig>;
38
+ /**
39
+ * Enable per-seat billing for this plan.
40
+ * When true, addSeat/removeSeat will update Stripe subscription quantity.
41
+ * Stripe automatically prorates charges when quantity changes.
42
+ */
43
+ perSeat?: boolean;
44
+ };
45
+ type BillingConfig = {
46
+ test?: {
47
+ plans?: Plan[];
48
+ };
49
+ production?: {
50
+ plans?: Plan[];
51
+ };
52
+ };
53
+
54
+ export type { AutoTopUp as A, BillingConfig as B, CreditConfig as C, OnDemandTopUp as O, PriceInterval as P, Price as a, Plan as b };
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { P as PriceInterval } from './BillingConfig-n6VbfqGY.mjs';
1
+ import { P as PriceInterval } from './BillingConfig-CpHPJg4Q.mjs';
2
2
 
3
3
  interface CheckoutOptions {
4
4
  /**
@@ -21,10 +21,6 @@ interface CheckoutOptions {
21
21
  * Quantity of the item (defaults to 1)
22
22
  */
23
23
  quantity?: number;
24
- /**
25
- * Customer email for prefilling checkout
26
- */
27
- customerEmail?: string;
28
24
  /**
29
25
  * Override success URL for this checkout
30
26
  */
@@ -43,6 +39,28 @@ interface CheckoutClientConfig {
43
39
  * API endpoint for checkout (defaults to /api/stripe/checkout)
44
40
  */
45
41
  checkoutEndpoint?: string;
42
+ /**
43
+ * API endpoint for customer portal (defaults to /api/stripe/customer_portal)
44
+ */
45
+ customerPortalEndpoint?: string;
46
+ /**
47
+ * Called when loading state changes (start/end of API calls)
48
+ */
49
+ onLoading?: (isLoading: boolean) => void;
50
+ /**
51
+ * Called when an error occurs during checkout or portal access
52
+ */
53
+ onError?: (error: Error) => void;
54
+ /**
55
+ * Called right before redirecting to Stripe (checkout or portal)
56
+ */
57
+ onRedirect?: (url: string) => void;
58
+ /**
59
+ * Called when a plan switch completes successfully.
60
+ * Receives the redirect URL. Component is responsible for showing success UI
61
+ * and redirecting after a delay.
62
+ */
63
+ onPlanChanged?: (redirectUrl: string) => void;
46
64
  }
47
65
  /**
48
66
  * Creates a checkout client for initiating Stripe checkouts from the frontend.
@@ -61,19 +79,25 @@ interface CheckoutClientConfig {
61
79
  */
62
80
  declare function createCheckoutClient(config?: CheckoutClientConfig): {
63
81
  checkout: (options: CheckoutOptions) => Promise<void>;
82
+ customerPortal: () => Promise<void>;
64
83
  };
65
84
  /**
66
- * Default checkout client instance using /api/stripe/checkout endpoint.
85
+ * Default client instance using /api/stripe endpoints.
67
86
  *
68
87
  * @example
69
88
  * ```ts
70
- * import { checkout } from "stripe-no-webhooks/client";
89
+ * import { checkout, customerPortal } from "stripe-no-webhooks/client";
71
90
  *
72
91
  * <button onClick={() => checkout({ planName: "pro", interval: "month" })}>
73
92
  * Subscribe to Pro
74
93
  * </button>
94
+ *
95
+ * <button onClick={() => customerPortal()}>
96
+ * Manage Billing
97
+ * </button>
75
98
  * ```
76
99
  */
77
100
  declare const checkout: (options: CheckoutOptions) => Promise<void>;
101
+ declare const customerPortal: () => Promise<void>;
78
102
 
79
- export { type CheckoutClientConfig, type CheckoutOptions, checkout, createCheckoutClient };
103
+ export { type CheckoutClientConfig, type CheckoutOptions, checkout, createCheckoutClient, customerPortal };
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { P as PriceInterval } from './BillingConfig-n6VbfqGY.js';
1
+ import { P as PriceInterval } from './BillingConfig-CpHPJg4Q.js';
2
2
 
3
3
  interface CheckoutOptions {
4
4
  /**
@@ -21,10 +21,6 @@ interface CheckoutOptions {
21
21
  * Quantity of the item (defaults to 1)
22
22
  */
23
23
  quantity?: number;
24
- /**
25
- * Customer email for prefilling checkout
26
- */
27
- customerEmail?: string;
28
24
  /**
29
25
  * Override success URL for this checkout
30
26
  */
@@ -43,6 +39,28 @@ interface CheckoutClientConfig {
43
39
  * API endpoint for checkout (defaults to /api/stripe/checkout)
44
40
  */
45
41
  checkoutEndpoint?: string;
42
+ /**
43
+ * API endpoint for customer portal (defaults to /api/stripe/customer_portal)
44
+ */
45
+ customerPortalEndpoint?: string;
46
+ /**
47
+ * Called when loading state changes (start/end of API calls)
48
+ */
49
+ onLoading?: (isLoading: boolean) => void;
50
+ /**
51
+ * Called when an error occurs during checkout or portal access
52
+ */
53
+ onError?: (error: Error) => void;
54
+ /**
55
+ * Called right before redirecting to Stripe (checkout or portal)
56
+ */
57
+ onRedirect?: (url: string) => void;
58
+ /**
59
+ * Called when a plan switch completes successfully.
60
+ * Receives the redirect URL. Component is responsible for showing success UI
61
+ * and redirecting after a delay.
62
+ */
63
+ onPlanChanged?: (redirectUrl: string) => void;
46
64
  }
47
65
  /**
48
66
  * Creates a checkout client for initiating Stripe checkouts from the frontend.
@@ -61,19 +79,25 @@ interface CheckoutClientConfig {
61
79
  */
62
80
  declare function createCheckoutClient(config?: CheckoutClientConfig): {
63
81
  checkout: (options: CheckoutOptions) => Promise<void>;
82
+ customerPortal: () => Promise<void>;
64
83
  };
65
84
  /**
66
- * Default checkout client instance using /api/stripe/checkout endpoint.
85
+ * Default client instance using /api/stripe endpoints.
67
86
  *
68
87
  * @example
69
88
  * ```ts
70
- * import { checkout } from "stripe-no-webhooks/client";
89
+ * import { checkout, customerPortal } from "stripe-no-webhooks/client";
71
90
  *
72
91
  * <button onClick={() => checkout({ planName: "pro", interval: "month" })}>
73
92
  * Subscribe to Pro
74
93
  * </button>
94
+ *
95
+ * <button onClick={() => customerPortal()}>
96
+ * Manage Billing
97
+ * </button>
75
98
  * ```
76
99
  */
77
100
  declare const checkout: (options: CheckoutOptions) => Promise<void>;
101
+ declare const customerPortal: () => Promise<void>;
78
102
 
79
- export { type CheckoutClientConfig, type CheckoutOptions, checkout, createCheckoutClient };
103
+ export { type CheckoutClientConfig, type CheckoutOptions, checkout, createCheckoutClient, customerPortal };
package/dist/client.js CHANGED
@@ -21,35 +21,97 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var client_exports = {};
22
22
  __export(client_exports, {
23
23
  checkout: () => checkout,
24
- createCheckoutClient: () => createCheckoutClient
24
+ createCheckoutClient: () => createCheckoutClient,
25
+ customerPortal: () => customerPortal
25
26
  });
26
27
  module.exports = __toCommonJS(client_exports);
27
28
  function createCheckoutClient(config = {}) {
28
- const { checkoutEndpoint = "/api/stripe/checkout" } = config;
29
+ const {
30
+ checkoutEndpoint = "/api/stripe/checkout",
31
+ customerPortalEndpoint = "/api/stripe/customer_portal",
32
+ onLoading,
33
+ onError,
34
+ onRedirect,
35
+ onPlanChanged
36
+ } = config;
29
37
  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) {
38
+ try {
39
+ onLoading?.(true);
40
+ const response = await fetch(checkoutEndpoint, {
41
+ method: "POST",
42
+ headers: {
43
+ "Content-Type": "application/json",
44
+ Accept: "application/json"
45
+ },
46
+ body: JSON.stringify(options)
47
+ });
48
+ if (!response.ok) {
49
+ const errorData = await response.json().catch(() => ({}));
50
+ throw new Error(errorData.error || `Checkout failed: ${response.status}`);
51
+ }
52
+ const data = await response.json();
53
+ if (data.alreadySubscribed) {
54
+ onLoading?.(false);
55
+ return;
56
+ }
57
+ if (data.success && data.redirectUrl) {
58
+ onLoading?.(false);
59
+ if (onPlanChanged) {
60
+ onPlanChanged(data.redirectUrl);
61
+ return;
62
+ }
63
+ onRedirect?.(data.redirectUrl);
64
+ window.location.href = data.redirectUrl;
65
+ return;
66
+ }
67
+ if (data.url) {
68
+ onRedirect?.(data.url);
69
+ window.location.href = data.url;
70
+ return;
71
+ }
44
72
  throw new Error("No checkout URL returned");
73
+ } catch (err) {
74
+ onLoading?.(false);
75
+ const error = err instanceof Error ? err : new Error(String(err));
76
+ onError?.(error);
77
+ throw error;
78
+ }
79
+ }
80
+ async function customerPortal2() {
81
+ try {
82
+ onLoading?.(true);
83
+ const response = await fetch(customerPortalEndpoint, {
84
+ method: "POST",
85
+ headers: {
86
+ "Content-Type": "application/json",
87
+ Accept: "application/json"
88
+ }
89
+ });
90
+ if (!response.ok) {
91
+ const errorData = await response.json().catch(() => ({}));
92
+ throw new Error(
93
+ errorData.error || `Customer portal failed: ${response.status}`
94
+ );
95
+ }
96
+ const data = await response.json();
97
+ if (!data.url) {
98
+ throw new Error("No portal URL returned");
99
+ }
100
+ onRedirect?.(data.url);
101
+ window.location.href = data.url;
102
+ } catch (err) {
103
+ onLoading?.(false);
104
+ const error = err instanceof Error ? err : new Error(String(err));
105
+ onError?.(error);
106
+ throw error;
45
107
  }
46
- window.location.href = data.url;
47
108
  }
48
- return { checkout: checkout2 };
109
+ return { checkout: checkout2, customerPortal: customerPortal2 };
49
110
  }
50
- var { checkout } = createCheckoutClient();
111
+ var { checkout, customerPortal } = createCheckoutClient();
51
112
  // Annotate the CommonJS export names for ESM import in node:
52
113
  0 && (module.exports = {
53
114
  checkout,
54
- createCheckoutClient
115
+ createCheckoutClient,
116
+ customerPortal
55
117
  });
package/dist/client.mjs CHANGED
@@ -1,29 +1,90 @@
1
1
  // src/client.ts
2
2
  function createCheckoutClient(config = {}) {
3
- const { checkoutEndpoint = "/api/stripe/checkout" } = config;
3
+ const {
4
+ checkoutEndpoint = "/api/stripe/checkout",
5
+ customerPortalEndpoint = "/api/stripe/customer_portal",
6
+ onLoading,
7
+ onError,
8
+ onRedirect,
9
+ onPlanChanged
10
+ } = config;
4
11
  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) {
12
+ try {
13
+ onLoading?.(true);
14
+ const response = await fetch(checkoutEndpoint, {
15
+ method: "POST",
16
+ headers: {
17
+ "Content-Type": "application/json",
18
+ Accept: "application/json"
19
+ },
20
+ body: JSON.stringify(options)
21
+ });
22
+ if (!response.ok) {
23
+ const errorData = await response.json().catch(() => ({}));
24
+ throw new Error(errorData.error || `Checkout failed: ${response.status}`);
25
+ }
26
+ const data = await response.json();
27
+ if (data.alreadySubscribed) {
28
+ onLoading?.(false);
29
+ return;
30
+ }
31
+ if (data.success && data.redirectUrl) {
32
+ onLoading?.(false);
33
+ if (onPlanChanged) {
34
+ onPlanChanged(data.redirectUrl);
35
+ return;
36
+ }
37
+ onRedirect?.(data.redirectUrl);
38
+ window.location.href = data.redirectUrl;
39
+ return;
40
+ }
41
+ if (data.url) {
42
+ onRedirect?.(data.url);
43
+ window.location.href = data.url;
44
+ return;
45
+ }
19
46
  throw new Error("No checkout URL returned");
47
+ } catch (err) {
48
+ onLoading?.(false);
49
+ const error = err instanceof Error ? err : new Error(String(err));
50
+ onError?.(error);
51
+ throw error;
52
+ }
53
+ }
54
+ async function customerPortal2() {
55
+ try {
56
+ onLoading?.(true);
57
+ const response = await fetch(customerPortalEndpoint, {
58
+ method: "POST",
59
+ headers: {
60
+ "Content-Type": "application/json",
61
+ Accept: "application/json"
62
+ }
63
+ });
64
+ if (!response.ok) {
65
+ const errorData = await response.json().catch(() => ({}));
66
+ throw new Error(
67
+ errorData.error || `Customer portal failed: ${response.status}`
68
+ );
69
+ }
70
+ const data = await response.json();
71
+ if (!data.url) {
72
+ throw new Error("No portal URL returned");
73
+ }
74
+ onRedirect?.(data.url);
75
+ window.location.href = data.url;
76
+ } catch (err) {
77
+ onLoading?.(false);
78
+ const error = err instanceof Error ? err : new Error(String(err));
79
+ onError?.(error);
80
+ throw error;
20
81
  }
21
- window.location.href = data.url;
22
82
  }
23
- return { checkout: checkout2 };
83
+ return { checkout: checkout2, customerPortal: customerPortal2 };
24
84
  }
25
- var { checkout } = createCheckoutClient();
85
+ var { checkout, customerPortal } = createCheckoutClient();
26
86
  export {
27
87
  checkout,
28
- createCheckoutClient
88
+ createCheckoutClient,
89
+ customerPortal
29
90
  };