@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/README.md +2 -0
- package/dist/api.js +2 -2
- package/dist/api.js.map +1 -1
- package/dist/api.mjs +2 -2
- package/dist/api.mjs.map +1 -1
- package/dist/index.d.mts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +222 -151
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +219 -148
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
127
|
-
|
|
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
|
-
|
|
156
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
|
245
|
-
|
|
246
|
-
|
|
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,
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
|
302
|
-
|
|
303
|
-
|
|
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,
|
|
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(
|
|
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
|
|
404
|
-
var
|
|
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
|
|
425
|
-
setProviders(
|
|
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
|
|
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
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
}
|
|
575
|
-
{
|
|
576
|
-
|
|
577
|
-
|
|
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
|
-
|
|
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({
|
|
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,
|
|
613
|
-
const [showStrength, setShowStrength] = (0,
|
|
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)(
|
|
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
|
|
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,
|
|
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
|
|
1034
|
-
const [
|
|
1035
|
-
const [
|
|
1036
|
-
const [
|
|
1037
|
-
const [
|
|
1038
|
-
const
|
|
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
|
|
1131
|
-
var
|
|
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
|
|
1157
|
-
const [
|
|
1158
|
-
const [
|
|
1159
|
-
const [
|
|
1160
|
-
const [
|
|
1161
|
-
const
|
|
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
|
|
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,
|
|
1280
|
-
const dropdownRef = (0,
|
|
1281
|
-
(0,
|
|
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
|
|
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,
|
|
1428
|
+
(0, import_react9.useEffect)(() => {
|
|
1358
1429
|
if (isLoaded && !isSignedIn) {
|
|
1359
1430
|
router.push(redirectTo);
|
|
1360
1431
|
} else if (isLoaded && isSignedIn && condition && user) {
|