@contentgrowth/content-auth 0.2.5 → 0.2.7

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.
@@ -1104,6 +1104,23 @@ interface AuthConfig {
1104
1104
  * Defaults to true. Set to false to use Better Auth's default (Scrypt/Argon2).
1105
1105
  */
1106
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
+ };
1107
1124
  [key: string]: any;
1108
1125
  }
1109
1126
  declare const createAuth: (config: AuthConfig) => better_auth.Auth<any>;
@@ -6,7 +6,7 @@ import {
6
6
  getInvitationLink,
7
7
  getSessionToken,
8
8
  schema_exports
9
- } from "../chunk-6DFIEMYG.js";
9
+ } from "../chunk-N5OK3XPK.js";
10
10
  import "../chunk-R5U7XKVJ.js";
11
11
  export {
12
12
  Hono,
@@ -201,7 +201,7 @@ var createAuth = (config) => {
201
201
  } else {
202
202
  db = config.database;
203
203
  }
204
- const { database, secret, baseUrl, provider: _, useCloudflareNativeHashing = true, ...rest } = config;
204
+ const { database, secret, baseUrl, provider: _, useCloudflareNativeHashing = true, emailVerification, ...rest } = config;
205
205
  let adapterOptions = {
206
206
  provider,
207
207
  schema: {
@@ -230,6 +230,8 @@ var createAuth = (config) => {
230
230
  secret,
231
231
  baseURL: baseUrl,
232
232
  emailAndPassword: emailPasswordOptions,
233
+ // Pass emailVerification config if provided
234
+ ...emailVerification ? { emailVerification } : {},
233
235
  ...otherOptions
234
236
  });
235
237
  return auth;
@@ -37,21 +37,22 @@ var AuthForm = ({
37
37
  setLoading(true);
38
38
  setError(null);
39
39
  try {
40
+ let response;
40
41
  if (isLogin) {
41
- const { error: error2 } = await client.signIn.email({
42
+ response = await client.signIn.email({
42
43
  email,
43
44
  password
44
45
  });
45
- if (error2) throw error2;
46
+ if (response.error) throw response.error;
46
47
  } else {
47
- const { error: error2 } = await client.signUp.email({
48
+ response = await client.signUp.email({
48
49
  email,
49
50
  password,
50
51
  name
51
52
  });
52
- if (error2) throw error2;
53
+ if (response.error) throw response.error;
53
54
  }
54
- onSuccess?.();
55
+ onSuccess?.(response.data);
55
56
  } catch (err) {
56
57
  setError(err.message || "An error occurred");
57
58
  } finally {
@@ -574,11 +575,187 @@ var InviteMemberForm = ({
574
575
  ] });
575
576
  };
576
577
 
578
+ // src/frontend/components/ProfileEditor.tsx
579
+ import { useState as useState5, useEffect as useEffect2 } from "react";
580
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
581
+ var ProfileEditor = ({
582
+ client = authClient,
583
+ onSuccess,
584
+ onError,
585
+ defaultName = "",
586
+ defaultImage = "",
587
+ className
588
+ }) => {
589
+ const [name, setName] = useState5(defaultName);
590
+ const [image, setImage] = useState5(defaultImage);
591
+ const [loading, setLoading] = useState5(false);
592
+ useEffect2(() => {
593
+ if (defaultName) setName(defaultName);
594
+ if (defaultImage) setImage(defaultImage);
595
+ }, [defaultName, defaultImage]);
596
+ const handleSubmit = async (e) => {
597
+ e.preventDefault();
598
+ setLoading(true);
599
+ try {
600
+ await client.updateUser({
601
+ name,
602
+ image
603
+ });
604
+ onSuccess?.();
605
+ } catch (err) {
606
+ onError?.(err.message || "Failed to update profile");
607
+ } finally {
608
+ setLoading(false);
609
+ }
610
+ };
611
+ return /* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className: `ca-form ${className || ""}`, children: [
612
+ /* @__PURE__ */ jsxs5("div", { className: "ca-input-group", children: [
613
+ /* @__PURE__ */ jsx5("label", { className: "ca-label", htmlFor: "profile-name", children: "Name" }),
614
+ /* @__PURE__ */ jsx5(
615
+ "input",
616
+ {
617
+ id: "profile-name",
618
+ type: "text",
619
+ className: "ca-input",
620
+ value: name,
621
+ onChange: (e) => setName(e.target.value),
622
+ placeholder: "Your Name"
623
+ }
624
+ )
625
+ ] }),
626
+ /* @__PURE__ */ jsxs5("div", { className: "ca-input-group", children: [
627
+ /* @__PURE__ */ jsx5("label", { className: "ca-label", htmlFor: "profile-image", children: "Avatar URL" }),
628
+ /* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "10px", alignItems: "center" }, children: [
629
+ /* @__PURE__ */ jsx5(
630
+ "input",
631
+ {
632
+ id: "profile-image",
633
+ type: "url",
634
+ className: "ca-input",
635
+ value: image,
636
+ onChange: (e) => setImage(e.target.value),
637
+ placeholder: "https://example.com/avatar.jpg",
638
+ style: { flex: 1 }
639
+ }
640
+ ),
641
+ image && /* @__PURE__ */ jsx5("div", { style: {
642
+ width: "40px",
643
+ height: "40px",
644
+ borderRadius: "50%",
645
+ overflow: "hidden",
646
+ flexShrink: 0,
647
+ border: "1px solid #eee"
648
+ }, children: /* @__PURE__ */ jsx5(
649
+ "img",
650
+ {
651
+ src: image,
652
+ alt: "Preview",
653
+ style: { width: "100%", height: "100%", objectFit: "cover" },
654
+ onError: (e) => e.currentTarget.style.display = "none"
655
+ }
656
+ ) })
657
+ ] })
658
+ ] }),
659
+ /* @__PURE__ */ jsx5("button", { type: "submit", className: "ca-button", disabled: loading, children: loading ? "Saving..." : "Save Profile" })
660
+ ] });
661
+ };
662
+
663
+ // src/frontend/components/PasswordChanger.tsx
664
+ import { useState as useState6 } from "react";
665
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
666
+ var PasswordChanger = ({
667
+ client = authClient,
668
+ onSuccess,
669
+ onError,
670
+ className,
671
+ revokeSessionsByDefault = true
672
+ }) => {
673
+ const [currentPassword, setCurrentPassword] = useState6("");
674
+ const [newPassword, setNewPassword] = useState6("");
675
+ const [confirmPassword, setConfirmPassword] = useState6("");
676
+ const [loading, setLoading] = useState6(false);
677
+ const handleSubmit = async (e) => {
678
+ e.preventDefault();
679
+ if (newPassword !== confirmPassword) {
680
+ onError?.("New passwords don't match");
681
+ return;
682
+ }
683
+ setLoading(true);
684
+ try {
685
+ const res = await client.changePassword({
686
+ currentPassword,
687
+ newPassword,
688
+ revokeOtherSessions: revokeSessionsByDefault
689
+ });
690
+ if (res?.error) {
691
+ throw new Error(res.error.message);
692
+ }
693
+ setCurrentPassword("");
694
+ setNewPassword("");
695
+ setConfirmPassword("");
696
+ onSuccess?.(res?.data);
697
+ } catch (err) {
698
+ onError?.(err.message || "Failed to change password");
699
+ } finally {
700
+ setLoading(false);
701
+ }
702
+ };
703
+ return /* @__PURE__ */ jsxs6("form", { onSubmit: handleSubmit, className: `ca-form ${className || ""}`, children: [
704
+ /* @__PURE__ */ jsxs6("div", { className: "ca-input-group", children: [
705
+ /* @__PURE__ */ jsx6("label", { className: "ca-label", htmlFor: "current-password", children: "Current Password" }),
706
+ /* @__PURE__ */ jsx6(
707
+ "input",
708
+ {
709
+ id: "current-password",
710
+ type: "password",
711
+ className: "ca-input",
712
+ value: currentPassword,
713
+ onChange: (e) => setCurrentPassword(e.target.value),
714
+ required: true
715
+ }
716
+ )
717
+ ] }),
718
+ /* @__PURE__ */ jsxs6("div", { className: "ca-input-group", children: [
719
+ /* @__PURE__ */ jsx6("label", { className: "ca-label", htmlFor: "new-password", children: "New Password" }),
720
+ /* @__PURE__ */ jsx6(
721
+ "input",
722
+ {
723
+ id: "new-password",
724
+ type: "password",
725
+ className: "ca-input",
726
+ value: newPassword,
727
+ onChange: (e) => setNewPassword(e.target.value),
728
+ required: true,
729
+ minLength: 8
730
+ }
731
+ )
732
+ ] }),
733
+ /* @__PURE__ */ jsxs6("div", { className: "ca-input-group", children: [
734
+ /* @__PURE__ */ jsx6("label", { className: "ca-label", htmlFor: "confirm-password", children: "Confirm New Password" }),
735
+ /* @__PURE__ */ jsx6(
736
+ "input",
737
+ {
738
+ id: "confirm-password",
739
+ type: "password",
740
+ className: "ca-input",
741
+ value: confirmPassword,
742
+ onChange: (e) => setConfirmPassword(e.target.value),
743
+ required: true,
744
+ minLength: 8
745
+ }
746
+ )
747
+ ] }),
748
+ /* @__PURE__ */ jsx6("button", { type: "submit", className: "ca-button", disabled: loading, children: loading ? "Updating..." : "Update Password" })
749
+ ] });
750
+ };
751
+
577
752
  export {
578
753
  AuthForm,
579
754
  ForgotPasswordForm,
580
755
  ResetPasswordForm,
581
756
  CreateOrganizationForm,
582
757
  OrganizationSwitcher,
583
- InviteMemberForm
758
+ InviteMemberForm,
759
+ ProfileEditor,
760
+ PasswordChanger
584
761
  };
@@ -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';
@@ -63,4 +63,23 @@ declare const InviteMemberForm: React.FC<BaseOrgProps & {
63
63
  organizationId?: string;
64
64
  }>;
65
65
 
66
- export { AuthForm, CreateOrganizationForm, ForgotPasswordForm, InviteMemberForm, OrganizationSwitcher, ResetPasswordForm, authClient };
66
+ interface ProfileEditorProps {
67
+ client?: typeof authClient;
68
+ onSuccess?: (data?: any) => void;
69
+ onError?: (error: string) => void;
70
+ defaultName?: string;
71
+ defaultImage?: string;
72
+ className?: string;
73
+ }
74
+ declare const ProfileEditor: React.FC<ProfileEditorProps>;
75
+
76
+ interface PasswordChangerProps {
77
+ client?: typeof authClient;
78
+ onSuccess?: (data?: any) => void;
79
+ onError?: (error: string) => void;
80
+ className?: string;
81
+ revokeSessionsByDefault?: boolean;
82
+ }
83
+ declare const PasswordChanger: React.FC<PasswordChangerProps>;
84
+
85
+ export { AuthForm, CreateOrganizationForm, ForgotPasswordForm, InviteMemberForm, OrganizationSwitcher, PasswordChanger, type PasswordChangerProps, ProfileEditor, type ProfileEditorProps, ResetPasswordForm, authClient };
@@ -4,8 +4,10 @@ import {
4
4
  ForgotPasswordForm,
5
5
  InviteMemberForm,
6
6
  OrganizationSwitcher,
7
+ PasswordChanger,
8
+ ProfileEditor,
7
9
  ResetPasswordForm
8
- } from "../chunk-7JTB52CI.js";
10
+ } from "../chunk-U7I4VK3Z.js";
9
11
  import {
10
12
  authClient,
11
13
  createClient
@@ -17,6 +19,8 @@ export {
17
19
  ForgotPasswordForm,
18
20
  InviteMemberForm,
19
21
  OrganizationSwitcher,
22
+ PasswordChanger,
23
+ ProfileEditor,
20
24
  ResetPasswordForm,
21
25
  authClient,
22
26
  createClient
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
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';
2
+ export { AuthForm, CreateOrganizationForm, ForgotPasswordForm, InviteMemberForm, OrganizationSwitcher, PasswordChanger, PasswordChangerProps, ProfileEditor, ProfileEditorProps, 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
@@ -6,15 +6,17 @@ import {
6
6
  getInvitationLink,
7
7
  getSessionToken,
8
8
  schema_exports
9
- } from "./chunk-6DFIEMYG.js";
9
+ } from "./chunk-N5OK3XPK.js";
10
10
  import {
11
11
  AuthForm,
12
12
  CreateOrganizationForm,
13
13
  ForgotPasswordForm,
14
14
  InviteMemberForm,
15
15
  OrganizationSwitcher,
16
+ PasswordChanger,
17
+ ProfileEditor,
16
18
  ResetPasswordForm
17
- } from "./chunk-7JTB52CI.js";
19
+ } from "./chunk-U7I4VK3Z.js";
18
20
  import {
19
21
  authClient,
20
22
  createClient
@@ -27,6 +29,8 @@ export {
27
29
  Hono,
28
30
  InviteMemberForm,
29
31
  OrganizationSwitcher,
32
+ PasswordChanger,
33
+ ProfileEditor,
30
34
  ResetPasswordForm,
31
35
  authClient,
32
36
  authMiddleware,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentgrowth/content-auth",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Better Auth wrapper with UI components for Cloudflare Workers & Pages",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",