@dodopayments/better-auth 1.4.4 → 1.6.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.
Files changed (50) hide show
  1. package/README.md +75 -5
  2. package/dist/chunk-527Y7FSE.js +90 -0
  3. package/dist/chunk-527Y7FSE.js.map +1 -0
  4. package/dist/{chunk-47N33D2M.js → chunk-ARA27DRZ.js} +17 -32
  5. package/dist/chunk-ARA27DRZ.js.map +1 -0
  6. package/dist/{chunk-KXU6PYZF.js → chunk-DTOB4IQZ.js} +22 -45
  7. package/dist/chunk-DTOB4IQZ.js.map +1 -0
  8. package/dist/chunk-TOPOAYYO.js +23 -0
  9. package/dist/chunk-TOPOAYYO.js.map +1 -0
  10. package/dist/client.d.cts +1 -1
  11. package/dist/client.d.ts +1 -1
  12. package/dist/hooks/customer.cjs +39 -11
  13. package/dist/hooks/customer.cjs.map +1 -1
  14. package/dist/hooks/customer.d.cts +1 -1
  15. package/dist/hooks/customer.d.ts +1 -1
  16. package/dist/hooks/customer.js +1 -1
  17. package/dist/index.cjs +100 -86
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +13 -2
  20. package/dist/index.d.ts +13 -2
  21. package/dist/index.js +18 -6
  22. package/dist/index.js.map +1 -1
  23. package/dist/plugins/checkout.d.cts +1 -1
  24. package/dist/plugins/checkout.d.ts +1 -1
  25. package/dist/plugins/portal.cjs +38 -44
  26. package/dist/plugins/portal.cjs.map +1 -1
  27. package/dist/plugins/portal.d.cts +1 -1
  28. package/dist/plugins/portal.d.ts +1 -1
  29. package/dist/plugins/portal.js +2 -1
  30. package/dist/plugins/usage.cjs +33 -31
  31. package/dist/plugins/usage.cjs.map +1 -1
  32. package/dist/plugins/usage.js +2 -1
  33. package/dist/plugins/webhooks.d.cts +1 -1
  34. package/dist/plugins/webhooks.d.ts +1 -1
  35. package/dist/{types-4JE4OwKb.d.cts → types-3pb2RGTM.d.cts} +12 -1
  36. package/dist/{types-B9rx1bt7.d.ts → types-DygjjcRn.d.ts} +12 -1
  37. package/dist/types.cjs.map +1 -1
  38. package/dist/types.d.cts +1 -1
  39. package/dist/types.d.ts +1 -1
  40. package/dist/utils.cjs +47 -0
  41. package/dist/utils.cjs.map +1 -0
  42. package/dist/utils.d.cts +13 -0
  43. package/dist/utils.d.ts +13 -0
  44. package/dist/utils.js +7 -0
  45. package/dist/utils.js.map +1 -0
  46. package/package.json +1 -1
  47. package/dist/chunk-47N33D2M.js.map +0 -1
  48. package/dist/chunk-BII7QAPD.js +0 -62
  49. package/dist/chunk-BII7QAPD.js.map +0 -1
  50. package/dist/chunk-KXU6PYZF.js.map +0 -1
package/README.md CHANGED
@@ -188,6 +188,19 @@ webhooks({
188
188
  - **`client`** (required) - DodoPayments client instance
189
189
  - **`createCustomerOnSignUp`** (optional) - Auto-create customers on user signup
190
190
  - **`use`** (required) - Array of plugins to enable (checkout, portal, webhooks)
191
+ - **`getCustomerParams`** (optional) - Function that receives the BetterAuth `User` and returns extra fields to attach to the DodoPayments customer on creation and update (e.g. `metadata`, `phone_number`)
192
+
193
+ ```typescript
194
+ dodopayments({
195
+ client: dodoPayments,
196
+ createCustomerOnSignUp: true,
197
+ use: [portal()],
198
+ getCustomerParams: (user) => ({
199
+ metadata: { userId: user.id },
200
+ phone_number: user.phoneNumber ?? null,
201
+ }),
202
+ })
203
+ ```
191
204
 
192
205
  ### Checkout Plugin Options
193
206
 
@@ -256,6 +269,11 @@ export const { auth, endpoints, client } = BetterAuth({
256
269
  client: dodoPayments,
257
270
  createCustomerOnSignUp: true, // Auto-create customers on signup
258
271
  use: [], // We'll add plugins here in Stage 2
272
+ // Optional: attach metadata or phone_number to DodoPayments customer records
273
+ // getCustomerParams: (user) => ({
274
+ // metadata: { userId: user.id },
275
+ // phone_number: user.phoneNumber ?? null,
276
+ // }),
259
277
  }),
260
278
  ],
261
279
  });
@@ -485,9 +503,6 @@ use: [
485
503
  onSubscriptionRenewed: async (payload) => {
486
504
  console.log("Subscription renewed:", payload);
487
505
  },
488
- onSubscriptionPaused: async (payload) => {
489
- console.log("Subscription paused:", payload);
490
- },
491
506
  onSubscriptionPlanChanged: async (payload) => {
492
507
  console.log("Subscription plan changed:", payload);
493
508
  },
@@ -500,10 +515,52 @@ use: [
500
515
  onSubscriptionExpired: async (payload) => {
501
516
  console.log("Subscription expired:", payload);
502
517
  },
518
+ onSubscriptionUpdated: async (payload) => {
519
+ console.log("Subscription updated:", payload);
520
+ },
503
521
  // License key event handlers
504
522
  onLicenseKeyCreated: async (payload) => {
505
523
  console.log("License key created:", payload);
506
524
  },
525
+ // Abandoned checkout event handlers
526
+ onAbandonedCheckoutDetected: async (payload) => {
527
+ console.log("Abandoned checkout detected:", payload);
528
+ },
529
+ onAbandonedCheckoutRecovered: async (payload) => {
530
+ console.log("Abandoned checkout recovered:", payload);
531
+ },
532
+ // Dunning event handlers
533
+ onDunningStarted: async (payload) => {
534
+ console.log("Dunning started:", payload);
535
+ },
536
+ onDunningRecovered: async (payload) => {
537
+ console.log("Dunning recovered:", payload);
538
+ },
539
+ // Credit event handlers
540
+ onCreditAdded: async (payload) => {
541
+ console.log("Credit added:", payload);
542
+ },
543
+ onCreditDeducted: async (payload) => {
544
+ console.log("Credit deducted:", payload);
545
+ },
546
+ onCreditExpired: async (payload) => {
547
+ console.log("Credit expired:", payload);
548
+ },
549
+ onCreditRolledOver: async (payload) => {
550
+ console.log("Credit rolled over:", payload);
551
+ },
552
+ onCreditRolloverForfeited: async (payload) => {
553
+ console.log("Credit rollover forfeited:", payload);
554
+ },
555
+ onCreditOverageCharged: async (payload) => {
556
+ console.log("Credit overage charged:", payload);
557
+ },
558
+ onCreditManualAdjustment: async (payload) => {
559
+ console.log("Credit manual adjustment:", payload);
560
+ },
561
+ onCreditBalanceLow: async (payload) => {
562
+ console.log("Credit balance low:", payload);
563
+ },
507
564
  }),
508
565
  ],
509
566
 
@@ -525,12 +582,24 @@ Supported Webhook Event Handlers:
525
582
  - onSubscriptionActive: Subscription became active
526
583
  - onSubscriptionOnHold: Subscription was put on hold
527
584
  - onSubscriptionRenewed: Subscription was renewed
528
- - onSubscriptionPaused: Subscription was paused
529
585
  - onSubscriptionPlanChanged: Subscription plan was changed
530
586
  - onSubscriptionCancelled: Subscription was cancelled
531
587
  - onSubscriptionFailed: Subscription failed
532
588
  - onSubscriptionExpired: Subscription expired
589
+ - onSubscriptionUpdated: Subscription was updated
533
590
  - onLicenseKeyCreated: License key was created
591
+ - onAbandonedCheckoutDetected: Abandoned checkout was detected
592
+ - onAbandonedCheckoutRecovered: Abandoned checkout was recovered
593
+ - onDunningStarted: Dunning process started
594
+ - onDunningRecovered: Dunning process recovered
595
+ - onCreditAdded: Credit was added
596
+ - onCreditDeducted: Credit was deducted
597
+ - onCreditExpired: Credit expired
598
+ - onCreditRolledOver: Credit was rolled over
599
+ - onCreditRolloverForfeited: Credit rollover was forfeited
600
+ - onCreditOverageCharged: Credit overage was charged
601
+ - onCreditManualAdjustment: Credit manual adjustment was made
602
+ - onCreditBalanceLow: Credit balance is low
534
603
 
535
604
  COMBINING SELECTED PLUGINS:
536
605
 
@@ -583,5 +652,6 @@ IMPORTANT NOTES:
583
652
  8. The webhook endpoint is automatically created and secured with signature verification (if webhooks plugin is selected)
584
653
  9. Customer portal and subscription listing require user authentication (if portal plugin is selected)
585
654
  10. Handle errors appropriately and test webhook functionality in development before going live
586
- 11. Present all external setup tasks as clear TODO lists with specific environment variable names
655
+ 11. Use getCustomerParams to attach metadata or phone_number to DodoPayments customer records the function receives the BetterAuth User object and runs on every customer creation and update
656
+ 12. Present all external setup tasks as clear TODO lists with specific environment variable names
587
657
  ```
@@ -0,0 +1,90 @@
1
+ // src/hooks/customer.ts
2
+ import { APIError } from "better-auth/api";
3
+ var onUserCreate = (options) => async (user, ctx) => {
4
+ if (ctx && options.createCustomerOnSignUp) {
5
+ try {
6
+ const customers = await options.client.customers.list({
7
+ email: user.email
8
+ });
9
+ const existingCustomer = customers.items[0];
10
+ let customerId;
11
+ const additionalParams = options.getCustomerParams ? await options.getCustomerParams(user) : void 0;
12
+ if (existingCustomer) {
13
+ await options.client.customers.update(existingCustomer.customer_id, {
14
+ name: user.name,
15
+ metadata: additionalParams?.metadata,
16
+ phone_number: additionalParams?.phone_number
17
+ });
18
+ customerId = existingCustomer.customer_id;
19
+ } else {
20
+ const newCustomer = await options.client.customers.create({
21
+ email: user.email,
22
+ name: user.name,
23
+ metadata: additionalParams?.metadata,
24
+ phone_number: additionalParams?.phone_number
25
+ }, { idempotencyKey: user.id });
26
+ customerId = newCustomer.customer_id;
27
+ }
28
+ ctx.context.internalAdapter.updateUser(user.id, {
29
+ dodoCustomerId: customerId
30
+ }).catch((e) => {
31
+ ctx.context.logger.warn(
32
+ `DodoPayments: failed to store dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`
33
+ );
34
+ });
35
+ } catch (e) {
36
+ if (e instanceof Error) {
37
+ throw new APIError("INTERNAL_SERVER_ERROR", {
38
+ message: `DodoPayments customer creation failed. Error: ${e.message}`
39
+ });
40
+ }
41
+ throw new APIError("INTERNAL_SERVER_ERROR", {
42
+ message: `DodoPayments customer creation failed. Error: ${e}`
43
+ });
44
+ }
45
+ }
46
+ };
47
+ var onUserUpdate = (options) => async (user, ctx) => {
48
+ if (ctx && options.createCustomerOnSignUp) {
49
+ try {
50
+ let customerId = user.dodoCustomerId;
51
+ if (!customerId) {
52
+ const customers = await options.client.customers.list({
53
+ email: user.email
54
+ });
55
+ const existingCustomer = customers.items[0];
56
+ if (!existingCustomer) return;
57
+ customerId = existingCustomer.customer_id;
58
+ ctx.context.internalAdapter.updateUser(user.id, {
59
+ dodoCustomerId: customerId
60
+ }).catch((e) => {
61
+ ctx.context.logger.warn(
62
+ `DodoPayments: failed to backfill dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`
63
+ );
64
+ });
65
+ }
66
+ const additionalParams = options.getCustomerParams ? await options.getCustomerParams(user) : void 0;
67
+ await options.client.customers.update(customerId, {
68
+ name: user.name,
69
+ metadata: additionalParams?.metadata,
70
+ phone_number: additionalParams?.phone_number
71
+ });
72
+ } catch (e) {
73
+ if (e instanceof Error) {
74
+ ctx.context.logger.error(
75
+ `DodoPayments customer update failed. Error: ${e.message}`
76
+ );
77
+ } else {
78
+ ctx.context.logger.error(
79
+ `DodoPayments customer update failed. Error: ${e}`
80
+ );
81
+ }
82
+ }
83
+ }
84
+ };
85
+
86
+ export {
87
+ onUserCreate,
88
+ onUserUpdate
89
+ };
90
+ //# sourceMappingURL=chunk-527Y7FSE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/customer.ts"],"sourcesContent":["import type { GenericEndpointContext, User } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\nimport type { DodoPaymentsOptions } from \"../types\";\n\nexport const onUserCreate =\n (options: DodoPaymentsOptions) =>\n async (user: User, ctx: GenericEndpointContext | null) => {\n if (ctx && options.createCustomerOnSignUp) {\n try {\n const customers = await options.client.customers.list({\n email: user.email,\n });\n const existingCustomer = customers.items[0];\n\n let customerId: string;\n\n const additionalParams = options.getCustomerParams\n ? await options.getCustomerParams(user)\n : undefined;\n\n if (existingCustomer) {\n await options.client.customers.update(existingCustomer.customer_id, {\n name: user.name,\n metadata: additionalParams?.metadata,\n phone_number: additionalParams?.phone_number,\n });\n customerId = existingCustomer.customer_id;\n } else {\n const newCustomer = await options.client.customers.create({\n email: user.email,\n name: user.name,\n metadata: additionalParams?.metadata,\n phone_number: additionalParams?.phone_number,\n }, { idempotencyKey: user.id });\n customerId = newCustomer.customer_id;\n }\n\n ctx.context.internalAdapter.updateUser(user.id, {\n dodoCustomerId: customerId,\n }).catch((e: unknown) => {\n ctx.context.logger.warn(\n `DodoPayments: failed to store dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`,\n );\n });\n } catch (e: unknown) {\n if (e instanceof Error) {\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: `DodoPayments customer creation failed. Error: ${e.message}`,\n });\n }\n\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: `DodoPayments customer creation failed. Error: ${e}`,\n });\n }\n }\n };\n\nexport const onUserUpdate =\n (options: DodoPaymentsOptions) =>\n async (user: User, ctx: GenericEndpointContext | null) => {\n if (ctx && options.createCustomerOnSignUp) {\n try {\n let customerId = (user as User & { dodoCustomerId?: string }).dodoCustomerId;\n\n if (!customerId) {\n // Fallback to email lookup if dodoCustomerId is not stored yet\n const customers = await options.client.customers.list({\n email: user.email,\n });\n const existingCustomer = customers.items[0];\n\n if (!existingCustomer) return;\n\n customerId = existingCustomer.customer_id;\n\n // Backfill dodoCustomerId\n ctx.context.internalAdapter.updateUser(user.id, {\n dodoCustomerId: customerId,\n }).catch((e: unknown) => {\n ctx.context.logger.warn(\n `DodoPayments: failed to backfill dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`,\n );\n });\n }\n\n const additionalParams = options.getCustomerParams\n ? await options.getCustomerParams(user)\n : undefined;\n\n await options.client.customers.update(customerId, {\n name: user.name,\n metadata: additionalParams?.metadata,\n phone_number: additionalParams?.phone_number,\n });\n } catch (e: unknown) {\n if (e instanceof Error) {\n ctx.context.logger.error(\n `DodoPayments customer update failed. Error: ${e.message}`,\n );\n } else {\n ctx.context.logger.error(\n `DodoPayments customer update failed. Error: ${e}`,\n );\n }\n }\n }\n };\n"],"mappings":";AACA,SAAS,gBAAgB;AAGlB,IAAM,eACX,CAAC,YACD,OAAO,MAAY,QAAuC;AACxD,MAAI,OAAO,QAAQ,wBAAwB;AACzC,QAAI;AACF,YAAM,YAAY,MAAM,QAAQ,OAAO,UAAU,KAAK;AAAA,QACpD,OAAO,KAAK;AAAA,MACd,CAAC;AACD,YAAM,mBAAmB,UAAU,MAAM,CAAC;AAE1C,UAAI;AAEJ,YAAM,mBAAmB,QAAQ,oBAC7B,MAAM,QAAQ,kBAAkB,IAAI,IACpC;AAEJ,UAAI,kBAAkB;AACpB,cAAM,QAAQ,OAAO,UAAU,OAAO,iBAAiB,aAAa;AAAA,UAClE,MAAM,KAAK;AAAA,UACX,UAAU,kBAAkB;AAAA,UAC5B,cAAc,kBAAkB;AAAA,QAClC,CAAC;AACD,qBAAa,iBAAiB;AAAA,MAChC,OAAO;AACL,cAAM,cAAc,MAAM,QAAQ,OAAO,UAAU,OAAO;AAAA,UACxD,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,UACX,UAAU,kBAAkB;AAAA,UAC5B,cAAc,kBAAkB;AAAA,QAClC,GAAG,EAAE,gBAAgB,KAAK,GAAG,CAAC;AAC9B,qBAAa,YAAY;AAAA,MAC3B;AAEA,UAAI,QAAQ,gBAAgB,WAAW,KAAK,IAAI;AAAA,QAC9C,gBAAgB;AAAA,MAClB,CAAC,EAAE,MAAM,CAAC,MAAe;AACvB,YAAI,QAAQ,OAAO;AAAA,UACjB,yDAAyD,KAAK,EAAE,YAAY,aAAa,QAAQ,EAAE,UAAU,CAAC;AAAA,QAChH;AAAA,MACF,CAAC;AAAA,IACH,SAAS,GAAY;AACnB,UAAI,aAAa,OAAO;AACtB,cAAM,IAAI,SAAS,yBAAyB;AAAA,UAC1C,SAAS,iDAAiD,EAAE,OAAO;AAAA,QACrE,CAAC;AAAA,MACH;AAEA,YAAM,IAAI,SAAS,yBAAyB;AAAA,QAC1C,SAAS,iDAAiD,CAAC;AAAA,MAC7D,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEK,IAAM,eACX,CAAC,YACD,OAAO,MAAY,QAAuC;AACxD,MAAI,OAAO,QAAQ,wBAAwB;AACzC,QAAI;AACF,UAAI,aAAc,KAA4C;AAE9D,UAAI,CAAC,YAAY;AAEf,cAAM,YAAY,MAAM,QAAQ,OAAO,UAAU,KAAK;AAAA,UACpD,OAAO,KAAK;AAAA,QACd,CAAC;AACD,cAAM,mBAAmB,UAAU,MAAM,CAAC;AAE1C,YAAI,CAAC,iBAAkB;AAEvB,qBAAa,iBAAiB;AAG9B,YAAI,QAAQ,gBAAgB,WAAW,KAAK,IAAI;AAAA,UAC9C,gBAAgB;AAAA,QAClB,CAAC,EAAE,MAAM,CAAC,MAAe;AACvB,cAAI,QAAQ,OAAO;AAAA,YACjB,4DAA4D,KAAK,EAAE,YAAY,aAAa,QAAQ,EAAE,UAAU,CAAC;AAAA,UACnH;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,mBAAmB,QAAQ,oBAC7B,MAAM,QAAQ,kBAAkB,IAAI,IACpC;AAEJ,YAAM,QAAQ,OAAO,UAAU,OAAO,YAAY;AAAA,QAChD,MAAM,KAAK;AAAA,QACX,UAAU,kBAAkB;AAAA,QAC5B,cAAc,kBAAkB;AAAA,MAClC,CAAC;AAAA,IACH,SAAS,GAAY;AACnB,UAAI,aAAa,OAAO;AACtB,YAAI,QAAQ,OAAO;AAAA,UACjB,+CAA+C,EAAE,OAAO;AAAA,QAC1D;AAAA,MACF,OAAO;AACL,YAAI,QAAQ,OAAO;AAAA,UACjB,+CAA+C,CAAC;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1,3 +1,7 @@
1
+ import {
2
+ getOrCreateCustomerId
3
+ } from "./chunk-TOPOAYYO.js";
4
+
1
5
  // src/plugins/usage.ts
2
6
  import {
3
7
  APIError,
@@ -35,22 +39,16 @@ var usage = () => (dodopayments) => {
35
39
  });
36
40
  }
37
41
  try {
38
- const customers = await dodopayments.customers.list({
39
- email: ctx.context.session.user.email
40
- });
41
- let customer = customers.items[0];
42
- if (!customer) {
43
- customer = await createCustomer(
44
- dodopayments,
45
- ctx.context.session.user.email,
46
- ctx.context.session.user.name
47
- );
48
- }
42
+ const customerId = await getOrCreateCustomerId(
43
+ dodopayments,
44
+ ctx.context.session,
45
+ ctx.context.internalAdapter
46
+ );
49
47
  const result = await dodopayments.usageEvents.ingest({
50
48
  events: [
51
49
  {
52
50
  event_id: ctx.body.event_id,
53
- customer_id: customer.customer_id,
51
+ customer_id: customerId,
54
52
  event_name: ctx.body.event_name,
55
53
  timestamp: ctx.body.timestamp,
56
54
  metadata: ctx.body.metadata
@@ -97,19 +95,13 @@ var usage = () => (dodopayments) => {
97
95
  });
98
96
  }
99
97
  try {
100
- const customers = await dodopayments.customers.list({
101
- email: ctx.context.session.user.email
102
- });
103
- let customer = customers.items[0];
104
- if (!customer) {
105
- customer = await createCustomer(
106
- dodopayments,
107
- ctx.context.session.user.email,
108
- ctx.context.session.user.name
109
- );
110
- }
98
+ const customerId = await getOrCreateCustomerId(
99
+ dodopayments,
100
+ ctx.context.session,
101
+ ctx.context.internalAdapter
102
+ );
111
103
  const meters = await dodopayments.usageEvents.list({
112
- customer_id: customer.customer_id,
104
+ customer_id: customerId,
113
105
  ...ctx.query
114
106
  });
115
107
  return ctx.json({ items: meters.items });
@@ -127,15 +119,8 @@ var usage = () => (dodopayments) => {
127
119
  )
128
120
  };
129
121
  };
130
- async function createCustomer(dodopayments, email, name) {
131
- const customer = await dodopayments.customers.create({
132
- email,
133
- name
134
- });
135
- return customer;
136
- }
137
122
 
138
123
  export {
139
124
  usage
140
125
  };
141
- //# sourceMappingURL=chunk-47N33D2M.js.map
126
+ //# sourceMappingURL=chunk-ARA27DRZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/usage.ts"],"sourcesContent":["import {\n APIError,\n createAuthEndpoint,\n sessionMiddleware,\n} from \"better-auth/api\";\nimport type { DodoPayments } from \"dodopayments\";\nimport { Event } from \"dodopayments/resources/usage-events.mjs\";\nimport { z } from \"zod/v3\";\nimport { getOrCreateCustomerId } from \"../utils\";\n\nconst EventInputSchema = z.object({\n event_id: z.string(),\n event_name: z.string(),\n metadata: z\n .record(z.union([z.string(), z.number(), z.boolean()]))\n .nullable()\n .optional(),\n timestamp: z\n // NOTE: coerce because the date object gets converted to a string over network requests\n // but we still want to enforce that it's a Date type\n .date({ coerce: true })\n .transform((d) => d.toISOString())\n .optional()\n .describe(\n \"Custom Timestamp. Defaults to current timestamp in UTC.\\\n Timestamps that are older that 1 hour or after 5 mins from\\\n current timestamp will be rejected.\",\n ),\n});\n\nexport const usage = () => (dodopayments: DodoPayments) => {\n return {\n // Ingest usage data\n dodoUsageIngest: createAuthEndpoint(\n \"/dodopayments/usage/ingest\",\n {\n method: \"POST\",\n body: EventInputSchema,\n use: [sessionMiddleware],\n },\n async (ctx): Promise<{ ingested_count: number }> => {\n if (!ctx.context.session?.user?.id) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"User not found\",\n });\n }\n\n if (!ctx.context.session?.user.emailVerified) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"User email not verified\",\n });\n }\n\n try {\n const customerId = await getOrCreateCustomerId(\n dodopayments,\n ctx.context.session,\n ctx.context.internalAdapter,\n );\n\n const result = await dodopayments.usageEvents.ingest({\n events: [\n {\n event_id: ctx.body.event_id,\n customer_id: customerId,\n event_name: ctx.body.event_name,\n timestamp: ctx.body.timestamp,\n metadata: ctx.body.metadata,\n },\n ],\n });\n\n return ctx.json({ ingested_count: result.ingested_count });\n } catch (e: unknown) {\n if (e instanceof Error) {\n ctx.context.logger.error(\n `User usage ingestion error: ${e.message}`,\n );\n }\n\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Failed to record the user usage\",\n });\n }\n },\n ),\n\n // List usage meters\n dodoUsageMetersList: createAuthEndpoint(\n \"/dodopayments/usage/meters/list\",\n {\n method: \"GET\",\n query: z\n .object({\n page_number: z.coerce.number().optional(),\n page_size: z.coerce.number().optional(),\n event_name: z.string().optional(),\n meter_id: z.string().optional(),\n start: z.string().optional(),\n end: z.string().optional(),\n })\n .optional(),\n use: [sessionMiddleware],\n },\n async (ctx): Promise<{ items: Event[] }> => {\n if (!ctx.context.session?.user?.id) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"User not found\",\n });\n }\n\n if (!ctx.context.session?.user.emailVerified) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"User email not verified\",\n });\n }\n\n try {\n const customerId = await getOrCreateCustomerId(\n dodopayments,\n ctx.context.session,\n ctx.context.internalAdapter,\n );\n\n const meters = await dodopayments.usageEvents.list({\n customer_id: customerId,\n ...ctx.query,\n });\n\n return ctx.json({ items: meters.items });\n } catch (e: unknown) {\n if (e instanceof Error) {\n ctx.context.logger.error(\n `User usage meter list error: ${e.message}`,\n );\n }\n\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Failed to fetch the user usage\",\n });\n }\n },\n ),\n };\n};\n\n"],"mappings":"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","names":[]}
@@ -1,3 +1,7 @@
1
+ import {
2
+ getOrCreateCustomerId
3
+ } from "./chunk-TOPOAYYO.js";
4
+
1
5
  // src/plugins/portal.ts
2
6
  import { APIError, createAuthEndpoint, sessionMiddleware } from "better-auth/api";
3
7
  import { z } from "zod/v3";
@@ -21,20 +25,12 @@ var portal = () => (dodopayments) => {
21
25
  });
22
26
  }
23
27
  try {
24
- const customers = await dodopayments.customers.list({
25
- email: ctx.context.session?.user.email
26
- });
27
- let customer = customers.items[0];
28
- if (!customer) {
29
- customer = await createCustomer(
30
- dodopayments,
31
- ctx.context.session.user.email,
32
- ctx.context.session.user.name
33
- );
34
- }
35
- const customerSession = await dodopayments.customers.customerPortal.create(
36
- customer.customer_id
28
+ const customerId = await getOrCreateCustomerId(
29
+ dodopayments,
30
+ ctx.context.session,
31
+ ctx.context.internalAdapter
37
32
  );
33
+ const customerSession = await dodopayments.customers.customerPortal.create(customerId);
38
34
  return ctx.json({
39
35
  url: customerSession.link,
40
36
  redirect: true
@@ -81,19 +77,13 @@ var portal = () => (dodopayments) => {
81
77
  });
82
78
  }
83
79
  try {
84
- const customers = await dodopayments.customers.list({
85
- email: ctx.context.session?.user.email
86
- });
87
- let customer = customers.items[0];
88
- if (!customer) {
89
- customer = await createCustomer(
90
- dodopayments,
91
- ctx.context.session.user.email,
92
- ctx.context.session.user.name
93
- );
94
- }
80
+ const customerId = await getOrCreateCustomerId(
81
+ dodopayments,
82
+ ctx.context.session,
83
+ ctx.context.internalAdapter
84
+ );
95
85
  const subscriptions = await dodopayments.subscriptions.list({
96
- customer_id: customer.customer_id,
86
+ customer_id: customerId,
97
87
  // page number is 0-indexed
98
88
  page_number: ctx.query?.page ? ctx.query.page - 1 : void 0,
99
89
  page_size: ctx.query?.limit,
@@ -147,19 +137,13 @@ var portal = () => (dodopayments) => {
147
137
  });
148
138
  }
149
139
  try {
150
- const customers = await dodopayments.customers.list({
151
- email: ctx.context.session?.user.email
152
- });
153
- let customer = customers.items[0];
154
- if (!customer) {
155
- customer = await createCustomer(
156
- dodopayments,
157
- ctx.context.session.user.email,
158
- ctx.context.session.user.name
159
- );
160
- }
140
+ const customerId = await getOrCreateCustomerId(
141
+ dodopayments,
142
+ ctx.context.session,
143
+ ctx.context.internalAdapter
144
+ );
161
145
  const payments = await dodopayments.payments.list({
162
- customer_id: customer.customer_id,
146
+ customer_id: customerId,
163
147
  // page number is 0-indexed
164
148
  page_number: ctx.query?.page ? ctx.query.page - 1 : void 0,
165
149
  page_size: ctx.query?.limit,
@@ -180,15 +164,8 @@ var portal = () => (dodopayments) => {
180
164
  )
181
165
  };
182
166
  };
183
- async function createCustomer(dodopayments, email, name) {
184
- const customer = await dodopayments.customers.create({
185
- email,
186
- name
187
- });
188
- return customer;
189
- }
190
167
 
191
168
  export {
192
169
  portal
193
170
  };
194
- //# sourceMappingURL=chunk-KXU6PYZF.js.map
171
+ //# sourceMappingURL=chunk-DTOB4IQZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/portal.ts"],"sourcesContent":["import type { DodoPayments } from \"dodopayments\";\nimport { APIError, createAuthEndpoint, sessionMiddleware } from \"better-auth/api\";\nimport { z } from \"zod/v3\";\nimport {\n CustomerPortalResponse,\n PaymentItems,\n SubscriptionItems,\n} from \"../types\";\nimport { getOrCreateCustomerId } from \"../utils\";\n\nexport const portal = () => (dodopayments: DodoPayments) => {\n return {\n dodoPortal: createAuthEndpoint(\n \"/dodopayments/customer/portal\",\n {\n method: \"GET\",\n use: [sessionMiddleware],\n },\n async (ctx): Promise<CustomerPortalResponse> => {\n if (!ctx.context.session?.user.id) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"User not found\",\n });\n }\n\n if (!ctx.context.session?.user.emailVerified) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"User email not verified\",\n });\n }\n\n try {\n const customerId = await getOrCreateCustomerId(\n dodopayments,\n ctx.context.session,\n ctx.context.internalAdapter,\n );\n\n const customerSession =\n await dodopayments.customers.customerPortal.create(customerId);\n\n return ctx.json({\n url: customerSession.link,\n redirect: true,\n });\n } catch (e: unknown) {\n if (e instanceof Error) {\n ctx.context.logger.error(\n `DodoPayments customer portal creation failed. Error: ${e.message}`,\n );\n }\n\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Customer portal creation failed\",\n });\n }\n },\n ),\n dodoSubscriptions: createAuthEndpoint(\n \"/dodopayments/customer/subscriptions/list\",\n {\n method: \"GET\",\n query: z\n .object({\n page: z.coerce.number().optional(),\n limit: z.coerce.number().optional(),\n status: z\n .enum([\n \"active\",\n \"cancelled\",\n \"on_hold\",\n \"pending\",\n \"failed\",\n \"expired\",\n ])\n .optional(),\n })\n .optional(),\n use: [sessionMiddleware],\n },\n async (ctx): Promise<SubscriptionItems> => {\n if (!ctx.context.session.user.id) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"User not found\",\n });\n }\n\n if (!ctx.context.session?.user.emailVerified) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"User email not verified\",\n });\n }\n\n try {\n const customerId = await getOrCreateCustomerId(\n dodopayments,\n ctx.context.session,\n ctx.context.internalAdapter,\n );\n\n const subscriptions = await dodopayments.subscriptions.list({\n customer_id: customerId,\n // page number is 0-indexed\n page_number: ctx.query?.page ? ctx.query.page - 1 : undefined,\n page_size: ctx.query?.limit,\n status: ctx.query?.status,\n });\n\n return ctx.json({ items: subscriptions.items });\n } catch (e: unknown) {\n if (e instanceof Error) {\n ctx.context.logger.error(\n `DodoPayments subscriptions list failed. Error: ${e.message}`,\n );\n }\n\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: \"DodoPayments subscriptions list failed\",\n });\n }\n },\n ),\n dodoPayments: createAuthEndpoint(\n \"/dodopayments/customer/payments/list\",\n {\n method: \"GET\",\n query: z\n .object({\n page: z.coerce.number().optional(),\n limit: z.coerce.number().optional(),\n status: z\n .enum([\n \"succeeded\",\n \"failed\",\n \"cancelled\",\n \"processing\",\n \"requires_customer_action\",\n \"requires_merchant_action\",\n \"requires_payment_method\",\n \"requires_confirmation\",\n \"requires_capture\",\n \"partially_captured\",\n \"partially_captured_and_capturable\",\n ])\n .optional(),\n })\n .optional(),\n use: [sessionMiddleware],\n },\n async (ctx): Promise<PaymentItems> => {\n if (!ctx.context.session.user.id) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"User not found\",\n });\n }\n\n if (!ctx.context.session?.user.emailVerified) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"User email not verified\",\n });\n }\n\n try {\n const customerId = await getOrCreateCustomerId(\n dodopayments,\n ctx.context.session,\n ctx.context.internalAdapter,\n );\n\n const payments = await dodopayments.payments.list({\n customer_id: customerId,\n // page number is 0-indexed\n page_number: ctx.query?.page ? ctx.query.page - 1 : undefined,\n page_size: ctx.query?.limit,\n status: ctx.query?.status,\n });\n\n return ctx.json({ items: payments.items });\n } catch (e: unknown) {\n if (e instanceof Error) {\n ctx.context.logger.error(\n `DodoPayments orders list failed. Error: ${e.message}`,\n );\n }\n\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: \"Orders list failed\",\n });\n }\n },\n ),\n };\n};\n\n"],"mappings":"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","names":[]}
@@ -0,0 +1,23 @@
1
+ // src/utils.ts
2
+ async function getOrCreateCustomerId(dodopayments, session, internalAdapter) {
3
+ const dodoCustomerId = session.user["dodoCustomerId"];
4
+ if (dodoCustomerId) return dodoCustomerId;
5
+ const customers = await dodopayments.customers.list({
6
+ email: session.user.email
7
+ });
8
+ let customer = customers.items[0];
9
+ if (!customer) {
10
+ customer = await dodopayments.customers.create({
11
+ email: session.user.email,
12
+ name: session.user.name
13
+ }, { idempotencyKey: session.user.id });
14
+ }
15
+ internalAdapter.updateUser(session.user.id, { dodoCustomerId: customer.customer_id }).catch(() => {
16
+ });
17
+ return customer.customer_id;
18
+ }
19
+
20
+ export {
21
+ getOrCreateCustomerId
22
+ };
23
+ //# sourceMappingURL=chunk-TOPOAYYO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import type { DodoPayments } from \"dodopayments\";\n\nexport async function getOrCreateCustomerId(\n dodopayments: DodoPayments,\n session: { user: { id: string; email: string; name: string } & Record<string, unknown> },\n internalAdapter: { updateUser: (id: string, data: Record<string, unknown>) => Promise<unknown> },\n): Promise<string> {\n const dodoCustomerId = session.user[\"dodoCustomerId\"] as string | undefined;\n if (dodoCustomerId) return dodoCustomerId;\n\n // Fallback to get customer from email if dodoCustomerId doesn't exist\n const customers = await dodopayments.customers.list({\n email: session.user.email,\n });\n let customer = customers.items[0];\n\n if (!customer) {\n customer = await dodopayments.customers.create({\n email: session.user.email,\n name: session.user.name,\n }, { idempotencyKey: session.user.id });\n }\n\n internalAdapter\n .updateUser(session.user.id, { dodoCustomerId: customer.customer_id })\n .catch(() => {});\n\n return customer.customer_id;\n}\n"],"mappings":";AAEA,eAAsB,sBACpB,cACA,SACA,iBACiB;AACjB,QAAM,iBAAiB,QAAQ,KAAK,gBAAgB;AACpD,MAAI,eAAgB,QAAO;AAG3B,QAAM,YAAY,MAAM,aAAa,UAAU,KAAK;AAAA,IAClD,OAAO,QAAQ,KAAK;AAAA,EACtB,CAAC;AACD,MAAI,WAAW,UAAU,MAAM,CAAC;AAEhC,MAAI,CAAC,UAAU;AACb,eAAW,MAAM,aAAa,UAAU,OAAO;AAAA,MAC7C,OAAO,QAAQ,KAAK;AAAA,MACpB,MAAM,QAAQ,KAAK;AAAA,IACrB,GAAG,EAAE,gBAAgB,QAAQ,KAAK,GAAG,CAAC;AAAA,EACxC;AAEA,kBACG,WAAW,QAAQ,KAAK,IAAI,EAAE,gBAAgB,SAAS,YAAY,CAAC,EACpE,MAAM,MAAM;AAAA,EAAC,CAAC;AAEjB,SAAO,SAAS;AAClB;","names":[]}
package/dist/client.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { dodopaymentsClient } from './index.cjs';
2
- export { C as CreateCheckoutResponse, a as CustomerPortalResponse, e as DodoPaymentsEndpoints, D as DodoPaymentsOptions, P as PaymentItems, b as Product, S as SubscriptionItems, W as WebhookResponse } from './types-4JE4OwKb.cjs';
2
+ export { C as CreateCheckoutResponse, a as CustomerPortalResponse, e as DodoPaymentsEndpoints, D as DodoPaymentsOptions, P as PaymentItems, b as Product, S as SubscriptionItems, W as WebhookResponse } from './types-3pb2RGTM.cjs';
3
3
  import 'dodopayments/resources/usage-events.mjs';
4
4
  import 'better-auth';
5
5
  import 'zod/v3';
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { dodopaymentsClient } from './index.js';
2
- export { C as CreateCheckoutResponse, a as CustomerPortalResponse, e as DodoPaymentsEndpoints, D as DodoPaymentsOptions, P as PaymentItems, b as Product, S as SubscriptionItems, W as WebhookResponse } from './types-B9rx1bt7.js';
2
+ export { C as CreateCheckoutResponse, a as CustomerPortalResponse, e as DodoPaymentsEndpoints, D as DodoPaymentsOptions, P as PaymentItems, b as Product, S as SubscriptionItems, W as WebhookResponse } from './types-DygjjcRn.js';
3
3
  import 'dodopayments/resources/usage-events.mjs';
4
4
  import 'better-auth';
5
5
  import 'zod/v3';
@@ -32,16 +32,31 @@ var onUserCreate = (options) => async (user, ctx) => {
32
32
  email: user.email
33
33
  });
34
34
  const existingCustomer = customers.items[0];
35
+ let customerId;
36
+ const additionalParams = options.getCustomerParams ? await options.getCustomerParams(user) : void 0;
35
37
  if (existingCustomer) {
36
38
  await options.client.customers.update(existingCustomer.customer_id, {
37
- name: user.name
39
+ name: user.name,
40
+ metadata: additionalParams?.metadata,
41
+ phone_number: additionalParams?.phone_number
38
42
  });
43
+ customerId = existingCustomer.customer_id;
39
44
  } else {
40
- await options.client.customers.create({
45
+ const newCustomer = await options.client.customers.create({
41
46
  email: user.email,
42
- name: user.name
43
- });
47
+ name: user.name,
48
+ metadata: additionalParams?.metadata,
49
+ phone_number: additionalParams?.phone_number
50
+ }, { idempotencyKey: user.id });
51
+ customerId = newCustomer.customer_id;
44
52
  }
53
+ ctx.context.internalAdapter.updateUser(user.id, {
54
+ dodoCustomerId: customerId
55
+ }).catch((e) => {
56
+ ctx.context.logger.warn(
57
+ `DodoPayments: failed to store dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`
58
+ );
59
+ });
45
60
  } catch (e) {
46
61
  if (e instanceof Error) {
47
62
  throw new import_api.APIError("INTERNAL_SERVER_ERROR", {
@@ -57,15 +72,28 @@ var onUserCreate = (options) => async (user, ctx) => {
57
72
  var onUserUpdate = (options) => async (user, ctx) => {
58
73
  if (ctx && options.createCustomerOnSignUp) {
59
74
  try {
60
- const customers = await options.client.customers.list({
61
- email: user.email
62
- });
63
- const existingCustomer = customers.items[0];
64
- if (existingCustomer) {
65
- await options.client.customers.update(existingCustomer.customer_id, {
66
- name: user.name
75
+ let customerId = user.dodoCustomerId;
76
+ if (!customerId) {
77
+ const customers = await options.client.customers.list({
78
+ email: user.email
79
+ });
80
+ const existingCustomer = customers.items[0];
81
+ if (!existingCustomer) return;
82
+ customerId = existingCustomer.customer_id;
83
+ ctx.context.internalAdapter.updateUser(user.id, {
84
+ dodoCustomerId: customerId
85
+ }).catch((e) => {
86
+ ctx.context.logger.warn(
87
+ `DodoPayments: failed to backfill dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`
88
+ );
67
89
  });
68
90
  }
91
+ const additionalParams = options.getCustomerParams ? await options.getCustomerParams(user) : void 0;
92
+ await options.client.customers.update(customerId, {
93
+ name: user.name,
94
+ metadata: additionalParams?.metadata,
95
+ phone_number: additionalParams?.phone_number
96
+ });
69
97
  } catch (e) {
70
98
  if (e instanceof Error) {
71
99
  ctx.context.logger.error(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/customer.ts"],"sourcesContent":["import type { GenericEndpointContext, User } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\nimport type { DodoPaymentsOptions } from \"../types\";\n\nexport const onUserCreate =\n (options: DodoPaymentsOptions) =>\n async (user: User, ctx: GenericEndpointContext | null) => {\n if (ctx && options.createCustomerOnSignUp) {\n try {\n const customers = await options.client.customers.list({\n email: user.email,\n });\n const existingCustomer = customers.items[0];\n\n if (existingCustomer) {\n await options.client.customers.update(existingCustomer.customer_id, {\n name: user.name,\n });\n } else {\n // TODO: Add metadata to customer object via\n // getCustomerCreateParams option when it becomes\n // available in the API\n await options.client.customers.create({\n email: user.email,\n name: user.name,\n });\n }\n } catch (e: unknown) {\n if (e instanceof Error) {\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: `DodoPayments customer creation failed. Error: ${e.message}`,\n });\n }\n\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: `DodoPayments customer creation failed. Error: ${e}`,\n });\n }\n }\n };\n\nexport const onUserUpdate =\n (options: DodoPaymentsOptions) =>\n async (user: User, ctx: GenericEndpointContext | null) => {\n if (ctx && options.createCustomerOnSignUp) {\n try {\n const customers = await options.client.customers.list({\n email: user.email,\n });\n const existingCustomer = customers.items[0];\n\n if (existingCustomer) {\n // TODO: Add metadata to customer object via\n // getCustomerCreateParams option when it becomes\n // available in the API\n await options.client.customers.update(existingCustomer.customer_id, {\n name: user.name,\n });\n }\n } catch (e: unknown) {\n if (e instanceof Error) {\n ctx.context.logger.error(\n `DodoPayments customer update failed. Error: ${e.message}`,\n );\n } else {\n ctx.context.logger.error(\n `DodoPayments customer update failed. Error: ${e}`,\n );\n }\n }\n }\n };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,iBAAyB;AAGlB,IAAM,eACX,CAAC,YACD,OAAO,MAAY,QAAuC;AACxD,MAAI,OAAO,QAAQ,wBAAwB;AACzC,QAAI;AACF,YAAM,YAAY,MAAM,QAAQ,OAAO,UAAU,KAAK;AAAA,QACpD,OAAO,KAAK;AAAA,MACd,CAAC;AACD,YAAM,mBAAmB,UAAU,MAAM,CAAC;AAE1C,UAAI,kBAAkB;AACpB,cAAM,QAAQ,OAAO,UAAU,OAAO,iBAAiB,aAAa;AAAA,UAClE,MAAM,KAAK;AAAA,QACb,CAAC;AAAA,MACH,OAAO;AAIL,cAAM,QAAQ,OAAO,UAAU,OAAO;AAAA,UACpC,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF,SAAS,GAAY;AACnB,UAAI,aAAa,OAAO;AACtB,cAAM,IAAI,oBAAS,yBAAyB;AAAA,UAC1C,SAAS,iDAAiD,EAAE,OAAO;AAAA,QACrE,CAAC;AAAA,MACH;AAEA,YAAM,IAAI,oBAAS,yBAAyB;AAAA,QAC1C,SAAS,iDAAiD,CAAC;AAAA,MAC7D,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEK,IAAM,eACX,CAAC,YACD,OAAO,MAAY,QAAuC;AACxD,MAAI,OAAO,QAAQ,wBAAwB;AACzC,QAAI;AACF,YAAM,YAAY,MAAM,QAAQ,OAAO,UAAU,KAAK;AAAA,QACpD,OAAO,KAAK;AAAA,MACd,CAAC;AACD,YAAM,mBAAmB,UAAU,MAAM,CAAC;AAE1C,UAAI,kBAAkB;AAIpB,cAAM,QAAQ,OAAO,UAAU,OAAO,iBAAiB,aAAa;AAAA,UAClE,MAAM,KAAK;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF,SAAS,GAAY;AACnB,UAAI,aAAa,OAAO;AACtB,YAAI,QAAQ,OAAO;AAAA,UACjB,+CAA+C,EAAE,OAAO;AAAA,QAC1D;AAAA,MACF,OAAO;AACL,YAAI,QAAQ,OAAO;AAAA,UACjB,+CAA+C,CAAC;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/hooks/customer.ts"],"sourcesContent":["import type { GenericEndpointContext, User } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\nimport type { DodoPaymentsOptions } from \"../types\";\n\nexport const onUserCreate =\n (options: DodoPaymentsOptions) =>\n async (user: User, ctx: GenericEndpointContext | null) => {\n if (ctx && options.createCustomerOnSignUp) {\n try {\n const customers = await options.client.customers.list({\n email: user.email,\n });\n const existingCustomer = customers.items[0];\n\n let customerId: string;\n\n const additionalParams = options.getCustomerParams\n ? await options.getCustomerParams(user)\n : undefined;\n\n if (existingCustomer) {\n await options.client.customers.update(existingCustomer.customer_id, {\n name: user.name,\n metadata: additionalParams?.metadata,\n phone_number: additionalParams?.phone_number,\n });\n customerId = existingCustomer.customer_id;\n } else {\n const newCustomer = await options.client.customers.create({\n email: user.email,\n name: user.name,\n metadata: additionalParams?.metadata,\n phone_number: additionalParams?.phone_number,\n }, { idempotencyKey: user.id });\n customerId = newCustomer.customer_id;\n }\n\n ctx.context.internalAdapter.updateUser(user.id, {\n dodoCustomerId: customerId,\n }).catch((e: unknown) => {\n ctx.context.logger.warn(\n `DodoPayments: failed to store dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`,\n );\n });\n } catch (e: unknown) {\n if (e instanceof Error) {\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: `DodoPayments customer creation failed. Error: ${e.message}`,\n });\n }\n\n throw new APIError(\"INTERNAL_SERVER_ERROR\", {\n message: `DodoPayments customer creation failed. Error: ${e}`,\n });\n }\n }\n };\n\nexport const onUserUpdate =\n (options: DodoPaymentsOptions) =>\n async (user: User, ctx: GenericEndpointContext | null) => {\n if (ctx && options.createCustomerOnSignUp) {\n try {\n let customerId = (user as User & { dodoCustomerId?: string }).dodoCustomerId;\n\n if (!customerId) {\n // Fallback to email lookup if dodoCustomerId is not stored yet\n const customers = await options.client.customers.list({\n email: user.email,\n });\n const existingCustomer = customers.items[0];\n\n if (!existingCustomer) return;\n\n customerId = existingCustomer.customer_id;\n\n // Backfill dodoCustomerId\n ctx.context.internalAdapter.updateUser(user.id, {\n dodoCustomerId: customerId,\n }).catch((e: unknown) => {\n ctx.context.logger.warn(\n `DodoPayments: failed to backfill dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`,\n );\n });\n }\n\n const additionalParams = options.getCustomerParams\n ? await options.getCustomerParams(user)\n : undefined;\n\n await options.client.customers.update(customerId, {\n name: user.name,\n metadata: additionalParams?.metadata,\n phone_number: additionalParams?.phone_number,\n });\n } catch (e: unknown) {\n if (e instanceof Error) {\n ctx.context.logger.error(\n `DodoPayments customer update failed. Error: ${e.message}`,\n );\n } else {\n ctx.context.logger.error(\n `DodoPayments customer update failed. Error: ${e}`,\n );\n }\n }\n }\n };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,iBAAyB;AAGlB,IAAM,eACX,CAAC,YACD,OAAO,MAAY,QAAuC;AACxD,MAAI,OAAO,QAAQ,wBAAwB;AACzC,QAAI;AACF,YAAM,YAAY,MAAM,QAAQ,OAAO,UAAU,KAAK;AAAA,QACpD,OAAO,KAAK;AAAA,MACd,CAAC;AACD,YAAM,mBAAmB,UAAU,MAAM,CAAC;AAE1C,UAAI;AAEJ,YAAM,mBAAmB,QAAQ,oBAC7B,MAAM,QAAQ,kBAAkB,IAAI,IACpC;AAEJ,UAAI,kBAAkB;AACpB,cAAM,QAAQ,OAAO,UAAU,OAAO,iBAAiB,aAAa;AAAA,UAClE,MAAM,KAAK;AAAA,UACX,UAAU,kBAAkB;AAAA,UAC5B,cAAc,kBAAkB;AAAA,QAClC,CAAC;AACD,qBAAa,iBAAiB;AAAA,MAChC,OAAO;AACL,cAAM,cAAc,MAAM,QAAQ,OAAO,UAAU,OAAO;AAAA,UACxD,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,UACX,UAAU,kBAAkB;AAAA,UAC5B,cAAc,kBAAkB;AAAA,QAClC,GAAG,EAAE,gBAAgB,KAAK,GAAG,CAAC;AAC9B,qBAAa,YAAY;AAAA,MAC3B;AAEA,UAAI,QAAQ,gBAAgB,WAAW,KAAK,IAAI;AAAA,QAC9C,gBAAgB;AAAA,MAClB,CAAC,EAAE,MAAM,CAAC,MAAe;AACvB,YAAI,QAAQ,OAAO;AAAA,UACjB,yDAAyD,KAAK,EAAE,YAAY,aAAa,QAAQ,EAAE,UAAU,CAAC;AAAA,QAChH;AAAA,MACF,CAAC;AAAA,IACH,SAAS,GAAY;AACnB,UAAI,aAAa,OAAO;AACtB,cAAM,IAAI,oBAAS,yBAAyB;AAAA,UAC1C,SAAS,iDAAiD,EAAE,OAAO;AAAA,QACrE,CAAC;AAAA,MACH;AAEA,YAAM,IAAI,oBAAS,yBAAyB;AAAA,QAC1C,SAAS,iDAAiD,CAAC;AAAA,MAC7D,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEK,IAAM,eACX,CAAC,YACD,OAAO,MAAY,QAAuC;AACxD,MAAI,OAAO,QAAQ,wBAAwB;AACzC,QAAI;AACF,UAAI,aAAc,KAA4C;AAE9D,UAAI,CAAC,YAAY;AAEf,cAAM,YAAY,MAAM,QAAQ,OAAO,UAAU,KAAK;AAAA,UACpD,OAAO,KAAK;AAAA,QACd,CAAC;AACD,cAAM,mBAAmB,UAAU,MAAM,CAAC;AAE1C,YAAI,CAAC,iBAAkB;AAEvB,qBAAa,iBAAiB;AAG9B,YAAI,QAAQ,gBAAgB,WAAW,KAAK,IAAI;AAAA,UAC9C,gBAAgB;AAAA,QAClB,CAAC,EAAE,MAAM,CAAC,MAAe;AACvB,cAAI,QAAQ,OAAO;AAAA,YACjB,4DAA4D,KAAK,EAAE,YAAY,aAAa,QAAQ,EAAE,UAAU,CAAC;AAAA,UACnH;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,mBAAmB,QAAQ,oBAC7B,MAAM,QAAQ,kBAAkB,IAAI,IACpC;AAEJ,YAAM,QAAQ,OAAO,UAAU,OAAO,YAAY;AAAA,QAChD,MAAM,KAAK;AAAA,QACX,UAAU,kBAAkB;AAAA,QAC5B,cAAc,kBAAkB;AAAA,MAClC,CAAC;AAAA,IACH,SAAS,GAAY;AACnB,UAAI,aAAa,OAAO;AACtB,YAAI,QAAQ,OAAO;AAAA,UACjB,+CAA+C,EAAE,OAAO;AAAA,QAC1D;AAAA,MACF,OAAO;AACL,YAAI,QAAQ,OAAO;AAAA,UACjB,+CAA+C,CAAC;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1,5 +1,5 @@
1
1
  import { User, GenericEndpointContext } from 'better-auth';
2
- import { D as DodoPaymentsOptions } from '../types-4JE4OwKb.cjs';
2
+ import { D as DodoPaymentsOptions } from '../types-3pb2RGTM.cjs';
3
3
  import 'dodopayments';
4
4
  import 'zod/v3';
5
5
  import '@dodopayments/core/webhook';
@@ -1,5 +1,5 @@
1
1
  import { User, GenericEndpointContext } from 'better-auth';
2
- import { D as DodoPaymentsOptions } from '../types-B9rx1bt7.js';
2
+ import { D as DodoPaymentsOptions } from '../types-DygjjcRn.js';
3
3
  import 'dodopayments';
4
4
  import 'zod/v3';
5
5
  import '@dodopayments/core/webhook';
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  onUserCreate,
3
3
  onUserUpdate
4
- } from "../chunk-BII7QAPD.js";
4
+ } from "../chunk-527Y7FSE.js";
5
5
  export {
6
6
  onUserCreate,
7
7
  onUserUpdate