better-auth-lead 0.0.1-dev.2 → 0.2.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 +52 -0
- package/dist/client.d.mts +2 -2
- package/dist/client.mjs +2 -3
- package/dist/client.mjs.map +1 -1
- package/dist/{error-codes-d1rquQlA.mjs → error-codes-CZUPEOrE.mjs} +4 -4
- package/dist/{error-codes-d1rquQlA.mjs.map → error-codes-CZUPEOrE.mjs.map} +1 -1
- package/dist/index-CGt_sc05.d.mts +210 -0
- package/dist/index.d.mts +2 -100
- package/dist/index.mjs +29 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/dist/type-KTJzD7Eo.d.mts +0 -98
package/README.md
CHANGED
|
@@ -11,6 +11,8 @@ 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
|
|
@@ -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:
|
|
@@ -99,6 +108,16 @@ const { data, error } = await authClient.lead.update({
|
|
|
99
108
|
|
|
100
109
|
### Email Verification
|
|
101
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
|
+
- `createdAt`: The timestamp when the lead was created.
|
|
117
|
+
- `isNewLead`: whether the lead was newly created or already existed - useful to bounce verification emails together with `createdAt`
|
|
118
|
+
|
|
119
|
+
and a `request` object as the second parameter.
|
|
120
|
+
|
|
102
121
|
```ts
|
|
103
122
|
// server/auth.ts
|
|
104
123
|
import { betterAuth } from 'better-auth';
|
|
@@ -115,6 +134,10 @@ export const auth = betterAuth({
|
|
|
115
134
|
text: `Click the link to verify your email: ${url}`,
|
|
116
135
|
});
|
|
117
136
|
},
|
|
137
|
+
onEmailVerified: async ({ lead }) => {
|
|
138
|
+
// do something when a lead's email is verified
|
|
139
|
+
console.log(`Lead ${lead.email} has been verified!`);
|
|
140
|
+
},
|
|
118
141
|
}),
|
|
119
142
|
],
|
|
120
143
|
});
|
|
@@ -122,6 +145,35 @@ export const auth = betterAuth({
|
|
|
122
145
|
|
|
123
146
|
> Avoid awaiting the email sending to prevent timing attacks.
|
|
124
147
|
|
|
148
|
+
Additionally, you can provide an `onEmailVerified` callback to execute logic after a lead's email is verified.
|
|
149
|
+
|
|
150
|
+
### Metadata Validation
|
|
151
|
+
|
|
152
|
+
To validate and parse metadata, you can pass a Standard Schema compatible schema (e.g. Zod, Valibot, ArkType).
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
// server/auth.ts
|
|
156
|
+
import { betterAuth } from 'better-auth';
|
|
157
|
+
import { lead } from 'better-auth-lead';
|
|
158
|
+
import * as z from 'zod';
|
|
159
|
+
|
|
160
|
+
const metadataSchema = z.object({
|
|
161
|
+
preferences: z.enum(['engineering', 'marketing', 'design']),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
export const auth = betterAuth({
|
|
165
|
+
plugins: [
|
|
166
|
+
lead({
|
|
167
|
+
metadata: {
|
|
168
|
+
validationSchema: metadataSchema,
|
|
169
|
+
},
|
|
170
|
+
}),
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
If the schema validation fails, the API `subscribe` and `update` routes will return a `400 Bad Request` error with `INVALID_METADATA`.
|
|
176
|
+
|
|
125
177
|
## Schema
|
|
126
178
|
|
|
127
179
|
### Lead
|
package/dist/client.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import { lead } from "./index.mjs";
|
|
1
|
+
import { t as lead } from "./index-CGt_sc05.mjs";
|
|
3
2
|
import * as better_auth0 from "better-auth";
|
|
4
3
|
|
|
5
4
|
//#region src/client.d.ts
|
|
@@ -10,6 +9,7 @@ declare const leadClient: () => {
|
|
|
10
9
|
INVALID_EMAIL: better_auth0.RawError<"INVALID_EMAIL">;
|
|
11
10
|
INVALID_TOKEN: better_auth0.RawError<"INVALID_TOKEN">;
|
|
12
11
|
TOKEN_EXPIRED: better_auth0.RawError<"TOKEN_EXPIRED">;
|
|
12
|
+
INVALID_METADATA: better_auth0.RawError<"INVALID_METADATA">;
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
15
|
//#endregion
|
package/dist/client.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { t as LEAD_ERROR_CODES } from "./error-codes-
|
|
2
|
-
|
|
1
|
+
import { t as LEAD_ERROR_CODES } from "./error-codes-CZUPEOrE.mjs";
|
|
3
2
|
//#region src/client.ts
|
|
4
3
|
const leadClient = () => {
|
|
5
4
|
return {
|
|
@@ -8,7 +7,7 @@ const leadClient = () => {
|
|
|
8
7
|
$ERROR_CODES: LEAD_ERROR_CODES
|
|
9
8
|
};
|
|
10
9
|
};
|
|
11
|
-
|
|
12
10
|
//#endregion
|
|
13
11
|
export { leadClient };
|
|
12
|
+
|
|
14
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';\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":"
|
|
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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { defineErrorCodes } from "better-auth";
|
|
2
|
-
|
|
3
2
|
//#region src/error-codes.ts
|
|
4
3
|
const LEAD_ERROR_CODES = defineErrorCodes({
|
|
5
4
|
INVALID_EMAIL: "Invalid email",
|
|
6
5
|
INVALID_TOKEN: "Invalid token",
|
|
7
|
-
TOKEN_EXPIRED: "Token expired"
|
|
6
|
+
TOKEN_EXPIRED: "Token expired",
|
|
7
|
+
INVALID_METADATA: "Invalid metadata"
|
|
8
8
|
});
|
|
9
|
-
|
|
10
9
|
//#endregion
|
|
11
10
|
export { LEAD_ERROR_CODES as t };
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=error-codes-CZUPEOrE.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-codes-
|
|
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,210 @@
|
|
|
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
|
+
* @param createdAt the date the lead was created
|
|
54
|
+
* @param isNewLead whether the lead was newly created or already existed - useful to bounce verification emails together with `createdAt`
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
data: {
|
|
58
|
+
email: string;
|
|
59
|
+
url: string;
|
|
60
|
+
token: string;
|
|
61
|
+
createdAt: Date;
|
|
62
|
+
isNewLead: boolean;
|
|
63
|
+
}, request?: Request) => Promise<void>;
|
|
64
|
+
onEmailVerified?: (
|
|
65
|
+
/**
|
|
66
|
+
* @param lead the lead that was verified
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
data: {
|
|
70
|
+
lead: Lead;
|
|
71
|
+
}, request?: Request) => Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Number of seconds the verification token is
|
|
74
|
+
* valid for.
|
|
75
|
+
* @default 3600 seconds (1 hour)
|
|
76
|
+
*/
|
|
77
|
+
expiresIn?: number;
|
|
78
|
+
/**
|
|
79
|
+
* Rate limit configuration for /lead/subscribe and /lead/resend endpoints.
|
|
80
|
+
*/
|
|
81
|
+
rateLimit?: {
|
|
82
|
+
/**
|
|
83
|
+
* Time window in seconds for which the rate limit applies.
|
|
84
|
+
* @default 10 seconds
|
|
85
|
+
*/
|
|
86
|
+
window: number;
|
|
87
|
+
/**
|
|
88
|
+
* Maximum number of requests allowed within the time window.
|
|
89
|
+
* @default 3 requests
|
|
90
|
+
*/
|
|
91
|
+
max: number;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Schema for the lead plugin
|
|
95
|
+
*/
|
|
96
|
+
schema?: InferOptionSchema<typeof lead$1> | undefined;
|
|
97
|
+
metadata?: {
|
|
98
|
+
validationSchema?: StandardSchemaV1;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
interface Lead {
|
|
102
|
+
/**
|
|
103
|
+
* Database identifier
|
|
104
|
+
*/
|
|
105
|
+
id: string;
|
|
106
|
+
createdAt: Date;
|
|
107
|
+
updatedAt: Date;
|
|
108
|
+
email: string;
|
|
109
|
+
emailVerified: boolean;
|
|
110
|
+
metadata?: string;
|
|
111
|
+
}
|
|
112
|
+
type LeadPayload = Omit<Lead, 'id' | 'createdAt' | 'updatedAt' | 'emailVerified'>;
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/index.d.ts
|
|
115
|
+
declare const lead: <O extends LeadOptions>(options?: O) => {
|
|
116
|
+
id: "lead";
|
|
117
|
+
schema: {
|
|
118
|
+
lead: {
|
|
119
|
+
fields: {
|
|
120
|
+
createdAt: {
|
|
121
|
+
type: "date";
|
|
122
|
+
defaultValue: () => Date;
|
|
123
|
+
required: true;
|
|
124
|
+
input: false;
|
|
125
|
+
};
|
|
126
|
+
updatedAt: {
|
|
127
|
+
type: "date";
|
|
128
|
+
defaultValue: () => Date;
|
|
129
|
+
onUpdate: () => Date;
|
|
130
|
+
required: true;
|
|
131
|
+
input: false;
|
|
132
|
+
};
|
|
133
|
+
email: {
|
|
134
|
+
type: "string";
|
|
135
|
+
required: true;
|
|
136
|
+
unique: true;
|
|
137
|
+
};
|
|
138
|
+
emailVerified: {
|
|
139
|
+
type: "boolean";
|
|
140
|
+
defaultValue: false;
|
|
141
|
+
required: true;
|
|
142
|
+
input: false;
|
|
143
|
+
};
|
|
144
|
+
metadata: {
|
|
145
|
+
type: "string";
|
|
146
|
+
required: false;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
endpoints: {
|
|
152
|
+
subscribe: better_auth0.StrictEndpoint<"/lead/subscribe", {
|
|
153
|
+
method: "POST";
|
|
154
|
+
body: zod.ZodObject<{
|
|
155
|
+
email: zod.ZodString;
|
|
156
|
+
metadata: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodAny>>;
|
|
157
|
+
}, better_auth0.$strip>;
|
|
158
|
+
}, {
|
|
159
|
+
status: boolean;
|
|
160
|
+
}>;
|
|
161
|
+
verify: better_auth0.StrictEndpoint<"/lead/verify", {
|
|
162
|
+
method: "GET";
|
|
163
|
+
query: zod.ZodObject<{
|
|
164
|
+
token: zod.ZodString;
|
|
165
|
+
}, better_auth0.$strip>;
|
|
166
|
+
}, {
|
|
167
|
+
status: boolean;
|
|
168
|
+
}>;
|
|
169
|
+
unsubscribe: better_auth0.StrictEndpoint<"/lead/unsubscribe", {
|
|
170
|
+
method: "POST";
|
|
171
|
+
body: zod.ZodObject<{
|
|
172
|
+
id: zod.ZodString;
|
|
173
|
+
}, better_auth0.$strip>;
|
|
174
|
+
}, {
|
|
175
|
+
status: boolean;
|
|
176
|
+
}>;
|
|
177
|
+
resend: better_auth0.StrictEndpoint<"/lead/resend", {
|
|
178
|
+
method: "POST";
|
|
179
|
+
body: zod.ZodObject<{
|
|
180
|
+
email: zod.ZodString;
|
|
181
|
+
}, better_auth0.$strip>;
|
|
182
|
+
}, {
|
|
183
|
+
status: boolean;
|
|
184
|
+
}>;
|
|
185
|
+
update: better_auth0.StrictEndpoint<"/lead/update", {
|
|
186
|
+
method: "POST";
|
|
187
|
+
body: zod.ZodObject<{
|
|
188
|
+
id: zod.ZodString;
|
|
189
|
+
metadata: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodAny>>;
|
|
190
|
+
}, better_auth0.$strip>;
|
|
191
|
+
}, {
|
|
192
|
+
status: boolean;
|
|
193
|
+
}>;
|
|
194
|
+
};
|
|
195
|
+
options: NoInfer<O>;
|
|
196
|
+
rateLimit: {
|
|
197
|
+
pathMatcher: (path: string) => boolean;
|
|
198
|
+
window: number;
|
|
199
|
+
max: number;
|
|
200
|
+
}[];
|
|
201
|
+
$ERROR_CODES: {
|
|
202
|
+
INVALID_EMAIL: better_auth0.RawError<"INVALID_EMAIL">;
|
|
203
|
+
INVALID_TOKEN: better_auth0.RawError<"INVALID_TOKEN">;
|
|
204
|
+
TOKEN_EXPIRED: better_auth0.RawError<"TOKEN_EXPIRED">;
|
|
205
|
+
INVALID_METADATA: better_auth0.RawError<"INVALID_METADATA">;
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
//#endregion
|
|
209
|
+
export { LeadPayload as i, Lead as n, LeadOptions as r, lead as t };
|
|
210
|
+
//# sourceMappingURL=index-CGt_sc05.d.mts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,100 +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.ZodString;
|
|
47
|
-
metadata: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodAny>>;
|
|
48
|
-
}, better_auth0.$strip>;
|
|
49
|
-
}, {
|
|
50
|
-
status: boolean;
|
|
51
|
-
}>;
|
|
52
|
-
verify: better_auth0.StrictEndpoint<"/lead/verify", {
|
|
53
|
-
method: "GET";
|
|
54
|
-
query: zod.ZodObject<{
|
|
55
|
-
token: zod.ZodString;
|
|
56
|
-
}, better_auth0.$strip>;
|
|
57
|
-
}, {
|
|
58
|
-
status: boolean;
|
|
59
|
-
}>;
|
|
60
|
-
unsubscribe: better_auth0.StrictEndpoint<"/lead/unsubscribe", {
|
|
61
|
-
method: "POST";
|
|
62
|
-
body: zod.ZodObject<{
|
|
63
|
-
id: zod.ZodString;
|
|
64
|
-
}, better_auth0.$strip>;
|
|
65
|
-
}, {
|
|
66
|
-
status: boolean;
|
|
67
|
-
}>;
|
|
68
|
-
resend: better_auth0.StrictEndpoint<"/lead/resend", {
|
|
69
|
-
method: "POST";
|
|
70
|
-
body: zod.ZodObject<{
|
|
71
|
-
email: zod.ZodString;
|
|
72
|
-
}, better_auth0.$strip>;
|
|
73
|
-
}, {
|
|
74
|
-
status: boolean;
|
|
75
|
-
}>;
|
|
76
|
-
update: better_auth0.StrictEndpoint<"/lead/update", {
|
|
77
|
-
method: "POST";
|
|
78
|
-
body: zod.ZodObject<{
|
|
79
|
-
id: zod.ZodString;
|
|
80
|
-
metadata: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodAny>>;
|
|
81
|
-
}, better_auth0.$strip>;
|
|
82
|
-
}, {
|
|
83
|
-
status: boolean;
|
|
84
|
-
}>;
|
|
85
|
-
};
|
|
86
|
-
options: NoInfer<O>;
|
|
87
|
-
rateLimit: {
|
|
88
|
-
pathMatcher: (path: string) => boolean;
|
|
89
|
-
window: number;
|
|
90
|
-
max: number;
|
|
91
|
-
}[];
|
|
92
|
-
$ERROR_CODES: {
|
|
93
|
-
INVALID_EMAIL: better_auth0.RawError<"INVALID_EMAIL">;
|
|
94
|
-
INVALID_TOKEN: better_auth0.RawError<"INVALID_TOKEN">;
|
|
95
|
-
TOKEN_EXPIRED: better_auth0.RawError<"TOKEN_EXPIRED">;
|
|
96
|
-
};
|
|
97
|
-
};
|
|
98
|
-
//#endregion
|
|
99
|
-
export { Lead, LeadOptions, LeadPayload, lead };
|
|
100
|
-
//# sourceMappingURL=index.d.mts.map
|
|
1
|
+
import { i as LeadPayload, n as Lead, r as LeadOptions, t as lead } from "./index-CGt_sc05.mjs";
|
|
2
|
+
export { Lead, LeadOptions, LeadPayload, lead };
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { t as LEAD_ERROR_CODES } from "./error-codes-
|
|
2
|
-
import "better-auth";
|
|
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
4
|
import { jwtVerify } from "jose";
|
|
5
5
|
import { JWTExpired } from "jose/errors";
|
|
6
6
|
import * as z from "zod";
|
|
7
7
|
import { mergeSchema } from "better-auth/db";
|
|
8
|
-
|
|
9
8
|
//#region src/routes.ts
|
|
10
9
|
const subscribeSchema = z.object({
|
|
11
10
|
email: z.string().meta({ description: "Email address of the lead" }),
|
|
@@ -15,8 +14,9 @@ const subscribe = (options) => createAuthEndpoint("/lead/subscribe", {
|
|
|
15
14
|
method: "POST",
|
|
16
15
|
body: subscribeSchema
|
|
17
16
|
}, async (ctx) => {
|
|
18
|
-
const { email
|
|
17
|
+
const { email } = ctx.body;
|
|
19
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);
|
|
20
20
|
const normalizedEmail = email.toLowerCase();
|
|
21
21
|
let lead = await ctx.context.adapter.findOne({
|
|
22
22
|
model: "lead",
|
|
@@ -25,6 +25,7 @@ const subscribe = (options) => createAuthEndpoint("/lead/subscribe", {
|
|
|
25
25
|
value: normalizedEmail
|
|
26
26
|
}]
|
|
27
27
|
});
|
|
28
|
+
let isNewLead = false;
|
|
28
29
|
if (!lead) try {
|
|
29
30
|
lead = await ctx.context.adapter.create({
|
|
30
31
|
model: "lead",
|
|
@@ -33,6 +34,7 @@ const subscribe = (options) => createAuthEndpoint("/lead/subscribe", {
|
|
|
33
34
|
metadata: metadata ? JSON.stringify(metadata) : void 0
|
|
34
35
|
}
|
|
35
36
|
});
|
|
37
|
+
isNewLead = true;
|
|
36
38
|
} catch (e) {
|
|
37
39
|
ctx.context.logger.info("Error creating lead");
|
|
38
40
|
lead = await ctx.context.adapter.findOne({
|
|
@@ -49,7 +51,9 @@ const subscribe = (options) => createAuthEndpoint("/lead/subscribe", {
|
|
|
49
51
|
await ctx.context.runInBackgroundOrAwait(options.sendVerificationEmail({
|
|
50
52
|
email: normalizedEmail,
|
|
51
53
|
url,
|
|
52
|
-
token
|
|
54
|
+
token,
|
|
55
|
+
createdAt: lead.createdAt,
|
|
56
|
+
isNewLead
|
|
53
57
|
}, ctx.request));
|
|
54
58
|
}
|
|
55
59
|
return ctx.json({ status: true });
|
|
@@ -68,7 +72,7 @@ const verify = (options) => createAuthEndpoint("/lead/verify", {
|
|
|
68
72
|
throw APIError.from("UNAUTHORIZED", LEAD_ERROR_CODES.INVALID_TOKEN);
|
|
69
73
|
}
|
|
70
74
|
const parsed = subscribeSchema.parse(jwt.payload);
|
|
71
|
-
|
|
75
|
+
let lead = await ctx.context.adapter.findOne({
|
|
72
76
|
model: "lead",
|
|
73
77
|
where: [{
|
|
74
78
|
field: "email",
|
|
@@ -77,7 +81,7 @@ const verify = (options) => createAuthEndpoint("/lead/verify", {
|
|
|
77
81
|
});
|
|
78
82
|
if (!lead) return ctx.json({ status: true });
|
|
79
83
|
if (lead.emailVerified) return ctx.json({ status: true });
|
|
80
|
-
await ctx.context.adapter.update({
|
|
84
|
+
lead = await ctx.context.adapter.update({
|
|
81
85
|
model: "lead",
|
|
82
86
|
where: [{
|
|
83
87
|
field: "email",
|
|
@@ -85,6 +89,8 @@ const verify = (options) => createAuthEndpoint("/lead/verify", {
|
|
|
85
89
|
}],
|
|
86
90
|
update: { emailVerified: true }
|
|
87
91
|
});
|
|
92
|
+
if (!lead) return ctx.json({ status: true });
|
|
93
|
+
if (options.onEmailVerified) await ctx.context.runInBackgroundOrAwait(options.onEmailVerified({ lead }, ctx.request));
|
|
88
94
|
return ctx.json({ status: true });
|
|
89
95
|
});
|
|
90
96
|
const unsubscribeSchema = z.object({ id: z.string().meta({ description: "The id of the lead to unsubscribe" }) });
|
|
@@ -131,7 +137,9 @@ const resend = (options) => createAuthEndpoint("/lead/resend", {
|
|
|
131
137
|
await ctx.context.runInBackgroundOrAwait(options.sendVerificationEmail({
|
|
132
138
|
email: normalizedEmail,
|
|
133
139
|
url,
|
|
134
|
-
token
|
|
140
|
+
token,
|
|
141
|
+
createdAt: lead.createdAt,
|
|
142
|
+
isNewLead: false
|
|
135
143
|
}, ctx.request));
|
|
136
144
|
}
|
|
137
145
|
return ctx.json({ status: true });
|
|
@@ -144,7 +152,7 @@ const update = (options) => createAuthEndpoint("/lead/update", {
|
|
|
144
152
|
method: "POST",
|
|
145
153
|
body: updateSchema
|
|
146
154
|
}, async (ctx) => {
|
|
147
|
-
const { id
|
|
155
|
+
const { id } = ctx.body;
|
|
148
156
|
if (!await ctx.context.adapter.findOne({
|
|
149
157
|
model: "lead",
|
|
150
158
|
where: [{
|
|
@@ -152,6 +160,7 @@ const update = (options) => createAuthEndpoint("/lead/update", {
|
|
|
152
160
|
value: id
|
|
153
161
|
}]
|
|
154
162
|
})) return ctx.json({ status: true });
|
|
163
|
+
const metadata = validateMetadata(options, ctx.body.metadata, ctx.context.logger);
|
|
155
164
|
await ctx.context.adapter.update({
|
|
156
165
|
model: "lead",
|
|
157
166
|
where: [{
|
|
@@ -162,7 +171,16 @@ const update = (options) => createAuthEndpoint("/lead/update", {
|
|
|
162
171
|
});
|
|
163
172
|
return ctx.json({ status: true });
|
|
164
173
|
});
|
|
165
|
-
|
|
174
|
+
function validateMetadata(options, metadata, logger) {
|
|
175
|
+
if (!metadata || !options.metadata?.validationSchema) return metadata;
|
|
176
|
+
const validationResult = options.metadata.validationSchema["~standard"].validate(metadata);
|
|
177
|
+
if (validationResult instanceof Promise) throw APIError.from("INTERNAL_SERVER_ERROR", BASE_ERROR_CODES.ASYNC_VALIDATION_NOT_SUPPORTED);
|
|
178
|
+
if (validationResult.issues) {
|
|
179
|
+
logger.error("Invalid metadata", validationResult.issues);
|
|
180
|
+
throw APIError.from("BAD_REQUEST", LEAD_ERROR_CODES.INVALID_METADATA);
|
|
181
|
+
}
|
|
182
|
+
return validationResult.value;
|
|
183
|
+
}
|
|
166
184
|
//#endregion
|
|
167
185
|
//#region src/schema.ts
|
|
168
186
|
const lead$1 = { lead: { fields: {
|
|
@@ -198,7 +216,6 @@ const lead$1 = { lead: { fields: {
|
|
|
198
216
|
const getSchema = (options) => {
|
|
199
217
|
return mergeSchema(lead$1, options.schema);
|
|
200
218
|
};
|
|
201
|
-
|
|
202
219
|
//#endregion
|
|
203
220
|
//#region src/index.ts
|
|
204
221
|
const lead = (options = {}) => {
|
|
@@ -221,7 +238,7 @@ const lead = (options = {}) => {
|
|
|
221
238
|
$ERROR_CODES: LEAD_ERROR_CODES
|
|
222
239
|
};
|
|
223
240
|
};
|
|
224
|
-
|
|
225
241
|
//#endregion
|
|
226
242
|
export { lead };
|
|
243
|
+
|
|
227
244
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["lead"],"sources":["../src/routes.ts","../src/schema.ts","../src/index.ts"],"sourcesContent":["import { 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, metadata } = 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 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 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().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, metadata } = 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.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","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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"}
|
|
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 let isNewLead = false;\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 isNewLead = true;\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(\n { email: normalizedEmail, url, token, createdAt: lead.createdAt, isNewLead },\n ctx.request,\n ),\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(\n { email: normalizedEmail, url, token, createdAt: lead.createdAt, isNewLead: false },\n ctx.request,\n ),\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.0
|
|
3
|
+
"version": "0.2.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-KTJzD7Eo.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-KTJzD7Eo.d.mts.map
|