@dodopayments/better-auth 1.4.3 → 1.5.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.
@@ -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":";;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,SAAS;AAGlB,IAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,UAAU,EAAE,OAAO;AAAA,EACnB,YAAY,EAAE,OAAO;AAAA,EACrB,UAAU,EACP,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,EACrD,SAAS,EACT,SAAS;AAAA,EACZ,WAAW,EAGR,KAAK,EAAE,QAAQ,KAAK,CAAC,EACrB,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC,EAChC,SAAS,EACT;AAAA,IACC;AAAA,EAGF;AACJ,CAAC;AAEM,IAAM,QAAQ,MAAM,CAAC,iBAA+B;AACzD,SAAO;AAAA;AAAA,IAEL,iBAAiB;AAAA,MACf;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,KAAK,CAAC,iBAAiB;AAAA,MACzB;AAAA,MACA,OAAO,QAA6C;AAClD,YAAI,CAAC,IAAI,QAAQ,SAAS,MAAM,IAAI;AAClC,gBAAM,IAAI,SAAS,eAAe;AAAA,YAChC,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAEA,YAAI,CAAC,IAAI,QAAQ,SAAS,KAAK,eAAe;AAC5C,gBAAM,IAAI,SAAS,gBAAgB;AAAA,YACjC,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAEA,YAAI;AACF,gBAAM,aAAa,MAAM;AAAA,YACvB;AAAA,YACA,IAAI,QAAQ;AAAA,YACZ,IAAI,QAAQ;AAAA,UACd;AAEA,gBAAM,SAAS,MAAM,aAAa,YAAY,OAAO;AAAA,YACnD,QAAQ;AAAA,cACN;AAAA,gBACE,UAAU,IAAI,KAAK;AAAA,gBACnB,aAAa;AAAA,gBACb,YAAY,IAAI,KAAK;AAAA,gBACrB,WAAW,IAAI,KAAK;AAAA,gBACpB,UAAU,IAAI,KAAK;AAAA,cACrB;AAAA,YACF;AAAA,UACF,CAAC;AAED,iBAAO,IAAI,KAAK,EAAE,gBAAgB,OAAO,eAAe,CAAC;AAAA,QAC3D,SAAS,GAAY;AACnB,cAAI,aAAa,OAAO;AACtB,gBAAI,QAAQ,OAAO;AAAA,cACjB,+BAA+B,EAAE,OAAO;AAAA,YAC1C;AAAA,UACF;AAEA,gBAAM,IAAI,SAAS,yBAAyB;AAAA,YAC1C,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGA,qBAAqB;AAAA,MACnB;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO,EACJ,OAAO;AAAA,UACN,aAAa,EAAE,OAAO,OAAO,EAAE,SAAS;AAAA,UACxC,WAAW,EAAE,OAAO,OAAO,EAAE,SAAS;AAAA,UACtC,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,UAChC,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,UAC9B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,UAC3B,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA,QAC3B,CAAC,EACA,SAAS;AAAA,QACZ,KAAK,CAAC,iBAAiB;AAAA,MACzB;AAAA,MACA,OAAO,QAAqC;AAC1C,YAAI,CAAC,IAAI,QAAQ,SAAS,MAAM,IAAI;AAClC,gBAAM,IAAI,SAAS,eAAe;AAAA,YAChC,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAEA,YAAI,CAAC,IAAI,QAAQ,SAAS,KAAK,eAAe;AAC5C,gBAAM,IAAI,SAAS,gBAAgB;AAAA,YACjC,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAEA,YAAI;AACF,gBAAM,aAAa,MAAM;AAAA,YACvB;AAAA,YACA,IAAI,QAAQ;AAAA,YACZ,IAAI,QAAQ;AAAA,UACd;AAEA,gBAAM,SAAS,MAAM,aAAa,YAAY,KAAK;AAAA,YACjD,aAAa;AAAA,YACb,GAAG,IAAI;AAAA,UACT,CAAC;AAED,iBAAO,IAAI,KAAK,EAAE,OAAO,OAAO,MAAM,CAAC;AAAA,QACzC,SAAS,GAAY;AACnB,cAAI,aAAa,OAAO;AACtB,gBAAI,QAAQ,OAAO;AAAA,cACjB,gCAAgC,EAAE,OAAO;AAAA,YAC3C;AAAA,UACF;AAEA,gBAAM,IAAI,SAAS,yBAAyB;AAAA,YAC1C,SAAS;AAAA,UACX,CAAC;AAAA,QACH;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/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":[]}
@@ -7,16 +7,26 @@ var onUserCreate = (options) => async (user, ctx) => {
7
7
  email: user.email
8
8
  });
9
9
  const existingCustomer = customers.items[0];
10
+ let customerId;
10
11
  if (existingCustomer) {
11
12
  await options.client.customers.update(existingCustomer.customer_id, {
12
13
  name: user.name
13
14
  });
15
+ customerId = existingCustomer.customer_id;
14
16
  } else {
15
- await options.client.customers.create({
17
+ const newCustomer = await options.client.customers.create({
16
18
  email: user.email,
17
19
  name: user.name
18
- });
20
+ }, { idempotencyKey: user.id });
21
+ customerId = newCustomer.customer_id;
19
22
  }
23
+ ctx.context.internalAdapter.updateUser(user.id, {
24
+ dodoCustomerId: customerId
25
+ }).catch((e) => {
26
+ ctx.context.logger.warn(
27
+ `DodoPayments: failed to store dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`
28
+ );
29
+ });
20
30
  } catch (e) {
21
31
  if (e instanceof Error) {
22
32
  throw new APIError("INTERNAL_SERVER_ERROR", {
@@ -40,6 +50,15 @@ var onUserUpdate = (options) => async (user, ctx) => {
40
50
  await options.client.customers.update(existingCustomer.customer_id, {
41
51
  name: user.name
42
52
  });
53
+ if (!user.dodoCustomerId) {
54
+ ctx.context.internalAdapter.updateUser(user.id, {
55
+ dodoCustomerId: existingCustomer.customer_id
56
+ }).catch((e) => {
57
+ ctx.context.logger.warn(
58
+ `DodoPayments: failed to backfill dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`
59
+ );
60
+ });
61
+ }
43
62
  }
44
63
  } catch (e) {
45
64
  if (e instanceof Error) {
@@ -59,4 +78,4 @@ export {
59
78
  onUserCreate,
60
79
  onUserUpdate
61
80
  };
62
- //# sourceMappingURL=chunk-BII7QAPD.js.map
81
+ //# sourceMappingURL=chunk-R5TTSJK4.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 if (existingCustomer) {\n await options.client.customers.update(existingCustomer.customer_id, {\n name: user.name,\n });\n customerId = existingCustomer.customer_id;\n } else {\n // TODO: Add metadata to customer object via\n // getCustomerCreateParams option when it becomes\n // available in the API\n const newCustomer = await options.client.customers.create({\n email: user.email,\n name: user.name,\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 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 // Backfill dodoCustomerId if it doesn't exist\n if (!(user as User & { dodoCustomerId?: string }).dodoCustomerId) {\n ctx.context.internalAdapter.updateUser(user.id, {\n dodoCustomerId: existingCustomer.customer_id,\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 } 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,UAAI,kBAAkB;AACpB,cAAM,QAAQ,OAAO,UAAU,OAAO,iBAAiB,aAAa;AAAA,UAClE,MAAM,KAAK;AAAA,QACb,CAAC;AACD,qBAAa,iBAAiB;AAAA,MAChC,OAAO;AAIL,cAAM,cAAc,MAAM,QAAQ,OAAO,UAAU,OAAO;AAAA,UACxD,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,QACb,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,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;AAGD,YAAI,CAAE,KAA4C,gBAAgB;AAChE,cAAI,QAAQ,gBAAgB,WAAW,KAAK,IAAI;AAAA,YAC9C,gBAAgB,iBAAiB;AAAA,UACnC,CAAC,EAAE,MAAM,CAAC,MAAe;AACvB,gBAAI,QAAQ,OAAO;AAAA,cACjB,4DAA4D,KAAK,EAAE,YAAY,aAAa,QAAQ,EAAE,UAAU,CAAC;AAAA,YACnH;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;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":[]}
@@ -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":[]}
@@ -32,16 +32,26 @@ var onUserCreate = (options) => async (user, ctx) => {
32
32
  email: user.email
33
33
  });
34
34
  const existingCustomer = customers.items[0];
35
+ let customerId;
35
36
  if (existingCustomer) {
36
37
  await options.client.customers.update(existingCustomer.customer_id, {
37
38
  name: user.name
38
39
  });
40
+ customerId = existingCustomer.customer_id;
39
41
  } else {
40
- await options.client.customers.create({
42
+ const newCustomer = await options.client.customers.create({
41
43
  email: user.email,
42
44
  name: user.name
43
- });
45
+ }, { idempotencyKey: user.id });
46
+ customerId = newCustomer.customer_id;
44
47
  }
48
+ ctx.context.internalAdapter.updateUser(user.id, {
49
+ dodoCustomerId: customerId
50
+ }).catch((e) => {
51
+ ctx.context.logger.warn(
52
+ `DodoPayments: failed to store dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`
53
+ );
54
+ });
45
55
  } catch (e) {
46
56
  if (e instanceof Error) {
47
57
  throw new import_api.APIError("INTERNAL_SERVER_ERROR", {
@@ -65,6 +75,15 @@ var onUserUpdate = (options) => async (user, ctx) => {
65
75
  await options.client.customers.update(existingCustomer.customer_id, {
66
76
  name: user.name
67
77
  });
78
+ if (!user.dodoCustomerId) {
79
+ ctx.context.internalAdapter.updateUser(user.id, {
80
+ dodoCustomerId: existingCustomer.customer_id
81
+ }).catch((e) => {
82
+ ctx.context.logger.warn(
83
+ `DodoPayments: failed to backfill dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`
84
+ );
85
+ });
86
+ }
68
87
  }
69
88
  } catch (e) {
70
89
  if (e instanceof 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 if (existingCustomer) {\n await options.client.customers.update(existingCustomer.customer_id, {\n name: user.name,\n });\n customerId = existingCustomer.customer_id;\n } else {\n // TODO: Add metadata to customer object via\n // getCustomerCreateParams option when it becomes\n // available in the API\n const newCustomer = await options.client.customers.create({\n email: user.email,\n name: user.name,\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 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 // Backfill dodoCustomerId if it doesn't exist\n if (!(user as User & { dodoCustomerId?: string }).dodoCustomerId) {\n ctx.context.internalAdapter.updateUser(user.id, {\n dodoCustomerId: existingCustomer.customer_id,\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 } 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,UAAI,kBAAkB;AACpB,cAAM,QAAQ,OAAO,UAAU,OAAO,iBAAiB,aAAa;AAAA,UAClE,MAAM,KAAK;AAAA,QACb,CAAC;AACD,qBAAa,iBAAiB;AAAA,MAChC,OAAO;AAIL,cAAM,cAAc,MAAM,QAAQ,OAAO,UAAU,OAAO;AAAA,UACxD,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,QACb,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,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;AAGD,YAAI,CAAE,KAA4C,gBAAgB;AAChE,cAAI,QAAQ,gBAAgB,WAAW,KAAK,IAAI;AAAA,YAC9C,gBAAgB,iBAAiB;AAAA,UACnC,CAAC,EAAE,MAAM,CAAC,MAAe;AACvB,gBAAI,QAAQ,OAAO;AAAA,cACjB,4DAA4D,KAAK,EAAE,YAAY,aAAa,QAAQ,EAAE,UAAU,CAAC;AAAA,YACnH;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;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,7 +1,7 @@
1
1
  import {
2
2
  onUserCreate,
3
3
  onUserUpdate
4
- } from "../chunk-BII7QAPD.js";
4
+ } from "../chunk-R5TTSJK4.js";
5
5
  export {
6
6
  onUserCreate,
7
7
  onUserUpdate
package/dist/index.cjs CHANGED
@@ -38,16 +38,26 @@ var onUserCreate = (options) => async (user, ctx) => {
38
38
  email: user.email
39
39
  });
40
40
  const existingCustomer = customers.items[0];
41
+ let customerId;
41
42
  if (existingCustomer) {
42
43
  await options.client.customers.update(existingCustomer.customer_id, {
43
44
  name: user.name
44
45
  });
46
+ customerId = existingCustomer.customer_id;
45
47
  } else {
46
- await options.client.customers.create({
48
+ const newCustomer = await options.client.customers.create({
47
49
  email: user.email,
48
50
  name: user.name
49
- });
51
+ }, { idempotencyKey: user.id });
52
+ customerId = newCustomer.customer_id;
50
53
  }
54
+ ctx.context.internalAdapter.updateUser(user.id, {
55
+ dodoCustomerId: customerId
56
+ }).catch((e) => {
57
+ ctx.context.logger.warn(
58
+ `DodoPayments: failed to store dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`
59
+ );
60
+ });
51
61
  } catch (e) {
52
62
  if (e instanceof Error) {
53
63
  throw new import_api.APIError("INTERNAL_SERVER_ERROR", {
@@ -71,6 +81,15 @@ var onUserUpdate = (options) => async (user, ctx) => {
71
81
  await options.client.customers.update(existingCustomer.customer_id, {
72
82
  name: user.name
73
83
  });
84
+ if (!user.dodoCustomerId) {
85
+ ctx.context.internalAdapter.updateUser(user.id, {
86
+ dodoCustomerId: existingCustomer.customer_id
87
+ }).catch((e) => {
88
+ ctx.context.logger.warn(
89
+ `DodoPayments: failed to backfill dodoCustomerId for user ${user.id}. Error: ${e instanceof Error ? e.message : e}`
90
+ );
91
+ });
92
+ }
74
93
  }
75
94
  } catch (e) {
76
95
  if (e instanceof Error) {
@@ -97,6 +116,27 @@ var dodopaymentsClient = () => {
97
116
  // src/plugins/portal.ts
98
117
  var import_api2 = require("better-auth/api");
99
118
  var import_v3 = require("zod/v3");
119
+
120
+ // src/utils.ts
121
+ async function getOrCreateCustomerId(dodopayments2, session, internalAdapter) {
122
+ const dodoCustomerId = session.user["dodoCustomerId"];
123
+ if (dodoCustomerId) return dodoCustomerId;
124
+ const customers = await dodopayments2.customers.list({
125
+ email: session.user.email
126
+ });
127
+ let customer = customers.items[0];
128
+ if (!customer) {
129
+ customer = await dodopayments2.customers.create({
130
+ email: session.user.email,
131
+ name: session.user.name
132
+ }, { idempotencyKey: session.user.id });
133
+ }
134
+ internalAdapter.updateUser(session.user.id, { dodoCustomerId: customer.customer_id }).catch(() => {
135
+ });
136
+ return customer.customer_id;
137
+ }
138
+
139
+ // src/plugins/portal.ts
100
140
  var portal = () => (dodopayments2) => {
101
141
  return {
102
142
  dodoPortal: (0, import_api2.createAuthEndpoint)(
@@ -117,20 +157,12 @@ var portal = () => (dodopayments2) => {
117
157
  });
118
158
  }
119
159
  try {
120
- const customers = await dodopayments2.customers.list({
121
- email: ctx.context.session?.user.email
122
- });
123
- let customer = customers.items[0];
124
- if (!customer) {
125
- customer = await createCustomer(
126
- dodopayments2,
127
- ctx.context.session.user.email,
128
- ctx.context.session.user.name
129
- );
130
- }
131
- const customerSession = await dodopayments2.customers.customerPortal.create(
132
- customer.customer_id
160
+ const customerId = await getOrCreateCustomerId(
161
+ dodopayments2,
162
+ ctx.context.session,
163
+ ctx.context.internalAdapter
133
164
  );
165
+ const customerSession = await dodopayments2.customers.customerPortal.create(customerId);
134
166
  return ctx.json({
135
167
  url: customerSession.link,
136
168
  redirect: true
@@ -177,19 +209,13 @@ var portal = () => (dodopayments2) => {
177
209
  });
178
210
  }
179
211
  try {
180
- const customers = await dodopayments2.customers.list({
181
- email: ctx.context.session?.user.email
182
- });
183
- let customer = customers.items[0];
184
- if (!customer) {
185
- customer = await createCustomer(
186
- dodopayments2,
187
- ctx.context.session.user.email,
188
- ctx.context.session.user.name
189
- );
190
- }
212
+ const customerId = await getOrCreateCustomerId(
213
+ dodopayments2,
214
+ ctx.context.session,
215
+ ctx.context.internalAdapter
216
+ );
191
217
  const subscriptions = await dodopayments2.subscriptions.list({
192
- customer_id: customer.customer_id,
218
+ customer_id: customerId,
193
219
  // page number is 0-indexed
194
220
  page_number: ctx.query?.page ? ctx.query.page - 1 : void 0,
195
221
  page_size: ctx.query?.limit,
@@ -243,19 +269,13 @@ var portal = () => (dodopayments2) => {
243
269
  });
244
270
  }
245
271
  try {
246
- const customers = await dodopayments2.customers.list({
247
- email: ctx.context.session?.user.email
248
- });
249
- let customer = customers.items[0];
250
- if (!customer) {
251
- customer = await createCustomer(
252
- dodopayments2,
253
- ctx.context.session.user.email,
254
- ctx.context.session.user.name
255
- );
256
- }
272
+ const customerId = await getOrCreateCustomerId(
273
+ dodopayments2,
274
+ ctx.context.session,
275
+ ctx.context.internalAdapter
276
+ );
257
277
  const payments = await dodopayments2.payments.list({
258
- customer_id: customer.customer_id,
278
+ customer_id: customerId,
259
279
  // page number is 0-indexed
260
280
  page_number: ctx.query?.page ? ctx.query.page - 1 : void 0,
261
281
  page_size: ctx.query?.limit,
@@ -276,13 +296,6 @@ var portal = () => (dodopayments2) => {
276
296
  )
277
297
  };
278
298
  };
279
- async function createCustomer(dodopayments2, email, name) {
280
- const customer = await dodopayments2.customers.create({
281
- email,
282
- name
283
- });
284
- return customer;
285
- }
286
299
 
287
300
  // src/plugins/checkout.ts
288
301
  var import_api3 = require("better-auth/api");
@@ -558,22 +571,16 @@ var usage = () => (dodopayments2) => {
558
571
  });
559
572
  }
560
573
  try {
561
- const customers = await dodopayments2.customers.list({
562
- email: ctx.context.session.user.email
563
- });
564
- let customer = customers.items[0];
565
- if (!customer) {
566
- customer = await createCustomer2(
567
- dodopayments2,
568
- ctx.context.session.user.email,
569
- ctx.context.session.user.name
570
- );
571
- }
574
+ const customerId = await getOrCreateCustomerId(
575
+ dodopayments2,
576
+ ctx.context.session,
577
+ ctx.context.internalAdapter
578
+ );
572
579
  const result = await dodopayments2.usageEvents.ingest({
573
580
  events: [
574
581
  {
575
582
  event_id: ctx.body.event_id,
576
- customer_id: customer.customer_id,
583
+ customer_id: customerId,
577
584
  event_name: ctx.body.event_name,
578
585
  timestamp: ctx.body.timestamp,
579
586
  metadata: ctx.body.metadata
@@ -620,19 +627,13 @@ var usage = () => (dodopayments2) => {
620
627
  });
621
628
  }
622
629
  try {
623
- const customers = await dodopayments2.customers.list({
624
- email: ctx.context.session.user.email
625
- });
626
- let customer = customers.items[0];
627
- if (!customer) {
628
- customer = await createCustomer2(
629
- dodopayments2,
630
- ctx.context.session.user.email,
631
- ctx.context.session.user.name
632
- );
633
- }
630
+ const customerId = await getOrCreateCustomerId(
631
+ dodopayments2,
632
+ ctx.context.session,
633
+ ctx.context.internalAdapter
634
+ );
634
635
  const meters = await dodopayments2.usageEvents.list({
635
- customer_id: customer.customer_id,
636
+ customer_id: customerId,
636
637
  ...ctx.query
637
638
  });
638
639
  return ctx.json({ items: meters.items });
@@ -650,13 +651,6 @@ var usage = () => (dodopayments2) => {
650
651
  )
651
652
  };
652
653
  };
653
- async function createCustomer2(dodopayments2, email, name) {
654
- const customer = await dodopayments2.customers.create({
655
- email,
656
- name
657
- });
658
- return customer;
659
- }
660
654
 
661
655
  // src/index.ts
662
656
  var dodopayments = (options) => {
@@ -666,6 +660,17 @@ var dodopayments = (options) => {
666
660
  }, {});
667
661
  return {
668
662
  id: "dodopayments",
663
+ schema: {
664
+ user: {
665
+ fields: {
666
+ dodoCustomerId: {
667
+ type: "string",
668
+ required: false,
669
+ input: false
670
+ }
671
+ }
672
+ }
673
+ },
669
674
  endpoints: {
670
675
  ...plugins
671
676
  },