@insforge/nextjs 0.7.0 → 0.7.2

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.js CHANGED
@@ -1,4 +1,18 @@
1
1
  "use client";
2
+
3
+ // Auto-inject InsForge styles
4
+ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
5
+ const styleId = 'insforge-nextjs-styles';
6
+ if (!document.getElementById(styleId)) {
7
+ const style = document.createElement('style');
8
+ style.id = styleId;
9
+ style.textContent = "/**\n * InsForge Next.js Component Library Styles\n * A standalone CSS file for auth components - no Tailwind required!\n */\n\n/* Font Face Declaration */\n@font-face {\n font-family: 'Manrope';\n src: url('./fonts/Manrope-VariableFont_wght.ttf') format('truetype');\n font-weight: 100 900;\n font-style: normal;\n font-display: swap;\n}\n\n/* CSS Variables */\n:root {\n --font-manrope: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n/* Reset and Base Styles */\n.insforge-auth-container * {\n box-sizing: border-box;\n}\n\n/* Main Container - App handles layout, we just provide the card */\n.insforge-auth-container {\n width: 100%;\n max-width: 400px;\n background: white;\n}\n\n.insforge-branding {\n background: #FAFAFA;\n padding: 8px 8px 16px 8px;\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n gap: 4px;\n}\n\n.insforge-branding-text {\n color: #000;\n font-family: var(--font-manrope);\n font-size: 12px;\n font-style: normal;\n font-weight: 400;\n line-height: normal;\n}\n\n/* Form Card */\n.insforge-auth-card {\n width: 100%;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.25);\n}\n\n.insforge-auth-content {\n padding: 24px;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: stretch;\n gap: 24px;\n}\n\n/* Header */\n.insforge-auth-header {\n display: flex;\n flex-direction: column;\n justify-content: start;\n align-items: start;\n gap: 8px;\n}\n\n.insforge-auth-title {\n color: #000;\n font-family: Inter;\n font-size: 24px;\n font-style: normal;\n font-weight: 600;\n line-height: 32px; /* 133.333% */\n}\n\n.insforge-auth-subtitle {\n color: #828282;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 24px; /* 171.429% */\n}\n\n/* Error Banner */\n.insforge-error-banner {\n display: flex;\n padding: 8px 8px 8px 12px;\n margin-bottom: 16px;\n align-items: center;\n gap: 8px;\n align-self: stretch;\n border-radius: 4px;\n border: 2px solid #DC2626;\n background: #FEF2F2;\n color: #DC2626;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 20px; /* 142.857% */\n}\n\n.insforge-error-icon {\n color: #EF4444;\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n}\n\n/* Form Elements */\n.insforge-form {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: stretch;\n gap: 24px;\n}\n\n.insforge-form-group {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: stretch;\n gap: 4px;\n}\n\n.insforge-form-label-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.insforge-form-label {\n color: #000;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 24px;\n}\n\n.insforge-form-link {\n color: #828282;\n text-align: right;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 24px;\n}\n\n.insforge-form-link:hover {\n color: #828282;\n text-decoration: underline;\n}\n\n/* Input Container for Password (with icon) */\n.insforge-input-wrapper {\n position: relative;\n}\n\n.insforge-input {\n width: 100%;\n display: flex;\n padding: 8px 8px 10px 12px;\n align-items: center;\n gap: 8px;\n align-self: stretch;\n border-radius: 4px;\n border: 1px solid #BCBCBC;\n background: #FFF;\n font-family: Inter;\n font-size: 16px;\n font-style: normal;\n font-weight: 400;\n line-height: 20px;\n}\n\n.insforge-input::placeholder {\n color: #A6A6A6;\n}\n\n.insforge-input:focus {\n outline: none;\n}\n\n.insforge-input-with-icon {\n padding-right: 3rem;\n}\n\n.insforge-input-icon-btn {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: transparent;\n border: none;\n color: #A6A6A6;\n cursor: pointer;\n transition: color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.insforge-input-icon-btn:hover {\n color: #6b7280;\n}\n\n/* Primary Button */\n.insforge-btn-primary {\n border-radius: 4px;\n background: #000;\n width: 100%;\n display: flex;\n margin: 16px 0 0 0;\n padding: 8px 16px;\n justify-content: center;\n align-items: center;\n gap: 10px;\n align-self: stretch;\n color: #FFF;\n font-family: Manrope;\n font-size: 16px;\n font-style: normal;\n font-weight: 600;\n line-height: normal;\n border: none;\n cursor: pointer;\n}\n\n.insforge-btn-primary:hover {\n background: #303030;\n}\n\n.insforge-btn-primary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.insforge-btn-primary .insforge-btn-loader {\n display: none;\n animation: insforge-spin 1s linear infinite;\n}\n\n.insforge-btn-primary[data-loading] .insforge-btn-loader {\n display: block;\n}\n\n.insforge-btn-primary .insforge-btn-check {\n display: none;\n}\n\n.insforge-btn-primary[data-confirmed] .insforge-btn-check {\n display: block;\n}\n\n/* Text Link Section */\n.insforge-text-center {\n text-align: center;\n color: #828282;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 24px;\n}\n\n.insforge-link-primary {\n color: #000;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n line-height: 24px;\n}\n\n/* Divider */\n.insforge-divider {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 24px;\n align-self: stretch;\n}\n\n.insforge-divider::before,\n.insforge-divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: #C6C6C6;\n}\n\n.insforge-divider-text {\n color: #C6C6C6;\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 600;\n line-height: normal;\n}\n\n/* OAuth Section */\n.insforge-oauth-container {\n display: grid;\n gap: 12px;\n width: 100%;\n}\n\n/* ============================================================================\n SMART OAUTH GRID LAYOUT SYSTEM\n Pattern: 1→1x1, 2→1x2, 3→1x3, 4→2x2, 5+→auto (3 per row, last row centered)\n ============================================================================ */\n\n/* 1 provider: single column, full width - displays \"Continue with Provider\" */\n.insforge-oauth-container[data-provider-count=\"1\"] {\n grid-template-columns: 1fr;\n}\n\n/* 2 providers: two columns - displays \"Provider\" */\n.insforge-oauth-container[data-provider-count=\"2\"] {\n grid-template-columns: repeat(2, 1fr);\n}\n\n/* 3 providers: three columns - icon only */\n.insforge-oauth-container[data-provider-count=\"3\"] {\n grid-template-columns: repeat(3, 1fr);\n}\n\n/* 4 providers: 2x2 grid - displays \"Provider\" */\n.insforge-oauth-container[data-provider-count=\"4\"] {\n grid-template-columns: repeat(2, 1fr);\n}\n\n/* 5+ providers: Universal 6-column grid system\n - Grid columns managed by OAuthProviderList component via inline styles\n - This provides precise control over button positioning */\n.insforge-oauth-container:not([data-provider-count=\"1\"]):not([data-provider-count=\"2\"]):not([data-provider-count=\"3\"]):not([data-provider-count=\"4\"]) {\n grid-template-columns: repeat(6, 1fr);\n}\n\n/* OAuth Button */\n.insforge-oauth-btn {\n display: flex;\n width: 100%;\n height: 36px;\n padding: 8px 12px;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n gap: 12px;\n border-radius: 6px;\n border: 1px solid #E4E4E7;\n background: #FFF;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.10);\n color: #09090B;\n text-align: center;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n line-height: 20px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n/* Full mode: show icon + \"Continue with Provider\" */\n.insforge-oauth-btn[data-display-mode=\"full\"] {\n justify-content: center;\n}\n\n/* Short mode: show icon + \"Provider\" */\n.insforge-oauth-btn[data-display-mode=\"short\"] {\n justify-content: center;\n padding: 8px;\n gap: 8px;\n}\n\n/* Icon only mode: show only icon */\n.insforge-oauth-btn[data-display-mode=\"icon\"] {\n justify-content: center;\n gap: 0;\n}\n\n.insforge-oauth-btn[data-display-mode=\"icon\"] .insforge-oauth-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.insforge-oauth-btn:hover {\n background: #f9fafb;\n border-color: #9ca3af;\n}\n\n.insforge-oauth-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.insforge-oauth-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.insforge-oauth-loader {\n display: none;\n animation: insforge-spin 1s linear infinite;\n}\n\n.insforge-oauth-btn[data-loading] .insforge-oauth-icon {\n display: none;\n}\n\n.insforge-oauth-btn[data-loading] .insforge-oauth-loader {\n display: block;\n}\n\n/* Spin Animation */\n@keyframes insforge-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* UserButton Styles */\n.insforge-user-button-container {\n position: relative;\n display: inline-block;\n}\n\n.insforge-user-button {\n padding: 0.25rem;\n background: transparent;\n border: none;\n border-radius: 9999px;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n}\n\n.insforge-user-button:hover {\n background: rgba(0, 0, 0, 0.05);\n}\n\n.insforge-user-button-detailed {\n border-radius: 0.5rem;\n padding: 0.5rem;\n}\n\n.insforge-user-button-info {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0.125rem;\n}\n\n.insforge-user-button-name {\n font-size: 0.875rem;\n font-weight: 600;\n color: #111827;\n line-height: 1.25rem;\n text-align: left;\n}\n\n.insforge-user-button-email {\n font-size: 0.75rem;\n color: #6b7280;\n line-height: 1rem;\n text-align: left;\n}\n\n.insforge-user-avatar {\n width: 2.5rem;\n height: 2.5rem;\n border-radius: 9999px;\n object-fit: cover;\n}\n\n.insforge-user-avatar-placeholder {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n background: #3b82f6;\n color: white;\n font-weight: 600;\n font-size: 0.875rem;\n border-radius: 9999px;\n}\n\n.insforge-user-dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 0.5rem;\n min-width: 10rem;\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 0.5rem;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n z-index: 50;\n overflow: hidden;\n padding: 0.25rem;\n}\n\n.insforge-sign-out-button {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 0.75rem;\n font-size: 0.875rem;\n font-family: inherit;\n color: #dc2626;\n background: transparent;\n border: none;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: background 0.2s;\n text-align: left;\n}\n\n.insforge-sign-out-button:hover {\n background: #fef2f2;\n}\n\n/* Loading State */\n.insforge-loading {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 2rem;\n color: #6b7280;\n font-size: 0.875rem;\n}\n\n/* Password Strength Indicator */\n.insforge-password-strength {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n margin-top: 0.5rem;\n}\n\n.insforge-password-requirement {\n height: 1.5rem;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.insforge-password-check {\n width: 1.25rem;\n height: 1.25rem;\n border-radius: 9999px;\n display: flex;\n border-width: 2px;\n border-style: solid;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease-in-out;\n background-color: transparent;\n border-color: #a3a3a3;\n flex-shrink: 0;\n}\n\n.insforge-password-check-valid {\n background-color: #22c55e;\n border-color: transparent;\n}\n\n.insforge-password-check-icon {\n color: #fff;\n stroke-width: 3;\n}\n\n.insforge-password-requirement-label {\n color:#000;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 24px;\n}\n\n/* Verification Code Input */\n.insforge-verification-code-container {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n gap: 24px;\n}\n\n.insforge-verification-instructions {\n color: #525252;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 20px;\n}\n\n.insforge-verification-instructions > span {\n color: #000;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 600;\n line-height: 20px;\n}\n\n.insforge-verification-code-inputs {\n display: flex;\n flex-direction: row;\n gap: 12px;\n justify-content: center;\n align-items: center;\n}\n\n.insforge-verification-code-input {\n width: 100%;\n height: 48px;\n padding: 8px 12px;\n border-radius: 4px;\n border: 1px solid #E0E0E0;\n background: #FFF;\n text-align: center;\n font-size: 16px;\n font-style: normal;\n line-height: 20px;\n font-weight: 600;\n font-family: var(--font-manrope);\n color: #000;\n transition: all 0.2s ease-in-out;\n outline: none;\n}\n\n.insforge-verification-code-input:focus {\n border-color: #000;\n box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);\n}\n\n.insforge-verification-code-input:disabled {\n background-color: #F5F5F5;\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n/* Verification Instructions */\n.insforge-verification-instructions {\n color: #4F4F4F;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 24px;\n margin-bottom: 8px;\n}\n\n.insforge-verification-email {\n color: #000;\n font-weight: 600;\n}\n\n.insforge-resend-code {\n color: #525252;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 24px;\n text-align: center;\n}\n\n.insforge-resend-link {\n color: #000;\n font-family: Inter;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n line-height: 24px;\n}\n\n.insforge-resend-link:hover {\n text-decoration: underline;\n}\n\n.insforge-resend-link:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Responsive adjustments */\n@media (max-width: 640px) {\n .insforge-auth-card {\n padding: 2rem 1.5rem;\n }\n\n .insforge-auth-title {\n font-size: 1.75rem;\n }\n\n .insforge-verification-code-container {\n gap: 8px;\n }\n\n .insforge-verification-code-input {\n width: 40px;\n height: 48px;\n font-size: 20px;\n }\n}\n\n";
10
+ if (document.head) {
11
+ document.head.appendChild(style);
12
+ }
13
+ }
14
+ }
15
+
2
16
  "use strict";
3
17
  "use client";
4
18
  var __create = Object.create;
@@ -123,9 +137,8 @@ function InsforgeProvider({
123
137
  const userData = {
124
138
  id: cachedData.user.id,
125
139
  email: cachedData.user.email,
126
- createdAt: cachedData.user.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
127
- updatedAt: cachedData.user.updatedAt || (/* @__PURE__ */ new Date()).toISOString(),
128
- ...cachedData.profile
140
+ name: cachedData.profile?.nickname || "",
141
+ avatarUrl: cachedData.profile?.avatar_url || ""
129
142
  };
130
143
  setUser(userData);
131
144
  setSession({
@@ -152,9 +165,8 @@ function InsforgeProvider({
152
165
  const userData = {
153
166
  id: userResult.data.user.id,
154
167
  email: userResult.data.user.email,
155
- createdAt: userResult.data.user.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
156
- updatedAt: userResult.data.user.updatedAt || (/* @__PURE__ */ new Date()).toISOString(),
157
- ...userResult.data.profile
168
+ name: userResult.data.profile?.nickname || "",
169
+ avatarUrl: userResult.data.profile?.avatar_url || ""
158
170
  };
159
171
  setUser(userData);
160
172
  setSession({
@@ -205,120 +217,90 @@ function InsforgeProvider({
205
217
  }
206
218
  };
207
219
  }, []);
220
+ const handleAuthSuccess = (0, import_react.useCallback)(
221
+ async (authToken, fallbackUser) => {
222
+ const userResult = await insforge.auth.getCurrentUser();
223
+ if (userResult.data) {
224
+ const userData = {
225
+ id: userResult.data.user.id,
226
+ email: userResult.data.user.email,
227
+ name: userResult.data.profile?.nickname || "",
228
+ avatarUrl: userResult.data.profile?.avatar_url || ""
229
+ };
230
+ const sessionData = {
231
+ userId: userResult.data.user.id,
232
+ token: authToken,
233
+ expiresAt: "",
234
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
235
+ };
236
+ setUser(userData);
237
+ setSession(sessionData);
238
+ localStorage.setItem("insforge-user-profile", JSON.stringify(userResult.data));
239
+ if (onAuthChange) {
240
+ onAuthChange(userData);
241
+ }
242
+ try {
243
+ await syncTokenToCookie(authToken);
244
+ } catch (error) {
245
+ }
246
+ } else if (fallbackUser) {
247
+ const userData = {
248
+ id: fallbackUser.id || "",
249
+ email: fallbackUser.email || "",
250
+ name: fallbackUser.name || "",
251
+ avatarUrl: ""
252
+ };
253
+ setUser(userData);
254
+ setSession({
255
+ userId: fallbackUser.id || "",
256
+ token: authToken,
257
+ expiresAt: "",
258
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
259
+ });
260
+ if (onAuthChange) {
261
+ onAuthChange(userData);
262
+ }
263
+ }
264
+ },
265
+ [insforge, onAuthChange]
266
+ );
208
267
  const signIn = (0, import_react.useCallback)(
209
268
  async (email, password) => {
210
269
  const sdkResult = await insforge.auth.signInWithPassword({ email, password });
211
270
  if (sdkResult.data) {
212
- const userResult = await insforge.auth.getCurrentUser();
213
- if (userResult.data) {
214
- const userData = {
215
- id: userResult.data.user.id,
216
- email: userResult.data.user.email,
217
- name: userResult.data.user.name || void 0,
218
- createdAt: userResult.data.user.createdAt,
219
- updatedAt: userResult.data.user.updatedAt,
220
- ...userResult.data.profile
221
- // Include profile fields (nickname, avatar_url, etc.)
222
- };
223
- const sessionData = {
224
- userId: userResult.data.user.id,
225
- token: sdkResult.data.accessToken || "",
226
- expiresAt: "",
227
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
228
- };
229
- setUser(userData);
230
- setSession(sessionData);
231
- localStorage.setItem("insforge-user-profile", JSON.stringify(userResult.data));
232
- if (onAuthChange) {
233
- onAuthChange(userData);
234
- }
235
- try {
236
- await syncTokenToCookie(sdkResult.data.accessToken || "");
237
- } catch (error) {
238
- console.error("Please add /api/auth route to your server to sync token to cookie:", error);
239
- }
240
- } else {
241
- const userData = {
271
+ await handleAuthSuccess(
272
+ sdkResult.data.accessToken || "",
273
+ sdkResult.data.user ? {
242
274
  id: sdkResult.data.user.id,
243
275
  email: sdkResult.data.user.email,
244
- name: sdkResult.data.user.name || void 0,
245
- createdAt: sdkResult.data.user.createdAt,
246
- updatedAt: sdkResult.data.user.updatedAt
247
- };
248
- setUser(userData);
249
- setSession({
250
- userId: sdkResult.data.user.id,
251
- token: sdkResult.data.accessToken || "",
252
- expiresAt: "",
253
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
254
- });
255
- if (onAuthChange) {
256
- onAuthChange(userData);
257
- }
258
- }
276
+ name: sdkResult.data.user.name
277
+ } : void 0
278
+ );
259
279
  } else {
260
280
  const errorMessage = sdkResult.error?.message || "Invalid email or password";
261
281
  throw new Error(errorMessage);
262
282
  }
263
283
  },
264
- [insforge, onAuthChange]
284
+ [insforge, handleAuthSuccess]
265
285
  );
266
286
  const signUp = (0, import_react.useCallback)(
267
287
  async (email, password) => {
268
288
  const sdkResult = await insforge.auth.signUp({ email, password });
269
289
  if (sdkResult.data) {
270
- const userResult = await insforge.auth.getCurrentUser();
271
- if (userResult.data) {
272
- const userData = {
273
- id: userResult.data.user.id,
274
- email: userResult.data.user.email,
275
- name: userResult.data.user.name || void 0,
276
- createdAt: userResult.data.user.createdAt,
277
- updatedAt: userResult.data.user.updatedAt,
278
- ...userResult.data.profile
279
- // Include profile fields (nickname, avatar_url, etc.)
280
- };
281
- const sessionData = {
282
- userId: userResult.data.user.id,
283
- token: sdkResult.data.accessToken || "",
284
- expiresAt: "",
285
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
286
- };
287
- setUser(userData);
288
- setSession(sessionData);
289
- localStorage.setItem("insforge-user-profile", JSON.stringify(userResult.data));
290
- if (onAuthChange) {
291
- onAuthChange(userData);
292
- }
293
- try {
294
- await syncTokenToCookie(sdkResult.data.accessToken || "");
295
- } catch (error) {
296
- }
297
- } else {
298
- const userData = {
290
+ await handleAuthSuccess(
291
+ sdkResult.data.accessToken || "",
292
+ sdkResult.data.user ? {
299
293
  id: sdkResult.data.user.id,
300
294
  email: sdkResult.data.user.email,
301
- name: sdkResult.data.user.name || void 0,
302
- createdAt: sdkResult.data.user.createdAt,
303
- updatedAt: sdkResult.data.user.updatedAt
304
- };
305
- setUser(userData);
306
- setSession({
307
- userId: sdkResult.data.user.id,
308
- token: sdkResult.data.accessToken || "",
309
- expiresAt: "",
310
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
311
- });
312
- if (onAuthChange) {
313
- onAuthChange(userData);
314
- }
315
- }
295
+ name: sdkResult.data.user.name
296
+ } : void 0
297
+ );
316
298
  } else {
317
299
  const errorMessage = sdkResult.error?.message || "Sign up failed";
318
300
  throw new Error(errorMessage);
319
301
  }
320
302
  },
321
- [insforge, onAuthChange]
303
+ [insforge, handleAuthSuccess]
322
304
  );
323
305
  const signOut = (0, import_react.useCallback)(async () => {
324
306
  await insforge.auth.signOut();
@@ -337,7 +319,10 @@ function InsforgeProvider({
337
319
  const updateUser = (0, import_react.useCallback)(
338
320
  async (data) => {
339
321
  if (!user) throw new Error("No user signed in");
340
- const result = await insforge.auth.setProfile(data);
322
+ const result = await insforge.auth.setProfile({
323
+ nickname: data.name || "",
324
+ avatar_url: data.avatarUrl || ""
325
+ });
341
326
  if (result.data) {
342
327
  const updatedUser = { ...user, ...result.data };
343
328
  setUser(updatedUser);
@@ -400,8 +385,8 @@ function useSession() {
400
385
  }
401
386
 
402
387
  // src/components/SignIn.tsx
403
- var import_react5 = require("react");
404
- var import_sdk3 = require("@insforge/sdk");
388
+ var import_react6 = require("react");
389
+ var import_sdk4 = require("@insforge/sdk");
405
390
 
406
391
  // src/hooks/useOAuthProviders.ts
407
392
  var import_react2 = require("react");
@@ -421,8 +406,8 @@ function useOAuthProviders() {
421
406
  console.warn("[useOAuthProviders] Failed to fetch OAuth providers:", error);
422
407
  setProviders([]);
423
408
  } else if (data) {
424
- const configuredProviders = data.filter((p) => p.isConfigured).map((p) => p.provider);
425
- setProviders(configuredProviders);
409
+ const providerNames = data.map((p) => p.provider);
410
+ setProviders(providerNames);
426
411
  } else {
427
412
  setProviders([]);
428
413
  }
@@ -443,6 +428,43 @@ function useOAuthProviders() {
443
428
  return { providers, isLoaded };
444
429
  }
445
430
 
431
+ // src/hooks/useEmailAuthConfig.ts
432
+ var import_react3 = require("react");
433
+ var import_sdk3 = require("@insforge/sdk");
434
+ function useEmailAuthConfig() {
435
+ const { baseUrl } = useInsforge();
436
+ const [config, setConfig] = (0, import_react3.useState)(null);
437
+ const [isLoaded, setIsLoaded] = (0, import_react3.useState)(false);
438
+ (0, import_react3.useEffect)(() => {
439
+ let mounted = true;
440
+ async function fetchConfig() {
441
+ try {
442
+ const insforge = (0, import_sdk3.createClient)({ baseUrl });
443
+ const { data, error } = await insforge.auth.getEmailAuthConfig();
444
+ if (!mounted) return;
445
+ if (error) {
446
+ console.warn("[useEmailAuthConfig] Failed to fetch email auth config:", error);
447
+ setConfig(null);
448
+ } else {
449
+ setConfig(data);
450
+ }
451
+ setIsLoaded(true);
452
+ } catch (error) {
453
+ console.warn("[useEmailAuthConfig] Unexpected error:", error);
454
+ if (mounted) {
455
+ setConfig(null);
456
+ setIsLoaded(true);
457
+ }
458
+ }
459
+ }
460
+ fetchConfig();
461
+ return () => {
462
+ mounted = false;
463
+ };
464
+ }, [baseUrl]);
465
+ return { config, isLoaded };
466
+ }
467
+
446
468
  // src/components/auth/AuthBranding.tsx
447
469
  var import_link = __toESM(require("next/link"));
448
470
  var import_jsx_runtime2 = require("react/jsx-runtime");
@@ -553,35 +575,59 @@ function AuthFormField({ label, id, className = "", ...props }) {
553
575
  }
554
576
 
555
577
  // src/components/auth/AuthPasswordField.tsx
556
- var import_react3 = require("react");
578
+ var import_react4 = require("react");
557
579
  var import_lucide_react3 = require("lucide-react");
558
580
 
559
581
  // src/components/auth/AuthPasswordStrengthIndicator.tsx
560
582
  var import_lucide_react2 = require("lucide-react");
561
583
  var import_jsx_runtime7 = require("react/jsx-runtime");
562
- var requirements = [
563
- {
564
- label: "At least 1 Uppercase letter",
565
- test: (pwd) => /[A-Z]/.test(pwd)
566
- },
567
- {
568
- label: "At least 1 Number",
569
- test: (pwd) => /\d/.test(pwd)
570
- },
571
- {
572
- label: "Special character (e.g. !?<>@#$%)",
573
- test: (pwd) => /[!@#$%^&*()_+\-=[\]{};\\|,.<>/?]/.test(pwd)
574
- },
575
- {
576
- label: "8 characters or more",
577
- test: (pwd) => pwd.length >= 8
584
+ function createRequirements(config) {
585
+ const requirements = [];
586
+ const minLength = config.passwordMinLength;
587
+ const requireUppercase = config.requireUppercase;
588
+ const requireLowercase = config.requireLowercase;
589
+ const requireNumber = config.requireNumber;
590
+ const requireSpecialChar = config.requireSpecialChar;
591
+ if (requireUppercase) {
592
+ requirements.push({
593
+ label: "At least 1 Uppercase letter",
594
+ test: (pwd) => /[A-Z]/.test(pwd)
595
+ });
596
+ }
597
+ if (requireLowercase) {
598
+ requirements.push({
599
+ label: "At least 1 Lowercase letter",
600
+ test: (pwd) => /[a-z]/.test(pwd)
601
+ });
602
+ }
603
+ if (requireNumber) {
604
+ requirements.push({
605
+ label: "At least 1 Number",
606
+ test: (pwd) => /\d/.test(pwd)
607
+ });
608
+ }
609
+ if (requireSpecialChar) {
610
+ requirements.push({
611
+ label: "Special character (e.g. !?<>@#$%)",
612
+ test: (pwd) => /[!@#$%^&*()_+\-=[\]{};\\|,.<>/?]/.test(pwd)
613
+ });
578
614
  }
579
- ];
580
- function validatePasswordStrength(password) {
615
+ requirements.push({
616
+ label: `${minLength} characters or more`,
617
+ test: (pwd) => pwd.length >= minLength
618
+ });
619
+ return requirements;
620
+ }
621
+ function validatePasswordStrength(password, config) {
581
622
  if (!password) return false;
623
+ const requirements = createRequirements(config);
582
624
  return requirements.every((req) => req.test(password));
583
625
  }
584
- function AuthPasswordStrengthIndicator({ password }) {
626
+ function AuthPasswordStrengthIndicator({
627
+ password,
628
+ config
629
+ }) {
630
+ const requirements = createRequirements(config);
585
631
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "insforge-password-strength", children: requirements.map((requirement, index) => {
586
632
  const isValid = requirement.test(password);
587
633
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "insforge-password-requirement", children: [
@@ -603,14 +649,15 @@ function AuthPasswordField({
603
649
  label,
604
650
  id,
605
651
  showStrengthIndicator = false,
652
+ emailAuthConfig,
606
653
  forgotPasswordLink,
607
654
  value,
608
655
  className = "",
609
656
  onFocus,
610
657
  ...props
611
658
  }) {
612
- const [showPassword, setShowPassword] = (0, import_react3.useState)(false);
613
- const [showStrength, setShowStrength] = (0, import_react3.useState)(false);
659
+ const [showPassword, setShowPassword] = (0, import_react4.useState)(false);
660
+ const [showStrength, setShowStrength] = (0, import_react4.useState)(false);
614
661
  const handleFocus = (e) => {
615
662
  if (showStrengthIndicator) {
616
663
  setShowStrength(true);
@@ -645,7 +692,13 @@ function AuthPasswordField({
645
692
  }
646
693
  )
647
694
  ] }),
648
- showStrengthIndicator && showStrength && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AuthPasswordStrengthIndicator, { password: String(value || "") })
695
+ showStrengthIndicator && showStrength && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
696
+ AuthPasswordStrengthIndicator,
697
+ {
698
+ password: String(value || ""),
699
+ config: emailAuthConfig
700
+ }
701
+ )
649
702
  ] });
650
703
  }
651
704
 
@@ -937,7 +990,7 @@ function AuthOAuthProviders({
937
990
  }
938
991
 
939
992
  // src/components/auth/AuthVerificationCodeInput.tsx
940
- var import_react4 = require("react");
993
+ var import_react5 = require("react");
941
994
  var import_jsx_runtime15 = require("react/jsx-runtime");
942
995
  function AuthVerificationCodeInput({
943
996
  length = 6,
@@ -946,7 +999,7 @@ function AuthVerificationCodeInput({
946
999
  onChange,
947
1000
  disabled = false
948
1001
  }) {
949
- const inputRefs = (0, import_react4.useRef)([]);
1002
+ const inputRefs = (0, import_react5.useRef)([]);
950
1003
  const handleChange = (index, digit) => {
951
1004
  if (digit.length > 1) return;
952
1005
  if (digit && !/^\d$/.test(digit)) return;
@@ -1030,12 +1083,13 @@ function SignIn({
1030
1083
  }) {
1031
1084
  const { signIn, baseUrl } = useInsforge();
1032
1085
  const { providers: oauthProviders } = useOAuthProviders();
1033
- const [email, setEmail] = (0, import_react5.useState)("");
1034
- const [password, setPassword] = (0, import_react5.useState)("");
1035
- const [error, setError] = (0, import_react5.useState)("");
1036
- const [loading, setLoading] = (0, import_react5.useState)(false);
1037
- const [oauthLoading, setOauthLoading] = (0, import_react5.useState)(null);
1038
- const insforge = (0, import_react5.useState)(() => (0, import_sdk3.createClient)({ baseUrl }))[0];
1086
+ const { config: emailAuthConfig } = useEmailAuthConfig();
1087
+ const [email, setEmail] = (0, import_react6.useState)("");
1088
+ const [password, setPassword] = (0, import_react6.useState)("");
1089
+ const [error, setError] = (0, import_react6.useState)("");
1090
+ const [loading, setLoading] = (0, import_react6.useState)(false);
1091
+ const [oauthLoading, setOauthLoading] = (0, import_react6.useState)(null);
1092
+ const insforge = (0, import_react6.useState)(() => (0, import_sdk4.createClient)({ baseUrl }))[0];
1039
1093
  async function handleSubmit(e) {
1040
1094
  e.preventDefault();
1041
1095
  setLoading(true);
@@ -1097,7 +1151,15 @@ function SignIn({
1097
1151
  value: password,
1098
1152
  onChange: (e) => setPassword(e.target.value),
1099
1153
  required: true,
1100
- autoComplete: "current-password"
1154
+ autoComplete: "current-password",
1155
+ emailAuthConfig: emailAuthConfig || {
1156
+ requireEmailVerification: false,
1157
+ passwordMinLength: 6,
1158
+ requireNumber: false,
1159
+ requireLowercase: false,
1160
+ requireUppercase: false,
1161
+ requireSpecialChar: false
1162
+ }
1101
1163
  }
1102
1164
  ),
1103
1165
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -1127,8 +1189,8 @@ function SignIn({
1127
1189
  }
1128
1190
 
1129
1191
  // src/components/SignUp.tsx
1130
- var import_react6 = require("react");
1131
- var import_sdk4 = require("@insforge/sdk");
1192
+ var import_react7 = require("react");
1193
+ var import_sdk5 = require("@insforge/sdk");
1132
1194
  var import_jsx_runtime17 = require("react/jsx-runtime");
1133
1195
  function SignUp({
1134
1196
  afterSignUpUrl = "/",
@@ -1153,17 +1215,18 @@ function SignUp({
1153
1215
  }) {
1154
1216
  const { signUp, baseUrl } = useInsforge();
1155
1217
  const { providers: oauthProviders } = useOAuthProviders();
1156
- const [email, setEmail] = (0, import_react6.useState)("");
1157
- const [password, setPassword] = (0, import_react6.useState)("");
1158
- const [error, setError] = (0, import_react6.useState)("");
1159
- const [loading, setLoading] = (0, import_react6.useState)(false);
1160
- const [oauthLoading, setOauthLoading] = (0, import_react6.useState)(null);
1161
- const insforge = (0, import_react6.useState)(() => (0, import_sdk4.createClient)({ baseUrl }))[0];
1218
+ const { config: emailAuthConfig } = useEmailAuthConfig();
1219
+ const [email, setEmail] = (0, import_react7.useState)("");
1220
+ const [password, setPassword] = (0, import_react7.useState)("");
1221
+ const [error, setError] = (0, import_react7.useState)("");
1222
+ const [loading, setLoading] = (0, import_react7.useState)(false);
1223
+ const [oauthLoading, setOauthLoading] = (0, import_react7.useState)(null);
1224
+ const insforge = (0, import_react7.useState)(() => (0, import_sdk5.createClient)({ baseUrl }))[0];
1162
1225
  async function handleCredentialsSubmit(e) {
1163
1226
  e.preventDefault();
1164
1227
  setLoading(true);
1165
1228
  setError("");
1166
- if (!validatePasswordStrength(password)) {
1229
+ if (emailAuthConfig && !validatePasswordStrength(password, emailAuthConfig)) {
1167
1230
  setError("Password does not meet all requirements");
1168
1231
  setLoading(false);
1169
1232
  return;
@@ -1228,9 +1291,17 @@ function SignUp({
1228
1291
  value: password,
1229
1292
  onChange: (e) => setPassword(e.target.value),
1230
1293
  required: true,
1231
- minLength: 8,
1294
+ minLength: emailAuthConfig?.passwordMinLength ?? 8,
1232
1295
  autoComplete: "new-password",
1233
- showStrengthIndicator: true
1296
+ showStrengthIndicator: true,
1297
+ emailAuthConfig: emailAuthConfig || {
1298
+ requireEmailVerification: false,
1299
+ passwordMinLength: 6,
1300
+ requireNumber: false,
1301
+ requireLowercase: false,
1302
+ requireUppercase: false,
1303
+ requireSpecialChar: false
1304
+ }
1234
1305
  }
1235
1306
  ),
1236
1307
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
@@ -1267,7 +1338,7 @@ function SignUp({
1267
1338
  }
1268
1339
 
1269
1340
  // src/components/UserButton.tsx
1270
- var import_react7 = require("react");
1341
+ var import_react8 = require("react");
1271
1342
  var import_lucide_react6 = require("lucide-react");
1272
1343
  var import_jsx_runtime18 = require("react/jsx-runtime");
1273
1344
  function UserButton({
@@ -1276,9 +1347,9 @@ function UserButton({
1276
1347
  appearance = {}
1277
1348
  }) {
1278
1349
  const { user, signOut } = useInsforge();
1279
- const [isOpen, setIsOpen] = (0, import_react7.useState)(false);
1280
- const dropdownRef = (0, import_react7.useRef)(null);
1281
- (0, import_react7.useEffect)(() => {
1350
+ const [isOpen, setIsOpen] = (0, import_react8.useState)(false);
1351
+ const dropdownRef = (0, import_react8.useRef)(null);
1352
+ (0, import_react8.useEffect)(() => {
1282
1353
  function handleClickOutside(event) {
1283
1354
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
1284
1355
  setIsOpen(false);
@@ -1343,7 +1414,7 @@ function SignedOut({ children }) {
1343
1414
  }
1344
1415
 
1345
1416
  // src/components/Protect.tsx
1346
- var import_react8 = require("react");
1417
+ var import_react9 = require("react");
1347
1418
  var import_navigation = require("next/navigation");
1348
1419
  var import_jsx_runtime21 = require("react/jsx-runtime");
1349
1420
  function Protect({
@@ -1354,7 +1425,7 @@ function Protect({
1354
1425
  }) {
1355
1426
  const { isSignedIn, isLoaded, user } = useInsforge();
1356
1427
  const router = (0, import_navigation.useRouter)();
1357
- (0, import_react8.useEffect)(() => {
1428
+ (0, import_react9.useEffect)(() => {
1358
1429
  if (isLoaded && !isSignedIn) {
1359
1430
  router.push(redirectTo);
1360
1431
  } else if (isLoaded && isSignedIn && condition && user) {