@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.
- package/README.md +75 -5
- package/dist/chunk-527Y7FSE.js +90 -0
- package/dist/chunk-527Y7FSE.js.map +1 -0
- package/dist/{chunk-47N33D2M.js → chunk-ARA27DRZ.js} +17 -32
- package/dist/chunk-ARA27DRZ.js.map +1 -0
- package/dist/{chunk-KXU6PYZF.js → chunk-DTOB4IQZ.js} +22 -45
- package/dist/chunk-DTOB4IQZ.js.map +1 -0
- package/dist/chunk-TOPOAYYO.js +23 -0
- package/dist/chunk-TOPOAYYO.js.map +1 -0
- package/dist/client.d.cts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/hooks/customer.cjs +39 -11
- package/dist/hooks/customer.cjs.map +1 -1
- package/dist/hooks/customer.d.cts +1 -1
- package/dist/hooks/customer.d.ts +1 -1
- package/dist/hooks/customer.js +1 -1
- package/dist/index.cjs +100 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +18 -6
- package/dist/index.js.map +1 -1
- package/dist/plugins/checkout.d.cts +1 -1
- package/dist/plugins/checkout.d.ts +1 -1
- package/dist/plugins/portal.cjs +38 -44
- package/dist/plugins/portal.cjs.map +1 -1
- package/dist/plugins/portal.d.cts +1 -1
- package/dist/plugins/portal.d.ts +1 -1
- package/dist/plugins/portal.js +2 -1
- package/dist/plugins/usage.cjs +33 -31
- package/dist/plugins/usage.cjs.map +1 -1
- package/dist/plugins/usage.js +2 -1
- package/dist/plugins/webhooks.d.cts +1 -1
- package/dist/plugins/webhooks.d.ts +1 -1
- package/dist/{types-4JE4OwKb.d.cts → types-3pb2RGTM.d.cts} +12 -1
- package/dist/{types-B9rx1bt7.d.ts → types-DygjjcRn.d.ts} +12 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utils.cjs +47 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +13 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.js +7 -0
- package/dist/utils.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-47N33D2M.js.map +0 -1
- package/dist/chunk-BII7QAPD.js +0 -62
- package/dist/chunk-BII7QAPD.js.map +0 -1
- 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.
|
|
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
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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:
|
|
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
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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:
|
|
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-
|
|
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
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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:
|
|
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
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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:
|
|
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-
|
|
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-
|
|
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-
|
|
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';
|
package/dist/hooks/customer.cjs
CHANGED
|
@@ -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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
|
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-
|
|
2
|
+
import { D as DodoPaymentsOptions } from '../types-3pb2RGTM.cjs';
|
|
3
3
|
import 'dodopayments';
|
|
4
4
|
import 'zod/v3';
|
|
5
5
|
import '@dodopayments/core/webhook';
|
package/dist/hooks/customer.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { User, GenericEndpointContext } from 'better-auth';
|
|
2
|
-
import { D as DodoPaymentsOptions } from '../types-
|
|
2
|
+
import { D as DodoPaymentsOptions } from '../types-DygjjcRn.js';
|
|
3
3
|
import 'dodopayments';
|
|
4
4
|
import 'zod/v3';
|
|
5
5
|
import '@dodopayments/core/webhook';
|