@insforge/nextjs 0.6.9 → 0.7.1

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/dist/index.mjs CHANGED
@@ -5,19 +5,6 @@ import { createContext, useContext, useEffect, useState, useCallback, useRef } f
5
5
  import { createClient } from "@insforge/sdk";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  var InsforgeContext = createContext(void 0);
8
- function getTokenFromSDK() {
9
- console.log("[InsforgeProvider] Getting token from SDK");
10
- if (typeof window === "undefined") return null;
11
- console.log("[InsforgeProvider] Window:", window);
12
- try {
13
- const token = localStorage.getItem("insforge-auth-token");
14
- console.log("[InsforgeProvider] Token:", token);
15
- return token;
16
- } catch (error) {
17
- console.error("[InsforgeProvider] Error getting token from SDK:", error);
18
- return null;
19
- }
20
- }
21
8
  async function syncTokenToCookie(token) {
22
9
  try {
23
10
  const response = await fetch("/api/auth", {
@@ -52,7 +39,9 @@ function InsforgeProvider({
52
39
  const [insforge] = useState(() => createClient({ baseUrl }));
53
40
  const loadAuthState = useCallback(async () => {
54
41
  try {
55
- const token = getTokenFromSDK();
42
+ const sessionResult = insforge.auth.getCurrentSession();
43
+ const session2 = sessionResult.data?.session;
44
+ const token = session2?.accessToken || null;
56
45
  if (!token) {
57
46
  setUser(null);
58
47
  setSession(null);
@@ -67,13 +56,11 @@ function InsforgeProvider({
67
56
  try {
68
57
  const cachedData = JSON.parse(cachedUserStr);
69
58
  if (cachedData.user) {
70
- console.log("[InsforgeProvider] Loading user from cache");
71
59
  const userData = {
72
60
  id: cachedData.user.id,
73
61
  email: cachedData.user.email,
74
- createdAt: cachedData.user.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
75
- updatedAt: cachedData.user.updatedAt || (/* @__PURE__ */ new Date()).toISOString(),
76
- ...cachedData.profile
62
+ name: cachedData.profile?.nickname || "",
63
+ avatarUrl: cachedData.profile?.avatar_url || ""
77
64
  };
78
65
  setUser(userData);
79
66
  setSession({
@@ -97,13 +84,11 @@ function InsforgeProvider({
97
84
  }
98
85
  const userResult = await insforge.auth.getCurrentUser();
99
86
  if (userResult.data) {
100
- console.log("[InsforgeProvider] User data refreshed from API");
101
87
  const userData = {
102
88
  id: userResult.data.user.id,
103
89
  email: userResult.data.user.email,
104
- createdAt: userResult.data.user.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
105
- updatedAt: userResult.data.user.updatedAt || (/* @__PURE__ */ new Date()).toISOString(),
106
- ...userResult.data.profile
90
+ name: userResult.data.profile?.nickname || "",
91
+ avatarUrl: userResult.data.profile?.avatar_url || ""
107
92
  };
108
93
  setUser(userData);
109
94
  setSession({
@@ -154,72 +139,90 @@ function InsforgeProvider({
154
139
  }
155
140
  };
156
141
  }, []);
157
- const signIn = useCallback(
158
- async (email, password) => {
159
- const sdkResult = await insforge.auth.signInWithPassword({ email, password });
160
- if (sdkResult.data) {
142
+ const handleAuthSuccess = useCallback(
143
+ async (authToken, fallbackUser) => {
144
+ const userResult = await insforge.auth.getCurrentUser();
145
+ if (userResult.data) {
161
146
  const userData = {
162
- id: sdkResult.data.user.id,
163
- email: sdkResult.data.user.email,
164
- name: sdkResult.data.user.name || void 0,
165
- createdAt: sdkResult.data.user.createdAt,
166
- updatedAt: sdkResult.data.user.updatedAt
147
+ id: userResult.data.user.id,
148
+ email: userResult.data.user.email,
149
+ name: userResult.data.profile?.nickname || "",
150
+ avatarUrl: userResult.data.profile?.avatar_url || ""
167
151
  };
168
152
  const sessionData = {
169
- userId: sdkResult.data.user.id,
170
- token: sdkResult.data.accessToken,
153
+ userId: userResult.data.user.id,
154
+ token: authToken,
171
155
  expiresAt: "",
172
156
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
173
157
  };
174
158
  setUser(userData);
175
159
  setSession(sessionData);
160
+ localStorage.setItem("insforge-user-profile", JSON.stringify(userResult.data));
176
161
  if (onAuthChange) {
177
162
  onAuthChange(userData);
178
163
  }
179
164
  try {
180
- await syncTokenToCookie(sdkResult.data.accessToken);
165
+ await syncTokenToCookie(authToken);
181
166
  } catch (error) {
182
- console.error("Please add /api/auth route to your server to sync token to cookie:", error);
183
167
  }
168
+ } else if (fallbackUser) {
169
+ const userData = {
170
+ id: fallbackUser.id || "",
171
+ email: fallbackUser.email || "",
172
+ name: fallbackUser.name || "",
173
+ avatarUrl: ""
174
+ };
175
+ setUser(userData);
176
+ setSession({
177
+ userId: fallbackUser.id || "",
178
+ token: authToken,
179
+ expiresAt: "",
180
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
181
+ });
182
+ if (onAuthChange) {
183
+ onAuthChange(userData);
184
+ }
185
+ }
186
+ },
187
+ [insforge, onAuthChange]
188
+ );
189
+ const signIn = useCallback(
190
+ async (email, password) => {
191
+ const sdkResult = await insforge.auth.signInWithPassword({ email, password });
192
+ if (sdkResult.data) {
193
+ await handleAuthSuccess(
194
+ sdkResult.data.accessToken || "",
195
+ sdkResult.data.user ? {
196
+ id: sdkResult.data.user.id,
197
+ email: sdkResult.data.user.email,
198
+ name: sdkResult.data.user.name
199
+ } : void 0
200
+ );
184
201
  } else {
185
202
  const errorMessage = sdkResult.error?.message || "Invalid email or password";
186
203
  throw new Error(errorMessage);
187
204
  }
188
205
  },
189
- [insforge, onAuthChange]
206
+ [insforge, handleAuthSuccess]
190
207
  );
191
208
  const signUp = useCallback(
192
209
  async (email, password) => {
193
210
  const sdkResult = await insforge.auth.signUp({ email, password });
194
211
  if (sdkResult.data) {
195
- const userData = {
196
- id: sdkResult.data.user.id,
197
- email: sdkResult.data.user.email,
198
- name: sdkResult.data.user.name || void 0,
199
- createdAt: sdkResult.data.user.createdAt,
200
- updatedAt: sdkResult.data.user.updatedAt
201
- };
202
- const sessionData = {
203
- userId: sdkResult.data.user.id,
204
- token: sdkResult.data.accessToken,
205
- expiresAt: "",
206
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
207
- };
208
- setUser(userData);
209
- setSession(sessionData);
210
- if (onAuthChange) {
211
- onAuthChange(userData);
212
- }
213
- try {
214
- await syncTokenToCookie(sdkResult.data.accessToken);
215
- } catch (error) {
216
- }
212
+ await handleAuthSuccess(
213
+ sdkResult.data.accessToken || "",
214
+ sdkResult.data.user ? {
215
+ id: sdkResult.data.user.id,
216
+ email: sdkResult.data.user.email,
217
+ name: sdkResult.data.user.name
218
+ } : void 0
219
+ );
217
220
  } else {
218
221
  const errorMessage = sdkResult.error?.message || "Sign up failed";
219
222
  throw new Error(errorMessage);
220
223
  }
221
224
  },
222
- [insforge, onAuthChange]
225
+ [insforge, handleAuthSuccess]
223
226
  );
224
227
  const signOut = useCallback(async () => {
225
228
  await insforge.auth.signOut();
@@ -238,7 +241,10 @@ function InsforgeProvider({
238
241
  const updateUser = useCallback(
239
242
  async (data) => {
240
243
  if (!user) throw new Error("No user signed in");
241
- const result = await insforge.auth.setProfile(data);
244
+ const result = await insforge.auth.setProfile({
245
+ nickname: data.name || "",
246
+ avatar_url: data.avatarUrl || ""
247
+ });
242
248
  if (result.data) {
243
249
  const updatedUser = { ...user, ...result.data };
244
250
  setUser(updatedUser);
@@ -300,8 +306,13 @@ function useSession() {
300
306
  return { session, isLoaded };
301
307
  }
302
308
 
309
+ // src/components/SignIn.tsx
310
+ import { useState as useState5 } from "react";
311
+ import { createClient as createClient4 } from "@insforge/sdk";
312
+
303
313
  // src/hooks/useOAuthProviders.ts
304
314
  import { useState as useState2, useEffect as useEffect2 } from "react";
315
+ import { createClient as createClient2 } from "@insforge/sdk";
305
316
  function useOAuthProviders() {
306
317
  const { baseUrl } = useInsforge();
307
318
  const [providers, setProviders] = useState2([]);
@@ -310,25 +321,21 @@ function useOAuthProviders() {
310
321
  let mounted = true;
311
322
  async function fetchProviders() {
312
323
  try {
313
- const response = await fetch(`${baseUrl}/api/auth/oauth/providers`);
314
- if (!response.ok) {
315
- if (mounted) {
316
- setProviders([]);
317
- setIsLoaded(true);
318
- }
319
- return;
320
- }
321
- const result = await response.json();
322
- if (mounted) {
323
- if (result?.data && Array.isArray(result.data)) {
324
- setProviders(result.data);
325
- } else {
326
- setProviders([]);
327
- }
328
- setIsLoaded(true);
324
+ const insforge = createClient2({ baseUrl });
325
+ const { data, error } = await insforge.auth.getOAuthProviders();
326
+ if (!mounted) return;
327
+ if (error) {
328
+ console.warn("[useOAuthProviders] Failed to fetch OAuth providers:", error);
329
+ setProviders([]);
330
+ } else if (data) {
331
+ const providerNames = data.map((p) => p.provider);
332
+ setProviders(providerNames);
333
+ } else {
334
+ setProviders([]);
329
335
  }
336
+ setIsLoaded(true);
330
337
  } catch (error) {
331
- console.warn("[useOAuthProviders] Failed to fetch OAuth providers:", error);
338
+ console.warn("[useOAuthProviders] Unexpected error:", error);
332
339
  if (mounted) {
333
340
  setProviders([]);
334
341
  setIsLoaded(true);
@@ -343,9 +350,42 @@ function useOAuthProviders() {
343
350
  return { providers, isLoaded };
344
351
  }
345
352
 
346
- // src/components/SignIn.tsx
347
- import { useState as useState4 } from "react";
348
- import { createClient as createClient2 } from "@insforge/sdk";
353
+ // src/hooks/useEmailAuthConfig.ts
354
+ import { useState as useState3, useEffect as useEffect3 } from "react";
355
+ import { createClient as createClient3 } from "@insforge/sdk";
356
+ function useEmailAuthConfig() {
357
+ const { baseUrl } = useInsforge();
358
+ const [config, setConfig] = useState3(null);
359
+ const [isLoaded, setIsLoaded] = useState3(false);
360
+ useEffect3(() => {
361
+ let mounted = true;
362
+ async function fetchConfig() {
363
+ try {
364
+ const insforge = createClient3({ baseUrl });
365
+ const { data, error } = await insforge.auth.getEmailAuthConfig();
366
+ if (!mounted) return;
367
+ if (error) {
368
+ console.warn("[useEmailAuthConfig] Failed to fetch email auth config:", error);
369
+ setConfig(null);
370
+ } else {
371
+ setConfig(data);
372
+ }
373
+ setIsLoaded(true);
374
+ } catch (error) {
375
+ console.warn("[useEmailAuthConfig] Unexpected error:", error);
376
+ if (mounted) {
377
+ setConfig(null);
378
+ setIsLoaded(true);
379
+ }
380
+ }
381
+ }
382
+ fetchConfig();
383
+ return () => {
384
+ mounted = false;
385
+ };
386
+ }, [baseUrl]);
387
+ return { config, isLoaded };
388
+ }
349
389
 
350
390
  // src/components/auth/AuthBranding.tsx
351
391
  import Link from "next/link";
@@ -457,35 +497,59 @@ function AuthFormField({ label, id, className = "", ...props }) {
457
497
  }
458
498
 
459
499
  // src/components/auth/AuthPasswordField.tsx
460
- import { useState as useState3 } from "react";
500
+ import { useState as useState4 } from "react";
461
501
  import { Eye, EyeOff } from "lucide-react";
462
502
 
463
503
  // src/components/auth/AuthPasswordStrengthIndicator.tsx
464
504
  import { Check } from "lucide-react";
465
505
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
466
- var requirements = [
467
- {
468
- label: "At least 1 Uppercase letter",
469
- test: (pwd) => /[A-Z]/.test(pwd)
470
- },
471
- {
472
- label: "At least 1 Number",
473
- test: (pwd) => /\d/.test(pwd)
474
- },
475
- {
476
- label: "Special character (e.g. !?<>@#$%)",
477
- test: (pwd) => /[!@#$%^&*()_+\-=[\]{};\\|,.<>/?]/.test(pwd)
478
- },
479
- {
480
- label: "8 characters or more",
481
- test: (pwd) => pwd.length >= 8
506
+ function createRequirements(config) {
507
+ const requirements = [];
508
+ const minLength = config.passwordMinLength;
509
+ const requireUppercase = config.requireUppercase;
510
+ const requireLowercase = config.requireLowercase;
511
+ const requireNumber = config.requireNumber;
512
+ const requireSpecialChar = config.requireSpecialChar;
513
+ if (requireUppercase) {
514
+ requirements.push({
515
+ label: "At least 1 Uppercase letter",
516
+ test: (pwd) => /[A-Z]/.test(pwd)
517
+ });
518
+ }
519
+ if (requireLowercase) {
520
+ requirements.push({
521
+ label: "At least 1 Lowercase letter",
522
+ test: (pwd) => /[a-z]/.test(pwd)
523
+ });
524
+ }
525
+ if (requireNumber) {
526
+ requirements.push({
527
+ label: "At least 1 Number",
528
+ test: (pwd) => /\d/.test(pwd)
529
+ });
530
+ }
531
+ if (requireSpecialChar) {
532
+ requirements.push({
533
+ label: "Special character (e.g. !?<>@#$%)",
534
+ test: (pwd) => /[!@#$%^&*()_+\-=[\]{};\\|,.<>/?]/.test(pwd)
535
+ });
482
536
  }
483
- ];
484
- function validatePasswordStrength(password) {
537
+ requirements.push({
538
+ label: `${minLength} characters or more`,
539
+ test: (pwd) => pwd.length >= minLength
540
+ });
541
+ return requirements;
542
+ }
543
+ function validatePasswordStrength(password, config) {
485
544
  if (!password) return false;
545
+ const requirements = createRequirements(config);
486
546
  return requirements.every((req) => req.test(password));
487
547
  }
488
- function AuthPasswordStrengthIndicator({ password }) {
548
+ function AuthPasswordStrengthIndicator({
549
+ password,
550
+ config
551
+ }) {
552
+ const requirements = createRequirements(config);
489
553
  return /* @__PURE__ */ jsx7("div", { className: "insforge-password-strength", children: requirements.map((requirement, index) => {
490
554
  const isValid = requirement.test(password);
491
555
  return /* @__PURE__ */ jsxs6("div", { className: "insforge-password-requirement", children: [
@@ -507,14 +571,15 @@ function AuthPasswordField({
507
571
  label,
508
572
  id,
509
573
  showStrengthIndicator = false,
574
+ emailAuthConfig,
510
575
  forgotPasswordLink,
511
576
  value,
512
577
  className = "",
513
578
  onFocus,
514
579
  ...props
515
580
  }) {
516
- const [showPassword, setShowPassword] = useState3(false);
517
- const [showStrength, setShowStrength] = useState3(false);
581
+ const [showPassword, setShowPassword] = useState4(false);
582
+ const [showStrength, setShowStrength] = useState4(false);
518
583
  const handleFocus = (e) => {
519
584
  if (showStrengthIndicator) {
520
585
  setShowStrength(true);
@@ -549,7 +614,13 @@ function AuthPasswordField({
549
614
  }
550
615
  )
551
616
  ] }),
552
- showStrengthIndicator && showStrength && /* @__PURE__ */ jsx8(AuthPasswordStrengthIndicator, { password: String(value || "") })
617
+ showStrengthIndicator && showStrength && /* @__PURE__ */ jsx8(
618
+ AuthPasswordStrengthIndicator,
619
+ {
620
+ password: String(value || ""),
621
+ config: emailAuthConfig
622
+ }
623
+ )
553
624
  ] });
554
625
  }
555
626
 
@@ -936,12 +1007,13 @@ function SignIn({
936
1007
  }) {
937
1008
  const { signIn, baseUrl } = useInsforge();
938
1009
  const { providers: oauthProviders } = useOAuthProviders();
939
- const [email, setEmail] = useState4("");
940
- const [password, setPassword] = useState4("");
941
- const [error, setError] = useState4("");
942
- const [loading, setLoading] = useState4(false);
943
- const [oauthLoading, setOauthLoading] = useState4(null);
944
- const insforge = useState4(() => createClient2({ baseUrl }))[0];
1010
+ const { config: emailAuthConfig } = useEmailAuthConfig();
1011
+ const [email, setEmail] = useState5("");
1012
+ const [password, setPassword] = useState5("");
1013
+ const [error, setError] = useState5("");
1014
+ const [loading, setLoading] = useState5(false);
1015
+ const [oauthLoading, setOauthLoading] = useState5(null);
1016
+ const insforge = useState5(() => createClient4({ baseUrl }))[0];
945
1017
  async function handleSubmit(e) {
946
1018
  e.preventDefault();
947
1019
  setLoading(true);
@@ -970,7 +1042,6 @@ function SignIn({
970
1042
  provider,
971
1043
  redirectTo
972
1044
  });
973
- console.log("handleOAuth result", result);
974
1045
  } catch (err) {
975
1046
  const errorMessage = err.message || `${provider} sign in failed`;
976
1047
  setError(errorMessage);
@@ -1004,7 +1075,15 @@ function SignIn({
1004
1075
  value: password,
1005
1076
  onChange: (e) => setPassword(e.target.value),
1006
1077
  required: true,
1007
- autoComplete: "current-password"
1078
+ autoComplete: "current-password",
1079
+ emailAuthConfig: emailAuthConfig || {
1080
+ requireEmailVerification: false,
1081
+ passwordMinLength: 6,
1082
+ requireNumber: false,
1083
+ requireLowercase: false,
1084
+ requireUppercase: false,
1085
+ requireSpecialChar: false
1086
+ }
1008
1087
  }
1009
1088
  ),
1010
1089
  /* @__PURE__ */ jsx16(
@@ -1034,8 +1113,8 @@ function SignIn({
1034
1113
  }
1035
1114
 
1036
1115
  // src/components/SignUp.tsx
1037
- import { useState as useState5 } from "react";
1038
- import { createClient as createClient3 } from "@insforge/sdk";
1116
+ import { useState as useState6 } from "react";
1117
+ import { createClient as createClient5 } from "@insforge/sdk";
1039
1118
  import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
1040
1119
  function SignUp({
1041
1120
  afterSignUpUrl = "/",
@@ -1060,17 +1139,18 @@ function SignUp({
1060
1139
  }) {
1061
1140
  const { signUp, baseUrl } = useInsforge();
1062
1141
  const { providers: oauthProviders } = useOAuthProviders();
1063
- const [email, setEmail] = useState5("");
1064
- const [password, setPassword] = useState5("");
1065
- const [error, setError] = useState5("");
1066
- const [loading, setLoading] = useState5(false);
1067
- const [oauthLoading, setOauthLoading] = useState5(null);
1068
- const insforge = useState5(() => createClient3({ baseUrl }))[0];
1142
+ const { config: emailAuthConfig } = useEmailAuthConfig();
1143
+ const [email, setEmail] = useState6("");
1144
+ const [password, setPassword] = useState6("");
1145
+ const [error, setError] = useState6("");
1146
+ const [loading, setLoading] = useState6(false);
1147
+ const [oauthLoading, setOauthLoading] = useState6(null);
1148
+ const insforge = useState6(() => createClient5({ baseUrl }))[0];
1069
1149
  async function handleCredentialsSubmit(e) {
1070
1150
  e.preventDefault();
1071
1151
  setLoading(true);
1072
1152
  setError("");
1073
- if (!validatePasswordStrength(password)) {
1153
+ if (emailAuthConfig && !validatePasswordStrength(password, emailAuthConfig)) {
1074
1154
  setError("Password does not meet all requirements");
1075
1155
  setLoading(false);
1076
1156
  return;
@@ -1135,9 +1215,17 @@ function SignUp({
1135
1215
  value: password,
1136
1216
  onChange: (e) => setPassword(e.target.value),
1137
1217
  required: true,
1138
- minLength: 8,
1218
+ minLength: emailAuthConfig?.passwordMinLength ?? 8,
1139
1219
  autoComplete: "new-password",
1140
- showStrengthIndicator: true
1220
+ showStrengthIndicator: true,
1221
+ emailAuthConfig: emailAuthConfig || {
1222
+ requireEmailVerification: false,
1223
+ passwordMinLength: 6,
1224
+ requireNumber: false,
1225
+ requireLowercase: false,
1226
+ requireUppercase: false,
1227
+ requireSpecialChar: false
1228
+ }
1141
1229
  }
1142
1230
  ),
1143
1231
  /* @__PURE__ */ jsx17(
@@ -1174,7 +1262,7 @@ function SignUp({
1174
1262
  }
1175
1263
 
1176
1264
  // src/components/UserButton.tsx
1177
- import { useState as useState6, useRef as useRef3, useEffect as useEffect3 } from "react";
1265
+ import { useState as useState7, useRef as useRef3, useEffect as useEffect4 } from "react";
1178
1266
  import { LogOut } from "lucide-react";
1179
1267
  import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1180
1268
  function UserButton({
@@ -1183,9 +1271,9 @@ function UserButton({
1183
1271
  appearance = {}
1184
1272
  }) {
1185
1273
  const { user, signOut } = useInsforge();
1186
- const [isOpen, setIsOpen] = useState6(false);
1274
+ const [isOpen, setIsOpen] = useState7(false);
1187
1275
  const dropdownRef = useRef3(null);
1188
- useEffect3(() => {
1276
+ useEffect4(() => {
1189
1277
  function handleClickOutside(event) {
1190
1278
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
1191
1279
  setIsOpen(false);
@@ -1250,7 +1338,7 @@ function SignedOut({ children }) {
1250
1338
  }
1251
1339
 
1252
1340
  // src/components/Protect.tsx
1253
- import { useEffect as useEffect4 } from "react";
1341
+ import { useEffect as useEffect5 } from "react";
1254
1342
  import { useRouter } from "next/navigation";
1255
1343
  import { Fragment as Fragment5, jsx as jsx21 } from "react/jsx-runtime";
1256
1344
  function Protect({
@@ -1261,7 +1349,7 @@ function Protect({
1261
1349
  }) {
1262
1350
  const { isSignedIn, isLoaded, user } = useInsforge();
1263
1351
  const router = useRouter();
1264
- useEffect4(() => {
1352
+ useEffect5(() => {
1265
1353
  if (isLoaded && !isSignedIn) {
1266
1354
  router.push(redirectTo);
1267
1355
  } else if (isLoaded && isSignedIn && condition && user) {
@@ -1308,7 +1396,6 @@ export {
1308
1396
  isProviderSupported,
1309
1397
  useAuth,
1310
1398
  useInsforge,
1311
- useOAuthProviders,
1312
1399
  useSession,
1313
1400
  useUser,
1314
1401
  validatePasswordStrength