@donotdev/billing 0.0.2 → 0.0.3
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/dist/components/StripeCheckoutButton.d.ts +1 -1
- package/dist/components/StripeCheckoutButton.d.ts.map +1 -1
- package/dist/components/StripeCheckoutButton.js +1 -1
- package/dist/components/SubscriptionManager.d.ts +1 -1
- package/dist/components/SubscriptionManager.d.ts.map +1 -1
- package/dist/components/SubscriptionManager.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/useStripeBilling.d.ts +12 -15
- package/dist/useStripeBilling.d.ts.map +1 -1
- package/dist/useStripeBilling.js +1 -1
- package/package.json +5 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AuthUser, BillingAPI } from '@donotdev/core';
|
|
1
|
+
import type { AuthUser, BillingAPI, FeatureStatus } from '@donotdev/core';
|
|
2
2
|
/**
|
|
3
3
|
* Auth state passed from parent component.
|
|
4
4
|
* Required for billing to work - removes race condition from dynamic import.
|
|
@@ -9,8 +9,7 @@ import type { AuthUser, BillingAPI } from '@donotdev/core';
|
|
|
9
9
|
*/
|
|
10
10
|
export interface BillingAuthState {
|
|
11
11
|
user: AuthUser | null;
|
|
12
|
-
|
|
13
|
-
authStateChecked: boolean;
|
|
12
|
+
status: FeatureStatus;
|
|
14
13
|
}
|
|
15
14
|
/**
|
|
16
15
|
* React hook for Stripe billing with property-based access
|
|
@@ -19,18 +18,17 @@ export interface BillingAuthState {
|
|
|
19
18
|
* Uses local state for loading/error (no store needed). Lazy loads Firebase SDK only when methods are called.
|
|
20
19
|
*
|
|
21
20
|
* **IMPORTANT:** Auth state must be passed from parent component to avoid race conditions.
|
|
22
|
-
* The hook returns `isAvailable: false` until auth is
|
|
21
|
+
* The hook returns `isAvailable: false` until auth status is `ready`.
|
|
23
22
|
*
|
|
24
23
|
* **Property-based access (matches useAuth pattern):**
|
|
25
24
|
* ```typescript
|
|
26
25
|
* // ✅ First, get auth state from useAuth
|
|
27
26
|
* const user = useAuth('user');
|
|
28
|
-
* const
|
|
29
|
-
* const
|
|
30
|
-
* const authState = { user, initialized, authStateChecked };
|
|
27
|
+
* const status = useAuth('status'); // 'initializing' | 'ready' | 'degraded' | 'error'
|
|
28
|
+
* const authState = { user, status };
|
|
31
29
|
*
|
|
32
30
|
* // ✅ State (reactive, re-renders on change)
|
|
33
|
-
* const
|
|
31
|
+
* const billingStatus = useStripeBilling('status', authState);
|
|
34
32
|
* const error = useStripeBilling('error', authState);
|
|
35
33
|
* const isAvailable = useStripeBilling('isAvailable', authState);
|
|
36
34
|
*
|
|
@@ -53,24 +51,23 @@ export interface BillingAuthState {
|
|
|
53
51
|
*
|
|
54
52
|
* @template K - The property key from BillingAPI
|
|
55
53
|
* @param key - Property name to access (loading, error, checkout, cancelSubscription, changePlan, refreshStatus, openCustomerPortal, clearError, isAvailable)
|
|
56
|
-
* @param authState - Auth state from useAuth hook (user,
|
|
54
|
+
* @param authState - Auth state from useAuth hook (user, status)
|
|
57
55
|
* @returns The value of the specified property
|
|
58
56
|
*
|
|
59
57
|
* @example
|
|
60
58
|
* ```typescript
|
|
61
59
|
* // Get auth state first (required)
|
|
62
60
|
* const user = useAuth('user');
|
|
63
|
-
* const
|
|
64
|
-
* const
|
|
65
|
-
* const authState = { user, initialized, authStateChecked };
|
|
61
|
+
* const status = useAuth('status');
|
|
62
|
+
* const authState = { user, status };
|
|
66
63
|
*
|
|
67
64
|
* // Check if billing is available before showing UI
|
|
68
65
|
* const isAvailable = useStripeBilling('isAvailable', authState);
|
|
69
66
|
* if (!isAvailable) return null; // Wait for auth
|
|
70
67
|
*
|
|
71
|
-
* // Get
|
|
72
|
-
* const
|
|
73
|
-
* if (
|
|
68
|
+
* // Get billing status (re-renders when status changes)
|
|
69
|
+
* const billingStatus = useStripeBilling('status', authState);
|
|
70
|
+
* if (billingStatus === 'initializing') return <Spinner />;
|
|
74
71
|
*
|
|
75
72
|
* // Get checkout method (stable, never re-renders)
|
|
76
73
|
* const checkout = useStripeBilling('checkout', authState);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStripeBilling.d.ts","sourceRoot":"","sources":["../src/useStripeBilling.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useStripeBilling.d.ts","sourceRoot":"","sources":["../src/useStripeBilling.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EAIV,aAAa,EACd,MAAM,gBAAgB,CAAC;AAqBxB;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,UAAU,EACzD,GAAG,EAAE,CAAC,EACN,SAAS,CAAC,EAAE,gBAAgB,GAC3B,UAAU,CAAC,CAAC,CAAC,CA+Vf"}
|
package/dist/useStripeBilling.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{useState as
|
|
1
|
+
"use client";import{useState as S,useCallback as c}from"react";import{DEGRADED_BILLING_API as N,FEATURE_STATUS as l,isClient as F,handleError as u,getPlatformEnvVar as d,FRAMEWORK_FEATURES as x,redirectToExternalUrlWithErrorHandling as M,useFeatureConsent as L}from"@donotdev/core";import{getFirebaseFunctions as w,httpsCallable as I}from"@donotdev/firebase";let h=!1;function K(i,E){const t=E?.user??null,p=(E?.status??l.DEGRADED)===l.READY,m=L(x.BILLING),[Y,a]=S(!1),[R,o]=S(null),A=c(async r=>{if(!F()||!m)throw new Error("Billing not available in SSR or consent required");if(!t){const e=u(new Error("User must be authenticated"),{userMessage:"Please sign in to continue with checkout.",severity:"warning"});throw o(e.message),e}a(!0),o(null);try{const e=d("FIREBASE_FUNCTIONS_REGION")||"europe-west1",s=await w(e),n=I(s,"createCheckoutSession"),f=t.providerData?.find(k=>k.providerId==="github.com"),y=f?.displayName,U=f?.uid,O={priceId:r.priceId,userId:t.id,userEmail:t.email||"",customerEmail:t.email||"",metadata:{firebaseUid:t.id,...y&&{githubUsername:y},...U&&{githubUid:U},...r.metadata},successUrl:r.successUrl||`${typeof window<"u"?window.location.origin:""}/billing/success`,cancelUrl:r.cancelUrl||(typeof window<"u"?window.location.href:""),allowPromotionCodes:r.allowPromotionCodes??!0,mode:r.mode},D=await n(O),{sessionId:B,sessionUrl:b}=D.data;if(!b)throw new Error("No checkout URL received from server");return h=!1,{sessionId:B,sessionUrl:b,success:!0,error:void 0}}catch(e){if(h){const s=e instanceof Error?e:new Error("Checkout failed");throw o(s.message),s}else{const s=u(e,{userMessage:"Unable to start checkout. Please try again or contact support if the problem persists.",context:{priceId:r.priceId,mode:r.mode},severity:"error"});throw o(s.message),h=!0,s}}finally{a(!1)}},[t,m]),C=c(async()=>{if(!t)throw new Error("User must be authenticated");a(!0),o(null);try{const r=d("FIREBASE_FUNCTIONS_REGION")||"europe-west1",e=await w(r);return(await I(e,"cancelSubscription")({userId:t.id})).data}catch(r){const e=u(r,{userMessage:"Failed to cancel subscription. Please try again or contact support.",context:{operation:"cancelSubscription",userId:t.id},severity:"error"});throw o(e.message),e}finally{a(!1)}},[t]),P=c(async(r,e)=>{if(!t)throw new Error("User must be authenticated");a(!0),o(null);try{const s=d("FIREBASE_FUNCTIONS_REGION")||"europe-west1",n=await w(s);return(await I(n,"changePlan")({userId:t.id,newPriceId:r,billingConfigKey:e})).data}catch(s){const n=u(s,{userMessage:"Failed to change plan. Please try again or contact support.",context:{operation:"changePlan",userId:t.id,newPriceId:r,billingConfigKey:e},severity:"error"});throw o(n.message),n}finally{a(!1)}},[t]),v=c(async()=>{if(!t)throw new Error("User must be authenticated");a(!0),o(null);try{const r=d("FIREBASE_FUNCTIONS_REGION")||"europe-west1",e=await w(r);await I(e,"refreshSubscriptionStatus")({userId:t.id})}catch(r){const e=u(r,{userMessage:"Failed to refresh subscription status. Please try again.",context:{operation:"refreshStatus",userId:t.id},severity:"error"});throw o(e.message),e}finally{a(!1)}},[t]),_=c(async r=>{if(!t)throw new Error("User must be authenticated");a(!0),o(null);try{const e=d("FIREBASE_FUNCTIONS_REGION")||"europe-west1",s=await w(e),n=await I(s,"createCustomerPortal")({userId:t.id,returnUrl:r||(typeof window<"u"?window.location.href:"")});await M(n.data.url,{},"Failed to redirect to customer portal")}catch(e){const s=u(e,{userMessage:"Failed to open customer portal. Please try again or contact support.",context:{operation:"openCustomerPortal",userId:t.id},severity:"error"});throw o(s.message),s}finally{a(!1)}},[t]),T=c(()=>{o(null),h=!1},[]),g={checkout:A,cancelSubscription:C,changePlan:P,refreshStatus:v,openCustomerPortal:_,clearError:T};if(!F()||!m)return N[i];const G=p?l.READY:l.INITIALIZING;return i==="status"?G:i==="isAvailable"?!!p:i==="status"?p?l.READY:l.INITIALIZING:i==="error"?R:i in g?g[i]:N[i]}export{K as useStripeBilling};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@donotdev/billing",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@donotdev/auth": "0.0.
|
|
37
|
-
"@donotdev/components": "0.0.
|
|
38
|
-
"@donotdev/core": "0.0.
|
|
39
|
-
"@donotdev/firebase": "0.0.
|
|
36
|
+
"@donotdev/auth": "0.0.3",
|
|
37
|
+
"@donotdev/components": "0.0.3",
|
|
38
|
+
"@donotdev/core": "0.0.3",
|
|
39
|
+
"@donotdev/firebase": "0.0.3",
|
|
40
40
|
"lucide-react": "^0.562.0",
|
|
41
41
|
"react": "^19.2.3",
|
|
42
42
|
"react-dom": "^19.2.3",
|