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