@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/dist/index.cjs ADDED
@@ -0,0 +1,1115 @@
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/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ commet: () => commet,
24
+ commetClient: () => commetClient,
25
+ features: () => features,
26
+ portal: () => portal,
27
+ seats: () => seats,
28
+ subscriptions: () => subscriptions,
29
+ usage: () => usage,
30
+ webhooks: () => webhooks
31
+ });
32
+ module.exports = __toCommonJS(index_exports);
33
+
34
+ // src/hooks/customer.ts
35
+ var import_api = require("better-auth/api");
36
+ var onBeforeUserCreate = (options) => async (user, context) => {
37
+ if (!context || !options.createCustomerOnSignUp) {
38
+ return;
39
+ }
40
+ try {
41
+ const customParams = options.getCustomerCreateParams ? await options.getCustomerCreateParams({ user }, context.request) : {};
42
+ if (!user.email) {
43
+ throw new import_api.APIError("BAD_REQUEST", {
44
+ message: "An email is required to create a customer"
45
+ });
46
+ }
47
+ const existingCustomers = await options.client.customers.list({
48
+ search: user.email
49
+ });
50
+ const existingCustomer = existingCustomers.data?.find(
51
+ (c) => c.billingEmail === user.email
52
+ );
53
+ if (!existingCustomer) {
54
+ await options.client.customers.create({
55
+ email: user.email,
56
+ legalName: customParams.legalName ?? user.name,
57
+ displayName: customParams.displayName,
58
+ domain: customParams.domain,
59
+ metadata: customParams.metadata
60
+ });
61
+ }
62
+ } catch (e) {
63
+ if (e instanceof import_api.APIError) {
64
+ throw e;
65
+ }
66
+ if (e instanceof Error) {
67
+ throw new import_api.APIError("INTERNAL_SERVER_ERROR", {
68
+ message: `Commet customer creation failed: ${e.message}`
69
+ });
70
+ }
71
+ throw new import_api.APIError("INTERNAL_SERVER_ERROR", {
72
+ message: "Commet customer creation failed"
73
+ });
74
+ }
75
+ };
76
+ var onAfterUserCreate = (options) => async (user, context) => {
77
+ if (!context || !options.createCustomerOnSignUp) {
78
+ return;
79
+ }
80
+ try {
81
+ const existingCustomers = await options.client.customers.list({
82
+ search: user.email
83
+ });
84
+ const existingCustomer = existingCustomers.data?.find(
85
+ (c) => c.billingEmail === user.email
86
+ );
87
+ if (existingCustomer && existingCustomer.externalId !== user.id) {
88
+ await options.client.customers.update({
89
+ customerId: existingCustomer.id,
90
+ externalId: user.id
91
+ });
92
+ }
93
+ } catch (e) {
94
+ if (e instanceof Error) {
95
+ throw new import_api.APIError("INTERNAL_SERVER_ERROR", {
96
+ message: `Commet customer update failed: ${e.message}`
97
+ });
98
+ }
99
+ throw new import_api.APIError("INTERNAL_SERVER_ERROR", {
100
+ message: "Commet customer update failed"
101
+ });
102
+ }
103
+ };
104
+ var onUserUpdate = (options) => async (user, context) => {
105
+ if (!context || !options.createCustomerOnSignUp) {
106
+ return;
107
+ }
108
+ try {
109
+ const existingCustomers = await options.client.customers.list({
110
+ externalId: user.id
111
+ });
112
+ const existingCustomer = existingCustomers.data?.[0];
113
+ if (existingCustomer) {
114
+ await options.client.customers.update({
115
+ customerId: existingCustomer.id,
116
+ email: user.email,
117
+ legalName: user.name ?? void 0
118
+ });
119
+ }
120
+ } catch (e) {
121
+ if (e instanceof Error) {
122
+ context.context.logger.error(
123
+ `Commet customer update failed: ${e.message}`
124
+ );
125
+ } else {
126
+ context.context.logger.error("Commet customer update failed");
127
+ }
128
+ }
129
+ };
130
+ var onUserDelete = (options) => async (user, context) => {
131
+ if (!context || !options.createCustomerOnSignUp) {
132
+ return;
133
+ }
134
+ try {
135
+ const existingCustomers = await options.client.customers.list({
136
+ externalId: user.id
137
+ });
138
+ const existingCustomer = existingCustomers.data?.[0];
139
+ if (existingCustomer) {
140
+ await options.client.customers.archive(existingCustomer.id);
141
+ }
142
+ } catch (e) {
143
+ if (e instanceof Error) {
144
+ context?.context.logger.error(
145
+ `Commet customer archive failed: ${e.message}`
146
+ );
147
+ } else {
148
+ context?.context.logger.error("Commet customer archive failed");
149
+ }
150
+ }
151
+ };
152
+
153
+ // src/client.ts
154
+ var commetClient = () => {
155
+ return {
156
+ id: "commet-client",
157
+ $InferServerPlugin: {},
158
+ getActions: ($fetch) => {
159
+ return {
160
+ // Customer Portal
161
+ customer: {
162
+ /**
163
+ * Redirect to the Commet customer portal
164
+ */
165
+ portal: async (fetchOptions) => {
166
+ const res = await $fetch("/commet/portal", {
167
+ method: "GET",
168
+ ...fetchOptions
169
+ });
170
+ if (res.error) {
171
+ throw new Error(res.error.message);
172
+ }
173
+ const data = res.data;
174
+ if (data.redirect && typeof window !== "undefined") {
175
+ window.location.href = data.url;
176
+ }
177
+ return data;
178
+ }
179
+ },
180
+ // Subscription management
181
+ subscription: {
182
+ /**
183
+ * Get the current subscription for the authenticated user
184
+ */
185
+ get: async (fetchOptions) => {
186
+ return $fetch("/commet/subscription", {
187
+ method: "GET",
188
+ ...fetchOptions
189
+ });
190
+ },
191
+ /**
192
+ * Change the subscription plan (upgrade/downgrade)
193
+ */
194
+ changePlan: async (data, fetchOptions) => {
195
+ return $fetch("/commet/subscription/change-plan", {
196
+ method: "POST",
197
+ body: data,
198
+ ...fetchOptions
199
+ });
200
+ },
201
+ /**
202
+ * Cancel the subscription
203
+ */
204
+ cancel: async (data, fetchOptions) => {
205
+ return $fetch("/commet/subscription/cancel", {
206
+ method: "POST",
207
+ body: data ?? {},
208
+ ...fetchOptions
209
+ });
210
+ }
211
+ },
212
+ // Feature access
213
+ features: {
214
+ /**
215
+ * List all features for the authenticated user
216
+ */
217
+ list: async (fetchOptions) => {
218
+ return $fetch("/commet/features", {
219
+ method: "GET",
220
+ ...fetchOptions
221
+ });
222
+ },
223
+ /**
224
+ * Get a specific feature's access/usage
225
+ */
226
+ get: async (data, fetchOptions) => {
227
+ return $fetch(`/commet/features/${data.code}`, {
228
+ method: "GET",
229
+ ...fetchOptions
230
+ });
231
+ },
232
+ /**
233
+ * Check if a feature is enabled (boolean check)
234
+ */
235
+ check: async (data, fetchOptions) => {
236
+ return $fetch(`/features/${data.code}/check`, {
237
+ method: "GET",
238
+ ...fetchOptions
239
+ });
240
+ },
241
+ /**
242
+ * Check if user can use one more unit of a feature
243
+ * Returns { allowed: boolean, willBeCharged: boolean }
244
+ */
245
+ canUse: async (data, fetchOptions) => {
246
+ return $fetch(`/features/${data.code}/can-use`, {
247
+ method: "GET",
248
+ ...fetchOptions
249
+ });
250
+ }
251
+ },
252
+ // Usage tracking
253
+ usage: {
254
+ /**
255
+ * Track a usage event for the authenticated user
256
+ */
257
+ track: async (data, fetchOptions) => {
258
+ return $fetch("/commet/usage/track", {
259
+ method: "POST",
260
+ body: data,
261
+ ...fetchOptions
262
+ });
263
+ }
264
+ },
265
+ // Seat management
266
+ seats: {
267
+ /**
268
+ * List all seat balances for the authenticated user
269
+ */
270
+ list: async (fetchOptions) => {
271
+ return $fetch("/commet/seats", {
272
+ method: "GET",
273
+ ...fetchOptions
274
+ });
275
+ },
276
+ /**
277
+ * Add seats of a specific type
278
+ */
279
+ add: async (data, fetchOptions) => {
280
+ return $fetch("/commet/seats/add", {
281
+ method: "POST",
282
+ body: data,
283
+ ...fetchOptions
284
+ });
285
+ },
286
+ /**
287
+ * Remove seats of a specific type
288
+ */
289
+ remove: async (data, fetchOptions) => {
290
+ return $fetch("/commet/seats/remove", {
291
+ method: "POST",
292
+ body: data,
293
+ ...fetchOptions
294
+ });
295
+ },
296
+ /**
297
+ * Set seats to a specific count
298
+ */
299
+ set: async (data, fetchOptions) => {
300
+ return $fetch("/commet/seats/set", {
301
+ method: "POST",
302
+ body: data,
303
+ ...fetchOptions
304
+ });
305
+ },
306
+ /**
307
+ * Set all seat types at once
308
+ */
309
+ setAll: async (data, fetchOptions) => {
310
+ return $fetch("/commet/seats/set-all", {
311
+ method: "POST",
312
+ body: data,
313
+ ...fetchOptions
314
+ });
315
+ }
316
+ }
317
+ };
318
+ }
319
+ };
320
+ };
321
+
322
+ // src/plugins/portal.ts
323
+ var import_api2 = require("better-auth/api");
324
+ var import_plugins = require("better-auth/plugins");
325
+ var portal = ({ returnUrl } = {}) => (commet2) => {
326
+ return {
327
+ portal: (0, import_plugins.createAuthEndpoint)(
328
+ "/commet/portal",
329
+ {
330
+ method: "GET",
331
+ use: [import_api2.sessionMiddleware]
332
+ },
333
+ async (ctx) => {
334
+ const userId = ctx.context.session?.user.id;
335
+ if (!userId) {
336
+ throw new import_api2.APIError("UNAUTHORIZED", {
337
+ message: "You must be logged in to access the customer portal"
338
+ });
339
+ }
340
+ try {
341
+ const portalAccess = await commet2.portal.getUrl({
342
+ externalId: userId
343
+ });
344
+ if (!portalAccess.success || !portalAccess.data) {
345
+ throw new import_api2.APIError("INTERNAL_SERVER_ERROR", {
346
+ message: portalAccess.message || "Failed to generate portal URL"
347
+ });
348
+ }
349
+ let portalUrl = portalAccess.data.portalUrl;
350
+ if (returnUrl) {
351
+ const url = new URL(portalUrl);
352
+ url.searchParams.set("return_url", returnUrl);
353
+ portalUrl = url.toString();
354
+ }
355
+ return ctx.json({
356
+ url: portalUrl,
357
+ redirect: true
358
+ });
359
+ } catch (e) {
360
+ if (e instanceof import_api2.APIError) {
361
+ throw e;
362
+ }
363
+ if (e instanceof Error) {
364
+ ctx.context.logger.error(
365
+ `Commet portal access failed: ${e.message}`
366
+ );
367
+ }
368
+ throw new import_api2.APIError("INTERNAL_SERVER_ERROR", {
369
+ message: "Failed to access customer portal"
370
+ });
371
+ }
372
+ }
373
+ )
374
+ };
375
+ };
376
+
377
+ // src/plugins/subscriptions.ts
378
+ var import_api3 = require("better-auth/api");
379
+ var import_plugins2 = require("better-auth/plugins");
380
+ var import_zod = require("zod");
381
+ var ChangePlanSchema = import_zod.z.object({
382
+ planId: import_zod.z.string().optional(),
383
+ slug: import_zod.z.string().optional(),
384
+ billingInterval: import_zod.z.enum(["monthly", "quarterly", "yearly"]).optional()
385
+ });
386
+ var CancelSchema = import_zod.z.object({
387
+ reason: import_zod.z.string().optional(),
388
+ immediate: import_zod.z.boolean().optional()
389
+ });
390
+ var subscriptions = (config = {}) => (commet2) => {
391
+ return {
392
+ getSubscription: (0, import_plugins2.createAuthEndpoint)(
393
+ "/commet/subscription",
394
+ {
395
+ method: "GET",
396
+ use: [import_api3.sessionMiddleware]
397
+ },
398
+ async (ctx) => {
399
+ const userId = ctx.context.session?.user.id;
400
+ if (!userId) {
401
+ throw new import_api3.APIError("UNAUTHORIZED", {
402
+ message: "You must be logged in to view subscription"
403
+ });
404
+ }
405
+ try {
406
+ const subscription = await commet2.subscriptions.get(userId);
407
+ if (!subscription.success) {
408
+ throw new import_api3.APIError("INTERNAL_SERVER_ERROR", {
409
+ message: subscription.message || "Failed to retrieve subscription"
410
+ });
411
+ }
412
+ return ctx.json(subscription.data ?? null);
413
+ } catch (e) {
414
+ if (e instanceof import_api3.APIError) {
415
+ throw e;
416
+ }
417
+ if (e instanceof Error) {
418
+ ctx.context.logger.error(
419
+ `Commet subscription get failed: ${e.message}`
420
+ );
421
+ }
422
+ throw new import_api3.APIError("INTERNAL_SERVER_ERROR", {
423
+ message: "Failed to retrieve subscription"
424
+ });
425
+ }
426
+ }
427
+ ),
428
+ changePlan: (0, import_plugins2.createAuthEndpoint)(
429
+ "/commet/subscription/change-plan",
430
+ {
431
+ method: "POST",
432
+ body: ChangePlanSchema,
433
+ use: [import_api3.sessionMiddleware]
434
+ },
435
+ async (ctx) => {
436
+ const userId = ctx.context.session?.user.id;
437
+ if (!userId) {
438
+ throw new import_api3.APIError("UNAUTHORIZED", {
439
+ message: "You must be logged in to change plan"
440
+ });
441
+ }
442
+ let planId = ctx.body.planId;
443
+ if (ctx.body.slug && !planId) {
444
+ const plan = config.plans?.find((p) => p.slug === ctx.body.slug);
445
+ if (!plan) {
446
+ throw new import_api3.APIError("BAD_REQUEST", {
447
+ message: `Plan with slug "${ctx.body.slug}" not found`
448
+ });
449
+ }
450
+ planId = plan.planId;
451
+ }
452
+ if (!planId) {
453
+ throw new import_api3.APIError("BAD_REQUEST", {
454
+ message: "Either planId or slug must be provided"
455
+ });
456
+ }
457
+ try {
458
+ const currentSub = await commet2.subscriptions.get(userId);
459
+ if (!currentSub.success || !currentSub.data) {
460
+ throw new import_api3.APIError("BAD_REQUEST", {
461
+ message: "No active subscription found"
462
+ });
463
+ }
464
+ const result = await commet2.subscriptions.changePlan({
465
+ subscriptionId: currentSub.data.id,
466
+ planId,
467
+ billingInterval: ctx.body.billingInterval
468
+ });
469
+ if (!result.success) {
470
+ throw new import_api3.APIError("INTERNAL_SERVER_ERROR", {
471
+ message: result.message || "Failed to change plan"
472
+ });
473
+ }
474
+ return ctx.json(result.data ?? null);
475
+ } catch (e) {
476
+ if (e instanceof import_api3.APIError) {
477
+ throw e;
478
+ }
479
+ if (e instanceof Error) {
480
+ ctx.context.logger.error(
481
+ `Commet plan change failed: ${e.message}`
482
+ );
483
+ }
484
+ throw new import_api3.APIError("INTERNAL_SERVER_ERROR", {
485
+ message: "Failed to change plan"
486
+ });
487
+ }
488
+ }
489
+ ),
490
+ cancelSubscription: (0, import_plugins2.createAuthEndpoint)(
491
+ "/commet/subscription/cancel",
492
+ {
493
+ method: "POST",
494
+ body: CancelSchema.optional(),
495
+ use: [import_api3.sessionMiddleware]
496
+ },
497
+ async (ctx) => {
498
+ const userId = ctx.context.session?.user.id;
499
+ if (!userId) {
500
+ throw new import_api3.APIError("UNAUTHORIZED", {
501
+ message: "You must be logged in to cancel subscription"
502
+ });
503
+ }
504
+ try {
505
+ const currentSub = await commet2.subscriptions.get(userId);
506
+ if (!currentSub.success || !currentSub.data) {
507
+ throw new import_api3.APIError("BAD_REQUEST", {
508
+ message: "No active subscription found"
509
+ });
510
+ }
511
+ const result = await commet2.subscriptions.cancel({
512
+ subscriptionId: currentSub.data.id,
513
+ reason: ctx.body?.reason,
514
+ immediate: ctx.body?.immediate
515
+ });
516
+ if (!result.success) {
517
+ throw new import_api3.APIError("INTERNAL_SERVER_ERROR", {
518
+ message: result.message || "Failed to cancel subscription"
519
+ });
520
+ }
521
+ return ctx.json(result.data ?? null);
522
+ } catch (e) {
523
+ if (e instanceof import_api3.APIError) {
524
+ throw e;
525
+ }
526
+ if (e instanceof Error) {
527
+ ctx.context.logger.error(
528
+ `Commet subscription cancel failed: ${e.message}`
529
+ );
530
+ }
531
+ throw new import_api3.APIError("INTERNAL_SERVER_ERROR", {
532
+ message: "Failed to cancel subscription"
533
+ });
534
+ }
535
+ }
536
+ )
537
+ };
538
+ };
539
+
540
+ // src/plugins/features.ts
541
+ var import_api4 = require("better-auth/api");
542
+ var import_plugins3 = require("better-auth/plugins");
543
+ var features = (_config = {}) => (commet2) => {
544
+ return {
545
+ listFeatures: (0, import_plugins3.createAuthEndpoint)(
546
+ "/commet/features",
547
+ {
548
+ method: "GET",
549
+ use: [import_api4.sessionMiddleware]
550
+ },
551
+ async (ctx) => {
552
+ const userId = ctx.context.session?.user.id;
553
+ if (!userId) {
554
+ throw new import_api4.APIError("UNAUTHORIZED", {
555
+ message: "You must be logged in to view features"
556
+ });
557
+ }
558
+ try {
559
+ const result = await commet2.features.list(userId);
560
+ if (!result.success) {
561
+ throw new import_api4.APIError("INTERNAL_SERVER_ERROR", {
562
+ message: result.message || "Failed to list features"
563
+ });
564
+ }
565
+ return ctx.json(result.data ?? null);
566
+ } catch (e) {
567
+ if (e instanceof import_api4.APIError) {
568
+ throw e;
569
+ }
570
+ if (e instanceof Error) {
571
+ ctx.context.logger.error(
572
+ `Commet features list failed: ${e.message}`
573
+ );
574
+ }
575
+ throw new import_api4.APIError("INTERNAL_SERVER_ERROR", {
576
+ message: "Failed to list features"
577
+ });
578
+ }
579
+ }
580
+ ),
581
+ getFeature: (0, import_plugins3.createAuthEndpoint)(
582
+ "/commet/features/:code",
583
+ {
584
+ method: "GET",
585
+ use: [import_api4.sessionMiddleware]
586
+ },
587
+ async (ctx) => {
588
+ const userId = ctx.context.session?.user.id;
589
+ const code = ctx.params?.code;
590
+ if (!userId) {
591
+ throw new import_api4.APIError("UNAUTHORIZED", {
592
+ message: "You must be logged in to view feature"
593
+ });
594
+ }
595
+ if (!code) {
596
+ throw new import_api4.APIError("BAD_REQUEST", {
597
+ message: "Feature code is required"
598
+ });
599
+ }
600
+ try {
601
+ const result = await commet2.features.get({
602
+ externalId: userId,
603
+ code
604
+ });
605
+ if (!result.success) {
606
+ throw new import_api4.APIError("INTERNAL_SERVER_ERROR", {
607
+ message: result.message || "Failed to get feature"
608
+ });
609
+ }
610
+ return ctx.json(result.data ?? null);
611
+ } catch (e) {
612
+ if (e instanceof import_api4.APIError) {
613
+ throw e;
614
+ }
615
+ if (e instanceof Error) {
616
+ ctx.context.logger.error(
617
+ `Commet feature get failed: ${e.message}`
618
+ );
619
+ }
620
+ throw new import_api4.APIError("INTERNAL_SERVER_ERROR", {
621
+ message: "Failed to get feature"
622
+ });
623
+ }
624
+ }
625
+ ),
626
+ checkFeature: (0, import_plugins3.createAuthEndpoint)(
627
+ "/commet/features/:code/check",
628
+ {
629
+ method: "GET",
630
+ use: [import_api4.sessionMiddleware]
631
+ },
632
+ async (ctx) => {
633
+ const userId = ctx.context.session?.user.id;
634
+ const code = ctx.params?.code;
635
+ if (!userId) {
636
+ throw new import_api4.APIError("UNAUTHORIZED", {
637
+ message: "You must be logged in to check feature"
638
+ });
639
+ }
640
+ if (!code) {
641
+ throw new import_api4.APIError("BAD_REQUEST", {
642
+ message: "Feature code is required"
643
+ });
644
+ }
645
+ try {
646
+ const result = await commet2.features.check({
647
+ externalId: userId,
648
+ code
649
+ });
650
+ if (!result.success) {
651
+ throw new import_api4.APIError("INTERNAL_SERVER_ERROR", {
652
+ message: result.message || "Failed to check feature"
653
+ });
654
+ }
655
+ return ctx.json(result.data ?? null);
656
+ } catch (e) {
657
+ if (e instanceof import_api4.APIError) {
658
+ throw e;
659
+ }
660
+ if (e instanceof Error) {
661
+ ctx.context.logger.error(
662
+ `Commet feature check failed: ${e.message}`
663
+ );
664
+ }
665
+ throw new import_api4.APIError("INTERNAL_SERVER_ERROR", {
666
+ message: "Failed to check feature"
667
+ });
668
+ }
669
+ }
670
+ ),
671
+ canUseFeature: (0, import_plugins3.createAuthEndpoint)(
672
+ "/commet/features/:code/can-use",
673
+ {
674
+ method: "GET",
675
+ use: [import_api4.sessionMiddleware]
676
+ },
677
+ async (ctx) => {
678
+ const userId = ctx.context.session?.user.id;
679
+ const code = ctx.params?.code;
680
+ if (!userId) {
681
+ throw new import_api4.APIError("UNAUTHORIZED", {
682
+ message: "You must be logged in to check feature usage"
683
+ });
684
+ }
685
+ if (!code) {
686
+ throw new import_api4.APIError("BAD_REQUEST", {
687
+ message: "Feature code is required"
688
+ });
689
+ }
690
+ try {
691
+ const result = await commet2.features.canUse({
692
+ externalId: userId,
693
+ code
694
+ });
695
+ if (!result.success) {
696
+ throw new import_api4.APIError("INTERNAL_SERVER_ERROR", {
697
+ message: result.message || "Failed to check feature usage"
698
+ });
699
+ }
700
+ return ctx.json(result.data ?? null);
701
+ } catch (e) {
702
+ if (e instanceof import_api4.APIError) {
703
+ throw e;
704
+ }
705
+ if (e instanceof Error) {
706
+ ctx.context.logger.error(
707
+ `Commet feature canUse failed: ${e.message}`
708
+ );
709
+ }
710
+ throw new import_api4.APIError("INTERNAL_SERVER_ERROR", {
711
+ message: "Failed to check feature usage"
712
+ });
713
+ }
714
+ }
715
+ )
716
+ };
717
+ };
718
+
719
+ // src/plugins/usage.ts
720
+ var import_api5 = require("better-auth/api");
721
+ var import_plugins4 = require("better-auth/plugins");
722
+ var import_zod2 = require("zod");
723
+ var TrackEventSchema = import_zod2.z.object({
724
+ eventType: import_zod2.z.string(),
725
+ value: import_zod2.z.number().optional(),
726
+ idempotencyKey: import_zod2.z.string().optional(),
727
+ properties: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional()
728
+ });
729
+ var usage = (_config = {}) => (commet2) => {
730
+ return {
731
+ trackUsage: (0, import_plugins4.createAuthEndpoint)(
732
+ "/commet/usage/track",
733
+ {
734
+ method: "POST",
735
+ body: TrackEventSchema,
736
+ use: [import_api5.sessionMiddleware]
737
+ },
738
+ async (ctx) => {
739
+ const userId = ctx.context.session?.user.id;
740
+ if (!userId) {
741
+ throw new import_api5.APIError("UNAUTHORIZED", {
742
+ message: "You must be logged in to track usage"
743
+ });
744
+ }
745
+ try {
746
+ const result = await commet2.usage.track(
747
+ {
748
+ externalId: userId,
749
+ eventType: ctx.body.eventType,
750
+ idempotencyKey: ctx.body.idempotencyKey,
751
+ properties: ctx.body.properties
752
+ },
753
+ {}
754
+ );
755
+ if (!result.success) {
756
+ throw new import_api5.APIError("INTERNAL_SERVER_ERROR", {
757
+ message: result.message || "Failed to track usage"
758
+ });
759
+ }
760
+ return ctx.json(result.data ?? null);
761
+ } catch (e) {
762
+ if (e instanceof import_api5.APIError) {
763
+ throw e;
764
+ }
765
+ if (e instanceof Error) {
766
+ ctx.context.logger.error(
767
+ `Commet usage track failed: ${e.message}`
768
+ );
769
+ }
770
+ throw new import_api5.APIError("INTERNAL_SERVER_ERROR", {
771
+ message: "Failed to track usage"
772
+ });
773
+ }
774
+ }
775
+ )
776
+ };
777
+ };
778
+
779
+ // src/plugins/seats.ts
780
+ var import_api6 = require("better-auth/api");
781
+ var import_plugins5 = require("better-auth/plugins");
782
+ var import_zod3 = require("zod");
783
+ var SeatOperationSchema = import_zod3.z.object({
784
+ seatType: import_zod3.z.string(),
785
+ count: import_zod3.z.number().min(1)
786
+ });
787
+ var SetAllSeatsSchema = import_zod3.z.object({
788
+ seats: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.number())
789
+ });
790
+ var seats = (_config = {}) => (commet2) => {
791
+ return {
792
+ listSeats: (0, import_plugins5.createAuthEndpoint)(
793
+ "/commet/seats",
794
+ {
795
+ method: "GET",
796
+ use: [import_api6.sessionMiddleware]
797
+ },
798
+ async (ctx) => {
799
+ const userId = ctx.context.session?.user.id;
800
+ if (!userId) {
801
+ throw new import_api6.APIError("UNAUTHORIZED", {
802
+ message: "You must be logged in to view seats"
803
+ });
804
+ }
805
+ try {
806
+ const result = await commet2.seats.getAllBalances({
807
+ externalId: userId
808
+ });
809
+ if (!result.success) {
810
+ throw new import_api6.APIError("INTERNAL_SERVER_ERROR", {
811
+ message: result.message || "Failed to list seats"
812
+ });
813
+ }
814
+ return ctx.json(result.data ?? null);
815
+ } catch (e) {
816
+ if (e instanceof import_api6.APIError) {
817
+ throw e;
818
+ }
819
+ if (e instanceof Error) {
820
+ ctx.context.logger.error(
821
+ `Commet seats list failed: ${e.message}`
822
+ );
823
+ }
824
+ throw new import_api6.APIError("INTERNAL_SERVER_ERROR", {
825
+ message: "Failed to list seats"
826
+ });
827
+ }
828
+ }
829
+ ),
830
+ addSeats: (0, import_plugins5.createAuthEndpoint)(
831
+ "/commet/seats/add",
832
+ {
833
+ method: "POST",
834
+ body: SeatOperationSchema,
835
+ use: [import_api6.sessionMiddleware]
836
+ },
837
+ async (ctx) => {
838
+ const userId = ctx.context.session?.user.id;
839
+ if (!userId) {
840
+ throw new import_api6.APIError("UNAUTHORIZED", {
841
+ message: "You must be logged in to add seats"
842
+ });
843
+ }
844
+ try {
845
+ const result = await commet2.seats.add(
846
+ {
847
+ externalId: userId,
848
+ seatType: ctx.body.seatType,
849
+ count: ctx.body.count
850
+ },
851
+ {}
852
+ );
853
+ if (!result.success) {
854
+ throw new import_api6.APIError("INTERNAL_SERVER_ERROR", {
855
+ message: result.message || "Failed to add seats"
856
+ });
857
+ }
858
+ return ctx.json(result.data ?? null);
859
+ } catch (e) {
860
+ if (e instanceof import_api6.APIError) {
861
+ throw e;
862
+ }
863
+ if (e instanceof Error) {
864
+ ctx.context.logger.error(`Commet seats add failed: ${e.message}`);
865
+ }
866
+ throw new import_api6.APIError("INTERNAL_SERVER_ERROR", {
867
+ message: "Failed to add seats"
868
+ });
869
+ }
870
+ }
871
+ ),
872
+ removeSeats: (0, import_plugins5.createAuthEndpoint)(
873
+ "/commet/seats/remove",
874
+ {
875
+ method: "POST",
876
+ body: SeatOperationSchema,
877
+ use: [import_api6.sessionMiddleware]
878
+ },
879
+ async (ctx) => {
880
+ const userId = ctx.context.session?.user.id;
881
+ if (!userId) {
882
+ throw new import_api6.APIError("UNAUTHORIZED", {
883
+ message: "You must be logged in to remove seats"
884
+ });
885
+ }
886
+ try {
887
+ const result = await commet2.seats.remove(
888
+ {
889
+ externalId: userId,
890
+ seatType: ctx.body.seatType,
891
+ count: ctx.body.count
892
+ },
893
+ {}
894
+ );
895
+ if (!result.success) {
896
+ throw new import_api6.APIError("INTERNAL_SERVER_ERROR", {
897
+ message: result.message || "Failed to remove seats"
898
+ });
899
+ }
900
+ return ctx.json(result.data ?? null);
901
+ } catch (e) {
902
+ if (e instanceof import_api6.APIError) {
903
+ throw e;
904
+ }
905
+ if (e instanceof Error) {
906
+ ctx.context.logger.error(
907
+ `Commet seats remove failed: ${e.message}`
908
+ );
909
+ }
910
+ throw new import_api6.APIError("INTERNAL_SERVER_ERROR", {
911
+ message: "Failed to remove seats"
912
+ });
913
+ }
914
+ }
915
+ ),
916
+ setSeats: (0, import_plugins5.createAuthEndpoint)(
917
+ "/commet/seats/set",
918
+ {
919
+ method: "POST",
920
+ body: SeatOperationSchema,
921
+ use: [import_api6.sessionMiddleware]
922
+ },
923
+ async (ctx) => {
924
+ const userId = ctx.context.session?.user.id;
925
+ if (!userId) {
926
+ throw new import_api6.APIError("UNAUTHORIZED", {
927
+ message: "You must be logged in to set seats"
928
+ });
929
+ }
930
+ try {
931
+ const result = await commet2.seats.set(
932
+ {
933
+ externalId: userId,
934
+ seatType: ctx.body.seatType,
935
+ count: ctx.body.count
936
+ },
937
+ {}
938
+ );
939
+ if (!result.success) {
940
+ throw new import_api6.APIError("INTERNAL_SERVER_ERROR", {
941
+ message: result.message || "Failed to set seats"
942
+ });
943
+ }
944
+ return ctx.json(result.data ?? null);
945
+ } catch (e) {
946
+ if (e instanceof import_api6.APIError) {
947
+ throw e;
948
+ }
949
+ if (e instanceof Error) {
950
+ ctx.context.logger.error(`Commet seats set failed: ${e.message}`);
951
+ }
952
+ throw new import_api6.APIError("INTERNAL_SERVER_ERROR", {
953
+ message: "Failed to set seats"
954
+ });
955
+ }
956
+ }
957
+ ),
958
+ setAllSeats: (0, import_plugins5.createAuthEndpoint)(
959
+ "/commet/seats/set-all",
960
+ {
961
+ method: "POST",
962
+ body: SetAllSeatsSchema,
963
+ use: [import_api6.sessionMiddleware]
964
+ },
965
+ async (ctx) => {
966
+ const userId = ctx.context.session?.user.id;
967
+ if (!userId) {
968
+ throw new import_api6.APIError("UNAUTHORIZED", {
969
+ message: "You must be logged in to set seats"
970
+ });
971
+ }
972
+ try {
973
+ const result = await commet2.seats.setAll(
974
+ {
975
+ externalId: userId,
976
+ seats: ctx.body.seats
977
+ },
978
+ {}
979
+ );
980
+ if (!result.success) {
981
+ throw new import_api6.APIError("INTERNAL_SERVER_ERROR", {
982
+ message: result.message || "Failed to set all seats"
983
+ });
984
+ }
985
+ return ctx.json(result.data ?? null);
986
+ } catch (e) {
987
+ if (e instanceof import_api6.APIError) {
988
+ throw e;
989
+ }
990
+ if (e instanceof Error) {
991
+ ctx.context.logger.error(
992
+ `Commet seats set-all failed: ${e.message}`
993
+ );
994
+ }
995
+ throw new import_api6.APIError("INTERNAL_SERVER_ERROR", {
996
+ message: "Failed to set all seats"
997
+ });
998
+ }
999
+ }
1000
+ )
1001
+ };
1002
+ };
1003
+
1004
+ // src/plugins/webhooks.ts
1005
+ var import_api7 = require("better-auth/api");
1006
+ var EVENT_HANDLER_MAP = {
1007
+ "subscription.created": "onSubscriptionCreated",
1008
+ "subscription.activated": "onSubscriptionActivated",
1009
+ "subscription.canceled": "onSubscriptionCanceled",
1010
+ "subscription.updated": "onSubscriptionUpdated"
1011
+ };
1012
+ var webhooks = (config) => (commet2) => {
1013
+ return {
1014
+ commetWebhooks: (0, import_api7.createAuthEndpoint)(
1015
+ "/commet/webhooks",
1016
+ {
1017
+ method: "POST",
1018
+ metadata: {
1019
+ isAction: false
1020
+ },
1021
+ cloneRequest: true
1022
+ },
1023
+ async (ctx) => {
1024
+ if (!ctx.request?.body) {
1025
+ throw new import_api7.APIError("BAD_REQUEST", {
1026
+ message: "Request body is required"
1027
+ });
1028
+ }
1029
+ const rawBody = await ctx.request.text();
1030
+ const signature = ctx.request.headers.get("x-commet-signature");
1031
+ const payload = commet2.webhooks.verifyAndParse({
1032
+ rawBody,
1033
+ signature,
1034
+ secret: config.secret
1035
+ });
1036
+ if (!payload) {
1037
+ ctx.context.logger.error("Invalid webhook signature");
1038
+ throw new import_api7.APIError("UNAUTHORIZED", {
1039
+ message: "Invalid webhook signature"
1040
+ });
1041
+ }
1042
+ try {
1043
+ const handlerKey = EVENT_HANDLER_MAP[payload.event];
1044
+ if (handlerKey) {
1045
+ const handler = config[handlerKey];
1046
+ if (handler) {
1047
+ await handler(payload);
1048
+ }
1049
+ }
1050
+ if (config.onPayload) {
1051
+ await config.onPayload(payload);
1052
+ }
1053
+ return ctx.json({ received: true });
1054
+ } catch (e) {
1055
+ if (e instanceof Error) {
1056
+ ctx.context.logger.error(
1057
+ `Commet webhook handler error: ${e.message}`
1058
+ );
1059
+ } else {
1060
+ ctx.context.logger.error("Commet webhook handler error");
1061
+ }
1062
+ throw new import_api7.APIError("INTERNAL_SERVER_ERROR", {
1063
+ message: "Webhook handler error"
1064
+ });
1065
+ }
1066
+ }
1067
+ )
1068
+ };
1069
+ };
1070
+
1071
+ // src/index.ts
1072
+ var commet = (options) => {
1073
+ const plugins = options.use.map((use) => use(options.client)).reduce((acc, plugin) => {
1074
+ Object.assign(acc, plugin);
1075
+ return acc;
1076
+ }, {});
1077
+ return {
1078
+ id: "commet",
1079
+ endpoints: {
1080
+ ...plugins
1081
+ },
1082
+ init() {
1083
+ return {
1084
+ options: {
1085
+ databaseHooks: {
1086
+ user: {
1087
+ create: {
1088
+ before: onBeforeUserCreate(options),
1089
+ after: onAfterUserCreate(options)
1090
+ },
1091
+ update: {
1092
+ after: onUserUpdate(options)
1093
+ },
1094
+ delete: {
1095
+ after: onUserDelete(options)
1096
+ }
1097
+ }
1098
+ }
1099
+ }
1100
+ };
1101
+ }
1102
+ };
1103
+ };
1104
+ // Annotate the CommonJS export names for ESM import in node:
1105
+ 0 && (module.exports = {
1106
+ commet,
1107
+ commetClient,
1108
+ features,
1109
+ portal,
1110
+ seats,
1111
+ subscriptions,
1112
+ usage,
1113
+ webhooks
1114
+ });
1115
+ //# sourceMappingURL=index.cjs.map