@commet/better-auth 1.0.0
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 +306 -0
- package/dist/client.cjs +197 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +5 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.js +172 -0
- package/dist/client.js.map +1 -0
- package/dist/index.cjs +1115 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1366 -0
- package/dist/index.d.ts +1366 -0
- package/dist/index.js +1081 -0
- package/dist/index.js.map +1 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# @commet/better-auth
|
|
2
|
+
|
|
3
|
+
A [Better Auth](https://github.com/better-auth/better-auth) plugin for integrating [Commet](https://commet.co) billing into your authentication flow.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Automatic Customer creation on signup
|
|
8
|
+
- Customer Portal access
|
|
9
|
+
- Subscription management (get, change plan, cancel)
|
|
10
|
+
- Feature access checks (boolean, metered, seats)
|
|
11
|
+
- Usage event tracking
|
|
12
|
+
- Seat management
|
|
13
|
+
- Optional webhook handling
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add @commet/better-auth@^1.0.0 @commet/node@^1.0.0 better-auth
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Preparation
|
|
22
|
+
|
|
23
|
+
Go to your Commet Organization Settings and create an API key. Add it to your environment.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# .env
|
|
27
|
+
COMMET_API_KEY=ck_...
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Server Configuration
|
|
31
|
+
|
|
32
|
+
The Commet plugin comes with several sub-plugins that add functionality to your stack:
|
|
33
|
+
|
|
34
|
+
- **portal** - Customer portal access
|
|
35
|
+
- **subscriptions** - Subscription management
|
|
36
|
+
- **features** - Feature access checks
|
|
37
|
+
- **usage** - Usage event tracking for metered billing
|
|
38
|
+
- **seats** - Seat-based licensing
|
|
39
|
+
- **webhooks** - (Optional) Webhook handling
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { betterAuth } from "better-auth";
|
|
43
|
+
import { commet, portal, subscriptions, features, usage, seats, webhooks } from "@commet/better-auth";
|
|
44
|
+
import { Commet } from "@commet/node";
|
|
45
|
+
|
|
46
|
+
const commetClient = new Commet({
|
|
47
|
+
apiKey: process.env.COMMET_API_KEY,
|
|
48
|
+
environment: "production" // or "sandbox"
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const auth = betterAuth({
|
|
52
|
+
// ... Better Auth config
|
|
53
|
+
plugins: [
|
|
54
|
+
commet({
|
|
55
|
+
client: commetClient,
|
|
56
|
+
createCustomerOnSignUp: true,
|
|
57
|
+
getCustomerCreateParams: ({ user }) => ({
|
|
58
|
+
legalName: user.name,
|
|
59
|
+
metadata: { source: "signup" }
|
|
60
|
+
}),
|
|
61
|
+
use: [
|
|
62
|
+
portal({ returnUrl: "/dashboard" }),
|
|
63
|
+
subscriptions(),
|
|
64
|
+
features(),
|
|
65
|
+
usage(),
|
|
66
|
+
seats(),
|
|
67
|
+
// Webhooks are OPTIONAL - see note below
|
|
68
|
+
webhooks({
|
|
69
|
+
secret: process.env.COMMET_WEBHOOK_SECRET,
|
|
70
|
+
onSubscriptionActivated: async (payload) => {
|
|
71
|
+
// Handle activation
|
|
72
|
+
},
|
|
73
|
+
onSubscriptionCanceled: async (payload) => {
|
|
74
|
+
// Handle cancellation
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
]
|
|
78
|
+
})
|
|
79
|
+
]
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Client Configuration
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { createAuthClient } from "better-auth/react";
|
|
87
|
+
import { commetClient } from "@commet/better-auth";
|
|
88
|
+
|
|
89
|
+
export const authClient = createAuthClient({
|
|
90
|
+
plugins: [commetClient()]
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Note About Webhooks
|
|
95
|
+
|
|
96
|
+
**Webhooks are completely optional in Commet.** Unlike some billing platforms where you need webhooks to keep state synchronized, with Commet you can always query the current state directly:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// Always query current state - no webhooks needed!
|
|
100
|
+
const { data: subscription } = await authClient.subscription.get();
|
|
101
|
+
const { data: features } = await authClient.features.list();
|
|
102
|
+
const { data: canUse } = await authClient.features.canUse({ code: "api_calls" });
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Webhooks are only useful if you want to:
|
|
106
|
+
- React immediately to changes (e.g., send email on cancellation)
|
|
107
|
+
- Avoid polling latency in critical cases
|
|
108
|
+
- Logging/auditing of events
|
|
109
|
+
|
|
110
|
+
## Configuration Options
|
|
111
|
+
|
|
112
|
+
### Main Plugin Options
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
commet({
|
|
116
|
+
// Required: Commet SDK client instance
|
|
117
|
+
client: commetClient,
|
|
118
|
+
|
|
119
|
+
// Optional: Auto-create Commet customer on user signup (default: false)
|
|
120
|
+
createCustomerOnSignUp: true,
|
|
121
|
+
|
|
122
|
+
// Optional: Customize customer creation parameters
|
|
123
|
+
getCustomerCreateParams: ({ user }) => ({
|
|
124
|
+
legalName: user.name,
|
|
125
|
+
displayName: user.name,
|
|
126
|
+
domain: "example.com",
|
|
127
|
+
metadata: { plan: "starter" }
|
|
128
|
+
}),
|
|
129
|
+
|
|
130
|
+
// Required: Array of sub-plugins to use
|
|
131
|
+
use: [...]
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Portal Plugin
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
portal({
|
|
139
|
+
// Optional: URL to return to after leaving the portal
|
|
140
|
+
returnUrl: "/dashboard"
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Subscriptions Plugin
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
subscriptions({
|
|
148
|
+
// Optional: Plan mappings for slug-based plan changes
|
|
149
|
+
plans: [
|
|
150
|
+
{ planId: "plan_123", slug: "starter" },
|
|
151
|
+
{ planId: "plan_456", slug: "pro" },
|
|
152
|
+
{ planId: "plan_789", slug: "enterprise" }
|
|
153
|
+
]
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Webhooks Plugin
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
webhooks({
|
|
161
|
+
// Required: Webhook secret for signature verification
|
|
162
|
+
secret: process.env.COMMET_WEBHOOK_SECRET,
|
|
163
|
+
|
|
164
|
+
// Optional handlers
|
|
165
|
+
onSubscriptionCreated: async (payload) => {},
|
|
166
|
+
onSubscriptionActivated: async (payload) => {},
|
|
167
|
+
onSubscriptionCanceled: async (payload) => {},
|
|
168
|
+
onSubscriptionUpdated: async (payload) => {},
|
|
169
|
+
onPayload: async (payload) => {} // Catch-all
|
|
170
|
+
})
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Client Usage Examples
|
|
174
|
+
|
|
175
|
+
### Customer Portal
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Redirect to the Commet customer portal
|
|
179
|
+
await authClient.customer.portal();
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Subscription Management
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
// Get current subscription
|
|
186
|
+
const { data: subscription } = await authClient.subscription.get();
|
|
187
|
+
console.log(subscription?.status); // "active", "trialing", etc.
|
|
188
|
+
|
|
189
|
+
// Change plan (upgrade/downgrade)
|
|
190
|
+
await authClient.subscription.changePlan({
|
|
191
|
+
planId: "plan_456", // or use slug if configured
|
|
192
|
+
billingInterval: "yearly"
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Cancel subscription
|
|
196
|
+
await authClient.subscription.cancel({
|
|
197
|
+
reason: "switching_to_competitor",
|
|
198
|
+
immediate: false // Cancel at end of period
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Feature Access
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
// List all features
|
|
206
|
+
const { data: features } = await authClient.features.list();
|
|
207
|
+
|
|
208
|
+
// Get specific feature
|
|
209
|
+
const { data: feature } = await authClient.features.get({ code: "team_members" });
|
|
210
|
+
console.log(feature?.current, feature?.included, feature?.remaining);
|
|
211
|
+
|
|
212
|
+
// Check if feature is enabled (boolean)
|
|
213
|
+
const { data: check } = await authClient.features.check({ code: "custom_branding" });
|
|
214
|
+
if (!check?.allowed) {
|
|
215
|
+
redirect("/upgrade");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Check if user can use one more unit
|
|
219
|
+
const { data: canUse } = await authClient.features.canUse({ code: "api_calls" });
|
|
220
|
+
if (!canUse?.allowed) {
|
|
221
|
+
return { error: "Limit reached. Please upgrade." };
|
|
222
|
+
}
|
|
223
|
+
if (canUse?.willBeCharged) {
|
|
224
|
+
// Show confirmation: "This will incur overage charges"
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Usage Tracking
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// Track a usage event
|
|
232
|
+
await authClient.usage.track({
|
|
233
|
+
eventType: "api_call",
|
|
234
|
+
idempotencyKey: `req_${requestId}`,
|
|
235
|
+
properties: {
|
|
236
|
+
endpoint: "/users",
|
|
237
|
+
method: "GET"
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Seat Management
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
// List all seat balances
|
|
246
|
+
const { data: seats } = await authClient.seats.list();
|
|
247
|
+
|
|
248
|
+
// Add seats
|
|
249
|
+
await authClient.seats.add({
|
|
250
|
+
seatType: "editor",
|
|
251
|
+
count: 5
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Remove seats
|
|
255
|
+
await authClient.seats.remove({
|
|
256
|
+
seatType: "editor",
|
|
257
|
+
count: 2
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Set specific count
|
|
261
|
+
await authClient.seats.set({
|
|
262
|
+
seatType: "editor",
|
|
263
|
+
count: 10
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Set all seat types at once
|
|
267
|
+
await authClient.seats.setAll({
|
|
268
|
+
seats: {
|
|
269
|
+
editor: 10,
|
|
270
|
+
viewer: 50
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## API Endpoints
|
|
276
|
+
|
|
277
|
+
All endpoints are prefixed with `/commet/` to avoid collisions with other plugins.
|
|
278
|
+
|
|
279
|
+
| Plugin | Endpoint | Method | Description |
|
|
280
|
+
|--------|----------|--------|-------------|
|
|
281
|
+
| portal | `/commet/portal` | GET | Generates portal URL and redirects |
|
|
282
|
+
| subscriptions | `/commet/subscription` | GET | Gets active subscription |
|
|
283
|
+
| subscriptions | `/commet/subscription/change-plan` | POST | Changes plan |
|
|
284
|
+
| subscriptions | `/commet/subscription/cancel` | POST | Cancels subscription |
|
|
285
|
+
| features | `/commet/features` | GET | Lists all features |
|
|
286
|
+
| features | `/commet/features/:code` | GET | Gets a specific feature |
|
|
287
|
+
| features | `/commet/features/:code/check` | GET | Checks if feature is enabled |
|
|
288
|
+
| features | `/commet/features/:code/can-use` | GET | Checks if user can use +1 |
|
|
289
|
+
| usage | `/commet/usage/track` | POST | Tracks usage event |
|
|
290
|
+
| seats | `/commet/seats` | GET | Lists seat balances |
|
|
291
|
+
| seats | `/commet/seats/add` | POST | Adds seats |
|
|
292
|
+
| seats | `/commet/seats/remove` | POST | Removes seats |
|
|
293
|
+
| seats | `/commet/seats/set` | POST | Sets seat count |
|
|
294
|
+
| seats | `/commet/seats/set-all` | POST | Sets all seat types |
|
|
295
|
+
| webhooks | `/commet/webhooks` | POST | Receives webhooks (optional) |
|
|
296
|
+
|
|
297
|
+
## Resources
|
|
298
|
+
|
|
299
|
+
- [Commet Documentation](https://commet.co/docs)
|
|
300
|
+
- [Better Auth Documentation](https://www.better-auth.com)
|
|
301
|
+
- [@commet/node SDK](https://www.npmjs.com/package/@commet/node)
|
|
302
|
+
|
|
303
|
+
## License
|
|
304
|
+
|
|
305
|
+
MIT
|
|
306
|
+
|
package/dist/client.cjs
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
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
|
+
commetClient: () => commetClient
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(client_exports);
|
|
26
|
+
var commetClient = () => {
|
|
27
|
+
return {
|
|
28
|
+
id: "commet-client",
|
|
29
|
+
$InferServerPlugin: {},
|
|
30
|
+
getActions: ($fetch) => {
|
|
31
|
+
return {
|
|
32
|
+
// Customer Portal
|
|
33
|
+
customer: {
|
|
34
|
+
/**
|
|
35
|
+
* Redirect to the Commet customer portal
|
|
36
|
+
*/
|
|
37
|
+
portal: async (fetchOptions) => {
|
|
38
|
+
const res = await $fetch("/commet/portal", {
|
|
39
|
+
method: "GET",
|
|
40
|
+
...fetchOptions
|
|
41
|
+
});
|
|
42
|
+
if (res.error) {
|
|
43
|
+
throw new Error(res.error.message);
|
|
44
|
+
}
|
|
45
|
+
const data = res.data;
|
|
46
|
+
if (data.redirect && typeof window !== "undefined") {
|
|
47
|
+
window.location.href = data.url;
|
|
48
|
+
}
|
|
49
|
+
return data;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
// Subscription management
|
|
53
|
+
subscription: {
|
|
54
|
+
/**
|
|
55
|
+
* Get the current subscription for the authenticated user
|
|
56
|
+
*/
|
|
57
|
+
get: async (fetchOptions) => {
|
|
58
|
+
return $fetch("/commet/subscription", {
|
|
59
|
+
method: "GET",
|
|
60
|
+
...fetchOptions
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
/**
|
|
64
|
+
* Change the subscription plan (upgrade/downgrade)
|
|
65
|
+
*/
|
|
66
|
+
changePlan: async (data, fetchOptions) => {
|
|
67
|
+
return $fetch("/commet/subscription/change-plan", {
|
|
68
|
+
method: "POST",
|
|
69
|
+
body: data,
|
|
70
|
+
...fetchOptions
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
/**
|
|
74
|
+
* Cancel the subscription
|
|
75
|
+
*/
|
|
76
|
+
cancel: async (data, fetchOptions) => {
|
|
77
|
+
return $fetch("/commet/subscription/cancel", {
|
|
78
|
+
method: "POST",
|
|
79
|
+
body: data ?? {},
|
|
80
|
+
...fetchOptions
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
// Feature access
|
|
85
|
+
features: {
|
|
86
|
+
/**
|
|
87
|
+
* List all features for the authenticated user
|
|
88
|
+
*/
|
|
89
|
+
list: async (fetchOptions) => {
|
|
90
|
+
return $fetch("/commet/features", {
|
|
91
|
+
method: "GET",
|
|
92
|
+
...fetchOptions
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
/**
|
|
96
|
+
* Get a specific feature's access/usage
|
|
97
|
+
*/
|
|
98
|
+
get: async (data, fetchOptions) => {
|
|
99
|
+
return $fetch(`/commet/features/${data.code}`, {
|
|
100
|
+
method: "GET",
|
|
101
|
+
...fetchOptions
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
/**
|
|
105
|
+
* Check if a feature is enabled (boolean check)
|
|
106
|
+
*/
|
|
107
|
+
check: async (data, fetchOptions) => {
|
|
108
|
+
return $fetch(`/features/${data.code}/check`, {
|
|
109
|
+
method: "GET",
|
|
110
|
+
...fetchOptions
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
/**
|
|
114
|
+
* Check if user can use one more unit of a feature
|
|
115
|
+
* Returns { allowed: boolean, willBeCharged: boolean }
|
|
116
|
+
*/
|
|
117
|
+
canUse: async (data, fetchOptions) => {
|
|
118
|
+
return $fetch(`/features/${data.code}/can-use`, {
|
|
119
|
+
method: "GET",
|
|
120
|
+
...fetchOptions
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
// Usage tracking
|
|
125
|
+
usage: {
|
|
126
|
+
/**
|
|
127
|
+
* Track a usage event for the authenticated user
|
|
128
|
+
*/
|
|
129
|
+
track: async (data, fetchOptions) => {
|
|
130
|
+
return $fetch("/commet/usage/track", {
|
|
131
|
+
method: "POST",
|
|
132
|
+
body: data,
|
|
133
|
+
...fetchOptions
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
// Seat management
|
|
138
|
+
seats: {
|
|
139
|
+
/**
|
|
140
|
+
* List all seat balances for the authenticated user
|
|
141
|
+
*/
|
|
142
|
+
list: async (fetchOptions) => {
|
|
143
|
+
return $fetch("/commet/seats", {
|
|
144
|
+
method: "GET",
|
|
145
|
+
...fetchOptions
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
/**
|
|
149
|
+
* Add seats of a specific type
|
|
150
|
+
*/
|
|
151
|
+
add: async (data, fetchOptions) => {
|
|
152
|
+
return $fetch("/commet/seats/add", {
|
|
153
|
+
method: "POST",
|
|
154
|
+
body: data,
|
|
155
|
+
...fetchOptions
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
/**
|
|
159
|
+
* Remove seats of a specific type
|
|
160
|
+
*/
|
|
161
|
+
remove: async (data, fetchOptions) => {
|
|
162
|
+
return $fetch("/commet/seats/remove", {
|
|
163
|
+
method: "POST",
|
|
164
|
+
body: data,
|
|
165
|
+
...fetchOptions
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
/**
|
|
169
|
+
* Set seats to a specific count
|
|
170
|
+
*/
|
|
171
|
+
set: async (data, fetchOptions) => {
|
|
172
|
+
return $fetch("/commet/seats/set", {
|
|
173
|
+
method: "POST",
|
|
174
|
+
body: data,
|
|
175
|
+
...fetchOptions
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
/**
|
|
179
|
+
* Set all seat types at once
|
|
180
|
+
*/
|
|
181
|
+
setAll: async (data, fetchOptions) => {
|
|
182
|
+
return $fetch("/commet/seats/set-all", {
|
|
183
|
+
method: "POST",
|
|
184
|
+
body: data,
|
|
185
|
+
...fetchOptions
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
};
|
|
193
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
194
|
+
0 && (module.exports = {
|
|
195
|
+
commetClient
|
|
196
|
+
});
|
|
197
|
+
//# sourceMappingURL=client.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import type { BetterAuthClientPlugin } from \"better-auth\";\nimport type { BetterFetchOption } from \"better-auth/client\";\nimport type { commet } from \"./index\";\n\n/**\n * Commet client plugin for Better Auth\n *\n * Provides client-side methods to interact with Commet billing features.\n *\n * @example\n * ```typescript\n * import { createAuthClient } from \"better-auth/react\";\n * import { commetClient } from \"@commet/better-auth\";\n *\n * export const authClient = createAuthClient({\n * plugins: [commetClient()]\n * });\n *\n * // Usage - you can always query state directly (no webhooks needed)\n * const { data: subscription } = await authClient.subscription.get();\n * const { data: features } = await authClient.features.list();\n * const { data: canUse } = await authClient.features.canUse({ code: \"api_calls\" });\n * await authClient.usage.track({ eventType: \"api_call\" });\n * await authClient.customer.portal(); // Redirect to portal\n * ```\n */\nexport const commetClient = () => {\n return {\n id: \"commet-client\",\n $InferServerPlugin: {} as ReturnType<typeof commet>,\n getActions: ($fetch) => {\n return {\n // Customer Portal\n customer: {\n /**\n * Redirect to the Commet customer portal\n */\n portal: async (fetchOptions?: BetterFetchOption) => {\n const res = await $fetch(\"/commet/portal\", {\n method: \"GET\",\n ...fetchOptions,\n });\n\n if (res.error) {\n throw new Error(res.error.message);\n }\n\n const data = res.data as { url: string; redirect: boolean };\n\n if (data.redirect && typeof window !== \"undefined\") {\n window.location.href = data.url;\n }\n\n return data;\n },\n },\n\n // Subscription management\n subscription: {\n /**\n * Get the current subscription for the authenticated user\n */\n get: async (fetchOptions?: BetterFetchOption) => {\n return $fetch(\"/commet/subscription\", {\n method: \"GET\",\n ...fetchOptions,\n });\n },\n\n /**\n * Change the subscription plan (upgrade/downgrade)\n */\n changePlan: async (\n data: {\n planId?: string;\n slug?: string;\n billingInterval?: \"monthly\" | \"quarterly\" | \"yearly\";\n },\n fetchOptions?: BetterFetchOption,\n ) => {\n return $fetch(\"/commet/subscription/change-plan\", {\n method: \"POST\",\n body: data,\n ...fetchOptions,\n });\n },\n\n /**\n * Cancel the subscription\n */\n cancel: async (\n data?: { reason?: string; immediate?: boolean },\n fetchOptions?: BetterFetchOption,\n ) => {\n return $fetch(\"/commet/subscription/cancel\", {\n method: \"POST\",\n body: data ?? {},\n ...fetchOptions,\n });\n },\n },\n\n // Feature access\n features: {\n /**\n * List all features for the authenticated user\n */\n list: async (fetchOptions?: BetterFetchOption) => {\n return $fetch(\"/commet/features\", {\n method: \"GET\",\n ...fetchOptions,\n });\n },\n\n /**\n * Get a specific feature's access/usage\n */\n get: async (\n data: { code: string },\n fetchOptions?: BetterFetchOption,\n ) => {\n return $fetch(`/commet/features/${data.code}`, {\n method: \"GET\",\n ...fetchOptions,\n });\n },\n\n /**\n * Check if a feature is enabled (boolean check)\n */\n check: async (\n data: { code: string },\n fetchOptions?: BetterFetchOption,\n ) => {\n return $fetch(`/features/${data.code}/check`, {\n method: \"GET\",\n ...fetchOptions,\n });\n },\n\n /**\n * Check if user can use one more unit of a feature\n * Returns { allowed: boolean, willBeCharged: boolean }\n */\n canUse: async (\n data: { code: string },\n fetchOptions?: BetterFetchOption,\n ) => {\n return $fetch(`/features/${data.code}/can-use`, {\n method: \"GET\",\n ...fetchOptions,\n });\n },\n },\n\n // Usage tracking\n usage: {\n /**\n * Track a usage event for the authenticated user\n */\n track: async (\n data: {\n eventType: string;\n value?: number;\n idempotencyKey?: string;\n properties?: Record<string, string>;\n },\n fetchOptions?: BetterFetchOption,\n ) => {\n return $fetch(\"/commet/usage/track\", {\n method: \"POST\",\n body: data,\n ...fetchOptions,\n });\n },\n },\n\n // Seat management\n seats: {\n /**\n * List all seat balances for the authenticated user\n */\n list: async (fetchOptions?: BetterFetchOption) => {\n return $fetch(\"/commet/seats\", {\n method: \"GET\",\n ...fetchOptions,\n });\n },\n\n /**\n * Add seats of a specific type\n */\n add: async (\n data: { seatType: string; count: number },\n fetchOptions?: BetterFetchOption,\n ) => {\n return $fetch(\"/commet/seats/add\", {\n method: \"POST\",\n body: data,\n ...fetchOptions,\n });\n },\n\n /**\n * Remove seats of a specific type\n */\n remove: async (\n data: { seatType: string; count: number },\n fetchOptions?: BetterFetchOption,\n ) => {\n return $fetch(\"/commet/seats/remove\", {\n method: \"POST\",\n body: data,\n ...fetchOptions,\n });\n },\n\n /**\n * Set seats to a specific count\n */\n set: async (\n data: { seatType: string; count: number },\n fetchOptions?: BetterFetchOption,\n ) => {\n return $fetch(\"/commet/seats/set\", {\n method: \"POST\",\n body: data,\n ...fetchOptions,\n });\n },\n\n /**\n * Set all seat types at once\n */\n setAll: async (\n data: { seats: Record<string, number> },\n fetchOptions?: BetterFetchOption,\n ) => {\n return $fetch(\"/commet/seats/set-all\", {\n method: \"POST\",\n body: data,\n ...fetchOptions,\n });\n },\n },\n };\n },\n } satisfies BetterAuthClientPlugin;\n};\n\n"],"mappings":"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","names":[]}
|