@spaire/better-auth 2.0.1 → 3.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.js ADDED
@@ -0,0 +1,782 @@
1
+ import {
2
+ spaireClient
3
+ } from "./chunk-M473XWC5.js";
4
+
5
+ // src/hooks/customer.ts
6
+ import { APIError } from "better-auth/api";
7
+ var onBeforeUserCreate = (options) => async (user, context) => {
8
+ if (context && options.createCustomerOnSignUp) {
9
+ try {
10
+ const params = options.getCustomerCreateParams ? await options.getCustomerCreateParams({
11
+ user
12
+ }) : {};
13
+ if (!user.email) {
14
+ throw new APIError("BAD_REQUEST", {
15
+ message: "An associated email is required"
16
+ });
17
+ }
18
+ const { result: existingCustomers } = await options.client.customers.list({ email: user.email });
19
+ const existingCustomer = existingCustomers.items[0];
20
+ if (!existingCustomer) {
21
+ await options.client.customers.create({
22
+ ...params,
23
+ email: user.email,
24
+ name: user.name
25
+ });
26
+ }
27
+ } catch (e) {
28
+ if (e instanceof Error) {
29
+ throw new APIError("INTERNAL_SERVER_ERROR", {
30
+ message: `Spaire customer creation failed. Error: ${e.message}`
31
+ });
32
+ }
33
+ throw new APIError("INTERNAL_SERVER_ERROR", {
34
+ message: `Spaire customer creation failed. Error: ${e}`
35
+ });
36
+ }
37
+ }
38
+ };
39
+ var onAfterUserCreate = (options) => async (user, context) => {
40
+ if (context && options.createCustomerOnSignUp) {
41
+ try {
42
+ const { result: existingCustomers } = await options.client.customers.list({ email: user.email });
43
+ const existingCustomer = existingCustomers.items[0];
44
+ if (existingCustomer) {
45
+ if (existingCustomer.externalId !== user.id) {
46
+ await options.client.customers.update({
47
+ id: existingCustomer.id,
48
+ customerUpdate: {
49
+ externalId: user.id
50
+ }
51
+ });
52
+ }
53
+ }
54
+ } catch (e) {
55
+ if (e instanceof Error) {
56
+ throw new APIError("INTERNAL_SERVER_ERROR", {
57
+ message: `Spaire customer creation failed. Error: ${e.message}`
58
+ });
59
+ }
60
+ throw new APIError("INTERNAL_SERVER_ERROR", {
61
+ message: `Spaire customer creation failed. Error: ${e}`
62
+ });
63
+ }
64
+ }
65
+ };
66
+ var onUserUpdate = (options) => async (user, context) => {
67
+ if (context && options.createCustomerOnSignUp) {
68
+ try {
69
+ await options.client.customers.updateExternal({
70
+ externalId: user.id,
71
+ customerUpdateExternalID: {
72
+ email: user.email,
73
+ name: user.name
74
+ }
75
+ });
76
+ } catch (e) {
77
+ if (e instanceof Error) {
78
+ context.context.logger.error(
79
+ `Spaire customer update failed. Error: ${e.message}`
80
+ );
81
+ } else {
82
+ context.context.logger.error(
83
+ `Spaire customer update failed. Error: ${e}`
84
+ );
85
+ }
86
+ }
87
+ }
88
+ };
89
+ var onUserDelete = (options) => async (user, context) => {
90
+ if (context && options.createCustomerOnSignUp) {
91
+ try {
92
+ if (user.email) {
93
+ const { result: existingCustomers } = await options.client.customers.list({ email: user.email });
94
+ const existingCustomer = existingCustomers.items[0];
95
+ if (existingCustomer) {
96
+ await options.client.customers.delete({
97
+ id: existingCustomer.id
98
+ });
99
+ }
100
+ }
101
+ } catch (e) {
102
+ if (e instanceof Error) {
103
+ context?.context.logger.error(
104
+ `Spaire customer delete failed. Error: ${e.message}`
105
+ );
106
+ return;
107
+ }
108
+ context?.context.logger.error(
109
+ `Spaire customer delete failed. Error: ${e}`
110
+ );
111
+ }
112
+ }
113
+ };
114
+
115
+ // src/plugins/portal.ts
116
+ import { APIError as APIError2 } from "better-auth/api";
117
+ import { sessionMiddleware } from "better-auth/api";
118
+ import { createAuthEndpoint } from "better-auth/plugins";
119
+ import { z } from "zod";
120
+ var portal = ({ returnUrl } = {}) => (spaire2) => {
121
+ const retUrl = returnUrl ? new URL(returnUrl) : void 0;
122
+ return {
123
+ portal: createAuthEndpoint(
124
+ "/customer/portal",
125
+ {
126
+ method: "GET",
127
+ use: [sessionMiddleware]
128
+ },
129
+ async (ctx) => {
130
+ if (!ctx.context.session?.user.id) {
131
+ throw new APIError2("BAD_REQUEST", {
132
+ message: "User not found"
133
+ });
134
+ }
135
+ try {
136
+ const customerSession = await spaire2.customerSessions.create({
137
+ externalCustomerId: ctx.context.session?.user.id,
138
+ returnUrl: retUrl ? decodeURI(retUrl.toString()) : void 0
139
+ });
140
+ return ctx.json({
141
+ url: customerSession.customerPortalUrl,
142
+ redirect: true
143
+ });
144
+ } catch (e) {
145
+ if (e instanceof Error) {
146
+ ctx.context.logger.error(
147
+ `Spaire customer portal creation failed. Error: ${e.message}`
148
+ );
149
+ }
150
+ throw new APIError2("INTERNAL_SERVER_ERROR", {
151
+ message: "Customer portal creation failed"
152
+ });
153
+ }
154
+ }
155
+ ),
156
+ state: createAuthEndpoint(
157
+ "/customer/state",
158
+ {
159
+ method: "GET",
160
+ use: [sessionMiddleware]
161
+ },
162
+ async (ctx) => {
163
+ if (!ctx.context.session.user.id) {
164
+ throw new APIError2("BAD_REQUEST", {
165
+ message: "User not found"
166
+ });
167
+ }
168
+ try {
169
+ const state = await spaire2.customers.getStateExternal({
170
+ externalId: ctx.context.session?.user.id
171
+ });
172
+ return ctx.json(state);
173
+ } catch (e) {
174
+ if (e instanceof Error) {
175
+ ctx.context.logger.error(
176
+ `Spaire subscriptions list failed. Error: ${e.message}`
177
+ );
178
+ }
179
+ throw new APIError2("INTERNAL_SERVER_ERROR", {
180
+ message: "Subscriptions list failed"
181
+ });
182
+ }
183
+ }
184
+ ),
185
+ benefits: createAuthEndpoint(
186
+ "/customer/benefits/list",
187
+ {
188
+ method: "GET",
189
+ query: z.object({
190
+ page: z.coerce.number().optional(),
191
+ limit: z.coerce.number().optional()
192
+ }).optional(),
193
+ use: [sessionMiddleware]
194
+ },
195
+ async (ctx) => {
196
+ if (!ctx.context.session.user.id) {
197
+ throw new APIError2("BAD_REQUEST", {
198
+ message: "User not found"
199
+ });
200
+ }
201
+ try {
202
+ const customerSession = await spaire2.customerSessions.create({
203
+ externalCustomerId: ctx.context.session?.user.id
204
+ });
205
+ const benefits = await spaire2.customerPortal.benefitGrants.list(
206
+ { customerSession: customerSession.token },
207
+ {
208
+ page: ctx.query?.page,
209
+ limit: ctx.query?.limit
210
+ }
211
+ );
212
+ return ctx.json(benefits);
213
+ } catch (e) {
214
+ if (e instanceof Error) {
215
+ ctx.context.logger.error(
216
+ `Spaire benefits list failed. Error: ${e.message}`
217
+ );
218
+ }
219
+ throw new APIError2("INTERNAL_SERVER_ERROR", {
220
+ message: "Benefits list failed"
221
+ });
222
+ }
223
+ }
224
+ ),
225
+ subscriptions: createAuthEndpoint(
226
+ "/customer/subscriptions/list",
227
+ {
228
+ method: "GET",
229
+ query: z.object({
230
+ referenceId: z.string().optional(),
231
+ page: z.coerce.number().optional(),
232
+ limit: z.coerce.number().optional(),
233
+ active: z.coerce.boolean().optional()
234
+ }).optional(),
235
+ use: [sessionMiddleware]
236
+ },
237
+ async (ctx) => {
238
+ if (!ctx.context.session.user.id) {
239
+ throw new APIError2("BAD_REQUEST", {
240
+ message: "User not found"
241
+ });
242
+ }
243
+ if (ctx.query?.referenceId) {
244
+ try {
245
+ const subscriptions = await spaire2.subscriptions.list({
246
+ page: ctx.query?.page,
247
+ limit: ctx.query?.limit,
248
+ active: ctx.query?.active,
249
+ metadata: {
250
+ referenceId: ctx.query?.referenceId
251
+ }
252
+ });
253
+ return ctx.json(subscriptions);
254
+ } catch (e) {
255
+ console.log(e);
256
+ if (e instanceof Error) {
257
+ ctx.context.logger.error(
258
+ `Spaire subscriptions list with referenceId failed. Error: ${e.message}`
259
+ );
260
+ }
261
+ throw new APIError2("INTERNAL_SERVER_ERROR", {
262
+ message: "Subscriptions list with referenceId failed"
263
+ });
264
+ }
265
+ }
266
+ try {
267
+ const customerSession = await spaire2.customerSessions.create({
268
+ externalCustomerId: ctx.context.session?.user.id
269
+ });
270
+ const subscriptions = await spaire2.customerPortal.subscriptions.list(
271
+ { customerSession: customerSession.token },
272
+ {
273
+ page: ctx.query?.page,
274
+ limit: ctx.query?.limit,
275
+ active: ctx.query?.active
276
+ }
277
+ );
278
+ return ctx.json(subscriptions);
279
+ } catch (e) {
280
+ if (e instanceof Error) {
281
+ ctx.context.logger.error(
282
+ `Spaire subscriptions list failed. Error: ${e.message}`
283
+ );
284
+ }
285
+ throw new APIError2("INTERNAL_SERVER_ERROR", {
286
+ message: "Spaire subscriptions list failed"
287
+ });
288
+ }
289
+ }
290
+ ),
291
+ orders: createAuthEndpoint(
292
+ "/customer/orders/list",
293
+ {
294
+ method: "GET",
295
+ query: z.object({
296
+ page: z.coerce.number().optional(),
297
+ limit: z.coerce.number().optional(),
298
+ productBillingType: z.enum(["recurring", "one_time"]).optional()
299
+ }).optional(),
300
+ use: [sessionMiddleware]
301
+ },
302
+ async (ctx) => {
303
+ if (!ctx.context.session.user.id) {
304
+ throw new APIError2("BAD_REQUEST", {
305
+ message: "User not found"
306
+ });
307
+ }
308
+ try {
309
+ const customerSession = await spaire2.customerSessions.create({
310
+ externalCustomerId: ctx.context.session?.user.id
311
+ });
312
+ const orders = await spaire2.customerPortal.orders.list(
313
+ { customerSession: customerSession.token },
314
+ {
315
+ page: ctx.query?.page,
316
+ limit: ctx.query?.limit,
317
+ productBillingType: ctx.query?.productBillingType
318
+ }
319
+ );
320
+ return ctx.json(orders);
321
+ } catch (e) {
322
+ if (e instanceof Error) {
323
+ ctx.context.logger.error(
324
+ `Spaire orders list failed. Error: ${e.message}`
325
+ );
326
+ }
327
+ throw new APIError2("INTERNAL_SERVER_ERROR", {
328
+ message: "Orders list failed"
329
+ });
330
+ }
331
+ }
332
+ )
333
+ };
334
+ };
335
+
336
+ // src/plugins/checkout.ts
337
+ import { APIError as APIError3, getSessionFromCtx } from "better-auth/api";
338
+ import { createAuthEndpoint as createAuthEndpoint2 } from "better-auth/plugins";
339
+ import { z as z2 } from "zod";
340
+ var CheckoutParams = z2.object({
341
+ products: z2.union([z2.array(z2.string()), z2.string()]).optional(),
342
+ slug: z2.string().optional(),
343
+ referenceId: z2.string().optional(),
344
+ customFieldData: z2.record(z2.string(), z2.union([z2.string(), z2.number(), z2.boolean()])).optional(),
345
+ metadata: z2.record(z2.string(), z2.union([z2.string(), z2.number(), z2.boolean()])).optional(),
346
+ allowDiscountCodes: z2.coerce.boolean().optional(),
347
+ discountId: z2.string().optional(),
348
+ redirect: z2.coerce.boolean().optional(),
349
+ embedOrigin: z2.string().url().optional()
350
+ });
351
+ var checkout = (checkoutOptions = {}) => (spaire2) => {
352
+ return {
353
+ checkout: createAuthEndpoint2(
354
+ "/checkout",
355
+ {
356
+ method: "POST",
357
+ body: CheckoutParams
358
+ },
359
+ async (ctx) => {
360
+ const session = await getSessionFromCtx(ctx);
361
+ let productIds = [];
362
+ if (ctx.body.slug) {
363
+ const resolvedProducts = await (typeof checkoutOptions.products === "function" ? checkoutOptions.products() : checkoutOptions.products);
364
+ const productId = resolvedProducts?.find(
365
+ (product) => product.slug === ctx.body.slug
366
+ )?.productId;
367
+ if (!productId) {
368
+ throw new APIError3("BAD_REQUEST", {
369
+ message: "Product not found"
370
+ });
371
+ }
372
+ productIds = [productId];
373
+ } else {
374
+ productIds = Array.isArray(ctx.body.products) ? ctx.body.products.filter((id) => id !== void 0) : [ctx.body.products].filter((id) => id !== void 0);
375
+ }
376
+ if (checkoutOptions.authenticatedUsersOnly && !session?.user.id) {
377
+ throw new APIError3("UNAUTHORIZED", {
378
+ message: "You must be logged in to checkout"
379
+ });
380
+ }
381
+ try {
382
+ const checkout2 = await spaire2.checkouts.create({
383
+ externalCustomerId: session?.user.id,
384
+ products: productIds,
385
+ successUrl: checkoutOptions.successUrl ? new URL(
386
+ checkoutOptions.successUrl,
387
+ ctx.request?.url ?? ctx.context.baseURL
388
+ ).toString() : void 0,
389
+ metadata: ctx.body.referenceId ? {
390
+ referenceId: ctx.body.referenceId,
391
+ ...ctx.body.metadata
392
+ } : ctx.body.metadata,
393
+ customFieldData: ctx.body.customFieldData,
394
+ allowDiscountCodes: ctx.body.allowDiscountCodes ?? true,
395
+ discountId: ctx.body.discountId,
396
+ embedOrigin: ctx.body.embedOrigin,
397
+ returnUrl: checkoutOptions.returnUrl ? new URL(
398
+ checkoutOptions.returnUrl,
399
+ ctx.request?.url ?? ctx.context.baseURL
400
+ ).toString() : void 0
401
+ });
402
+ const redirectUrl = new URL(checkout2.url);
403
+ if (checkoutOptions.theme) {
404
+ redirectUrl.searchParams.set("theme", checkoutOptions.theme);
405
+ }
406
+ return ctx.json({
407
+ url: redirectUrl.toString(),
408
+ redirect: ctx.body.redirect ?? true
409
+ });
410
+ } catch (e) {
411
+ if (e instanceof Error) {
412
+ ctx.context.logger.error(
413
+ `Spaire checkout creation failed. Error: ${e.message}`
414
+ );
415
+ }
416
+ throw new APIError3("INTERNAL_SERVER_ERROR", {
417
+ message: "Checkout creation failed"
418
+ });
419
+ }
420
+ }
421
+ )
422
+ };
423
+ };
424
+
425
+ // src/plugins/usage.ts
426
+ import {
427
+ APIError as APIError4,
428
+ createAuthEndpoint as createAuthEndpoint3,
429
+ sessionMiddleware as sessionMiddleware2
430
+ } from "better-auth/api";
431
+ import { z as z3 } from "zod";
432
+ var usage = (_usageOptions) => (spaire2) => {
433
+ return {
434
+ meters: createAuthEndpoint3(
435
+ "/usage/meters/list",
436
+ {
437
+ method: "GET",
438
+ use: [sessionMiddleware2],
439
+ query: z3.object({
440
+ page: z3.coerce.number().optional(),
441
+ limit: z3.coerce.number().optional()
442
+ })
443
+ },
444
+ async (ctx) => {
445
+ if (!ctx.context.session.user.id) {
446
+ throw new APIError4("BAD_REQUEST", {
447
+ message: "User not found"
448
+ });
449
+ }
450
+ try {
451
+ const customerSession = await spaire2.customerSessions.create({
452
+ externalCustomerId: ctx.context.session.user.id
453
+ });
454
+ const customerMeters = await spaire2.customerPortal.customerMeters.list(
455
+ { customerSession: customerSession.token },
456
+ {
457
+ page: ctx.query?.page,
458
+ limit: ctx.query?.limit
459
+ }
460
+ );
461
+ return ctx.json(customerMeters);
462
+ } catch (e) {
463
+ if (e instanceof Error) {
464
+ ctx.context.logger.error(
465
+ `Spaire meters list failed. Error: ${e.message}`
466
+ );
467
+ }
468
+ throw new APIError4("INTERNAL_SERVER_ERROR", {
469
+ message: "Meters list failed"
470
+ });
471
+ }
472
+ }
473
+ ),
474
+ ingestion: createAuthEndpoint3(
475
+ "/usage/ingest",
476
+ {
477
+ method: "POST",
478
+ body: z3.object({
479
+ event: z3.string(),
480
+ metadata: z3.record(
481
+ z3.string(),
482
+ z3.union([z3.string(), z3.number(), z3.boolean()])
483
+ )
484
+ }),
485
+ use: [sessionMiddleware2]
486
+ },
487
+ async (ctx) => {
488
+ if (!ctx.context.session.user.id) {
489
+ throw new APIError4("BAD_REQUEST", {
490
+ message: "User not found"
491
+ });
492
+ }
493
+ try {
494
+ const ingestion = await spaire2.events.ingest({
495
+ events: [
496
+ {
497
+ name: ctx.body.event,
498
+ metadata: ctx.body.metadata,
499
+ externalCustomerId: ctx.context.session.user.id
500
+ }
501
+ ]
502
+ });
503
+ return ctx.json(ingestion);
504
+ } catch (e) {
505
+ if (e instanceof Error) {
506
+ ctx.context.logger.error(
507
+ `Spaire ingestion failed. Error: ${e.message}`
508
+ );
509
+ }
510
+ throw new APIError4("INTERNAL_SERVER_ERROR", {
511
+ message: "Ingestion failed"
512
+ });
513
+ }
514
+ }
515
+ )
516
+ };
517
+ };
518
+
519
+ // ../../node_modules/.pnpm/@spaire+adapter-utils@2.0.0/node_modules/@spaire/adapter-utils/dist/index.js
520
+ var handleWebhookPayload = async (payload, { webhookSecret, entitlements, onPayload, ...eventHandlers }) => {
521
+ const promises = [];
522
+ if (onPayload) {
523
+ promises.push(onPayload(payload));
524
+ }
525
+ switch (payload.type) {
526
+ case "checkout.created":
527
+ if (eventHandlers.onCheckoutCreated) {
528
+ promises.push(eventHandlers.onCheckoutCreated(payload));
529
+ }
530
+ break;
531
+ case "checkout.updated":
532
+ if (eventHandlers.onCheckoutUpdated) {
533
+ promises.push(eventHandlers.onCheckoutUpdated(payload));
534
+ }
535
+ break;
536
+ case "order.created":
537
+ if (eventHandlers.onOrderCreated) {
538
+ promises.push(eventHandlers.onOrderCreated(payload));
539
+ }
540
+ break;
541
+ case "order.updated":
542
+ if (eventHandlers.onOrderUpdated) {
543
+ promises.push(eventHandlers.onOrderUpdated(payload));
544
+ }
545
+ break;
546
+ case "order.paid":
547
+ if (eventHandlers.onOrderPaid) {
548
+ promises.push(eventHandlers.onOrderPaid(payload));
549
+ }
550
+ break;
551
+ case "subscription.created":
552
+ if (eventHandlers.onSubscriptionCreated) {
553
+ promises.push(eventHandlers.onSubscriptionCreated(payload));
554
+ }
555
+ break;
556
+ case "subscription.updated":
557
+ if (eventHandlers.onSubscriptionUpdated) {
558
+ promises.push(eventHandlers.onSubscriptionUpdated(payload));
559
+ }
560
+ break;
561
+ case "subscription.active":
562
+ if (eventHandlers.onSubscriptionActive) {
563
+ promises.push(eventHandlers.onSubscriptionActive(payload));
564
+ }
565
+ break;
566
+ case "subscription.canceled":
567
+ if (eventHandlers.onSubscriptionCanceled) {
568
+ promises.push(eventHandlers.onSubscriptionCanceled(payload));
569
+ }
570
+ break;
571
+ case "subscription.uncanceled":
572
+ if (eventHandlers.onSubscriptionUncanceled) {
573
+ promises.push(eventHandlers.onSubscriptionUncanceled(payload));
574
+ }
575
+ break;
576
+ case "subscription.revoked":
577
+ if (eventHandlers.onSubscriptionRevoked) {
578
+ promises.push(eventHandlers.onSubscriptionRevoked(payload));
579
+ }
580
+ break;
581
+ case "product.created":
582
+ if (eventHandlers.onProductCreated) {
583
+ promises.push(eventHandlers.onProductCreated(payload));
584
+ }
585
+ break;
586
+ case "product.updated":
587
+ if (eventHandlers.onProductUpdated) {
588
+ promises.push(eventHandlers.onProductUpdated(payload));
589
+ }
590
+ break;
591
+ case "organization.updated":
592
+ if (eventHandlers.onOrganizationUpdated) {
593
+ promises.push(eventHandlers.onOrganizationUpdated(payload));
594
+ }
595
+ break;
596
+ case "benefit.created":
597
+ if (eventHandlers.onBenefitCreated) {
598
+ promises.push(eventHandlers.onBenefitCreated(payload));
599
+ }
600
+ break;
601
+ case "benefit.updated":
602
+ if (eventHandlers.onBenefitUpdated) {
603
+ promises.push(eventHandlers.onBenefitUpdated(payload));
604
+ }
605
+ break;
606
+ case "benefit_grant.created":
607
+ if (eventHandlers.onBenefitGrantCreated) {
608
+ promises.push(eventHandlers.onBenefitGrantCreated(payload));
609
+ }
610
+ break;
611
+ case "benefit_grant.updated":
612
+ if (eventHandlers.onBenefitGrantUpdated) {
613
+ promises.push(eventHandlers.onBenefitGrantUpdated(payload));
614
+ }
615
+ break;
616
+ case "benefit_grant.revoked":
617
+ if (eventHandlers.onBenefitGrantRevoked) {
618
+ promises.push(eventHandlers.onBenefitGrantRevoked(payload));
619
+ }
620
+ break;
621
+ case "customer.created":
622
+ if (eventHandlers.onCustomerCreated) {
623
+ promises.push(eventHandlers.onCustomerCreated(payload));
624
+ }
625
+ break;
626
+ case "customer.updated":
627
+ if (eventHandlers.onCustomerUpdated) {
628
+ promises.push(eventHandlers.onCustomerUpdated(payload));
629
+ }
630
+ break;
631
+ case "customer.deleted":
632
+ if (eventHandlers.onCustomerDeleted) {
633
+ promises.push(eventHandlers.onCustomerDeleted(payload));
634
+ }
635
+ break;
636
+ case "customer.state_changed":
637
+ if (eventHandlers.onCustomerStateChanged) {
638
+ promises.push(eventHandlers.onCustomerStateChanged(payload));
639
+ }
640
+ break;
641
+ case "order.refunded":
642
+ if (eventHandlers.onOrderRefunded) {
643
+ promises.push(eventHandlers.onOrderRefunded(payload));
644
+ }
645
+ break;
646
+ case "refund.created":
647
+ if (eventHandlers.onRefundCreated) {
648
+ promises.push(eventHandlers.onRefundCreated(payload));
649
+ }
650
+ break;
651
+ case "refund.updated":
652
+ if (eventHandlers.onRefundUpdated) {
653
+ promises.push(eventHandlers.onRefundUpdated(payload));
654
+ }
655
+ break;
656
+ }
657
+ switch (payload.type) {
658
+ case "benefit_grant.created":
659
+ case "benefit_grant.revoked":
660
+ if (entitlements) {
661
+ for (const handler of entitlements.handlers) {
662
+ promises.push(handler(payload));
663
+ }
664
+ }
665
+ }
666
+ return Promise.all(promises);
667
+ };
668
+
669
+ // src/plugins/webhooks.ts
670
+ import { validateEvent } from "@spaire/sdk/webhooks";
671
+ import { APIError as APIError5, createAuthEndpoint as createAuthEndpoint4 } from "better-auth/api";
672
+ var webhooks = (options) => (_spaire) => {
673
+ return {
674
+ spaireWebhooks: createAuthEndpoint4(
675
+ "/spaire/webhooks",
676
+ {
677
+ method: "POST",
678
+ metadata: {
679
+ isAction: false
680
+ },
681
+ cloneRequest: true
682
+ },
683
+ async (ctx) => {
684
+ const { secret, ...eventHandlers } = options;
685
+ if (!ctx.request?.body) {
686
+ throw new APIError5("INTERNAL_SERVER_ERROR");
687
+ }
688
+ const buf = await ctx.request.text();
689
+ let event;
690
+ try {
691
+ if (!secret) {
692
+ throw new APIError5("INTERNAL_SERVER_ERROR", {
693
+ message: "Spaire webhook secret not found"
694
+ });
695
+ }
696
+ const headers = {
697
+ "webhook-id": ctx.request.headers.get("webhook-id"),
698
+ "webhook-timestamp": ctx.request.headers.get(
699
+ "webhook-timestamp"
700
+ ),
701
+ "webhook-signature": ctx.request.headers.get(
702
+ "webhook-signature"
703
+ )
704
+ };
705
+ event = validateEvent(buf, headers, secret);
706
+ } catch (err) {
707
+ if (err instanceof Error) {
708
+ ctx.context.logger.error(`${err.message}`);
709
+ throw new APIError5("BAD_REQUEST", {
710
+ message: `Webhook Error: ${err.message}`
711
+ });
712
+ }
713
+ throw new APIError5("BAD_REQUEST", {
714
+ message: `Webhook Error: ${err}`
715
+ });
716
+ }
717
+ try {
718
+ await handleWebhookPayload(event, {
719
+ webhookSecret: secret,
720
+ ...eventHandlers
721
+ });
722
+ } catch (e) {
723
+ if (e instanceof Error) {
724
+ ctx.context.logger.error(
725
+ `Spaire webhook failed. Error: ${e.message}`
726
+ );
727
+ } else {
728
+ ctx.context.logger.error(`Spaire webhook failed. Error: ${e}`);
729
+ }
730
+ throw new APIError5("BAD_REQUEST", {
731
+ message: "Webhook error: See server logs for more information."
732
+ });
733
+ }
734
+ return ctx.json({ received: true });
735
+ }
736
+ )
737
+ };
738
+ };
739
+
740
+ // src/index.ts
741
+ var spaire = (options) => {
742
+ const plugins = options.use.map((use) => use(options.client)).reduce((acc, plugin) => {
743
+ Object.assign(acc, plugin);
744
+ return acc;
745
+ }, {});
746
+ return {
747
+ id: "spaire",
748
+ endpoints: {
749
+ ...plugins
750
+ },
751
+ init() {
752
+ return {
753
+ options: {
754
+ databaseHooks: {
755
+ user: {
756
+ create: {
757
+ before: onBeforeUserCreate(options),
758
+ after: onAfterUserCreate(options)
759
+ },
760
+ update: {
761
+ after: onUserUpdate(options)
762
+ },
763
+ delete: {
764
+ after: onUserDelete(options)
765
+ }
766
+ }
767
+ }
768
+ }
769
+ };
770
+ }
771
+ };
772
+ };
773
+ export {
774
+ CheckoutParams,
775
+ checkout,
776
+ portal,
777
+ spaire,
778
+ spaireClient,
779
+ usage,
780
+ webhooks
781
+ };
782
+ //# sourceMappingURL=index.js.map