@contentgrowth/content-auth 0.2.4 → 0.2.6

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.
@@ -1083,18 +1083,6 @@ declare function getInvitationLink(data: any, baseUrl: string): {
1083
1083
  * @returns The session token or null if not found
1084
1084
  */
1085
1085
  declare function getSessionToken(req: Request): string | null;
1086
- /**
1087
- * Programmatically triggers a password reset email for a user.
1088
- * This bypasses the need for an HTTP call by using better-auth's internal API.
1089
- *
1090
- * @param auth The auth instance created by createAuth()
1091
- * @param email The user's email address
1092
- * @returns Promise that resolves when the reset email is triggered
1093
- */
1094
- declare function triggerPasswordReset(auth: any, email: string): Promise<{
1095
- success: boolean;
1096
- error?: string;
1097
- }>;
1098
1086
 
1099
1087
  interface AuthConfig {
1100
1088
  /**
@@ -1116,6 +1104,23 @@ interface AuthConfig {
1116
1104
  * Defaults to true. Set to false to use Better Auth's default (Scrypt/Argon2).
1117
1105
  */
1118
1106
  useCloudflareNativeHashing?: boolean;
1107
+ /**
1108
+ * Email verification configuration.
1109
+ * For email/password signups, you can enable automatic verification emails.
1110
+ * OAuth signups (Google, GitHub) automatically set emailVerified = true.
1111
+ */
1112
+ emailVerification?: {
1113
+ /** Send verification email automatically on signup. Default: false */
1114
+ sendOnSignUp?: boolean;
1115
+ /** Auto sign in user after email verification. Default: true */
1116
+ autoSignInAfterVerification?: boolean;
1117
+ /** Callback to send verification email */
1118
+ sendVerificationEmail?: (data: {
1119
+ user: any;
1120
+ url: string;
1121
+ token: string;
1122
+ }, request: any) => Promise<void> | void;
1123
+ };
1119
1124
  [key: string]: any;
1120
1125
  }
1121
1126
  declare const createAuth: (config: AuthConfig) => better_auth.Auth<any>;
@@ -1125,4 +1130,4 @@ declare const createAuthApp: (config: AuthConfig) => {
1125
1130
  auth: better_auth.Auth<any>;
1126
1131
  };
1127
1132
 
1128
- export { type AuthConfig, authMiddleware, createAuth, createAuthApp, getInvitationLink, getSessionToken, schema, triggerPasswordReset };
1133
+ export { type AuthConfig, authMiddleware, createAuth, createAuthApp, getInvitationLink, getSessionToken, schema };
@@ -5,9 +5,8 @@ import {
5
5
  createAuthApp,
6
6
  getInvitationLink,
7
7
  getSessionToken,
8
- schema_exports,
9
- triggerPasswordReset
10
- } from "../chunk-43OBL3NC.js";
8
+ schema_exports
9
+ } from "../chunk-N5OK3XPK.js";
11
10
  import "../chunk-R5U7XKVJ.js";
12
11
  export {
13
12
  Hono,
@@ -16,6 +15,5 @@ export {
16
15
  createAuthApp,
17
16
  getInvitationLink,
18
17
  getSessionToken,
19
- schema_exports as schema,
20
- triggerPasswordReset
18
+ schema_exports as schema
21
19
  };
@@ -191,17 +191,6 @@ function getSessionToken(req) {
191
191
  });
192
192
  return cookies["better-auth.session_token"] || cookies["session_token"] || cookies["__Secure-better-auth.session_token"] || null;
193
193
  }
194
- async function triggerPasswordReset(auth, email) {
195
- try {
196
- await auth.api.forgetPassword({
197
- body: { email }
198
- });
199
- return { success: true };
200
- } catch (e) {
201
- console.error("[triggerPasswordReset] Failed:", e);
202
- return { success: false, error: e.message || "Failed to trigger password reset" };
203
- }
204
- }
205
194
 
206
195
  // src/backend/index.ts
207
196
  var createAuth = (config) => {
@@ -212,7 +201,7 @@ var createAuth = (config) => {
212
201
  } else {
213
202
  db = config.database;
214
203
  }
215
- const { database, secret, baseUrl, provider: _, useCloudflareNativeHashing = true, ...rest } = config;
204
+ const { database, secret, baseUrl, provider: _, useCloudflareNativeHashing = true, emailVerification, ...rest } = config;
216
205
  let adapterOptions = {
217
206
  provider,
218
207
  schema: {
@@ -241,6 +230,8 @@ var createAuth = (config) => {
241
230
  secret,
242
231
  baseURL: baseUrl,
243
232
  emailAndPassword: emailPasswordOptions,
233
+ // Pass emailVerification config if provided
234
+ ...emailVerification ? { emailVerification } : {},
244
235
  ...otherOptions
245
236
  });
246
237
  return auth;
@@ -263,7 +254,6 @@ export {
263
254
  schema_exports,
264
255
  getInvitationLink,
265
256
  getSessionToken,
266
- triggerPasswordReset,
267
257
  Hono,
268
258
  createAuth,
269
259
  authMiddleware,
@@ -18,7 +18,8 @@ var AuthForm = ({
18
18
  view,
19
19
  onSwitchMode,
20
20
  defaultEmail = "",
21
- lockEmail = false
21
+ lockEmail = false,
22
+ forgotPasswordUrl
22
23
  }) => {
23
24
  const [isLogin, setIsLogin] = useState(view !== "signup");
24
25
  const [email, setEmail] = useState(defaultEmail);
@@ -36,21 +37,22 @@ var AuthForm = ({
36
37
  setLoading(true);
37
38
  setError(null);
38
39
  try {
40
+ let response;
39
41
  if (isLogin) {
40
- const { error: error2 } = await client.signIn.email({
42
+ response = await client.signIn.email({
41
43
  email,
42
44
  password
43
45
  });
44
- if (error2) throw error2;
46
+ if (response.error) throw response.error;
45
47
  } else {
46
- const { error: error2 } = await client.signUp.email({
48
+ response = await client.signUp.email({
47
49
  email,
48
50
  password,
49
51
  name
50
52
  });
51
- if (error2) throw error2;
53
+ if (response.error) throw response.error;
52
54
  }
53
- onSuccess?.();
55
+ onSuccess?.(response.data);
54
56
  } catch (err) {
55
57
  setError(err.message || "An error occurred");
56
58
  } finally {
@@ -136,7 +138,10 @@ var AuthForm = ({
136
138
  )
137
139
  ] }),
138
140
  /* @__PURE__ */ jsxs("div", { className: "ca-input-group", children: [
139
- /* @__PURE__ */ jsx("label", { className: "ca-label", htmlFor: "password", children: "Password" }),
141
+ /* @__PURE__ */ jsxs("div", { className: "ca-label-row", children: [
142
+ /* @__PURE__ */ jsx("label", { className: "ca-label", htmlFor: "password", children: "Password" }),
143
+ isLogin && forgotPasswordUrl && /* @__PURE__ */ jsx("a", { href: forgotPasswordUrl, className: "ca-forgot-link", children: "Forgot password?" })
144
+ ] }),
140
145
  /* @__PURE__ */ jsx(
141
146
  "input",
142
147
  {
@@ -205,18 +210,218 @@ var AuthForm = ({
205
210
  ] });
206
211
  };
207
212
 
208
- // src/frontend/components/Organization.tsx
209
- import { useState as useState2, useEffect } from "react";
213
+ // src/frontend/components/ForgotPasswordForm.tsx
214
+ import { useState as useState2 } from "react";
210
215
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
216
+ var ForgotPasswordForm = ({
217
+ client = authClient,
218
+ onSuccess,
219
+ onBackToLogin,
220
+ className,
221
+ title,
222
+ width = "default"
223
+ }) => {
224
+ const [email, setEmail] = useState2("");
225
+ const [loading, setLoading] = useState2(false);
226
+ const [error, setError] = useState2(null);
227
+ const [success, setSuccess] = useState2(false);
228
+ let widthClass = "";
229
+ if (width === "compact") widthClass = "ca-width-compact";
230
+ else if (width === "wide") widthClass = "ca-width-wide";
231
+ else widthClass = "ca-width-default";
232
+ const handleSubmit = async (e) => {
233
+ e.preventDefault();
234
+ setLoading(true);
235
+ setError(null);
236
+ try {
237
+ const { error: error2 } = await client.requestPasswordReset({
238
+ email,
239
+ redirectTo: window.location.origin + "/auth/reset-password"
240
+ });
241
+ if (error2) throw error2;
242
+ setSuccess(true);
243
+ onSuccess?.();
244
+ } catch (err) {
245
+ setError(err.message || "Failed to send reset email");
246
+ } finally {
247
+ setLoading(false);
248
+ }
249
+ };
250
+ const titleContent = title ? typeof title === "string" ? /* @__PURE__ */ jsx2("h2", { className: "ca-title", children: title }) : title : /* @__PURE__ */ jsx2("h2", { className: "ca-title", children: "Reset Password" });
251
+ if (success) {
252
+ return /* @__PURE__ */ jsxs2("div", { className: `ca-container ${widthClass} ${className || ""}`, children: [
253
+ titleContent,
254
+ /* @__PURE__ */ jsxs2("div", { className: "ca-success-message", children: [
255
+ /* @__PURE__ */ jsxs2("svg", { className: "ca-success-icon", viewBox: "0 0 24 24", width: "48", height: "48", children: [
256
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "10", fill: "#10B981" }),
257
+ /* @__PURE__ */ jsx2("path", { d: "M8 12l2.5 2.5L16 9", stroke: "white", strokeWidth: "2", fill: "none", strokeLinecap: "round", strokeLinejoin: "round" })
258
+ ] }),
259
+ /* @__PURE__ */ jsx2("h3", { className: "ca-success-title", children: "Check your email" }),
260
+ /* @__PURE__ */ jsxs2("p", { className: "ca-success-text", children: [
261
+ "We've sent a password reset link to ",
262
+ /* @__PURE__ */ jsx2("strong", { children: email }),
263
+ ". Please check your inbox and click the link to reset your password."
264
+ ] })
265
+ ] }),
266
+ onBackToLogin && /* @__PURE__ */ jsx2("div", { className: "ca-footer", children: /* @__PURE__ */ jsx2("button", { className: "ca-link", onClick: onBackToLogin, type: "button", children: "Back to Sign In" }) })
267
+ ] });
268
+ }
269
+ return /* @__PURE__ */ jsxs2("div", { className: `ca-container ${widthClass} ${className || ""}`, children: [
270
+ titleContent,
271
+ /* @__PURE__ */ jsx2("p", { className: "ca-subtitle", children: "Enter your email address and we'll send you a link to reset your password." }),
272
+ /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className: "ca-form", children: [
273
+ /* @__PURE__ */ jsxs2("div", { className: "ca-input-group", children: [
274
+ /* @__PURE__ */ jsx2("label", { className: "ca-label", htmlFor: "email", children: "Email" }),
275
+ /* @__PURE__ */ jsx2(
276
+ "input",
277
+ {
278
+ id: "email",
279
+ type: "email",
280
+ className: "ca-input",
281
+ value: email,
282
+ onChange: (e) => setEmail(e.target.value),
283
+ placeholder: "you@example.com",
284
+ required: true
285
+ }
286
+ )
287
+ ] }),
288
+ error && /* @__PURE__ */ jsx2("div", { className: "ca-error", children: error }),
289
+ /* @__PURE__ */ jsx2("button", { type: "submit", className: "ca-button", disabled: loading, children: loading ? "Sending..." : "Send Reset Link" })
290
+ ] }),
291
+ onBackToLogin && /* @__PURE__ */ jsx2("div", { className: "ca-footer", children: /* @__PURE__ */ jsx2("button", { className: "ca-link", onClick: onBackToLogin, type: "button", children: "Back to Sign In" }) })
292
+ ] });
293
+ };
294
+
295
+ // src/frontend/components/ResetPasswordForm.tsx
296
+ import { useState as useState3 } from "react";
297
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
298
+ var ResetPasswordForm = ({
299
+ token,
300
+ client = authClient,
301
+ onSuccess,
302
+ onBackToLogin,
303
+ className,
304
+ title,
305
+ width = "default"
306
+ }) => {
307
+ const [password, setPassword] = useState3("");
308
+ const [confirmPassword, setConfirmPassword] = useState3("");
309
+ const [loading, setLoading] = useState3(false);
310
+ const [error, setError] = useState3(null);
311
+ const [success, setSuccess] = useState3(false);
312
+ let widthClass = "";
313
+ if (width === "compact") widthClass = "ca-width-compact";
314
+ else if (width === "wide") widthClass = "ca-width-wide";
315
+ else widthClass = "ca-width-default";
316
+ const titleContent = title ? typeof title === "string" ? /* @__PURE__ */ jsx3("h2", { className: "ca-title", children: title }) : title : /* @__PURE__ */ jsx3("h2", { className: "ca-title", children: "Set New Password" });
317
+ if (!token) {
318
+ return /* @__PURE__ */ jsxs3("div", { className: `ca-container ${widthClass} ${className || ""}`, children: [
319
+ titleContent,
320
+ /* @__PURE__ */ jsxs3("div", { className: "ca-error-message", children: [
321
+ /* @__PURE__ */ jsxs3("svg", { className: "ca-error-icon", viewBox: "0 0 24 24", width: "48", height: "48", children: [
322
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "10", fill: "#EF4444" }),
323
+ /* @__PURE__ */ jsx3("path", { d: "M12 8v4M12 16h.01", stroke: "white", strokeWidth: "2", strokeLinecap: "round" })
324
+ ] }),
325
+ /* @__PURE__ */ jsx3("h3", { className: "ca-error-title", children: "Invalid or Missing Token" }),
326
+ /* @__PURE__ */ jsx3("p", { className: "ca-error-text", children: "The password reset link is invalid or has expired. Please request a new password reset." })
327
+ ] }),
328
+ onBackToLogin && /* @__PURE__ */ jsx3("div", { className: "ca-footer", children: /* @__PURE__ */ jsx3("button", { className: "ca-link", onClick: onBackToLogin, type: "button", children: "Back to Sign In" }) })
329
+ ] });
330
+ }
331
+ const handleSubmit = async (e) => {
332
+ e.preventDefault();
333
+ if (password !== confirmPassword) {
334
+ setError("Passwords do not match");
335
+ return;
336
+ }
337
+ if (password.length < 8) {
338
+ setError("Password must be at least 8 characters");
339
+ return;
340
+ }
341
+ setLoading(true);
342
+ setError(null);
343
+ try {
344
+ const { error: error2 } = await client.resetPassword({
345
+ token,
346
+ newPassword: password
347
+ });
348
+ if (error2) throw error2;
349
+ setSuccess(true);
350
+ onSuccess?.();
351
+ } catch (err) {
352
+ setError(err.message || "Failed to reset password");
353
+ } finally {
354
+ setLoading(false);
355
+ }
356
+ };
357
+ if (success) {
358
+ return /* @__PURE__ */ jsxs3("div", { className: `ca-container ${widthClass} ${className || ""}`, children: [
359
+ titleContent,
360
+ /* @__PURE__ */ jsxs3("div", { className: "ca-success-message", children: [
361
+ /* @__PURE__ */ jsxs3("svg", { className: "ca-success-icon", viewBox: "0 0 24 24", width: "48", height: "48", children: [
362
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "10", fill: "#10B981" }),
363
+ /* @__PURE__ */ jsx3("path", { d: "M8 12l2.5 2.5L16 9", stroke: "white", strokeWidth: "2", fill: "none", strokeLinecap: "round", strokeLinejoin: "round" })
364
+ ] }),
365
+ /* @__PURE__ */ jsx3("h3", { className: "ca-success-title", children: "Password Reset Successful" }),
366
+ /* @__PURE__ */ jsx3("p", { className: "ca-success-text", children: "Your password has been successfully reset. You can now sign in with your new password." })
367
+ ] }),
368
+ onBackToLogin && /* @__PURE__ */ jsx3("div", { className: "ca-footer", children: /* @__PURE__ */ jsx3("button", { className: "ca-link", onClick: onBackToLogin, type: "button", children: "Sign In" }) })
369
+ ] });
370
+ }
371
+ return /* @__PURE__ */ jsxs3("div", { className: `ca-container ${widthClass} ${className || ""}`, children: [
372
+ titleContent,
373
+ /* @__PURE__ */ jsx3("p", { className: "ca-subtitle", children: "Enter your new password below." }),
374
+ /* @__PURE__ */ jsxs3("form", { onSubmit: handleSubmit, className: "ca-form", children: [
375
+ /* @__PURE__ */ jsxs3("div", { className: "ca-input-group", children: [
376
+ /* @__PURE__ */ jsx3("label", { className: "ca-label", htmlFor: "password", children: "New Password" }),
377
+ /* @__PURE__ */ jsx3(
378
+ "input",
379
+ {
380
+ id: "password",
381
+ type: "password",
382
+ className: "ca-input",
383
+ value: password,
384
+ onChange: (e) => setPassword(e.target.value),
385
+ placeholder: "At least 8 characters",
386
+ minLength: 8,
387
+ required: true
388
+ }
389
+ )
390
+ ] }),
391
+ /* @__PURE__ */ jsxs3("div", { className: "ca-input-group", children: [
392
+ /* @__PURE__ */ jsx3("label", { className: "ca-label", htmlFor: "confirmPassword", children: "Confirm Password" }),
393
+ /* @__PURE__ */ jsx3(
394
+ "input",
395
+ {
396
+ id: "confirmPassword",
397
+ type: "password",
398
+ className: "ca-input",
399
+ value: confirmPassword,
400
+ onChange: (e) => setConfirmPassword(e.target.value),
401
+ placeholder: "Confirm your password",
402
+ required: true
403
+ }
404
+ )
405
+ ] }),
406
+ error && /* @__PURE__ */ jsx3("div", { className: "ca-error", children: error }),
407
+ /* @__PURE__ */ jsx3("button", { type: "submit", className: "ca-button", disabled: loading, children: loading ? "Resetting..." : "Reset Password" })
408
+ ] }),
409
+ onBackToLogin && /* @__PURE__ */ jsx3("div", { className: "ca-footer", children: /* @__PURE__ */ jsx3("button", { className: "ca-link", onClick: onBackToLogin, type: "button", children: "Back to Sign In" }) })
410
+ ] });
411
+ };
412
+
413
+ // src/frontend/components/Organization.tsx
414
+ import { useState as useState4, useEffect } from "react";
415
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
211
416
  var CreateOrganizationForm = ({
212
417
  client = authClient,
213
418
  className,
214
419
  onSuccess,
215
420
  onError
216
421
  }) => {
217
- const [name, setName] = useState2("");
218
- const [slug, setSlug] = useState2("");
219
- const [loading, setLoading] = useState2(false);
422
+ const [name, setName] = useState4("");
423
+ const [slug, setSlug] = useState4("");
424
+ const [loading, setLoading] = useState4(false);
220
425
  const handleSubmit = async (e) => {
221
426
  e.preventDefault();
222
427
  setLoading(true);
@@ -235,11 +440,11 @@ var CreateOrganizationForm = ({
235
440
  setLoading(false);
236
441
  }
237
442
  };
238
- return /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className: `ca-form ${className || ""}`, children: [
239
- /* @__PURE__ */ jsx2("h3", { className: "ca-subtitle", children: "Create Organization" }),
240
- /* @__PURE__ */ jsxs2("div", { className: "ca-input-group", children: [
241
- /* @__PURE__ */ jsx2("label", { className: "ca-label", children: "Organization Name" }),
242
- /* @__PURE__ */ jsx2(
443
+ return /* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, className: `ca-form ${className || ""}`, children: [
444
+ /* @__PURE__ */ jsx4("h3", { className: "ca-subtitle", children: "Create Organization" }),
445
+ /* @__PURE__ */ jsxs4("div", { className: "ca-input-group", children: [
446
+ /* @__PURE__ */ jsx4("label", { className: "ca-label", children: "Organization Name" }),
447
+ /* @__PURE__ */ jsx4(
243
448
  "input",
244
449
  {
245
450
  type: "text",
@@ -254,9 +459,9 @@ var CreateOrganizationForm = ({
254
459
  }
255
460
  )
256
461
  ] }),
257
- /* @__PURE__ */ jsxs2("div", { className: "ca-input-group", children: [
258
- /* @__PURE__ */ jsx2("label", { className: "ca-label", children: "Slug" }),
259
- /* @__PURE__ */ jsx2(
462
+ /* @__PURE__ */ jsxs4("div", { className: "ca-input-group", children: [
463
+ /* @__PURE__ */ jsx4("label", { className: "ca-label", children: "Slug" }),
464
+ /* @__PURE__ */ jsx4(
260
465
  "input",
261
466
  {
262
467
  type: "text",
@@ -268,7 +473,7 @@ var CreateOrganizationForm = ({
268
473
  }
269
474
  )
270
475
  ] }),
271
- /* @__PURE__ */ jsx2("button", { type: "submit", className: "ca-button", disabled: loading, children: loading ? "Creating..." : "Create Organization" })
476
+ /* @__PURE__ */ jsx4("button", { type: "submit", className: "ca-button", disabled: loading, children: loading ? "Creating..." : "Create Organization" })
272
477
  ] });
273
478
  };
274
479
  var OrganizationSwitcher = ({
@@ -277,8 +482,8 @@ var OrganizationSwitcher = ({
277
482
  currentOrgId,
278
483
  onSuccess
279
484
  }) => {
280
- const [orgs, setOrgs] = useState2([]);
281
- const [loading, setLoading] = useState2(true);
485
+ const [orgs, setOrgs] = useState4([]);
486
+ const [loading, setLoading] = useState4(true);
282
487
  useEffect(() => {
283
488
  const fetchOrgs = async () => {
284
489
  const { data } = await client.organization.list({});
@@ -291,18 +496,18 @@ var OrganizationSwitcher = ({
291
496
  await client.organization.setActive({ organizationId: orgId });
292
497
  onSuccess?.(orgId);
293
498
  };
294
- if (loading) return /* @__PURE__ */ jsx2("div", { className: "ca-loading", children: "Loading..." });
295
- return /* @__PURE__ */ jsxs2("div", { className: `ca-org-switcher ${className || ""}`, children: [
296
- /* @__PURE__ */ jsx2("label", { className: "ca-label", children: "Select Organization" }),
297
- /* @__PURE__ */ jsxs2(
499
+ if (loading) return /* @__PURE__ */ jsx4("div", { className: "ca-loading", children: "Loading..." });
500
+ return /* @__PURE__ */ jsxs4("div", { className: `ca-org-switcher ${className || ""}`, children: [
501
+ /* @__PURE__ */ jsx4("label", { className: "ca-label", children: "Select Organization" }),
502
+ /* @__PURE__ */ jsxs4(
298
503
  "select",
299
504
  {
300
505
  className: "ca-select",
301
506
  value: currentOrgId || "",
302
507
  onChange: (e) => handleSwitch(e.target.value),
303
508
  children: [
304
- /* @__PURE__ */ jsx2("option", { value: "", disabled: true, children: "Select an organization" }),
305
- orgs.map((org) => /* @__PURE__ */ jsx2("option", { value: org.id, children: org.name }, org.id))
509
+ /* @__PURE__ */ jsx4("option", { value: "", disabled: true, children: "Select an organization" }),
510
+ orgs.map((org) => /* @__PURE__ */ jsx4("option", { value: org.id, children: org.name }, org.id))
306
511
  ]
307
512
  }
308
513
  )
@@ -314,9 +519,9 @@ var InviteMemberForm = ({
314
519
  onSuccess,
315
520
  onError
316
521
  }) => {
317
- const [email, setEmail] = useState2("");
318
- const [role, setRole] = useState2("member");
319
- const [loading, setLoading] = useState2(false);
522
+ const [email, setEmail] = useState4("");
523
+ const [role, setRole] = useState4("member");
524
+ const [loading, setLoading] = useState4(false);
320
525
  const handleSubmit = async (e) => {
321
526
  e.preventDefault();
322
527
  setLoading(true);
@@ -334,11 +539,11 @@ var InviteMemberForm = ({
334
539
  setLoading(false);
335
540
  }
336
541
  };
337
- return /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className: `ca-form ${className || ""}`, children: [
338
- /* @__PURE__ */ jsx2("h3", { className: "ca-subtitle", children: "Invite Member" }),
339
- /* @__PURE__ */ jsxs2("div", { className: "ca-input-group", children: [
340
- /* @__PURE__ */ jsx2("label", { className: "ca-label", children: "Email Address" }),
341
- /* @__PURE__ */ jsx2(
542
+ return /* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, className: `ca-form ${className || ""}`, children: [
543
+ /* @__PURE__ */ jsx4("h3", { className: "ca-subtitle", children: "Invite Member" }),
544
+ /* @__PURE__ */ jsxs4("div", { className: "ca-input-group", children: [
545
+ /* @__PURE__ */ jsx4("label", { className: "ca-label", children: "Email Address" }),
546
+ /* @__PURE__ */ jsx4(
342
547
  "input",
343
548
  {
344
549
  type: "email",
@@ -350,28 +555,30 @@ var InviteMemberForm = ({
350
555
  }
351
556
  )
352
557
  ] }),
353
- /* @__PURE__ */ jsxs2("div", { className: "ca-input-group", children: [
354
- /* @__PURE__ */ jsx2("label", { className: "ca-label", children: "Role" }),
355
- /* @__PURE__ */ jsxs2(
558
+ /* @__PURE__ */ jsxs4("div", { className: "ca-input-group", children: [
559
+ /* @__PURE__ */ jsx4("label", { className: "ca-label", children: "Role" }),
560
+ /* @__PURE__ */ jsxs4(
356
561
  "select",
357
562
  {
358
563
  className: "ca-select",
359
564
  value: role,
360
565
  onChange: (e) => setRole(e.target.value),
361
566
  children: [
362
- /* @__PURE__ */ jsx2("option", { value: "member", children: "Member" }),
363
- /* @__PURE__ */ jsx2("option", { value: "admin", children: "Admin" }),
364
- /* @__PURE__ */ jsx2("option", { value: "owner", children: "Owner" })
567
+ /* @__PURE__ */ jsx4("option", { value: "member", children: "Member" }),
568
+ /* @__PURE__ */ jsx4("option", { value: "admin", children: "Admin" }),
569
+ /* @__PURE__ */ jsx4("option", { value: "owner", children: "Owner" })
365
570
  ]
366
571
  }
367
572
  )
368
573
  ] }),
369
- /* @__PURE__ */ jsx2("button", { type: "submit", className: "ca-button", disabled: loading, children: loading ? "Sending Invite..." : "Send Invite" })
574
+ /* @__PURE__ */ jsx4("button", { type: "submit", className: "ca-button", disabled: loading, children: loading ? "Sending Invite..." : "Send Invite" })
370
575
  ] });
371
576
  };
372
577
 
373
578
  export {
374
579
  AuthForm,
580
+ ForgotPasswordForm,
581
+ ResetPasswordForm,
375
582
  CreateOrganizationForm,
376
583
  OrganizationSwitcher,
377
584
  InviteMemberForm
@@ -628,7 +628,7 @@ declare const createClient: (baseUrl?: string) => {
628
628
  sortDirection?: "asc" | "desc" | undefined;
629
629
  filterField?: string | undefined;
630
630
  filterValue?: string | number | boolean | undefined;
631
- filterOperator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "contains" | undefined;
631
+ filterOperator?: "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "contains" | undefined;
632
632
  organizationId?: string | undefined;
633
633
  organizationSlug?: string | undefined;
634
634
  }> & Record<string, any>, Record<string, any> | undefined>>(data_0?: better_auth.Prettify<{
@@ -639,7 +639,7 @@ declare const createClient: (baseUrl?: string) => {
639
639
  sortDirection?: "asc" | "desc" | undefined;
640
640
  filterField?: string | undefined;
641
641
  filterValue?: string | number | boolean | undefined;
642
- filterOperator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "contains" | undefined;
642
+ filterOperator?: "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "contains" | undefined;
643
643
  organizationId?: string | undefined;
644
644
  organizationSlug?: string | undefined;
645
645
  } | undefined;
@@ -746,7 +746,7 @@ declare const createClient: (baseUrl?: string) => {
746
746
  } & {
747
747
  signIn: {
748
748
  social: <FetchOptions extends better_auth.ClientFetchOption<Partial<{
749
- provider: (string & {}) | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
749
+ provider: (string & {}) | "linear" | "huggingface" | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
750
750
  callbackURL?: string | undefined;
751
751
  newUserCallbackURL?: string | undefined;
752
752
  errorCallbackURL?: string | undefined;
@@ -763,7 +763,7 @@ declare const createClient: (baseUrl?: string) => {
763
763
  loginHint?: string | undefined;
764
764
  additionalData?: Record<string, any> | undefined;
765
765
  }> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0: better_auth.Prettify<{
766
- provider: (string & {}) | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
766
+ provider: (string & {}) | "linear" | "huggingface" | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
767
767
  callbackURL?: string | undefined;
768
768
  newUserCallbackURL?: string | undefined;
769
769
  errorCallbackURL?: string | undefined;
@@ -2205,7 +2205,7 @@ declare const authClient: {
2205
2205
  sortDirection?: "asc" | "desc" | undefined;
2206
2206
  filterField?: string | undefined;
2207
2207
  filterValue?: string | number | boolean | undefined;
2208
- filterOperator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "contains" | undefined;
2208
+ filterOperator?: "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "contains" | undefined;
2209
2209
  organizationId?: string | undefined;
2210
2210
  organizationSlug?: string | undefined;
2211
2211
  }> & Record<string, any>, Record<string, any> | undefined>>(data_0?: better_auth.Prettify<{
@@ -2216,7 +2216,7 @@ declare const authClient: {
2216
2216
  sortDirection?: "asc" | "desc" | undefined;
2217
2217
  filterField?: string | undefined;
2218
2218
  filterValue?: string | number | boolean | undefined;
2219
- filterOperator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "contains" | undefined;
2219
+ filterOperator?: "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "contains" | undefined;
2220
2220
  organizationId?: string | undefined;
2221
2221
  organizationSlug?: string | undefined;
2222
2222
  } | undefined;
@@ -2323,7 +2323,7 @@ declare const authClient: {
2323
2323
  } & {
2324
2324
  signIn: {
2325
2325
  social: <FetchOptions extends better_auth.ClientFetchOption<Partial<{
2326
- provider: (string & {}) | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
2326
+ provider: (string & {}) | "linear" | "huggingface" | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
2327
2327
  callbackURL?: string | undefined;
2328
2328
  newUserCallbackURL?: string | undefined;
2329
2329
  errorCallbackURL?: string | undefined;
@@ -2340,7 +2340,7 @@ declare const authClient: {
2340
2340
  loginHint?: string | undefined;
2341
2341
  additionalData?: Record<string, any> | undefined;
2342
2342
  }> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0: better_auth.Prettify<{
2343
- provider: (string & {}) | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
2343
+ provider: (string & {}) | "linear" | "huggingface" | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
2344
2344
  callbackURL?: string | undefined;
2345
2345
  newUserCallbackURL?: string | undefined;
2346
2346
  errorCallbackURL?: string | undefined;
@@ -9,7 +9,7 @@ import 'better-auth/plugins';
9
9
  interface AuthFormProps {
10
10
  view?: 'signin' | 'signup';
11
11
  client?: typeof authClient;
12
- onSuccess?: () => void;
12
+ onSuccess?: (data?: any) => void;
13
13
  className?: string;
14
14
  socialProviders?: string[];
15
15
  socialLayout?: 'row' | 'column';
@@ -22,9 +22,33 @@ interface AuthFormProps {
22
22
  defaultEmail?: string;
23
23
  /** Lock the email field (readonly) and hide social logins */
24
24
  lockEmail?: boolean;
25
+ /** URL for the forgot password page (shows link on login form if provided) */
26
+ forgotPasswordUrl?: string;
25
27
  }
26
28
  declare const AuthForm: React.FC<AuthFormProps>;
27
29
 
30
+ interface ForgotPasswordFormProps {
31
+ client?: typeof authClient;
32
+ onSuccess?: () => void;
33
+ onBackToLogin?: () => void;
34
+ className?: string;
35
+ title?: React.ReactNode;
36
+ width?: 'default' | 'compact' | 'wide';
37
+ }
38
+ declare const ForgotPasswordForm: React.FC<ForgotPasswordFormProps>;
39
+
40
+ interface ResetPasswordFormProps {
41
+ /** The reset token from the URL query parameter */
42
+ token: string | null;
43
+ client?: typeof authClient;
44
+ onSuccess?: () => void;
45
+ onBackToLogin?: () => void;
46
+ className?: string;
47
+ title?: React.ReactNode;
48
+ width?: 'default' | 'compact' | 'wide';
49
+ }
50
+ declare const ResetPasswordForm: React.FC<ResetPasswordFormProps>;
51
+
28
52
  interface BaseOrgProps {
29
53
  client?: typeof authClient;
30
54
  className?: string;
@@ -39,4 +63,4 @@ declare const InviteMemberForm: React.FC<BaseOrgProps & {
39
63
  organizationId?: string;
40
64
  }>;
41
65
 
42
- export { AuthForm, CreateOrganizationForm, InviteMemberForm, OrganizationSwitcher, authClient };
66
+ export { AuthForm, CreateOrganizationForm, ForgotPasswordForm, InviteMemberForm, OrganizationSwitcher, ResetPasswordForm, authClient };
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  AuthForm,
3
3
  CreateOrganizationForm,
4
+ ForgotPasswordForm,
4
5
  InviteMemberForm,
5
- OrganizationSwitcher
6
- } from "../chunk-2TPT2QM4.js";
6
+ OrganizationSwitcher,
7
+ ResetPasswordForm
8
+ } from "../chunk-YXUGDZZK.js";
7
9
  import {
8
10
  authClient,
9
11
  createClient
@@ -12,8 +14,10 @@ import "../chunk-R5U7XKVJ.js";
12
14
  export {
13
15
  AuthForm,
14
16
  CreateOrganizationForm,
17
+ ForgotPasswordForm,
15
18
  InviteMemberForm,
16
19
  OrganizationSwitcher,
20
+ ResetPasswordForm,
17
21
  authClient,
18
22
  createClient
19
23
  };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { AuthConfig, authMiddleware, createAuth, createAuthApp, getInvitationLink, getSessionToken, schema, triggerPasswordReset } from './backend/index.js';
2
- export { AuthForm, CreateOrganizationForm, InviteMemberForm, OrganizationSwitcher } from './frontend/index.js';
1
+ export { AuthConfig, authMiddleware, createAuth, createAuthApp, getInvitationLink, getSessionToken, schema } from './backend/index.js';
2
+ export { AuthForm, CreateOrganizationForm, ForgotPasswordForm, InviteMemberForm, OrganizationSwitcher, ResetPasswordForm } from './frontend/index.js';
3
3
  export { authClient, createClient } from './frontend/client.js';
4
4
  export * from 'better-auth';
5
5
  export { Hono } from 'hono';
package/dist/index.js CHANGED
@@ -5,15 +5,16 @@ import {
5
5
  createAuthApp,
6
6
  getInvitationLink,
7
7
  getSessionToken,
8
- schema_exports,
9
- triggerPasswordReset
10
- } from "./chunk-43OBL3NC.js";
8
+ schema_exports
9
+ } from "./chunk-N5OK3XPK.js";
11
10
  import {
12
11
  AuthForm,
13
12
  CreateOrganizationForm,
13
+ ForgotPasswordForm,
14
14
  InviteMemberForm,
15
- OrganizationSwitcher
16
- } from "./chunk-2TPT2QM4.js";
15
+ OrganizationSwitcher,
16
+ ResetPasswordForm
17
+ } from "./chunk-YXUGDZZK.js";
17
18
  import {
18
19
  authClient,
19
20
  createClient
@@ -22,9 +23,11 @@ import "./chunk-R5U7XKVJ.js";
22
23
  export {
23
24
  AuthForm,
24
25
  CreateOrganizationForm,
26
+ ForgotPasswordForm,
25
27
  Hono,
26
28
  InviteMemberForm,
27
29
  OrganizationSwitcher,
30
+ ResetPasswordForm,
28
31
  authClient,
29
32
  authMiddleware,
30
33
  createAuth,
@@ -32,6 +35,5 @@ export {
32
35
  createClient,
33
36
  getInvitationLink,
34
37
  getSessionToken,
35
- schema_exports as schema,
36
- triggerPasswordReset
38
+ schema_exports as schema
37
39
  };
package/dist/styles.css CHANGED
@@ -37,6 +37,24 @@
37
37
  color: #374151;
38
38
  }
39
39
 
40
+ .ca-label-row {
41
+ display: flex;
42
+ justify-content: space-between;
43
+ align-items: center;
44
+ }
45
+
46
+ .ca-forgot-link {
47
+ font-size: 0.8125rem;
48
+ color: #2563eb;
49
+ text-decoration: none;
50
+ font-weight: 500;
51
+ }
52
+
53
+ .ca-forgot-link:hover {
54
+ text-decoration: underline;
55
+ color: #1d4ed8;
56
+ }
57
+
40
58
  .ca-input {
41
59
  padding: 0.75rem 1rem;
42
60
  border-radius: 8px;
@@ -170,6 +188,64 @@ button[type="submit"]:disabled {
170
188
  color: #1d4ed8;
171
189
  }
172
190
 
191
+ /* Subtitle */
192
+ .ca-subtitle {
193
+ text-align: center;
194
+ color: #6b7280;
195
+ font-size: 0.9375rem;
196
+ margin-bottom: 1.5rem;
197
+ line-height: 1.5;
198
+ }
199
+
200
+ /* Success Message */
201
+ .ca-success-message {
202
+ text-align: center;
203
+ padding: 1.5rem 0;
204
+ }
205
+
206
+ .ca-success-icon {
207
+ margin: 0 auto 1rem;
208
+ display: block;
209
+ }
210
+
211
+ .ca-success-title {
212
+ font-size: 1.25rem;
213
+ font-weight: 600;
214
+ color: #111827;
215
+ margin-bottom: 0.75rem;
216
+ }
217
+
218
+ .ca-success-text {
219
+ color: #6b7280;
220
+ font-size: 0.9375rem;
221
+ line-height: 1.6;
222
+ }
223
+
224
+ /* Error Message Block */
225
+ .ca-error-message {
226
+ text-align: center;
227
+ padding: 1.5rem 0;
228
+ }
229
+
230
+ .ca-error-icon {
231
+ margin: 0 auto 1rem;
232
+ display: block;
233
+ }
234
+
235
+ .ca-error-title {
236
+ font-size: 1.25rem;
237
+ font-weight: 600;
238
+ color: #111827;
239
+ margin-bottom: 0.75rem;
240
+ }
241
+
242
+ .ca-error-text {
243
+ color: #6b7280;
244
+ font-size: 0.9375rem;
245
+ line-height: 1.6;
246
+ }
247
+
248
+ /* Inline Error */
173
249
  .ca-error {
174
250
  background-color: #fef2f2;
175
251
  color: #ef4444;
@@ -188,8 +264,17 @@ button[type="submit"]:disabled {
188
264
  margin-bottom: 1.5rem;
189
265
  }
190
266
 
191
- .ca-container-wide {
192
- max-width: 600px;
267
+ /* Width Modifiers */
268
+ .ca-width-wide {
269
+ max-width: 600px !important;
270
+ }
271
+
272
+ .ca-width-compact {
273
+ max-width: 360px !important;
274
+ }
275
+
276
+ .ca-width-default {
277
+ max-width: 420px !important;
193
278
  }
194
279
 
195
280
  /* Split Layout */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentgrowth/content-auth",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Better Auth wrapper with UI components for Cloudflare Workers & Pages",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",