better-auth-lead 0.0.1-dev.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 ADDED
@@ -0,0 +1,44 @@
1
+ # better-auth-lead
2
+
3
+ Better Auth plugin to add lead table and API for newsletter/waitlist functionality.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # npm
9
+ npm install better-auth-lead
10
+ # pnpm
11
+ pnpm add better-auth-lead
12
+ # yarn
13
+ yarn add better-auth-lead
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```ts
19
+ // server/auth.ts
20
+ import { createBetterAuth } from '@better-auth/core';
21
+ import { lead } from 'better-auth-lead';
22
+
23
+ const betterAuth = createBetterAuth({
24
+ plugins: [lead()],
25
+ });
26
+ ```
27
+
28
+ Run better auth migration to create the lead table:
29
+
30
+ ```bash
31
+ npx auth@latest generate
32
+ ```
33
+
34
+ Add the lead plugin to your auth client:
35
+
36
+ ```ts
37
+ // client/auth-client.ts
38
+ import { createAuthClient } from 'better-auth/client';
39
+ import { leadClient } from 'better-auth-lead/client';
40
+
41
+ const authClient = createAuthClient({
42
+ plugins: [leadClient()],
43
+ });
44
+ ```
@@ -0,0 +1,11 @@
1
+ import "./type-CedeOvZ6.mjs";
2
+ import { lead } from "./index.mjs";
3
+
4
+ //#region src/client.d.ts
5
+ declare const leadClient: () => {
6
+ id: "lead";
7
+ $InferServerPlugin: ReturnType<typeof lead>;
8
+ };
9
+ //#endregion
10
+ export { leadClient };
11
+ //# sourceMappingURL=client.d.mts.map
@@ -0,0 +1,11 @@
1
+ //#region src/client.ts
2
+ const leadClient = () => {
3
+ return {
4
+ id: "lead",
5
+ $InferServerPlugin: {}
6
+ };
7
+ };
8
+
9
+ //#endregion
10
+ export { leadClient };
11
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +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":";AAGA,MAAa,mBAAmB;AAC9B,QAAO;EACL,IAAI;EACJ,oBAAoB,EAAE;EACvB"}
@@ -0,0 +1,90 @@
1
+ import { n as LeadOptions, r as LeadPayload, t as Lead } from "./type-CedeOvZ6.mjs";
2
+ import * as better_auth0 from "better-auth";
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
package/dist/index.mjs ADDED
@@ -0,0 +1,208 @@
1
+ import "better-auth";
2
+ import { mergeSchema } from "better-auth/db";
3
+ import { APIError, createAuthEndpoint, createEmailVerificationToken } from "better-auth/api";
4
+ import * as z from "zod";
5
+ import { jwtVerify } from "jose";
6
+ import { JWTExpired } from "jose/errors";
7
+
8
+ //#region src/schema.ts
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
44
+ //#region src/routes.ts
45
+ const subscribeSchema = z.object({
46
+ email: z.email(),
47
+ metadata: z.record(z.string(), z.any()).optional()
48
+ });
49
+ const subscribe = (options) => createAuthEndpoint("/lead/subscribe", {
50
+ method: "POST",
51
+ body: subscribeSchema,
52
+ metadata: {}
53
+ }, async (ctx) => {
54
+ const { email, metadata } = ctx.body;
55
+ const normalizedEmail = email.toLowerCase();
56
+ let lead = await ctx.context.adapter.findOne({
57
+ model: "lead",
58
+ where: [{
59
+ field: "email",
60
+ value: normalizedEmail
61
+ }]
62
+ });
63
+ if (!lead) try {
64
+ lead = await ctx.context.adapter.create({
65
+ model: "lead",
66
+ data: {
67
+ email: normalizedEmail,
68
+ metadata: metadata ? JSON.stringify(metadata) : void 0
69
+ }
70
+ });
71
+ } catch (e) {
72
+ ctx.context.logger.info("Error creating lead");
73
+ lead = await ctx.context.adapter.findOne({
74
+ model: "lead",
75
+ where: [{
76
+ field: "email",
77
+ value: normalizedEmail
78
+ }]
79
+ });
80
+ }
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
+ if (options.sendVerificationEmail && lead && !lead.emailVerified) {
90
+ const token = await createEmailVerificationToken(ctx.context.secret, normalizedEmail, void 0, options.expiresIn ?? 3600);
91
+ const url = `${ctx.context.baseURL}/lead/verify?token=${token}`;
92
+ await ctx.context.runInBackgroundOrAwait(options.sendVerificationEmail({
93
+ email: normalizedEmail,
94
+ url,
95
+ token
96
+ }, ctx.request));
97
+ }
98
+ return ctx.json({ status: true });
99
+ });
100
+ const verifySchema = z.object({ token: z.string() });
101
+ const verify = (options) => createAuthEndpoint("/lead/verify", {
102
+ method: "GET",
103
+ query: verifySchema,
104
+ metadata: {}
105
+ }, async (ctx) => {
106
+ const { token } = ctx.query;
107
+ let jwt;
108
+ try {
109
+ jwt = await jwtVerify(token, new TextEncoder().encode(ctx.context.secret), { algorithms: ["HS256"] });
110
+ } catch (e) {
111
+ if (e instanceof JWTExpired) throw new APIError("UNAUTHORIZED", { message: "Token expired" });
112
+ throw new APIError("UNAUTHORIZED", { message: "Invalid token" });
113
+ }
114
+ const parsed = subscribeSchema.parse(jwt.payload);
115
+ const lead = await ctx.context.adapter.findOne({
116
+ model: "lead",
117
+ where: [{
118
+ field: "email",
119
+ value: parsed.email
120
+ }]
121
+ });
122
+ if (!lead) return ctx.json({ status: true });
123
+ if (lead.emailVerified) return ctx.json({ status: true });
124
+ await ctx.context.adapter.update({
125
+ model: "lead",
126
+ where: [{
127
+ field: "email",
128
+ value: parsed.email
129
+ }],
130
+ update: { emailVerified: true }
131
+ });
132
+ return ctx.json({ status: true });
133
+ });
134
+ const unsubscribeSchema = z.object({ id: z.string() });
135
+ const unsubscribe = (options) => createAuthEndpoint("/lead/unsubscribe", {
136
+ method: "POST",
137
+ body: unsubscribeSchema,
138
+ metadata: {}
139
+ }, async (ctx) => {
140
+ const { id } = ctx.body;
141
+ if (!await ctx.context.adapter.findOne({
142
+ model: "lead",
143
+ where: [{
144
+ field: "id",
145
+ value: id
146
+ }]
147
+ })) return ctx.json({ status: true });
148
+ await ctx.context.adapter.delete({
149
+ model: "lead",
150
+ where: [{
151
+ field: "id",
152
+ value: id
153
+ }]
154
+ });
155
+ return ctx.json({ status: true });
156
+ });
157
+ const resendSchema = z.object({ email: z.email() });
158
+ const resend = (options) => createAuthEndpoint("/lead/resend", {
159
+ method: "POST",
160
+ body: resendSchema,
161
+ metadata: {}
162
+ }, async (ctx) => {
163
+ const { email } = ctx.body;
164
+ const normalizedEmail = email.toLowerCase();
165
+ const lead = await ctx.context.adapter.findOne({
166
+ model: "lead",
167
+ where: [{
168
+ field: "email",
169
+ value: normalizedEmail
170
+ }]
171
+ });
172
+ if (!lead) return ctx.json({ status: true });
173
+ if (options.sendVerificationEmail && lead && !lead.emailVerified) {
174
+ const token = await createEmailVerificationToken(ctx.context.secret, normalizedEmail, void 0, options.expiresIn ?? 3600);
175
+ const url = `${ctx.context.baseURL}/lead/verify?token=${token}`;
176
+ await ctx.context.runInBackgroundOrAwait(options.sendVerificationEmail({
177
+ email: normalizedEmail,
178
+ url,
179
+ token
180
+ }, ctx.request));
181
+ }
182
+ return ctx.json({ status: true });
183
+ });
184
+
185
+ //#endregion
186
+ //#region src/index.ts
187
+ const lead = (options) => {
188
+ return {
189
+ id: "lead",
190
+ schema: getSchema(options),
191
+ endpoints: {
192
+ subscribe: subscribe(options),
193
+ verify: verify(options),
194
+ unsubscribe: unsubscribe(options),
195
+ resend: resend(options)
196
+ },
197
+ options,
198
+ rateLimit: [{
199
+ pathMatcher: (path) => ["/lead/subscribe", "/lead/resend"].includes(path),
200
+ window: options.rateLimit?.window ?? 10,
201
+ max: options.rateLimit?.max ?? 3
202
+ }]
203
+ };
204
+ };
205
+
206
+ //#endregion
207
+ export { lead };
208
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +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":";;;;;;;;AAIA,MAAaA,SAAO,EAClB,MAAM,EACJ,QAAQ;CACN,WAAW;EACT,MAAM;EACN,oCAAoB,IAAI,MAAM;EAC9B,UAAU;EACV,OAAO;EACR;CACD,WAAW;EACT,MAAM;EACN,oCAAoB,IAAI,MAAM;EAC9B,gCAAgB,IAAI,MAAM;EAC1B,UAAU;EACV,OAAO;EACR;CACD,OAAO;EACL,MAAM;EACN,UAAU;EACV,QAAQ;EACT;CACD,eAAe;EACb,MAAM;EACN,cAAc;EACd,UAAU;EACV,OAAO;EACR;CACD,UAAU;EACR,MAAM;EACN,UAAU;EACX;CACF,EACF,EACF;AAED,MAAa,aAAoC,YAAe;AAC9D,QAAO,YAAYA,QAAM,QAAQ,OAAO;;;;;ACjC1C,MAAM,kBAAkB,EAAE,OAAO;CAC/B,OAAO,EAAE,OAAO;CAChB,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC,UAAU;CACnD,CAAC;AAEF,MAAa,aAAoC,YAC/C,mBACE,mBACA;CACE,QAAQ;CACR,MAAM;CACN,UAAU,EAET;CACF,EACD,OAAO,QAAQ;CACb,MAAM,EAAE,OAAO,aAAa,IAAI;CAEhC,MAAM,kBAAkB,MAAM,aAAa;CAE3C,IAAI,OAAO,MAAM,IAAI,QAAQ,QAAQ,QAAc;EACjD,OAAO;EACP,OAAO,CACL;GACE,OAAO;GACP,OAAO;GACR,CACF;EACF,CAAC;AAEF,KAAI,CAAC,KACH,KAAI;AACF,SAAO,MAAM,IAAI,QAAQ,QAAQ,OAA0B;GACzD,OAAO;GACP,MAAM;IACJ,OAAO;IACP,UAAU,WAAW,KAAK,UAAU,SAAS,GAAG;IACjD;GACF,CAAC;UACK,GAAG;AACV,MAAI,QAAQ,OAAO,KAAK,sBAAsB;AAC9C,SAAO,MAAM,IAAI,QAAQ,QAAQ,QAAc;GAC7C,OAAO;GACP,OAAO,CACL;IACE,OAAO;IACP,OAAO;IACR,CACF;GACF,CAAC;;UAEK,CAAC,KAAK,cACf,QAAO,MAAM,IAAI,QAAQ,QAAQ,OAAa;EAC5C,OAAO;EACP,OAAO,CACL;GACE,OAAO;GACP,OAAO;GACR,CACF;EACD,QAAQ,EACN,UAAU,WAAW,KAAK,UAAU,SAAS,GAAG,KAAK,UACtD;EACF,CAAC;AAGJ,KAAI,QAAQ,yBAAyB,QAAQ,CAAC,KAAK,eAAe;EAChE,MAAM,QAAQ,MAAM,6BAClB,IAAI,QAAQ,QACZ,iBACA,QACA,QAAQ,aAAa,KACtB;EACD,MAAM,MAAM,GAAG,IAAI,QAAQ,QAAQ,qBAAqB;AAExD,QAAM,IAAI,QAAQ,uBAChB,QAAQ,sBAAsB;GAAE,OAAO;GAAiB;GAAK;GAAO,EAAE,IAAI,QAAQ,CACnF;;AAGH,QAAO,IAAI,KAAK,EACd,QAAQ,MACT,CAAC;EAEL;AAEH,MAAM,eAAe,EAAE,OAAO,EAC5B,OAAO,EAAE,QAAQ,EAClB,CAAC;AAEF,MAAa,UAAiC,YAC5C,mBACE,gBACA;CACE,QAAQ;CACR,OAAO;CACP,UAAU,EAET;CACF,EACD,OAAO,QAAQ;CACb,MAAM,EAAE,UAAU,IAAI;CAEtB,IAAI;AACJ,KAAI;AACF,QAAM,MAAM,UAAU,OAAO,IAAI,aAAa,CAAC,OAAO,IAAI,QAAQ,OAAO,EAAE,EACzE,YAAY,CAAC,QAAQ,EACtB,CAAC;UACK,GAAG;AACV,MAAI,aAAa,WACf,OAAM,IAAI,SAAS,gBAAgB,EACjC,SAAS,iBACV,CAAC;AAEJ,QAAM,IAAI,SAAS,gBAAgB,EACjC,SAAS,iBACV,CAAC;;CAGJ,MAAM,SAAS,gBAAgB,MAAM,IAAI,QAAQ;CAEjD,MAAM,OAAO,MAAM,IAAI,QAAQ,QAAQ,QAAc;EACnD,OAAO;EACP,OAAO,CACL;GACE,OAAO;GACP,OAAO,OAAO;GACf,CACF;EACF,CAAC;AAEF,KAAI,CAAC,KACH,QAAO,IAAI,KAAK,EACd,QAAQ,MACT,CAAC;AAGJ,KAAI,KAAK,cACP,QAAO,IAAI,KAAK,EACd,QAAQ,MACT,CAAC;AAGJ,OAAM,IAAI,QAAQ,QAAQ,OAAa;EACrC,OAAO;EACP,OAAO,CACL;GACE,OAAO;GACP,OAAO,OAAO;GACf,CACF;EACD,QAAQ,EACN,eAAe,MAChB;EACF,CAAC;AAEF,QAAO,IAAI,KAAK,EACd,QAAQ,MACT,CAAC;EAEL;AAEH,MAAM,oBAAoB,EAAE,OAAO,EACjC,IAAI,EAAE,QAAQ,EACf,CAAC;AAEF,MAAa,eAAsC,YACjD,mBACE,qBACA;CACE,QAAQ;CACR,MAAM;CACN,UAAU,EAET;CACF,EACD,OAAO,QAAQ;CACb,MAAM,EAAE,OAAO,IAAI;AAYnB,KAAI,CAVS,MAAM,IAAI,QAAQ,QAAQ,QAAc;EACnD,OAAO;EACP,OAAO,CACL;GACE,OAAO;GACP,OAAO;GACR,CACF;EACF,CAAC,CAGA,QAAO,IAAI,KAAK,EACd,QAAQ,MACT,CAAC;AAGJ,OAAM,IAAI,QAAQ,QAAQ,OAAO;EAC/B,OAAO;EACP,OAAO,CACL;GACE,OAAO;GACP,OAAO;GACR,CACF;EACF,CAAC;AAEF,QAAO,IAAI,KAAK,EACd,QAAQ,MACT,CAAC;EAEL;AAEH,MAAM,eAAe,EAAE,OAAO,EAC5B,OAAO,EAAE,OAAO,EACjB,CAAC;AAEF,MAAa,UAAiC,YAC5C,mBACE,gBACA;CACE,QAAQ;CACR,MAAM;CACN,UAAU,EAET;CACF,EACD,OAAO,QAAQ;CACb,MAAM,EAAE,UAAU,IAAI;CAEtB,MAAM,kBAAkB,MAAM,aAAa;CAE3C,MAAM,OAAO,MAAM,IAAI,QAAQ,QAAQ,QAAc;EACnD,OAAO;EACP,OAAO,CACL;GACE,OAAO;GACP,OAAO;GACR,CACF;EACF,CAAC;AAEF,KAAI,CAAC,KACH,QAAO,IAAI,KAAK,EACd,QAAQ,MACT,CAAC;AAGJ,KAAI,QAAQ,yBAAyB,QAAQ,CAAC,KAAK,eAAe;EAChE,MAAM,QAAQ,MAAM,6BAClB,IAAI,QAAQ,QACZ,iBACA,QACA,QAAQ,aAAa,KACtB;EACD,MAAM,MAAM,GAAG,IAAI,QAAQ,QAAQ,qBAAqB;AAExD,QAAM,IAAI,QAAQ,uBAChB,QAAQ,sBAAsB;GAAE,OAAO;GAAiB;GAAK;GAAO,EAAE,IAAI,QAAQ,CACnF;;AAGH,QAAO,IAAI,KAAK,EACd,QAAQ,MACT,CAAC;EAEL;;;;AC1QH,MAAa,QAA+B,YAAe;AACzD,QAAO;EACL,IAAI;EACJ,QAAQ,UAAU,QAAQ;EAC1B,WAAW;GACT,WAAW,UAAU,QAAQ;GAC7B,QAAQ,OAAO,QAAQ;GACvB,aAAa,YAAY,QAAQ;GACjC,QAAQ,OAAO,QAAQ;GACxB;EACQ;EACT,WAAW,CACT;GACE,cAAc,SAAS,CAAC,mBAAmB,eAAe,CAAC,SAAS,KAAK;GACzE,QAAQ,QAAQ,WAAW,UAAU;GACrC,KAAK,QAAQ,WAAW,OAAO;GAChC,CACF;EACF"}
@@ -0,0 +1,98 @@
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
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "better-auth-lead",
3
+ "version": "0.0.1-dev.0",
4
+ "description": "Better Auth Lead plugin",
5
+ "homepage": "https://github.com/marcjulian/better-auth-plugins#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/marcjulian/better-auth-plugins/issues"
8
+ },
9
+ "license": "MIT",
10
+ "author": "Marc Stammerjohann <me@marcjulian.de>",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/marcjulian/better-auth-plugins.git"
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "type": "module",
19
+ "main": "./dist/index.mjs",
20
+ "module": "./dist/index.mjs",
21
+ "types": "./dist/index.d.mts",
22
+ "exports": {
23
+ ".": "./dist/index.mjs",
24
+ "./client": "./dist/client.mjs",
25
+ "./package.json": "./package.json"
26
+ },
27
+ "dependencies": {
28
+ "jose": "^6.1.3",
29
+ "zod": "^4.3.6"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^25.3.0",
33
+ "bumpp": "^10.4.1",
34
+ "tsdown": "^0.20.3",
35
+ "typescript": "^5.9.3",
36
+ "vitest": "^4.0.18"
37
+ },
38
+ "peerDependencies": {
39
+ "better-auth": "^1.5.1"
40
+ },
41
+ "scripts": {
42
+ "build": "tsdown",
43
+ "dev": "tsdown --watch",
44
+ "test": "vitest",
45
+ "typecheck": "tsc --noEmit"
46
+ }
47
+ }