@polar-sh/better-auth 0.1.2 → 1.0.1

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