@delmaredigital/payload-better-auth 0.3.10 → 0.3.11

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 CHANGED
@@ -2,11 +2,19 @@
2
2
 
3
3
  Better Auth adapter and plugins for Payload CMS. Enables seamless integration between Better Auth and Payload.
4
4
 
5
- [![Demo](https://img.shields.io/badge/Demo-Live-blue)](https://demo.delmaredigital.com)
6
- [![Starter Template](https://img.shields.io/badge/Starter-Template-green)](https://github.com/delmaredigital/dd-starter)
7
- [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fdelmaredigital%2Fdd-starter&project-name=my-payload-site&build-command=pnpm%20run%20ci&env=PAYLOAD_SECRET,BETTER_AUTH_SECRET&stores=%5B%7B%22type%22%3A%22integration%22%2C%22protocol%22%3A%22storage%22%2C%22productSlug%22%3A%22neon%22%2C%22integrationSlug%22%3A%22neon%22%7D%2C%7B%22type%22%3A%22blob%22%7D%5D)
5
+ <p align="center">
6
+ <a href="https://demo.delmaredigital.com"><img src="https://img.shields.io/badge/Live_Demo-Try_It_Now-2ea44f?style=for-the-badge&logo=vercel&logoColor=white" alt="Live Demo - Try It Now"></a>
7
+ &nbsp;&nbsp;
8
+ <a href="https://github.com/delmaredigital/dd-starter"><img src="https://img.shields.io/badge/Starter_Template-Use_This-blue?style=for-the-badge&logo=github&logoColor=white" alt="Starter Template - Use This"></a>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fdelmaredigital%2Fdd-starter&project-name=my-payload-site&build-command=pnpm%20run%20ci&env=PAYLOAD_SECRET,BETTER_AUTH_SECRET&stores=%5B%7B%22type%22%3A%22integration%22%2C%22protocol%22%3A%22storage%22%2C%22productSlug%22%3A%22neon%22%2C%22integrationSlug%22%3A%22neon%22%7D%2C%7B%22type%22%3A%22blob%22%7D%5D"><img src="https://vercel.com/button" alt="Deploy with Vercel" height="32"></a>
13
+ </p>
8
14
 
9
15
  ---
16
+ ## Documentation
17
+ For additional documentation and references, visit: [https://deepwiki.com/delmaredigital/payload-better-auth](https://deepwiki.com/delmaredigital/payload-better-auth)
10
18
 
11
19
  ## Table of Contents
12
20
 
@@ -17,6 +25,7 @@ Better Auth adapter and plugins for Payload CMS. Enables seamless integration be
17
25
  - [Access Control Helpers](#access-control-helpers)
18
26
  - [API Key Scope Enforcement](#api-key-scope-enforcement)
19
27
  - [Plugin Compatibility](#plugin-compatibility)
28
+ - [Recipes](#recipes)
20
29
  - [Types](#types)
21
30
  - [License](#license)
22
31
 
@@ -1585,6 +1594,130 @@ createBetterAuthPlugin({
1585
1594
 
1586
1595
  ---
1587
1596
 
1597
+ ## Recipes
1598
+
1599
+ Common patterns and solutions for Better Auth integration.
1600
+
1601
+ ### Auto-Create Organization on User Signup
1602
+
1603
+ A common pattern is to automatically create a personal workspace/organization when a user signs up (and verifies their email). The key is to use Better Auth's organization API (`auth.api.createOrganization()`) rather than raw adapter calls, so that `organizationHooks` fire properly.
1604
+
1605
+ **The Challenge:** Database hooks are defined in `betterAuthOptions` before the `auth` instance exists, so you can't directly reference `auth.api` in your hooks.
1606
+
1607
+ **The Solution:** Use a lazy auth instance singleton:
1608
+
1609
+ **Step 1: Create an auth instance singleton**
1610
+
1611
+ ```typescript
1612
+ // src/lib/auth/instance.ts
1613
+ import type { betterAuth } from 'better-auth'
1614
+
1615
+ type AuthInstance = ReturnType<typeof betterAuth>
1616
+
1617
+ let authInstance: AuthInstance | null = null
1618
+
1619
+ export function setAuthInstance(auth: AuthInstance): void {
1620
+ authInstance = auth
1621
+ }
1622
+
1623
+ export function getAuthInstance(): AuthInstance {
1624
+ if (!authInstance) {
1625
+ throw new Error('Auth not initialized')
1626
+ }
1627
+ return authInstance
1628
+ }
1629
+ ```
1630
+
1631
+ **Step 2: Store the instance after creation**
1632
+
1633
+ ```typescript
1634
+ // src/payload.config.ts (or wherever you configure plugins)
1635
+ import { setAuthInstance } from '@/lib/auth/instance'
1636
+
1637
+ createBetterAuthPlugin({
1638
+ createAuth: (payload) => {
1639
+ const auth = betterAuth({
1640
+ ...betterAuthOptions,
1641
+ database: payloadAdapter({ payloadClient: payload }),
1642
+ // ... other options
1643
+ })
1644
+
1645
+ // Store for use in database hooks
1646
+ setAuthInstance(auth)
1647
+
1648
+ return auth
1649
+ },
1650
+ })
1651
+ ```
1652
+
1653
+ **Step 3: Use the organization API in database hooks**
1654
+
1655
+ ```typescript
1656
+ // src/lib/auth/config.ts
1657
+ import { getAuthInstance } from './instance'
1658
+
1659
+ export const betterAuthOptions: Partial<BetterAuthOptions> = {
1660
+ // ... other options
1661
+
1662
+ plugins: [
1663
+ organization({
1664
+ // organizationHooks fire when using auth.api.createOrganization()
1665
+ organizationHooks: {
1666
+ afterCreateOrganization: async ({ organization }) => {
1667
+ // This runs for ALL org creations - auto-created, manual, API
1668
+ console.log(`Organization ${organization.id} created`)
1669
+ // Create related records, send welcome email, etc.
1670
+ },
1671
+ },
1672
+ }),
1673
+ ],
1674
+
1675
+ databaseHooks: {
1676
+ user: {
1677
+ update: {
1678
+ after: async (user, ctx) => {
1679
+ // Only proceed if user just verified their email
1680
+ if (!user.emailVerified) return
1681
+
1682
+ // Check if user already has an organization (e.g., joined via invitation)
1683
+ const existingMembership = await ctx?.context?.adapter?.findOne({
1684
+ model: 'member',
1685
+ where: [{ field: 'userId', value: user.id }],
1686
+ })
1687
+ if (existingMembership) return
1688
+
1689
+ // Create organization using the proper API
1690
+ // This ensures organizationHooks.afterCreateOrganization fires
1691
+ const auth = getAuthInstance()
1692
+ await auth.api.createOrganization({
1693
+ body: {
1694
+ name: `${user.name}'s Workspace`,
1695
+ slug: generateUniqueSlug(user.name),
1696
+ userId: user.id,
1697
+ },
1698
+ })
1699
+ },
1700
+ },
1701
+ },
1702
+ },
1703
+ }
1704
+ ```
1705
+
1706
+ **Why This Matters:**
1707
+
1708
+ | Approach | organizationHooks fire? | Recommended? |
1709
+ |----------|------------------------|--------------|
1710
+ | `auth.api.createOrganization()` | ✅ Yes | ✅ Yes |
1711
+ | `ctx.context.adapter.create({ model: 'organization' })` | ❌ No | ❌ No |
1712
+
1713
+ Using the raw adapter bypasses Better Auth's organization plugin entirely. Any logic in `organizationHooks` (like creating related records, sending notifications, or syncing with external systems) won't run.
1714
+
1715
+ **Handling Invitations:**
1716
+
1717
+ Users who join via invitation already have a membership record (created when they accept the invitation), so the `existingMembership` check prevents creating a duplicate personal organization for them.
1718
+
1719
+ ---
1720
+
1588
1721
  ## Types
1589
1722
 
1590
1723
  The package exports comprehensive TypeScript types for Better Auth integration.
@@ -295,6 +295,19 @@
295
295
  }
296
296
  }
297
297
  }
298
+ // Convert date strings to Date objects
299
+ // Better Auth expects Date objects for date field comparisons
300
+ for (const [key, value] of Object.entries(transformed)){
301
+ if (typeof value !== 'string') continue;
302
+ // Check if schema defines this field as a date type
303
+ const fieldDef = modelSchema.fields[key];
304
+ if (fieldDef?.type === 'date') {
305
+ const dateValue = new Date(value);
306
+ if (!isNaN(dateValue.getTime())) {
307
+ transformed[key] = dateValue;
308
+ }
309
+ }
310
+ }
298
311
  // Convert semantic ID fields to numbers when using serial IDs
299
312
  // Heuristic: fields ending in 'Id' or '_id' containing numeric strings
300
313
  // Modified by allowlist (add) and blocklist (exclude)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delmaredigital/payload-better-auth",
3
- "version": "0.3.10",
3
+ "version": "0.3.11",
4
4
  "description": "Better Auth adapter and plugins for Payload CMS",
5
5
  "type": "module",
6
6
  "license": "MIT",