better-auth-lead 0.0.1-dev.1 → 0.1.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.
- package/README.md +161 -1
- package/dist/client.d.mts +8 -2
- package/dist/client.mjs +4 -2
- package/dist/client.mjs.map +1 -1
- package/dist/error-codes-CZUPEOrE.mjs +12 -0
- package/dist/error-codes-CZUPEOrE.mjs.map +1 -0
- package/dist/index-B-BhgW_e.d.mts +206 -0
- package/dist/index.d.mts +2 -90
- package/dist/index.mjs +101 -71
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/dist/type-CedeOvZ6.d.mts +0 -98
package/README.md
CHANGED
|
@@ -11,9 +11,11 @@ npm install better-auth-lead
|
|
|
11
11
|
pnpm add better-auth-lead
|
|
12
12
|
# yarn
|
|
13
13
|
yarn add better-auth-lead
|
|
14
|
+
# bun
|
|
15
|
+
bun add better-auth-lead
|
|
14
16
|
```
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
Add the plugin to your auth config
|
|
17
19
|
|
|
18
20
|
```ts
|
|
19
21
|
// server/auth.ts
|
|
@@ -28,7 +30,14 @@ const betterAuth = createBetterAuth({
|
|
|
28
30
|
Run better auth migration to create the lead table:
|
|
29
31
|
|
|
30
32
|
```bash
|
|
33
|
+
# npm
|
|
31
34
|
npx auth@latest generate
|
|
35
|
+
# pnpm
|
|
36
|
+
pnpm dlx auth@latest generate
|
|
37
|
+
# yarn
|
|
38
|
+
yarn dlx auth@latest generate
|
|
39
|
+
# bun
|
|
40
|
+
bun x auth@latest generate
|
|
32
41
|
```
|
|
33
42
|
|
|
34
43
|
Add the lead plugin to your auth client:
|
|
@@ -42,3 +51,154 @@ const authClient = createAuthClient({
|
|
|
42
51
|
plugins: [leadClient()],
|
|
43
52
|
});
|
|
44
53
|
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
### Subscribe
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
// POST /lead/subscribe
|
|
61
|
+
const { data, error } = await authClient.lead.subscribe({
|
|
62
|
+
email: 'user@example.com',
|
|
63
|
+
// json object
|
|
64
|
+
metadata: {
|
|
65
|
+
preferences: 'engineering',
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Verify
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
// GET /lead/verify
|
|
74
|
+
await authClient.lead.verify({
|
|
75
|
+
query: {
|
|
76
|
+
token,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Unsubscribe
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// POST /lead/unsubscribe
|
|
85
|
+
const { data, error } = await authClient.lead.unsubscribe({ id: 'lead-id' });
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Resend
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// POST /lead/resend
|
|
92
|
+
const { data, error } = await authClient.lead.resend({
|
|
93
|
+
email: 'user@example.com',
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Update
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
// POST /lead/update
|
|
101
|
+
const { data, error } = await authClient.lead.update({
|
|
102
|
+
id: 'lead-id',
|
|
103
|
+
metadata: {
|
|
104
|
+
preferences: 'ai',
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Email Verification
|
|
110
|
+
|
|
111
|
+
To enable email verification, you need to pass a function that sends a verification email with a link. The `sendVerificationEmail` takes a data object with the following properties:
|
|
112
|
+
|
|
113
|
+
- `email`: The lead email.
|
|
114
|
+
- `url`: The URL to send to the user which contains the token.
|
|
115
|
+
- `token`: A verification token used to complete the email verification.
|
|
116
|
+
|
|
117
|
+
and a `request` object as the second parameter.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
// server/auth.ts
|
|
121
|
+
import { betterAuth } from 'better-auth';
|
|
122
|
+
import { lead } from 'better-auth-lead';
|
|
123
|
+
import { sendEmail } from './email'; // your email sending function
|
|
124
|
+
|
|
125
|
+
export const auth = betterAuth({
|
|
126
|
+
plugins: [
|
|
127
|
+
lead({
|
|
128
|
+
sendVerificationEmail: async ({ email, url, token }) => {
|
|
129
|
+
void sendEmail({
|
|
130
|
+
to: email,
|
|
131
|
+
subject: 'Newsletter: Verify your email address',
|
|
132
|
+
text: `Click the link to verify your email: ${url}`,
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
onEmailVerified: async ({ lead }) => {
|
|
136
|
+
// do something when a lead's email is verified
|
|
137
|
+
console.log(`Lead ${lead.email} has been verified!`);
|
|
138
|
+
},
|
|
139
|
+
}),
|
|
140
|
+
],
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
> Avoid awaiting the email sending to prevent timing attacks.
|
|
145
|
+
|
|
146
|
+
Additionally, you can provide an `onEmailVerified` callback to execute logic after a lead's email is verified.
|
|
147
|
+
|
|
148
|
+
### Metadata Validation
|
|
149
|
+
|
|
150
|
+
To validate and parse metadata, you can pass a Standard Schema compatible schema (e.g. Zod, Valibot, ArkType).
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
// server/auth.ts
|
|
154
|
+
import { betterAuth } from 'better-auth';
|
|
155
|
+
import { lead } from 'better-auth-lead';
|
|
156
|
+
import * as z from 'zod';
|
|
157
|
+
|
|
158
|
+
const metadataSchema = z.object({
|
|
159
|
+
preferences: z.enum(['engineering', 'marketing', 'design']),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
export const auth = betterAuth({
|
|
163
|
+
plugins: [
|
|
164
|
+
lead({
|
|
165
|
+
metadata: {
|
|
166
|
+
validationSchema: metadataSchema,
|
|
167
|
+
},
|
|
168
|
+
}),
|
|
169
|
+
],
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
If the schema validation fails, the API `subscribe` and `update` routes will return a `400 Bad Request` error with `INVALID_METADATA`.
|
|
174
|
+
|
|
175
|
+
## Schema
|
|
176
|
+
|
|
177
|
+
### Lead
|
|
178
|
+
|
|
179
|
+
Table name: `lead`
|
|
180
|
+
|
|
181
|
+
| Field | Type | Key | Description |
|
|
182
|
+
| -------------- | ------- | ------ | ------------------------------- |
|
|
183
|
+
| id | string | pk | Unique identifier for each lead |
|
|
184
|
+
| email | string | unique | Email address of the lead |
|
|
185
|
+
| emailVerified | boolean | | Whether the email is verified |
|
|
186
|
+
| metadata | json | ? | Additional data about the lead |
|
|
187
|
+
| createdAt | date | | Timestamp of lead creation |
|
|
188
|
+
| updatedAt | date | | Timestamp of last update |
|
|
189
|
+
|
|
190
|
+
#### Prisma
|
|
191
|
+
|
|
192
|
+
```prisma
|
|
193
|
+
model Lead {
|
|
194
|
+
id String @id
|
|
195
|
+
createdAt DateTime @default(now())
|
|
196
|
+
updatedAt DateTime @updatedAt
|
|
197
|
+
email String
|
|
198
|
+
emailVerified Boolean @default(false)
|
|
199
|
+
metadata String?
|
|
200
|
+
|
|
201
|
+
@@unique([email])
|
|
202
|
+
@@map("lead")
|
|
203
|
+
}
|
|
204
|
+
```
|
package/dist/client.d.mts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import
|
|
1
|
+
import { t as lead } from "./index-B-BhgW_e.mjs";
|
|
2
|
+
import * as better_auth0 from "better-auth";
|
|
3
3
|
|
|
4
4
|
//#region src/client.d.ts
|
|
5
5
|
declare const leadClient: () => {
|
|
6
6
|
id: "lead";
|
|
7
7
|
$InferServerPlugin: ReturnType<typeof lead>;
|
|
8
|
+
$ERROR_CODES: {
|
|
9
|
+
INVALID_EMAIL: better_auth0.RawError<"INVALID_EMAIL">;
|
|
10
|
+
INVALID_TOKEN: better_auth0.RawError<"INVALID_TOKEN">;
|
|
11
|
+
TOKEN_EXPIRED: better_auth0.RawError<"TOKEN_EXPIRED">;
|
|
12
|
+
INVALID_METADATA: better_auth0.RawError<"INVALID_METADATA">;
|
|
13
|
+
};
|
|
8
14
|
};
|
|
9
15
|
//#endregion
|
|
10
16
|
export { leadClient };
|
package/dist/client.mjs
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { t as LEAD_ERROR_CODES } from "./error-codes-CZUPEOrE.mjs";
|
|
1
2
|
//#region src/client.ts
|
|
2
3
|
const leadClient = () => {
|
|
3
4
|
return {
|
|
4
5
|
id: "lead",
|
|
5
|
-
$InferServerPlugin: {}
|
|
6
|
+
$InferServerPlugin: {},
|
|
7
|
+
$ERROR_CODES: LEAD_ERROR_CODES
|
|
6
8
|
};
|
|
7
9
|
};
|
|
8
|
-
|
|
9
10
|
//#endregion
|
|
10
11
|
export { leadClient };
|
|
12
|
+
|
|
11
13
|
//# sourceMappingURL=client.mjs.map
|
package/dist/client.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import type { BetterAuthClientPlugin } from 'better-auth/client';\nimport type { lead } from './index';\n\nexport const leadClient = () => {\n return {\n id: 'lead',\n $InferServerPlugin: {} as ReturnType<typeof lead>,\n } satisfies BetterAuthClientPlugin;\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import type { BetterAuthClientPlugin } from 'better-auth/client';\n\nimport { LEAD_ERROR_CODES } from './error-codes';\nimport type { lead } from './index';\n\nexport const leadClient = () => {\n return {\n id: 'lead',\n $InferServerPlugin: {} as ReturnType<typeof lead>,\n $ERROR_CODES: LEAD_ERROR_CODES,\n } satisfies BetterAuthClientPlugin;\n};\n"],"mappings":";;AAKA,MAAa,mBAAmB;AAC9B,QAAO;EACL,IAAI;EACJ,oBAAoB,EAAE;EACtB,cAAc;EACf"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineErrorCodes } from "better-auth";
|
|
2
|
+
//#region src/error-codes.ts
|
|
3
|
+
const LEAD_ERROR_CODES = defineErrorCodes({
|
|
4
|
+
INVALID_EMAIL: "Invalid email",
|
|
5
|
+
INVALID_TOKEN: "Invalid token",
|
|
6
|
+
TOKEN_EXPIRED: "Token expired",
|
|
7
|
+
INVALID_METADATA: "Invalid metadata"
|
|
8
|
+
});
|
|
9
|
+
//#endregion
|
|
10
|
+
export { LEAD_ERROR_CODES as t };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=error-codes-CZUPEOrE.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-codes-CZUPEOrE.mjs","names":[],"sources":["../src/error-codes.ts"],"sourcesContent":["import { defineErrorCodes } from 'better-auth';\n\nexport const LEAD_ERROR_CODES = defineErrorCodes({\n INVALID_EMAIL: 'Invalid email',\n INVALID_TOKEN: 'Invalid token',\n TOKEN_EXPIRED: 'Token expired',\n INVALID_METADATA: 'Invalid metadata',\n});\n"],"mappings":";;AAEA,MAAa,mBAAmB,iBAAiB;CAC/C,eAAe;CACf,eAAe;CACf,eAAe;CACf,kBAAkB;CACnB,CAAC"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import * as better_auth0 from "better-auth";
|
|
2
|
+
import { InferOptionSchema, StandardSchemaV1 } from "better-auth";
|
|
3
|
+
import * as zod from "zod";
|
|
4
|
+
|
|
5
|
+
//#region src/schema.d.ts
|
|
6
|
+
declare const lead$1: {
|
|
7
|
+
lead: {
|
|
8
|
+
fields: {
|
|
9
|
+
createdAt: {
|
|
10
|
+
type: "date";
|
|
11
|
+
defaultValue: () => Date;
|
|
12
|
+
required: true;
|
|
13
|
+
input: false;
|
|
14
|
+
};
|
|
15
|
+
updatedAt: {
|
|
16
|
+
type: "date";
|
|
17
|
+
defaultValue: () => Date;
|
|
18
|
+
onUpdate: () => Date;
|
|
19
|
+
required: true;
|
|
20
|
+
input: false;
|
|
21
|
+
};
|
|
22
|
+
email: {
|
|
23
|
+
type: "string";
|
|
24
|
+
required: true;
|
|
25
|
+
unique: true;
|
|
26
|
+
};
|
|
27
|
+
emailVerified: {
|
|
28
|
+
type: "boolean";
|
|
29
|
+
defaultValue: false;
|
|
30
|
+
required: true;
|
|
31
|
+
input: false;
|
|
32
|
+
};
|
|
33
|
+
metadata: {
|
|
34
|
+
type: "string";
|
|
35
|
+
required: false;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/type.d.ts
|
|
42
|
+
interface LeadOptions {
|
|
43
|
+
/**
|
|
44
|
+
* Send a verification email
|
|
45
|
+
* @param data the data object
|
|
46
|
+
* @param request the request object
|
|
47
|
+
*/
|
|
48
|
+
sendVerificationEmail?: (
|
|
49
|
+
/**
|
|
50
|
+
* @param email the email to send the verification email to
|
|
51
|
+
* @param url the verification url
|
|
52
|
+
* @param token the verification token
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
data: {
|
|
56
|
+
email: string;
|
|
57
|
+
url: string;
|
|
58
|
+
token: string;
|
|
59
|
+
}, request?: Request) => Promise<void>;
|
|
60
|
+
onEmailVerified?: (
|
|
61
|
+
/**
|
|
62
|
+
* @param lead the lead that was verified
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
data: {
|
|
66
|
+
lead: Lead;
|
|
67
|
+
}, request?: Request) => Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Number of seconds the verification token is
|
|
70
|
+
* valid for.
|
|
71
|
+
* @default 3600 seconds (1 hour)
|
|
72
|
+
*/
|
|
73
|
+
expiresIn?: number;
|
|
74
|
+
/**
|
|
75
|
+
* Rate limit configuration for /lead/subscribe and /lead/resend endpoints.
|
|
76
|
+
*/
|
|
77
|
+
rateLimit?: {
|
|
78
|
+
/**
|
|
79
|
+
* Time window in seconds for which the rate limit applies.
|
|
80
|
+
* @default 10 seconds
|
|
81
|
+
*/
|
|
82
|
+
window: number;
|
|
83
|
+
/**
|
|
84
|
+
* Maximum number of requests allowed within the time window.
|
|
85
|
+
* @default 3 requests
|
|
86
|
+
*/
|
|
87
|
+
max: number;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Schema for the lead plugin
|
|
91
|
+
*/
|
|
92
|
+
schema?: InferOptionSchema<typeof lead$1> | undefined;
|
|
93
|
+
metadata?: {
|
|
94
|
+
validationSchema?: StandardSchemaV1;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
interface Lead {
|
|
98
|
+
/**
|
|
99
|
+
* Database identifier
|
|
100
|
+
*/
|
|
101
|
+
id: string;
|
|
102
|
+
createdAt: Date;
|
|
103
|
+
updatedAt: Date;
|
|
104
|
+
email: string;
|
|
105
|
+
emailVerified: boolean;
|
|
106
|
+
metadata?: string;
|
|
107
|
+
}
|
|
108
|
+
type LeadPayload = Omit<Lead, 'id' | 'createdAt' | 'updatedAt' | 'emailVerified'>;
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/index.d.ts
|
|
111
|
+
declare const lead: <O extends LeadOptions>(options?: O) => {
|
|
112
|
+
id: "lead";
|
|
113
|
+
schema: {
|
|
114
|
+
lead: {
|
|
115
|
+
fields: {
|
|
116
|
+
createdAt: {
|
|
117
|
+
type: "date";
|
|
118
|
+
defaultValue: () => Date;
|
|
119
|
+
required: true;
|
|
120
|
+
input: false;
|
|
121
|
+
};
|
|
122
|
+
updatedAt: {
|
|
123
|
+
type: "date";
|
|
124
|
+
defaultValue: () => Date;
|
|
125
|
+
onUpdate: () => Date;
|
|
126
|
+
required: true;
|
|
127
|
+
input: false;
|
|
128
|
+
};
|
|
129
|
+
email: {
|
|
130
|
+
type: "string";
|
|
131
|
+
required: true;
|
|
132
|
+
unique: true;
|
|
133
|
+
};
|
|
134
|
+
emailVerified: {
|
|
135
|
+
type: "boolean";
|
|
136
|
+
defaultValue: false;
|
|
137
|
+
required: true;
|
|
138
|
+
input: false;
|
|
139
|
+
};
|
|
140
|
+
metadata: {
|
|
141
|
+
type: "string";
|
|
142
|
+
required: false;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
endpoints: {
|
|
148
|
+
subscribe: better_auth0.StrictEndpoint<"/lead/subscribe", {
|
|
149
|
+
method: "POST";
|
|
150
|
+
body: zod.ZodObject<{
|
|
151
|
+
email: zod.ZodString;
|
|
152
|
+
metadata: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodAny>>;
|
|
153
|
+
}, better_auth0.$strip>;
|
|
154
|
+
}, {
|
|
155
|
+
status: boolean;
|
|
156
|
+
}>;
|
|
157
|
+
verify: better_auth0.StrictEndpoint<"/lead/verify", {
|
|
158
|
+
method: "GET";
|
|
159
|
+
query: zod.ZodObject<{
|
|
160
|
+
token: zod.ZodString;
|
|
161
|
+
}, better_auth0.$strip>;
|
|
162
|
+
}, {
|
|
163
|
+
status: boolean;
|
|
164
|
+
}>;
|
|
165
|
+
unsubscribe: better_auth0.StrictEndpoint<"/lead/unsubscribe", {
|
|
166
|
+
method: "POST";
|
|
167
|
+
body: zod.ZodObject<{
|
|
168
|
+
id: zod.ZodString;
|
|
169
|
+
}, better_auth0.$strip>;
|
|
170
|
+
}, {
|
|
171
|
+
status: boolean;
|
|
172
|
+
}>;
|
|
173
|
+
resend: better_auth0.StrictEndpoint<"/lead/resend", {
|
|
174
|
+
method: "POST";
|
|
175
|
+
body: zod.ZodObject<{
|
|
176
|
+
email: zod.ZodString;
|
|
177
|
+
}, better_auth0.$strip>;
|
|
178
|
+
}, {
|
|
179
|
+
status: boolean;
|
|
180
|
+
}>;
|
|
181
|
+
update: better_auth0.StrictEndpoint<"/lead/update", {
|
|
182
|
+
method: "POST";
|
|
183
|
+
body: zod.ZodObject<{
|
|
184
|
+
id: zod.ZodString;
|
|
185
|
+
metadata: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodAny>>;
|
|
186
|
+
}, better_auth0.$strip>;
|
|
187
|
+
}, {
|
|
188
|
+
status: boolean;
|
|
189
|
+
}>;
|
|
190
|
+
};
|
|
191
|
+
options: NoInfer<O>;
|
|
192
|
+
rateLimit: {
|
|
193
|
+
pathMatcher: (path: string) => boolean;
|
|
194
|
+
window: number;
|
|
195
|
+
max: number;
|
|
196
|
+
}[];
|
|
197
|
+
$ERROR_CODES: {
|
|
198
|
+
INVALID_EMAIL: better_auth0.RawError<"INVALID_EMAIL">;
|
|
199
|
+
INVALID_TOKEN: better_auth0.RawError<"INVALID_TOKEN">;
|
|
200
|
+
TOKEN_EXPIRED: better_auth0.RawError<"TOKEN_EXPIRED">;
|
|
201
|
+
INVALID_METADATA: better_auth0.RawError<"INVALID_METADATA">;
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
//#endregion
|
|
205
|
+
export { LeadPayload as i, Lead as n, LeadOptions as r, lead as t };
|
|
206
|
+
//# sourceMappingURL=index-B-BhgW_e.d.mts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,90 +1,2 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
|
|
3
|
-
import * as zod from "zod";
|
|
4
|
-
|
|
5
|
-
//#region src/index.d.ts
|
|
6
|
-
declare const lead: <O extends LeadOptions>(options: O) => {
|
|
7
|
-
id: "lead";
|
|
8
|
-
schema: {
|
|
9
|
-
lead: {
|
|
10
|
-
fields: {
|
|
11
|
-
createdAt: {
|
|
12
|
-
type: "date";
|
|
13
|
-
defaultValue: () => Date;
|
|
14
|
-
required: true;
|
|
15
|
-
input: false;
|
|
16
|
-
};
|
|
17
|
-
updatedAt: {
|
|
18
|
-
type: "date";
|
|
19
|
-
defaultValue: () => Date;
|
|
20
|
-
onUpdate: () => Date;
|
|
21
|
-
required: true;
|
|
22
|
-
input: false;
|
|
23
|
-
};
|
|
24
|
-
email: {
|
|
25
|
-
type: "string";
|
|
26
|
-
required: true;
|
|
27
|
-
unique: true;
|
|
28
|
-
};
|
|
29
|
-
emailVerified: {
|
|
30
|
-
type: "boolean";
|
|
31
|
-
defaultValue: false;
|
|
32
|
-
required: true;
|
|
33
|
-
input: false;
|
|
34
|
-
};
|
|
35
|
-
metadata: {
|
|
36
|
-
type: "string";
|
|
37
|
-
required: false;
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
endpoints: {
|
|
43
|
-
subscribe: better_auth0.StrictEndpoint<"/lead/subscribe", {
|
|
44
|
-
method: "POST";
|
|
45
|
-
body: zod.ZodObject<{
|
|
46
|
-
email: zod.ZodEmail;
|
|
47
|
-
metadata: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodAny>>;
|
|
48
|
-
}, better_auth0.$strip>;
|
|
49
|
-
metadata: {};
|
|
50
|
-
}, {
|
|
51
|
-
status: boolean;
|
|
52
|
-
}>;
|
|
53
|
-
verify: better_auth0.StrictEndpoint<"/lead/verify", {
|
|
54
|
-
method: "GET";
|
|
55
|
-
query: zod.ZodObject<{
|
|
56
|
-
token: zod.ZodString;
|
|
57
|
-
}, better_auth0.$strip>;
|
|
58
|
-
metadata: {};
|
|
59
|
-
}, {
|
|
60
|
-
status: boolean;
|
|
61
|
-
}>;
|
|
62
|
-
unsubscribe: better_auth0.StrictEndpoint<"/lead/unsubscribe", {
|
|
63
|
-
method: "POST";
|
|
64
|
-
body: zod.ZodObject<{
|
|
65
|
-
id: zod.ZodString;
|
|
66
|
-
}, better_auth0.$strip>;
|
|
67
|
-
metadata: {};
|
|
68
|
-
}, {
|
|
69
|
-
status: boolean;
|
|
70
|
-
}>;
|
|
71
|
-
resend: better_auth0.StrictEndpoint<"/lead/resend", {
|
|
72
|
-
method: "POST";
|
|
73
|
-
body: zod.ZodObject<{
|
|
74
|
-
email: zod.ZodEmail;
|
|
75
|
-
}, better_auth0.$strip>;
|
|
76
|
-
metadata: {};
|
|
77
|
-
}, {
|
|
78
|
-
status: boolean;
|
|
79
|
-
}>;
|
|
80
|
-
};
|
|
81
|
-
options: NoInfer<O>;
|
|
82
|
-
rateLimit: {
|
|
83
|
-
pathMatcher: (path: string) => boolean;
|
|
84
|
-
window: number;
|
|
85
|
-
max: number;
|
|
86
|
-
}[];
|
|
87
|
-
};
|
|
88
|
-
//#endregion
|
|
89
|
-
export { Lead, LeadOptions, LeadPayload, lead };
|
|
90
|
-
//# sourceMappingURL=index.d.mts.map
|
|
1
|
+
import { i as LeadPayload, n as Lead, r as LeadOptions, t as lead } from "./index-B-BhgW_e.mjs";
|
|
2
|
+
export { Lead, LeadOptions, LeadPayload, lead };
|
package/dist/index.mjs
CHANGED
|
@@ -1,57 +1,22 @@
|
|
|
1
|
-
import "
|
|
2
|
-
import {
|
|
1
|
+
import { t as LEAD_ERROR_CODES } from "./error-codes-CZUPEOrE.mjs";
|
|
2
|
+
import { BASE_ERROR_CODES } from "better-auth";
|
|
3
3
|
import { APIError, createAuthEndpoint, createEmailVerificationToken } from "better-auth/api";
|
|
4
|
-
import * as z from "zod";
|
|
5
4
|
import { jwtVerify } from "jose";
|
|
6
5
|
import { JWTExpired } from "jose/errors";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const lead$1 = { lead: { fields: {
|
|
10
|
-
createdAt: {
|
|
11
|
-
type: "date",
|
|
12
|
-
defaultValue: () => /* @__PURE__ */ new Date(),
|
|
13
|
-
required: true,
|
|
14
|
-
input: false
|
|
15
|
-
},
|
|
16
|
-
updatedAt: {
|
|
17
|
-
type: "date",
|
|
18
|
-
defaultValue: () => /* @__PURE__ */ new Date(),
|
|
19
|
-
onUpdate: () => /* @__PURE__ */ new Date(),
|
|
20
|
-
required: true,
|
|
21
|
-
input: false
|
|
22
|
-
},
|
|
23
|
-
email: {
|
|
24
|
-
type: "string",
|
|
25
|
-
required: true,
|
|
26
|
-
unique: true
|
|
27
|
-
},
|
|
28
|
-
emailVerified: {
|
|
29
|
-
type: "boolean",
|
|
30
|
-
defaultValue: false,
|
|
31
|
-
required: true,
|
|
32
|
-
input: false
|
|
33
|
-
},
|
|
34
|
-
metadata: {
|
|
35
|
-
type: "string",
|
|
36
|
-
required: false
|
|
37
|
-
}
|
|
38
|
-
} } };
|
|
39
|
-
const getSchema = (options) => {
|
|
40
|
-
return mergeSchema(lead$1, options.schema);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
//#endregion
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
import { mergeSchema } from "better-auth/db";
|
|
44
8
|
//#region src/routes.ts
|
|
45
9
|
const subscribeSchema = z.object({
|
|
46
|
-
email: z.
|
|
47
|
-
metadata: z.record(z.string(), z.any()).optional()
|
|
10
|
+
email: z.string().meta({ description: "Email address of the lead" }),
|
|
11
|
+
metadata: z.record(z.string(), z.any()).optional().meta({ description: "Additional metadata to store with the lead" })
|
|
48
12
|
});
|
|
49
13
|
const subscribe = (options) => createAuthEndpoint("/lead/subscribe", {
|
|
50
14
|
method: "POST",
|
|
51
|
-
body: subscribeSchema
|
|
52
|
-
metadata: {}
|
|
15
|
+
body: subscribeSchema
|
|
53
16
|
}, async (ctx) => {
|
|
54
|
-
const { email
|
|
17
|
+
const { email } = ctx.body;
|
|
18
|
+
if (!z.email().safeParse(email).success) throw APIError.from("BAD_REQUEST", LEAD_ERROR_CODES.INVALID_EMAIL);
|
|
19
|
+
const metadata = validateMetadata(options, ctx.body.metadata, ctx.context.logger);
|
|
55
20
|
const normalizedEmail = email.toLowerCase();
|
|
56
21
|
let lead = await ctx.context.adapter.findOne({
|
|
57
22
|
model: "lead",
|
|
@@ -78,14 +43,6 @@ const subscribe = (options) => createAuthEndpoint("/lead/subscribe", {
|
|
|
78
43
|
}]
|
|
79
44
|
});
|
|
80
45
|
}
|
|
81
|
-
else if (!lead.emailVerified) lead = await ctx.context.adapter.update({
|
|
82
|
-
model: "lead",
|
|
83
|
-
where: [{
|
|
84
|
-
field: "email",
|
|
85
|
-
value: normalizedEmail
|
|
86
|
-
}],
|
|
87
|
-
update: { metadata: metadata ? JSON.stringify(metadata) : lead.metadata }
|
|
88
|
-
});
|
|
89
46
|
if (options.sendVerificationEmail && lead && !lead.emailVerified) {
|
|
90
47
|
const token = await createEmailVerificationToken(ctx.context.secret, normalizedEmail, void 0, options.expiresIn ?? 3600);
|
|
91
48
|
const url = `${ctx.context.baseURL}/lead/verify?token=${token}`;
|
|
@@ -97,22 +54,21 @@ const subscribe = (options) => createAuthEndpoint("/lead/subscribe", {
|
|
|
97
54
|
}
|
|
98
55
|
return ctx.json({ status: true });
|
|
99
56
|
});
|
|
100
|
-
const verifySchema = z.object({ token: z.string() });
|
|
57
|
+
const verifySchema = z.object({ token: z.string().meta({ description: "The token to verify the email" }) });
|
|
101
58
|
const verify = (options) => createAuthEndpoint("/lead/verify", {
|
|
102
59
|
method: "GET",
|
|
103
|
-
query: verifySchema
|
|
104
|
-
metadata: {}
|
|
60
|
+
query: verifySchema
|
|
105
61
|
}, async (ctx) => {
|
|
106
62
|
const { token } = ctx.query;
|
|
107
63
|
let jwt;
|
|
108
64
|
try {
|
|
109
65
|
jwt = await jwtVerify(token, new TextEncoder().encode(ctx.context.secret), { algorithms: ["HS256"] });
|
|
110
66
|
} catch (e) {
|
|
111
|
-
if (e instanceof JWTExpired) throw
|
|
112
|
-
throw
|
|
67
|
+
if (e instanceof JWTExpired) throw APIError.from("UNAUTHORIZED", LEAD_ERROR_CODES.TOKEN_EXPIRED);
|
|
68
|
+
throw APIError.from("UNAUTHORIZED", LEAD_ERROR_CODES.INVALID_TOKEN);
|
|
113
69
|
}
|
|
114
70
|
const parsed = subscribeSchema.parse(jwt.payload);
|
|
115
|
-
|
|
71
|
+
let lead = await ctx.context.adapter.findOne({
|
|
116
72
|
model: "lead",
|
|
117
73
|
where: [{
|
|
118
74
|
field: "email",
|
|
@@ -121,7 +77,7 @@ const verify = (options) => createAuthEndpoint("/lead/verify", {
|
|
|
121
77
|
});
|
|
122
78
|
if (!lead) return ctx.json({ status: true });
|
|
123
79
|
if (lead.emailVerified) return ctx.json({ status: true });
|
|
124
|
-
await ctx.context.adapter.update({
|
|
80
|
+
lead = await ctx.context.adapter.update({
|
|
125
81
|
model: "lead",
|
|
126
82
|
where: [{
|
|
127
83
|
field: "email",
|
|
@@ -129,13 +85,14 @@ const verify = (options) => createAuthEndpoint("/lead/verify", {
|
|
|
129
85
|
}],
|
|
130
86
|
update: { emailVerified: true }
|
|
131
87
|
});
|
|
88
|
+
if (!lead) return ctx.json({ status: true });
|
|
89
|
+
if (options.onEmailVerified) await ctx.context.runInBackgroundOrAwait(options.onEmailVerified({ lead }, ctx.request));
|
|
132
90
|
return ctx.json({ status: true });
|
|
133
91
|
});
|
|
134
|
-
const unsubscribeSchema = z.object({ id: z.string() });
|
|
92
|
+
const unsubscribeSchema = z.object({ id: z.string().meta({ description: "The id of the lead to unsubscribe" }) });
|
|
135
93
|
const unsubscribe = (options) => createAuthEndpoint("/lead/unsubscribe", {
|
|
136
94
|
method: "POST",
|
|
137
|
-
body: unsubscribeSchema
|
|
138
|
-
metadata: {}
|
|
95
|
+
body: unsubscribeSchema
|
|
139
96
|
}, async (ctx) => {
|
|
140
97
|
const { id } = ctx.body;
|
|
141
98
|
if (!await ctx.context.adapter.findOne({
|
|
@@ -154,13 +111,13 @@ const unsubscribe = (options) => createAuthEndpoint("/lead/unsubscribe", {
|
|
|
154
111
|
});
|
|
155
112
|
return ctx.json({ status: true });
|
|
156
113
|
});
|
|
157
|
-
const resendSchema = z.object({ email: z.
|
|
114
|
+
const resendSchema = z.object({ email: z.string().meta({ description: "Email address to resend the verification email to" }) });
|
|
158
115
|
const resend = (options) => createAuthEndpoint("/lead/resend", {
|
|
159
116
|
method: "POST",
|
|
160
|
-
body: resendSchema
|
|
161
|
-
metadata: {}
|
|
117
|
+
body: resendSchema
|
|
162
118
|
}, async (ctx) => {
|
|
163
119
|
const { email } = ctx.body;
|
|
120
|
+
if (!z.email().safeParse(email).success) throw APIError.from("BAD_REQUEST", LEAD_ERROR_CODES.INVALID_EMAIL);
|
|
164
121
|
const normalizedEmail = email.toLowerCase();
|
|
165
122
|
const lead = await ctx.context.adapter.findOne({
|
|
166
123
|
model: "lead",
|
|
@@ -181,10 +138,81 @@ const resend = (options) => createAuthEndpoint("/lead/resend", {
|
|
|
181
138
|
}
|
|
182
139
|
return ctx.json({ status: true });
|
|
183
140
|
});
|
|
184
|
-
|
|
141
|
+
const updateSchema = z.object({
|
|
142
|
+
id: z.string().meta({ description: "The id of the lead to update" }),
|
|
143
|
+
metadata: z.record(z.string(), z.any()).optional().meta({ description: "Additional metadata to store with the lead" })
|
|
144
|
+
});
|
|
145
|
+
const update = (options) => createAuthEndpoint("/lead/update", {
|
|
146
|
+
method: "POST",
|
|
147
|
+
body: updateSchema
|
|
148
|
+
}, async (ctx) => {
|
|
149
|
+
const { id } = ctx.body;
|
|
150
|
+
if (!await ctx.context.adapter.findOne({
|
|
151
|
+
model: "lead",
|
|
152
|
+
where: [{
|
|
153
|
+
field: "id",
|
|
154
|
+
value: id
|
|
155
|
+
}]
|
|
156
|
+
})) return ctx.json({ status: true });
|
|
157
|
+
const metadata = validateMetadata(options, ctx.body.metadata, ctx.context.logger);
|
|
158
|
+
await ctx.context.adapter.update({
|
|
159
|
+
model: "lead",
|
|
160
|
+
where: [{
|
|
161
|
+
field: "id",
|
|
162
|
+
value: id
|
|
163
|
+
}],
|
|
164
|
+
update: { metadata: metadata ? JSON.stringify(metadata) : void 0 }
|
|
165
|
+
});
|
|
166
|
+
return ctx.json({ status: true });
|
|
167
|
+
});
|
|
168
|
+
function validateMetadata(options, metadata, logger) {
|
|
169
|
+
if (!metadata || !options.metadata?.validationSchema) return metadata;
|
|
170
|
+
const validationResult = options.metadata.validationSchema["~standard"].validate(metadata);
|
|
171
|
+
if (validationResult instanceof Promise) throw APIError.from("INTERNAL_SERVER_ERROR", BASE_ERROR_CODES.ASYNC_VALIDATION_NOT_SUPPORTED);
|
|
172
|
+
if (validationResult.issues) {
|
|
173
|
+
logger.error("Invalid metadata", validationResult.issues);
|
|
174
|
+
throw APIError.from("BAD_REQUEST", LEAD_ERROR_CODES.INVALID_METADATA);
|
|
175
|
+
}
|
|
176
|
+
return validationResult.value;
|
|
177
|
+
}
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/schema.ts
|
|
180
|
+
const lead$1 = { lead: { fields: {
|
|
181
|
+
createdAt: {
|
|
182
|
+
type: "date",
|
|
183
|
+
defaultValue: () => /* @__PURE__ */ new Date(),
|
|
184
|
+
required: true,
|
|
185
|
+
input: false
|
|
186
|
+
},
|
|
187
|
+
updatedAt: {
|
|
188
|
+
type: "date",
|
|
189
|
+
defaultValue: () => /* @__PURE__ */ new Date(),
|
|
190
|
+
onUpdate: () => /* @__PURE__ */ new Date(),
|
|
191
|
+
required: true,
|
|
192
|
+
input: false
|
|
193
|
+
},
|
|
194
|
+
email: {
|
|
195
|
+
type: "string",
|
|
196
|
+
required: true,
|
|
197
|
+
unique: true
|
|
198
|
+
},
|
|
199
|
+
emailVerified: {
|
|
200
|
+
type: "boolean",
|
|
201
|
+
defaultValue: false,
|
|
202
|
+
required: true,
|
|
203
|
+
input: false
|
|
204
|
+
},
|
|
205
|
+
metadata: {
|
|
206
|
+
type: "string",
|
|
207
|
+
required: false
|
|
208
|
+
}
|
|
209
|
+
} } };
|
|
210
|
+
const getSchema = (options) => {
|
|
211
|
+
return mergeSchema(lead$1, options.schema);
|
|
212
|
+
};
|
|
185
213
|
//#endregion
|
|
186
214
|
//#region src/index.ts
|
|
187
|
-
const lead = (options) => {
|
|
215
|
+
const lead = (options = {}) => {
|
|
188
216
|
return {
|
|
189
217
|
id: "lead",
|
|
190
218
|
schema: getSchema(options),
|
|
@@ -192,17 +220,19 @@ const lead = (options) => {
|
|
|
192
220
|
subscribe: subscribe(options),
|
|
193
221
|
verify: verify(options),
|
|
194
222
|
unsubscribe: unsubscribe(options),
|
|
195
|
-
resend: resend(options)
|
|
223
|
+
resend: resend(options),
|
|
224
|
+
update: update(options)
|
|
196
225
|
},
|
|
197
226
|
options,
|
|
198
227
|
rateLimit: [{
|
|
199
228
|
pathMatcher: (path) => ["/lead/subscribe", "/lead/resend"].includes(path),
|
|
200
229
|
window: options.rateLimit?.window ?? 10,
|
|
201
230
|
max: options.rateLimit?.max ?? 3
|
|
202
|
-
}]
|
|
231
|
+
}],
|
|
232
|
+
$ERROR_CODES: LEAD_ERROR_CODES
|
|
203
233
|
};
|
|
204
234
|
};
|
|
205
|
-
|
|
206
235
|
//#endregion
|
|
207
236
|
export { lead };
|
|
237
|
+
|
|
208
238
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["lead"],"sources":["../src/schema.ts","../src/routes.ts","../src/index.ts"],"sourcesContent":["import { type BetterAuthPluginDBSchema } from 'better-auth';\nimport type { LeadOptions } from './type';\nimport { mergeSchema } from 'better-auth/db';\n\nexport const lead = {\n lead: {\n fields: {\n createdAt: {\n type: 'date',\n defaultValue: () => new Date(),\n required: true,\n input: false,\n },\n updatedAt: {\n type: 'date',\n defaultValue: () => new Date(),\n onUpdate: () => new Date(),\n required: true,\n input: false,\n },\n email: {\n type: 'string',\n required: true,\n unique: true,\n },\n emailVerified: {\n type: 'boolean',\n defaultValue: false,\n required: true,\n input: false,\n },\n metadata: {\n type: 'string',\n required: false,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const getSchema = <O extends LeadOptions>(options: O) => {\n return mergeSchema(lead, options.schema);\n};\n","import { APIError, createAuthEndpoint, createEmailVerificationToken } from 'better-auth/api';\nimport * as z from 'zod';\nimport type { Lead, LeadOptions, LeadPayload } from './type';\nimport { jwtVerify } from 'jose';\nimport type { JWTPayload, JWTVerifyResult } from 'jose';\nimport { JWTExpired } from 'jose/errors';\n\nconst subscribeSchema = z.object({\n email: z.email(),\n metadata: z.record(z.string(), z.any()).optional(),\n});\n\nexport const subscribe = <O extends LeadOptions>(options: O) =>\n createAuthEndpoint(\n '/lead/subscribe',\n {\n method: 'POST',\n body: subscribeSchema,\n metadata: {\n // TODO add openapi\n },\n },\n async (ctx) => {\n const { email, metadata } = ctx.body;\n\n const normalizedEmail = email.toLowerCase();\n\n let lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: normalizedEmail,\n },\n ],\n });\n\n if (!lead) {\n try {\n lead = await ctx.context.adapter.create<LeadPayload, Lead>({\n model: 'lead',\n data: {\n email: normalizedEmail,\n metadata: metadata ? JSON.stringify(metadata) : undefined,\n },\n });\n } catch (e) {\n ctx.context.logger.info('Error creating lead');\n lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: normalizedEmail,\n },\n ],\n });\n }\n } else if (!lead.emailVerified) {\n lead = await ctx.context.adapter.update<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: normalizedEmail,\n },\n ],\n update: {\n metadata: metadata ? JSON.stringify(metadata) : lead.metadata,\n },\n });\n }\n\n if (options.sendVerificationEmail && lead && !lead.emailVerified) {\n const token = await createEmailVerificationToken(\n ctx.context.secret,\n normalizedEmail,\n undefined,\n options.expiresIn ?? 3600,\n );\n const url = `${ctx.context.baseURL}/lead/verify?token=${token}`;\n\n await ctx.context.runInBackgroundOrAwait(\n options.sendVerificationEmail({ email: normalizedEmail, url, token }, ctx.request),\n );\n }\n\n return ctx.json({\n status: true,\n });\n },\n );\n\nconst verifySchema = z.object({\n token: z.string(),\n});\n\nexport const verify = <O extends LeadOptions>(options: O) =>\n createAuthEndpoint(\n '/lead/verify',\n {\n method: 'GET',\n query: verifySchema,\n metadata: {\n // TODO add openapi\n },\n },\n async (ctx) => {\n const { token } = ctx.query;\n\n let jwt: JWTVerifyResult<JWTPayload>;\n try {\n jwt = await jwtVerify(token, new TextEncoder().encode(ctx.context.secret), {\n algorithms: ['HS256'],\n });\n } catch (e) {\n if (e instanceof JWTExpired) {\n throw new APIError('UNAUTHORIZED', {\n message: 'Token expired',\n });\n }\n throw new APIError('UNAUTHORIZED', {\n message: 'Invalid token',\n });\n }\n\n const parsed = subscribeSchema.parse(jwt.payload);\n\n const lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: parsed.email,\n },\n ],\n });\n\n if (!lead) {\n return ctx.json({\n status: true,\n });\n }\n\n if (lead.emailVerified) {\n return ctx.json({\n status: true,\n });\n }\n\n await ctx.context.adapter.update<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: parsed.email,\n },\n ],\n update: {\n emailVerified: true,\n },\n });\n\n return ctx.json({\n status: true,\n });\n },\n );\n\nconst unsubscribeSchema = z.object({\n id: z.string(),\n});\n\nexport const unsubscribe = <O extends LeadOptions>(options: O) =>\n createAuthEndpoint(\n '/lead/unsubscribe',\n {\n method: 'POST',\n body: unsubscribeSchema,\n metadata: {\n // TODO add openapi\n },\n },\n async (ctx) => {\n const { id } = ctx.body;\n\n const lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'id',\n value: id,\n },\n ],\n });\n\n if (!lead) {\n return ctx.json({\n status: true,\n });\n }\n\n await ctx.context.adapter.delete({\n model: 'lead',\n where: [\n {\n field: 'id',\n value: id,\n },\n ],\n });\n\n return ctx.json({\n status: true,\n });\n },\n );\n\nconst resendSchema = z.object({\n email: z.email(),\n});\n\nexport const resend = <O extends LeadOptions>(options: O) =>\n createAuthEndpoint(\n '/lead/resend',\n {\n method: 'POST',\n body: resendSchema,\n metadata: {\n // TODO add openapi\n },\n },\n async (ctx) => {\n const { email } = ctx.body;\n\n const normalizedEmail = email.toLowerCase();\n\n const lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: normalizedEmail,\n },\n ],\n });\n\n if (!lead) {\n return ctx.json({\n status: true,\n });\n }\n\n if (options.sendVerificationEmail && lead && !lead.emailVerified) {\n const token = await createEmailVerificationToken(\n ctx.context.secret,\n normalizedEmail,\n undefined,\n options.expiresIn ?? 3600,\n );\n const url = `${ctx.context.baseURL}/lead/verify?token=${token}`;\n\n await ctx.context.runInBackgroundOrAwait(\n options.sendVerificationEmail({ email: normalizedEmail, url, token }, ctx.request),\n );\n }\n\n return ctx.json({\n status: true,\n });\n },\n );\n","import type { BetterAuthPlugin } from 'better-auth';\nimport type { LeadOptions } from './type';\nimport { getSchema } from './schema';\nimport { resend, subscribe, unsubscribe, verify } from './routes';\n\nexport const lead = <O extends LeadOptions>(options: O) => {\n return {\n id: 'lead',\n schema: getSchema(options),\n endpoints: {\n subscribe: subscribe(options),\n verify: verify(options),\n unsubscribe: unsubscribe(options),\n resend: resend(options),\n },\n options: options as NoInfer<O>,\n rateLimit: [\n {\n pathMatcher: (path) => ['/lead/subscribe', '/lead/resend'].includes(path),\n window: options.rateLimit?.window ?? 10,\n max: options.rateLimit?.max ?? 3,\n },\n ],\n } satisfies BetterAuthPlugin;\n};\n\nexport type * from './type';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["lead"],"sources":["../src/routes.ts","../src/schema.ts","../src/index.ts"],"sourcesContent":["import { BASE_ERROR_CODES, type InternalLogger } from 'better-auth';\nimport { APIError, createAuthEndpoint, createEmailVerificationToken } from 'better-auth/api';\nimport { jwtVerify } from 'jose';\nimport type { JWTPayload, JWTVerifyResult } from 'jose';\nimport { JWTExpired } from 'jose/errors';\nimport * as z from 'zod';\n\nimport { LEAD_ERROR_CODES } from './error-codes';\nimport type { Lead, LeadOptions, LeadPayload } from './type';\n\nconst subscribeSchema = z.object({\n email: z.string().meta({\n description: 'Email address of the lead',\n }),\n metadata: z.record(z.string(), z.any()).optional().meta({\n description: 'Additional metadata to store with the lead',\n }),\n});\n\nexport const subscribe = <O extends LeadOptions>(options: O) =>\n createAuthEndpoint(\n '/lead/subscribe',\n {\n method: 'POST',\n body: subscribeSchema,\n },\n async (ctx) => {\n const { email } = ctx.body;\n\n const isValidEmail = z.email().safeParse(email);\n if (!isValidEmail.success) {\n throw APIError.from('BAD_REQUEST', LEAD_ERROR_CODES.INVALID_EMAIL);\n }\n\n const metadata = validateMetadata(options, ctx.body.metadata, ctx.context.logger);\n\n const normalizedEmail = email.toLowerCase();\n\n let lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: normalizedEmail,\n },\n ],\n });\n\n if (!lead) {\n try {\n lead = await ctx.context.adapter.create<LeadPayload, Lead>({\n model: 'lead',\n data: {\n email: normalizedEmail,\n metadata: metadata ? JSON.stringify(metadata) : undefined,\n },\n });\n } catch (e) {\n ctx.context.logger.info('Error creating lead');\n lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: normalizedEmail,\n },\n ],\n });\n }\n }\n\n if (options.sendVerificationEmail && lead && !lead.emailVerified) {\n const token = await createEmailVerificationToken(\n ctx.context.secret,\n normalizedEmail,\n undefined,\n options.expiresIn ?? 3600,\n );\n const url = `${ctx.context.baseURL}/lead/verify?token=${token}`;\n\n await ctx.context.runInBackgroundOrAwait(\n options.sendVerificationEmail({ email: normalizedEmail, url, token }, ctx.request),\n );\n }\n\n return ctx.json({\n status: true,\n });\n },\n );\n\nconst verifySchema = z.object({\n token: z.string().meta({\n description: 'The token to verify the email',\n }),\n});\n\nexport const verify = <O extends LeadOptions>(options: O) =>\n createAuthEndpoint(\n '/lead/verify',\n {\n method: 'GET',\n query: verifySchema,\n },\n async (ctx) => {\n const { token } = ctx.query;\n\n let jwt: JWTVerifyResult<JWTPayload>;\n try {\n jwt = await jwtVerify(token, new TextEncoder().encode(ctx.context.secret), {\n algorithms: ['HS256'],\n });\n } catch (e) {\n if (e instanceof JWTExpired) {\n throw APIError.from('UNAUTHORIZED', LEAD_ERROR_CODES.TOKEN_EXPIRED);\n }\n throw APIError.from('UNAUTHORIZED', LEAD_ERROR_CODES.INVALID_TOKEN);\n }\n\n const parsed = subscribeSchema.parse(jwt.payload);\n\n let lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: parsed.email,\n },\n ],\n });\n\n if (!lead) {\n return ctx.json({\n status: true,\n });\n }\n\n if (lead.emailVerified) {\n return ctx.json({\n status: true,\n });\n }\n\n lead = await ctx.context.adapter.update<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: parsed.email,\n },\n ],\n update: {\n emailVerified: true,\n },\n });\n\n if (!lead) {\n return ctx.json({\n status: true,\n });\n }\n\n if (options.onEmailVerified) {\n await ctx.context.runInBackgroundOrAwait(options.onEmailVerified({ lead }, ctx.request));\n }\n\n return ctx.json({\n status: true,\n });\n },\n );\n\nconst unsubscribeSchema = z.object({\n id: z.string().meta({\n description: 'The id of the lead to unsubscribe',\n }),\n});\n\nexport const unsubscribe = <O extends LeadOptions>(options: O) =>\n createAuthEndpoint(\n '/lead/unsubscribe',\n {\n method: 'POST',\n body: unsubscribeSchema,\n },\n async (ctx) => {\n const { id } = ctx.body;\n\n const lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'id',\n value: id,\n },\n ],\n });\n\n if (!lead) {\n return ctx.json({\n status: true,\n });\n }\n\n await ctx.context.adapter.delete({\n model: 'lead',\n where: [\n {\n field: 'id',\n value: id,\n },\n ],\n });\n\n return ctx.json({\n status: true,\n });\n },\n );\n\nconst resendSchema = z.object({\n email: z.string().meta({\n description: 'Email address to resend the verification email to',\n }),\n});\n\nexport const resend = <O extends LeadOptions>(options: O) =>\n createAuthEndpoint(\n '/lead/resend',\n {\n method: 'POST',\n body: resendSchema,\n },\n async (ctx) => {\n const { email } = ctx.body;\n\n const isValidEmail = z.email().safeParse(email);\n if (!isValidEmail.success) {\n throw APIError.from('BAD_REQUEST', LEAD_ERROR_CODES.INVALID_EMAIL);\n }\n\n const normalizedEmail = email.toLowerCase();\n\n const lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'email',\n value: normalizedEmail,\n },\n ],\n });\n\n if (!lead) {\n return ctx.json({\n status: true,\n });\n }\n\n if (options.sendVerificationEmail && lead && !lead.emailVerified) {\n const token = await createEmailVerificationToken(\n ctx.context.secret,\n normalizedEmail,\n undefined,\n options.expiresIn ?? 3600,\n );\n const url = `${ctx.context.baseURL}/lead/verify?token=${token}`;\n\n await ctx.context.runInBackgroundOrAwait(\n options.sendVerificationEmail({ email: normalizedEmail, url, token }, ctx.request),\n );\n }\n\n return ctx.json({\n status: true,\n });\n },\n );\n\nconst updateSchema = z.object({\n id: z.string().meta({\n description: 'The id of the lead to update',\n }),\n metadata: z.record(z.string(), z.any()).optional().meta({\n description: 'Additional metadata to store with the lead',\n }),\n});\n\nexport const update = <O extends LeadOptions>(options: O) =>\n createAuthEndpoint(\n '/lead/update',\n {\n method: 'POST',\n body: updateSchema,\n },\n async (ctx) => {\n const { id } = ctx.body;\n\n const lead = await ctx.context.adapter.findOne<Lead>({\n model: 'lead',\n where: [\n {\n field: 'id',\n value: id,\n },\n ],\n });\n\n if (!lead) {\n return ctx.json({\n status: true,\n });\n }\n\n const metadata = validateMetadata(options, ctx.body.metadata, ctx.context.logger);\n\n await ctx.context.adapter.update<Lead>({\n model: 'lead',\n where: [\n {\n field: 'id',\n value: id,\n },\n ],\n update: {\n metadata: metadata ? JSON.stringify(metadata) : undefined,\n },\n });\n\n return ctx.json({\n status: true,\n });\n },\n );\n\nfunction validateMetadata(\n options: LeadOptions,\n metadata: Record<string, any> | undefined,\n logger: InternalLogger,\n) {\n if (!metadata || !options.metadata?.validationSchema) {\n return metadata;\n }\n const validationResult = options.metadata.validationSchema['~standard'].validate(metadata);\n\n if (validationResult instanceof Promise) {\n throw APIError.from('INTERNAL_SERVER_ERROR', BASE_ERROR_CODES.ASYNC_VALIDATION_NOT_SUPPORTED);\n }\n\n if (validationResult.issues) {\n logger.error('Invalid metadata', validationResult.issues);\n throw APIError.from('BAD_REQUEST', LEAD_ERROR_CODES.INVALID_METADATA);\n }\n\n return validationResult.value as Record<string, any>;\n}\n","import { type BetterAuthPluginDBSchema } from 'better-auth';\nimport { mergeSchema } from 'better-auth/db';\n\nimport type { LeadOptions } from './type';\n\nexport const lead = {\n lead: {\n fields: {\n createdAt: {\n type: 'date',\n defaultValue: () => new Date(),\n required: true,\n input: false,\n },\n updatedAt: {\n type: 'date',\n defaultValue: () => new Date(),\n onUpdate: () => new Date(),\n required: true,\n input: false,\n },\n email: {\n type: 'string',\n required: true,\n unique: true,\n },\n emailVerified: {\n type: 'boolean',\n defaultValue: false,\n required: true,\n input: false,\n },\n metadata: {\n type: 'string',\n required: false,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const getSchema = <O extends LeadOptions>(options: O) => {\n return mergeSchema(lead, options.schema);\n};\n","import type { BetterAuthPlugin } from 'better-auth';\n\nimport { LEAD_ERROR_CODES } from './error-codes';\nimport { resend, subscribe, unsubscribe, update, verify } from './routes';\nimport { getSchema } from './schema';\nimport type { LeadOptions } from './type';\n\nexport const lead = <O extends LeadOptions>(options: O = {} as O) => {\n return {\n id: 'lead',\n schema: getSchema(options),\n endpoints: {\n subscribe: subscribe(options),\n verify: verify(options),\n unsubscribe: unsubscribe(options),\n resend: resend(options),\n update: update(options),\n },\n options: options as NoInfer<O>,\n rateLimit: [\n {\n pathMatcher: (path) => ['/lead/subscribe', '/lead/resend'].includes(path),\n window: options.rateLimit?.window ?? 10,\n max: options.rateLimit?.max ?? 3,\n },\n ],\n $ERROR_CODES: LEAD_ERROR_CODES,\n } satisfies BetterAuthPlugin;\n};\n\nexport type * from './type';\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-auth-lead",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Better Auth Lead plugin",
|
|
5
5
|
"homepage": "https://github.com/marcjulian/better-auth-plugins#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -25,18 +25,18 @@
|
|
|
25
25
|
"./package.json": "./package.json"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"jose": "^6.1
|
|
28
|
+
"jose": "^6.2.1",
|
|
29
29
|
"zod": "^4.3.6"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@types/node": "^25.3.
|
|
32
|
+
"@types/node": "^25.3.5",
|
|
33
33
|
"bumpp": "^10.4.1",
|
|
34
|
-
"tsdown": "^0.
|
|
34
|
+
"tsdown": "^0.21.1",
|
|
35
35
|
"typescript": "^5.9.3",
|
|
36
36
|
"vitest": "^4.0.18"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"better-auth": "^1.5.
|
|
39
|
+
"better-auth": "^1.5.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsdown",
|
package/dist/type-CedeOvZ6.d.mts
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { InferOptionSchema } from "better-auth";
|
|
2
|
-
|
|
3
|
-
//#region src/schema.d.ts
|
|
4
|
-
declare const lead: {
|
|
5
|
-
lead: {
|
|
6
|
-
fields: {
|
|
7
|
-
createdAt: {
|
|
8
|
-
type: "date";
|
|
9
|
-
defaultValue: () => Date;
|
|
10
|
-
required: true;
|
|
11
|
-
input: false;
|
|
12
|
-
};
|
|
13
|
-
updatedAt: {
|
|
14
|
-
type: "date";
|
|
15
|
-
defaultValue: () => Date;
|
|
16
|
-
onUpdate: () => Date;
|
|
17
|
-
required: true;
|
|
18
|
-
input: false;
|
|
19
|
-
};
|
|
20
|
-
email: {
|
|
21
|
-
type: "string";
|
|
22
|
-
required: true;
|
|
23
|
-
unique: true;
|
|
24
|
-
};
|
|
25
|
-
emailVerified: {
|
|
26
|
-
type: "boolean";
|
|
27
|
-
defaultValue: false;
|
|
28
|
-
required: true;
|
|
29
|
-
input: false;
|
|
30
|
-
};
|
|
31
|
-
metadata: {
|
|
32
|
-
type: "string";
|
|
33
|
-
required: false;
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
//#endregion
|
|
39
|
-
//#region src/type.d.ts
|
|
40
|
-
interface LeadOptions {
|
|
41
|
-
/**
|
|
42
|
-
* Send a verification email
|
|
43
|
-
* @param data the data object
|
|
44
|
-
* @param request the request object
|
|
45
|
-
*/
|
|
46
|
-
sendVerificationEmail?: (
|
|
47
|
-
/**
|
|
48
|
-
* @param email the email to send the verification email to
|
|
49
|
-
* @param url the verification url
|
|
50
|
-
* @param token the verification token
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
|
-
data: {
|
|
54
|
-
email: string;
|
|
55
|
-
url: string;
|
|
56
|
-
token: string;
|
|
57
|
-
}, request?: Request) => Promise<void>;
|
|
58
|
-
/**
|
|
59
|
-
* Number of seconds the verification token is
|
|
60
|
-
* valid for.
|
|
61
|
-
* @default 3600 seconds (1 hour)
|
|
62
|
-
*/
|
|
63
|
-
expiresIn?: number;
|
|
64
|
-
/**
|
|
65
|
-
* Rate limit configuration for /lead/subscribe and /lead/resend endpoints.
|
|
66
|
-
*/
|
|
67
|
-
rateLimit?: {
|
|
68
|
-
/**
|
|
69
|
-
* Time window in seconds for which the rate limit applies.
|
|
70
|
-
* @default 10 seconds
|
|
71
|
-
*/
|
|
72
|
-
window: number;
|
|
73
|
-
/**
|
|
74
|
-
* Maximum number of requests allowed within the time window.
|
|
75
|
-
* @default 3 requests
|
|
76
|
-
*/
|
|
77
|
-
max: number;
|
|
78
|
-
};
|
|
79
|
-
/**
|
|
80
|
-
* Schema for the lead plugin
|
|
81
|
-
*/
|
|
82
|
-
schema?: InferOptionSchema<typeof lead> | undefined;
|
|
83
|
-
}
|
|
84
|
-
interface Lead {
|
|
85
|
-
/**
|
|
86
|
-
* Database identifier
|
|
87
|
-
*/
|
|
88
|
-
id: string;
|
|
89
|
-
createdAt: Date;
|
|
90
|
-
updatedAt: Date;
|
|
91
|
-
email: string;
|
|
92
|
-
emailVerified: boolean;
|
|
93
|
-
metadata?: string;
|
|
94
|
-
}
|
|
95
|
-
type LeadPayload = Omit<Lead, 'id' | 'createdAt' | 'updatedAt' | 'emailVerified'>;
|
|
96
|
-
//#endregion
|
|
97
|
-
export { LeadOptions as n, LeadPayload as r, Lead as t };
|
|
98
|
-
//# sourceMappingURL=type-CedeOvZ6.d.mts.map
|