@@ -6,11 +6,21 @@ import { loadEnv } from '../env.js'
66export function createAutumnBillingApi ( secretKey : string ) : BillingApi {
77 const autumn = new Autumn ( { secretKey } )
88
9+ const allowByDefault = ( featureId : string ) =>
10+ Effect . succeed ( {
11+ allowed : true ,
12+ featureId,
13+ balance : null ,
14+ unlimited : undefined ,
15+ } as const )
16+
917 return {
1018 check : ( customerId , featureId ) =>
11- Effect . tryPromise ( ( ) =>
12- autumn . check ( { customer_id : customerId , feature_id : featureId } ) ,
13- ) . pipe (
19+ ! customerId
20+ ? allowByDefault ( featureId )
21+ : Effect . tryPromise ( ( ) =>
22+ autumn . check ( { customer_id : customerId , feature_id : featureId } ) ,
23+ ) . pipe (
1424 Effect . map ( ( result ) => ( {
1525 allowed : result . data ?. allowed ?? true ,
1626 featureId,
@@ -31,79 +41,85 @@ export function createAutumnBillingApi(secretKey: string): BillingApi {
3141 ) ,
3242
3343 track : ( customerId , featureId , value ) =>
34- Effect . tryPromise ( ( ) =>
35- autumn . track ( {
36- customer_id : customerId ,
37- feature_id : featureId ,
38- value : value ?? 1 ,
39- } ) ,
40- ) . pipe (
41- Effect . tapError ( ( err ) =>
42- Effect . logWarning ( `Billing track failed for ${ customerId } /${ featureId } : ${ err } ` ) ,
43- ) ,
44- Effect . catchAll ( ( ) => Effect . void ) ,
45- Effect . map ( ( ) => undefined ) ,
46- ) ,
44+ ! customerId
45+ ? Effect . void
46+ : Effect . tryPromise ( ( ) =>
47+ autumn . track ( {
48+ customer_id : customerId ,
49+ feature_id : featureId ,
50+ value : value ?? 1 ,
51+ } ) ,
52+ ) . pipe (
53+ Effect . tapError ( ( err ) =>
54+ Effect . logWarning ( `Billing track failed for ${ customerId } /${ featureId } : ${ err } ` ) ,
55+ ) ,
56+ Effect . catchAll ( ( ) => Effect . void ) ,
57+ Effect . map ( ( ) => undefined ) ,
58+ ) ,
4759
4860 trackCompute : ( customerId , dollarAmount , sandboxId ) =>
49- Effect . tryPromise ( ( ) =>
50- autumn . track ( {
51- customer_id : customerId ,
52- feature_id : 'compute' ,
53- value : dollarAmount ,
54- properties : { sandbox_id : sandboxId } ,
55- } ) ,
56- ) . pipe (
57- Effect . tapError ( ( err ) =>
58- Effect . logWarning ( `Billing trackCompute failed for ${ customerId } /${ sandboxId } : ${ err } ` ) ,
59- ) ,
60- Effect . catchAll ( ( ) => Effect . void ) ,
61- Effect . map ( ( ) => undefined ) ,
62- ) ,
61+ ! customerId
62+ ? Effect . void
63+ : Effect . tryPromise ( ( ) =>
64+ autumn . track ( {
65+ customer_id : customerId ,
66+ feature_id : 'compute' ,
67+ value : dollarAmount ,
68+ properties : { sandbox_id : sandboxId } ,
69+ } ) ,
70+ ) . pipe (
71+ Effect . tapError ( ( err ) =>
72+ Effect . logWarning ( `Billing trackCompute failed for ${ customerId } /${ sandboxId } : ${ err } ` ) ,
73+ ) ,
74+ Effect . catchAll ( ( ) => Effect . void ) ,
75+ Effect . map ( ( ) => undefined ) ,
76+ ) ,
6377
6478 checkCredits : ( customerId , estimatedDollars ) =>
65- Effect . tryPromise ( ( ) =>
66- autumn . check ( {
67- customer_id : customerId ,
68- feature_id : 'credits' ,
69- // Always send a required_balance so Autumn checks actual balance.
70- // Use the estimate if provided, otherwise check for at least $0.01.
71- required_balance : estimatedDollars > 0 ? estimatedDollars : 0.01 ,
72- } ) ,
73- ) . pipe (
74- Effect . map ( ( result ) => ( {
75- allowed : result . data ?. allowed ?? true ,
76- featureId : 'credits' ,
77- balance : result . data ?. balance ,
78- unlimited : result . data ?. unlimited ,
79- } ) ) ,
80- Effect . tapError ( ( err ) =>
81- Effect . logWarning ( `Failed to check credits for ${ customerId } : ${ err } ` ) ,
82- ) ,
83- Effect . catchAll ( ( ) =>
84- Effect . succeed ( {
85- allowed : true ,
86- featureId : 'credits' ,
87- balance : null ,
88- unlimited : undefined ,
89- } ) ,
90- ) ,
91- ) ,
79+ ! customerId
80+ ? allowByDefault ( 'credits' )
81+ : Effect . tryPromise ( ( ) =>
82+ autumn . check ( {
83+ customer_id : customerId ,
84+ feature_id : 'credits' ,
85+ required_balance : estimatedDollars > 0 ? estimatedDollars : 0.01 ,
86+ } ) ,
87+ ) . pipe (
88+ Effect . map ( ( result ) => ( {
89+ allowed : result . data ?. allowed ?? true ,
90+ featureId : 'credits' ,
91+ balance : result . data ?. balance ,
92+ unlimited : result . data ?. unlimited ,
93+ } ) ) ,
94+ Effect . tapError ( ( err ) =>
95+ Effect . logWarning ( `Failed to check credits for ${ customerId } : ${ err } ` ) ,
96+ ) ,
97+ Effect . catchAll ( ( ) =>
98+ Effect . succeed ( {
99+ allowed : true ,
100+ featureId : 'credits' ,
101+ balance : null ,
102+ unlimited : undefined ,
103+ } ) ,
104+ ) ,
105+ ) ,
92106 getBillingTier : ( customerId ) =>
93- Effect . tryPromise ( async ( ) => {
94- const customer = await autumn . customers . get ( customerId )
95- const products = customer ?. data ?. products ?? [ ]
96- const hasMax = products . some (
97- ( p : { id ?: string ; status ?: string } ) =>
98- p . id === 'max' && p . status === 'active' ,
99- )
100- return hasMax ? 'max' as const : 'free' as const
101- } ) . pipe (
102- Effect . tapError ( ( err ) =>
103- Effect . logWarning ( `Failed to get billing tier for ${ customerId } : ${ err } ` ) ,
104- ) ,
105- Effect . catchAll ( ( ) => Effect . succeed ( 'free' as const ) ) ,
106- ) ,
107+ ! customerId
108+ ? Effect . succeed ( 'free' as const )
109+ : Effect . tryPromise ( async ( ) => {
110+ const customer = await autumn . customers . get ( customerId )
111+ const products = customer ?. data ?. products ?? [ ]
112+ const hasMax = products . some (
113+ ( p : { id ?: string ; status ?: string } ) =>
114+ p . id === 'max' && p . status === 'active' ,
115+ )
116+ return hasMax ? 'max' as const : 'free' as const
117+ } ) . pipe (
118+ Effect . tapError ( ( err ) =>
119+ Effect . logWarning ( `Failed to get billing tier for ${ customerId } : ${ err } ` ) ,
120+ ) ,
121+ Effect . catchAll ( ( ) => Effect . succeed ( 'free' as const ) ) ,
122+ ) ,
107123 }
108124}
109125
0 commit comments