@githat/nextjs 0.2.1 → 0.2.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 +580 -45
- package/dist/githat.css +41 -0
- package/dist/index.d.mts +213 -2
- package/dist/index.d.ts +213 -2
- package/dist/index.js +778 -99
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +772 -98
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.d.mts +73 -4
- package/dist/middleware.d.ts +73 -4
- package/dist/middleware.js +96 -12
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +85 -13
- package/dist/middleware.mjs.map +1 -1
- package/dist/proxy.d.mts +78 -0
- package/dist/proxy.d.ts +78 -0
- package/dist/proxy.js +138 -0
- package/dist/proxy.js.map +1 -0
- package/dist/proxy.mjs +101 -0
- package/dist/proxy.mjs.map +1 -0
- package/dist/server.d.mts +164 -0
- package/dist/server.d.ts +164 -0
- package/dist/server.js +203 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +163 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +22 -2
package/dist/index.js
CHANGED
|
@@ -21,16 +21,21 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
// src/index.ts
|
|
22
22
|
var src_exports = {};
|
|
23
23
|
__export(src_exports, {
|
|
24
|
+
ChangePasswordForm: () => ChangePasswordForm,
|
|
25
|
+
ForgotPasswordForm: () => ForgotPasswordForm,
|
|
24
26
|
GitHatProvider: () => GitHatProvider,
|
|
25
27
|
OrgSwitcher: () => OrgSwitcher,
|
|
26
28
|
ProtectedRoute: () => ProtectedRoute,
|
|
29
|
+
ResetPasswordForm: () => ResetPasswordForm,
|
|
27
30
|
SignInButton: () => SignInButton,
|
|
28
31
|
SignInForm: () => SignInForm,
|
|
29
32
|
SignUpButton: () => SignUpButton,
|
|
30
33
|
SignUpForm: () => SignUpForm,
|
|
31
34
|
UserButton: () => UserButton,
|
|
32
35
|
VerifiedBadge: () => VerifiedBadge,
|
|
36
|
+
VerifyEmailStatus: () => VerifyEmailStatus,
|
|
33
37
|
useAuth: () => useAuth,
|
|
38
|
+
useData: () => useData,
|
|
34
39
|
useGitHat: () => useGitHat
|
|
35
40
|
});
|
|
36
41
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -53,15 +58,16 @@ function resolveConfig(config) {
|
|
|
53
58
|
signInUrl: config.signInUrl || "/sign-in",
|
|
54
59
|
signUpUrl: config.signUpUrl || "/sign-up",
|
|
55
60
|
afterSignInUrl: config.afterSignInUrl || "/dashboard",
|
|
56
|
-
afterSignOutUrl: config.afterSignOutUrl || "/"
|
|
61
|
+
afterSignOutUrl: config.afterSignOutUrl || "/",
|
|
62
|
+
tokenStorage: config.tokenStorage || "localStorage"
|
|
57
63
|
};
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
// src/client.ts
|
|
61
67
|
var _refreshPromise = null;
|
|
62
|
-
async function refreshTokens(apiUrl, appKey) {
|
|
63
|
-
const refreshToken = typeof window !== "undefined" ? localStorage.getItem(TOKEN_KEYS.refreshToken) : null;
|
|
64
|
-
if (!refreshToken) return false;
|
|
68
|
+
async function refreshTokens(apiUrl, appKey, useCookies) {
|
|
69
|
+
const refreshToken = typeof window !== "undefined" && !useCookies ? localStorage.getItem(TOKEN_KEYS.refreshToken) : null;
|
|
70
|
+
if (!useCookies && !refreshToken) return false;
|
|
65
71
|
let orgId = null;
|
|
66
72
|
try {
|
|
67
73
|
const orgStr = localStorage.getItem(TOKEN_KEYS.org);
|
|
@@ -69,18 +75,22 @@ async function refreshTokens(apiUrl, appKey) {
|
|
|
69
75
|
} catch {
|
|
70
76
|
}
|
|
71
77
|
try {
|
|
72
|
-
const
|
|
78
|
+
const refreshUrl = useCookies ? `${apiUrl}/auth/refresh?setCookie=true` : `${apiUrl}/auth/refresh`;
|
|
79
|
+
const res = await fetch(refreshUrl, {
|
|
73
80
|
method: "POST",
|
|
74
81
|
headers: {
|
|
75
82
|
"Content-Type": "application/json",
|
|
76
83
|
"X-GitHat-App-Key": appKey
|
|
77
84
|
},
|
|
78
|
-
|
|
85
|
+
credentials: useCookies ? "include" : "same-origin",
|
|
86
|
+
body: JSON.stringify(useCookies ? { orgId } : { refreshToken, orgId })
|
|
79
87
|
});
|
|
80
88
|
if (!res.ok) return false;
|
|
81
89
|
const data = await res.json();
|
|
82
|
-
if (
|
|
83
|
-
|
|
90
|
+
if (!useCookies) {
|
|
91
|
+
if (data.accessToken) localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
|
|
92
|
+
if (data.refreshToken) localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
|
|
93
|
+
}
|
|
84
94
|
if (data.org) localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
|
|
85
95
|
return true;
|
|
86
96
|
} catch {
|
|
@@ -90,53 +100,66 @@ async function refreshTokens(apiUrl, appKey) {
|
|
|
90
100
|
function clearAuth() {
|
|
91
101
|
if (typeof window === "undefined") return;
|
|
92
102
|
Object.values(TOKEN_KEYS).forEach((key) => localStorage.removeItem(key));
|
|
93
|
-
window.dispatchEvent(
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
window.dispatchEvent(
|
|
104
|
+
new CustomEvent("githat:auth-changed", {
|
|
105
|
+
detail: { user: null, org: null, signedIn: false }
|
|
106
|
+
})
|
|
107
|
+
);
|
|
96
108
|
}
|
|
97
|
-
function createClient(apiUrl, appKey) {
|
|
98
|
-
|
|
109
|
+
function createClient(apiUrl, appKey, options = {}) {
|
|
110
|
+
const { useCookies = false } = options;
|
|
111
|
+
async function fetchApi(endpoint, fetchOptions = {}) {
|
|
99
112
|
const url = `${apiUrl}${endpoint}`;
|
|
100
|
-
const token = typeof window !== "undefined" ? localStorage.getItem(TOKEN_KEYS.accessToken) : null;
|
|
113
|
+
const token = typeof window !== "undefined" && !useCookies ? localStorage.getItem(TOKEN_KEYS.accessToken) : null;
|
|
101
114
|
const headers = {
|
|
102
115
|
"Content-Type": "application/json",
|
|
103
116
|
"X-GitHat-App-Key": appKey,
|
|
104
117
|
...token && { Authorization: `Bearer ${token}` },
|
|
105
|
-
...
|
|
118
|
+
...fetchOptions.headers
|
|
106
119
|
};
|
|
107
120
|
let response;
|
|
108
121
|
try {
|
|
109
|
-
response = await fetch(url, {
|
|
122
|
+
response = await fetch(url, {
|
|
123
|
+
...fetchOptions,
|
|
124
|
+
headers,
|
|
125
|
+
credentials: useCookies ? "include" : "same-origin"
|
|
126
|
+
});
|
|
110
127
|
} catch (networkError) {
|
|
111
128
|
if (networkError instanceof TypeError) {
|
|
112
|
-
const isMissingKey = !appKey || !appKey.startsWith("pk_live_");
|
|
129
|
+
const isMissingKey = !appKey || !appKey.startsWith("pk_live_") && !appKey.startsWith("pk_test_");
|
|
113
130
|
const isLocalhost = typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1");
|
|
114
131
|
if (isMissingKey && !isLocalhost) {
|
|
115
132
|
throw new Error(
|
|
116
|
-
"Missing
|
|
133
|
+
"GitHat: Missing or invalid publishable key. Add NEXT_PUBLIC_GITHAT_PUBLISHABLE_KEY to your environment variables. Get your key at https://githat.io/dashboard/apps"
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
if (isLocalhost) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
"GitHat: Cannot reach api.githat.io. Check your internet connection."
|
|
117
139
|
);
|
|
118
140
|
}
|
|
119
141
|
throw new Error(
|
|
120
|
-
"
|
|
142
|
+
"GitHat: API request failed. Verify your publishable key and app domain at https://githat.io/dashboard/apps"
|
|
121
143
|
);
|
|
122
144
|
}
|
|
123
145
|
throw networkError;
|
|
124
146
|
}
|
|
125
147
|
if (response.status === 401) {
|
|
126
148
|
if (!_refreshPromise) {
|
|
127
|
-
_refreshPromise = refreshTokens(apiUrl, appKey).finally(() => {
|
|
149
|
+
_refreshPromise = refreshTokens(apiUrl, appKey, useCookies).finally(() => {
|
|
128
150
|
_refreshPromise = null;
|
|
129
151
|
});
|
|
130
152
|
}
|
|
131
153
|
const refreshed = await _refreshPromise;
|
|
132
154
|
if (refreshed) {
|
|
133
|
-
const newToken = localStorage.getItem(TOKEN_KEYS.accessToken);
|
|
155
|
+
const newToken = !useCookies && typeof window !== "undefined" ? localStorage.getItem(TOKEN_KEYS.accessToken) : null;
|
|
134
156
|
const retryResponse = await fetch(url, {
|
|
135
|
-
...
|
|
157
|
+
...fetchOptions,
|
|
136
158
|
headers: {
|
|
137
159
|
...headers,
|
|
138
160
|
...newToken && { Authorization: `Bearer ${newToken}` }
|
|
139
|
-
}
|
|
161
|
+
},
|
|
162
|
+
credentials: useCookies ? "include" : "same-origin"
|
|
140
163
|
});
|
|
141
164
|
const retryData = await retryResponse.json();
|
|
142
165
|
if (!retryResponse.ok) throw new Error(retryData.error || "Request failed");
|
|
@@ -155,40 +178,108 @@ function createClient(apiUrl, appKey) {
|
|
|
155
178
|
// src/provider.tsx
|
|
156
179
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
157
180
|
var GitHatContext = (0, import_react.createContext)(null);
|
|
181
|
+
function isDevMode(key) {
|
|
182
|
+
return !key || !key.startsWith("pk_live_") && !key.startsWith("pk_test_");
|
|
183
|
+
}
|
|
184
|
+
function DevModeBanner() {
|
|
185
|
+
const [dismissed, setDismissed] = (0, import_react.useState)(() => {
|
|
186
|
+
if (typeof window === "undefined") return true;
|
|
187
|
+
return localStorage.getItem("githat_dev_banner_dismissed") === "1";
|
|
188
|
+
});
|
|
189
|
+
if (dismissed || typeof window === "undefined") return null;
|
|
190
|
+
const hostname = window.location.hostname;
|
|
191
|
+
if (hostname !== "localhost" && hostname !== "127.0.0.1") return null;
|
|
192
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "githat-dev-banner", role: "status", children: [
|
|
193
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
194
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "GitHat Dev Mode" }),
|
|
195
|
+
" \u2014 No publishable key. Auth works on localhost.",
|
|
196
|
+
" ",
|
|
197
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: "https://githat.io/dashboard/apps", target: "_blank", rel: "noopener noreferrer", children: "Get your key" })
|
|
198
|
+
] }),
|
|
199
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
200
|
+
"button",
|
|
201
|
+
{
|
|
202
|
+
onClick: () => {
|
|
203
|
+
setDismissed(true);
|
|
204
|
+
localStorage.setItem("githat_dev_banner_dismissed", "1");
|
|
205
|
+
},
|
|
206
|
+
"aria-label": "Dismiss",
|
|
207
|
+
children: "\xD7"
|
|
208
|
+
}
|
|
209
|
+
)
|
|
210
|
+
] });
|
|
211
|
+
}
|
|
158
212
|
function GitHatProvider({ config: rawConfig, children }) {
|
|
159
213
|
const config = (0, import_react.useMemo)(() => resolveConfig(rawConfig), [rawConfig]);
|
|
160
|
-
const
|
|
214
|
+
const useCookies = config.tokenStorage === "cookie";
|
|
215
|
+
const devMode = isDevMode(config.publishableKey);
|
|
216
|
+
const clientRef = (0, import_react.useRef)(createClient(config.apiUrl, config.publishableKey, { useCookies }));
|
|
217
|
+
(0, import_react.useEffect)(() => {
|
|
218
|
+
if (!devMode || typeof window === "undefined") return;
|
|
219
|
+
const hostname = window.location.hostname;
|
|
220
|
+
if (hostname === "localhost" || hostname === "127.0.0.1") {
|
|
221
|
+
console.warn(
|
|
222
|
+
"%c GitHat Dev Mode %c No publishable key configured. Auth works on localhost but will fail in production. Get your key at https://githat.io/dashboard/apps",
|
|
223
|
+
"background: #f59e0b; color: #000; font-weight: bold; padding: 2px 6px; border-radius: 3px;",
|
|
224
|
+
"color: #f59e0b;"
|
|
225
|
+
);
|
|
226
|
+
} else {
|
|
227
|
+
console.error(
|
|
228
|
+
"%c GitHat %c Missing publishable key. Auth requests will fail. Add NEXT_PUBLIC_GITHAT_PUBLISHABLE_KEY to your environment. Get your key at https://githat.io/dashboard/apps",
|
|
229
|
+
"background: #ef4444; color: #fff; font-weight: bold; padding: 2px 6px; border-radius: 3px;",
|
|
230
|
+
"color: #ef4444;"
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}, []);
|
|
161
234
|
const [user, setUser] = (0, import_react.useState)(null);
|
|
162
235
|
const [org, setOrg] = (0, import_react.useState)(null);
|
|
163
236
|
const [isSignedIn, setIsSignedIn] = (0, import_react.useState)(false);
|
|
164
237
|
const [isLoading, setIsLoading] = (0, import_react.useState)(true);
|
|
165
238
|
const [authError, setAuthError] = (0, import_react.useState)(null);
|
|
166
239
|
(0, import_react.useEffect)(() => {
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (
|
|
240
|
+
const validateSession = async () => {
|
|
241
|
+
try {
|
|
242
|
+
if (!useCookies) {
|
|
243
|
+
const token = localStorage.getItem(TOKEN_KEYS.accessToken);
|
|
244
|
+
const storedUser = localStorage.getItem(TOKEN_KEYS.user);
|
|
245
|
+
if (!token || !storedUser) {
|
|
246
|
+
setIsLoading(false);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const data = await clientRef.current.fetchApi("/auth/me");
|
|
251
|
+
if (data.user) {
|
|
252
|
+
setUser(data.user);
|
|
253
|
+
setOrg(data.currentOrg || null);
|
|
254
|
+
setIsSignedIn(true);
|
|
255
|
+
setAuthError(null);
|
|
256
|
+
if (!useCookies) {
|
|
257
|
+
localStorage.setItem(TOKEN_KEYS.user, JSON.stringify(data.user));
|
|
258
|
+
if (data.currentOrg) {
|
|
259
|
+
localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.currentOrg));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
} catch (err) {
|
|
264
|
+
const error = err;
|
|
265
|
+
if (error.message === "Session expired") {
|
|
179
266
|
clientRef.current.clearAuth();
|
|
180
|
-
} else {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
267
|
+
} else if (!useCookies) {
|
|
268
|
+
const storedUser = localStorage.getItem(TOKEN_KEYS.user);
|
|
269
|
+
if (storedUser) {
|
|
270
|
+
try {
|
|
271
|
+
setUser(JSON.parse(storedUser));
|
|
272
|
+
setIsSignedIn(true);
|
|
273
|
+
} catch {
|
|
274
|
+
}
|
|
184
275
|
}
|
|
185
|
-
setAuthError(
|
|
276
|
+
setAuthError(error.message || "Failed to verify session");
|
|
186
277
|
}
|
|
187
|
-
}
|
|
188
|
-
} else {
|
|
278
|
+
}
|
|
189
279
|
setIsLoading(false);
|
|
190
|
-
}
|
|
191
|
-
|
|
280
|
+
};
|
|
281
|
+
validateSession();
|
|
282
|
+
}, [useCookies]);
|
|
192
283
|
(0, import_react.useEffect)(() => {
|
|
193
284
|
const handleAuthChanged = (e) => {
|
|
194
285
|
const detail = e.detail;
|
|
@@ -206,30 +297,36 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
206
297
|
return () => window.removeEventListener("githat:auth-changed", handleAuthChanged);
|
|
207
298
|
}, []);
|
|
208
299
|
const signIn = (0, import_react.useCallback)(async (email, password) => {
|
|
209
|
-
const
|
|
300
|
+
const loginUrl = useCookies ? "/auth/login?setCookie=true" : "/auth/login";
|
|
301
|
+
const data = await clientRef.current.fetchApi(loginUrl, {
|
|
210
302
|
method: "POST",
|
|
211
303
|
body: JSON.stringify({ email, password })
|
|
212
304
|
});
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
305
|
+
if (!useCookies && data.accessToken && data.refreshToken) {
|
|
306
|
+
localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
|
|
307
|
+
localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
|
|
308
|
+
localStorage.setItem(TOKEN_KEYS.user, JSON.stringify(data.user));
|
|
309
|
+
if (data.org) localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
|
|
310
|
+
}
|
|
217
311
|
setUser(data.user);
|
|
218
312
|
setOrg(data.org || null);
|
|
219
313
|
setIsSignedIn(true);
|
|
220
314
|
window.dispatchEvent(new CustomEvent("githat:auth-changed", {
|
|
221
315
|
detail: { user: data.user, org: data.org, signedIn: true }
|
|
222
316
|
}));
|
|
223
|
-
}, []);
|
|
317
|
+
}, [useCookies]);
|
|
224
318
|
const signUp = (0, import_react.useCallback)(async (signUpData) => {
|
|
225
|
-
const
|
|
319
|
+
const registerUrl = useCookies ? "/auth/register?setCookie=true" : "/auth/register";
|
|
320
|
+
const data = await clientRef.current.fetchApi(registerUrl, {
|
|
226
321
|
method: "POST",
|
|
227
322
|
body: JSON.stringify(signUpData)
|
|
228
323
|
});
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
324
|
+
if (!useCookies && data.accessToken && data.refreshToken) {
|
|
325
|
+
localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
|
|
326
|
+
localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
|
|
327
|
+
localStorage.setItem(TOKEN_KEYS.user, JSON.stringify(data.user));
|
|
328
|
+
if (data.org) localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
|
|
329
|
+
}
|
|
233
330
|
setUser(data.user);
|
|
234
331
|
setOrg(data.org || null);
|
|
235
332
|
setIsSignedIn(true);
|
|
@@ -237,10 +334,11 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
237
334
|
detail: { user: data.user, org: data.org, signedIn: true }
|
|
238
335
|
}));
|
|
239
336
|
return { requiresVerification: !data.user.emailVerified, email: signUpData.email };
|
|
240
|
-
}, []);
|
|
337
|
+
}, [useCookies]);
|
|
241
338
|
const signOut = (0, import_react.useCallback)(async () => {
|
|
242
339
|
try {
|
|
243
|
-
|
|
340
|
+
const logoutUrl = useCookies ? "/auth/logout?setCookie=true" : "/auth/logout";
|
|
341
|
+
await clientRef.current.fetchApi(logoutUrl, { method: "POST" });
|
|
244
342
|
} catch {
|
|
245
343
|
}
|
|
246
344
|
clientRef.current.clearAuth();
|
|
@@ -250,22 +348,24 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
250
348
|
if (typeof window !== "undefined" && config.afterSignOutUrl) {
|
|
251
349
|
window.location.href = config.afterSignOutUrl;
|
|
252
350
|
}
|
|
253
|
-
}, [config.afterSignOutUrl]);
|
|
351
|
+
}, [config.afterSignOutUrl, useCookies]);
|
|
254
352
|
const switchOrg = (0, import_react.useCallback)(async (orgId) => {
|
|
255
353
|
try {
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
354
|
+
const switchUrl = useCookies ? `/user/orgs/${orgId}/switch?setCookie=true` : `/user/orgs/${orgId}/switch`;
|
|
355
|
+
const data = await clientRef.current.fetchApi(switchUrl, { method: "POST" });
|
|
356
|
+
if (!useCookies) {
|
|
357
|
+
if (data.accessToken) localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
|
|
358
|
+
if (data.refreshToken) localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
|
|
359
|
+
localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
|
|
360
|
+
}
|
|
361
|
+
setOrg(data.org);
|
|
262
362
|
window.dispatchEvent(new CustomEvent("githat:auth-changed", {
|
|
263
|
-
detail: { user, org:
|
|
363
|
+
detail: { user, org: data.org, signedIn: true }
|
|
264
364
|
}));
|
|
265
365
|
} catch (e) {
|
|
266
366
|
console.error("Org switch failed:", e);
|
|
267
367
|
}
|
|
268
|
-
}, [user]);
|
|
368
|
+
}, [user, useCookies]);
|
|
269
369
|
const value = (0, import_react.useMemo)(() => ({
|
|
270
370
|
user,
|
|
271
371
|
org,
|
|
@@ -278,7 +378,10 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
278
378
|
signOut,
|
|
279
379
|
switchOrg
|
|
280
380
|
}), [user, org, isSignedIn, isLoading, authError, config, signIn, signUp, signOut, switchOrg]);
|
|
281
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
381
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(GitHatContext.Provider, { value, children: [
|
|
382
|
+
devMode && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DevModeBanner, {}),
|
|
383
|
+
children
|
|
384
|
+
] });
|
|
282
385
|
}
|
|
283
386
|
|
|
284
387
|
// src/hooks.ts
|
|
@@ -294,23 +397,205 @@ function useGitHat() {
|
|
|
294
397
|
() => createClient(ctx.config.apiUrl, ctx.config.publishableKey),
|
|
295
398
|
[ctx.config.apiUrl, ctx.config.publishableKey]
|
|
296
399
|
);
|
|
400
|
+
const getOrgMetadata = (0, import_react2.useCallback)(async () => {
|
|
401
|
+
if (!ctx.org?.id) {
|
|
402
|
+
throw new Error("No active organization");
|
|
403
|
+
}
|
|
404
|
+
const response = await client.fetchApi(
|
|
405
|
+
`/orgs/${ctx.org.id}/metadata`
|
|
406
|
+
);
|
|
407
|
+
return response.metadata || {};
|
|
408
|
+
}, [client, ctx.org?.id]);
|
|
409
|
+
const updateOrgMetadata = (0, import_react2.useCallback)(
|
|
410
|
+
async (updates) => {
|
|
411
|
+
if (!ctx.org?.id) {
|
|
412
|
+
throw new Error("No active organization");
|
|
413
|
+
}
|
|
414
|
+
const response = await client.fetchApi(
|
|
415
|
+
`/orgs/${ctx.org.id}/metadata`,
|
|
416
|
+
{
|
|
417
|
+
method: "PATCH",
|
|
418
|
+
body: JSON.stringify(updates)
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
return response.metadata || {};
|
|
422
|
+
},
|
|
423
|
+
[client, ctx.org?.id]
|
|
424
|
+
);
|
|
425
|
+
const forgotPassword = (0, import_react2.useCallback)(
|
|
426
|
+
async (email) => {
|
|
427
|
+
const response = await fetch(`${ctx.config.apiUrl}/auth/forgot-password`, {
|
|
428
|
+
method: "POST",
|
|
429
|
+
headers: { "Content-Type": "application/json" },
|
|
430
|
+
body: JSON.stringify({ email })
|
|
431
|
+
});
|
|
432
|
+
if (!response.ok) {
|
|
433
|
+
const error = await response.json().catch(() => ({}));
|
|
434
|
+
throw new Error(error.message || "Failed to send reset email");
|
|
435
|
+
}
|
|
436
|
+
return { success: true };
|
|
437
|
+
},
|
|
438
|
+
[ctx.config.apiUrl]
|
|
439
|
+
);
|
|
440
|
+
const resetPassword = (0, import_react2.useCallback)(
|
|
441
|
+
async (token, newPassword) => {
|
|
442
|
+
const response = await fetch(`${ctx.config.apiUrl}/auth/reset-password`, {
|
|
443
|
+
method: "POST",
|
|
444
|
+
headers: { "Content-Type": "application/json" },
|
|
445
|
+
body: JSON.stringify({ token, password: newPassword })
|
|
446
|
+
});
|
|
447
|
+
if (!response.ok) {
|
|
448
|
+
const error = await response.json().catch(() => ({}));
|
|
449
|
+
throw new Error(error.message || "Failed to reset password");
|
|
450
|
+
}
|
|
451
|
+
return { success: true };
|
|
452
|
+
},
|
|
453
|
+
[ctx.config.apiUrl]
|
|
454
|
+
);
|
|
455
|
+
const changePassword = (0, import_react2.useCallback)(
|
|
456
|
+
async (currentPassword, newPassword) => {
|
|
457
|
+
await client.fetchApi("/auth/change-password", {
|
|
458
|
+
method: "POST",
|
|
459
|
+
body: JSON.stringify({ currentPassword, newPassword })
|
|
460
|
+
});
|
|
461
|
+
return { success: true };
|
|
462
|
+
},
|
|
463
|
+
[client]
|
|
464
|
+
);
|
|
465
|
+
const verifyEmail = (0, import_react2.useCallback)(
|
|
466
|
+
async (token) => {
|
|
467
|
+
const response = await fetch(`${ctx.config.apiUrl}/auth/verify-email`, {
|
|
468
|
+
method: "POST",
|
|
469
|
+
headers: { "Content-Type": "application/json" },
|
|
470
|
+
body: JSON.stringify({ token })
|
|
471
|
+
});
|
|
472
|
+
if (!response.ok) {
|
|
473
|
+
const error = await response.json().catch(() => ({}));
|
|
474
|
+
throw new Error(error.message || "Failed to verify email");
|
|
475
|
+
}
|
|
476
|
+
return { success: true };
|
|
477
|
+
},
|
|
478
|
+
[ctx.config.apiUrl]
|
|
479
|
+
);
|
|
480
|
+
const resendVerificationEmail = (0, import_react2.useCallback)(
|
|
481
|
+
async (email) => {
|
|
482
|
+
const response = await fetch(`${ctx.config.apiUrl}/auth/resend-verification`, {
|
|
483
|
+
method: "POST",
|
|
484
|
+
headers: { "Content-Type": "application/json" },
|
|
485
|
+
body: JSON.stringify({ email })
|
|
486
|
+
});
|
|
487
|
+
if (!response.ok) {
|
|
488
|
+
const error = await response.json().catch(() => ({}));
|
|
489
|
+
throw new Error(error.message || "Failed to resend verification email");
|
|
490
|
+
}
|
|
491
|
+
return { success: true };
|
|
492
|
+
},
|
|
493
|
+
[ctx.config.apiUrl]
|
|
494
|
+
);
|
|
297
495
|
return {
|
|
298
496
|
fetch: client.fetchApi,
|
|
299
497
|
getUserOrgs: () => client.fetchApi("/user/orgs"),
|
|
300
498
|
verifyMCP: (domain) => client.fetchApi(`/verify/mcp/${domain}`),
|
|
301
|
-
verifyAgent: (wallet) => client.fetchApi(`/verify/agent/${wallet}`)
|
|
499
|
+
verifyAgent: (wallet) => client.fetchApi(`/verify/agent/${wallet}`),
|
|
500
|
+
getOrgMetadata,
|
|
501
|
+
updateOrgMetadata,
|
|
502
|
+
// Password management
|
|
503
|
+
forgotPassword,
|
|
504
|
+
resetPassword,
|
|
505
|
+
changePassword,
|
|
506
|
+
// Email verification
|
|
507
|
+
verifyEmail,
|
|
508
|
+
resendVerificationEmail
|
|
302
509
|
};
|
|
303
510
|
}
|
|
304
511
|
|
|
305
|
-
// src/
|
|
512
|
+
// src/data.ts
|
|
306
513
|
var import_react3 = require("react");
|
|
514
|
+
function useData() {
|
|
515
|
+
const ctx = useAuth();
|
|
516
|
+
const client = (0, import_react3.useMemo)(
|
|
517
|
+
() => createClient(ctx.config.apiUrl, ctx.config.publishableKey),
|
|
518
|
+
[ctx.config.apiUrl, ctx.config.publishableKey]
|
|
519
|
+
);
|
|
520
|
+
return (0, import_react3.useMemo)(() => ({
|
|
521
|
+
/**
|
|
522
|
+
* Store an item in a collection. If the item exists, it will be updated.
|
|
523
|
+
* @param collection - Collection name (e.g., 'orders', 'users')
|
|
524
|
+
* @param data - Data object with required `id` field
|
|
525
|
+
*/
|
|
526
|
+
put: async (collection, data) => {
|
|
527
|
+
if (!data.id) {
|
|
528
|
+
throw new Error('Data must include an "id" field');
|
|
529
|
+
}
|
|
530
|
+
return client.fetchApi(`/data/${collection}/${data.id}`, {
|
|
531
|
+
method: "PUT",
|
|
532
|
+
body: JSON.stringify(data)
|
|
533
|
+
});
|
|
534
|
+
},
|
|
535
|
+
/**
|
|
536
|
+
* Get a single item from a collection.
|
|
537
|
+
* @param collection - Collection name
|
|
538
|
+
* @param id - Item ID
|
|
539
|
+
*/
|
|
540
|
+
get: async (collection, id) => {
|
|
541
|
+
try {
|
|
542
|
+
const result = await client.fetchApi(`/data/${collection}/${id}`);
|
|
543
|
+
return result.item;
|
|
544
|
+
} catch (err) {
|
|
545
|
+
if (err instanceof Error && err.message === "Item not found") {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
throw err;
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
/**
|
|
552
|
+
* Query items from a collection with optional filters and pagination.
|
|
553
|
+
* @param collection - Collection name
|
|
554
|
+
* @param options - Query options (limit, cursor, filter)
|
|
555
|
+
*/
|
|
556
|
+
query: async (collection, options = {}) => {
|
|
557
|
+
const params = new URLSearchParams();
|
|
558
|
+
if (options.limit) params.set("limit", options.limit.toString());
|
|
559
|
+
if (options.cursor) params.set("cursor", options.cursor);
|
|
560
|
+
if (options.filter) params.set("filter", JSON.stringify(options.filter));
|
|
561
|
+
const queryString = params.toString();
|
|
562
|
+
const url = `/data/${collection}${queryString ? `?${queryString}` : ""}`;
|
|
563
|
+
return client.fetchApi(url);
|
|
564
|
+
},
|
|
565
|
+
/**
|
|
566
|
+
* Delete an item from a collection.
|
|
567
|
+
* @param collection - Collection name
|
|
568
|
+
* @param id - Item ID
|
|
569
|
+
*/
|
|
570
|
+
remove: async (collection, id) => {
|
|
571
|
+
return client.fetchApi(`/data/${collection}/${id}`, {
|
|
572
|
+
method: "DELETE"
|
|
573
|
+
});
|
|
574
|
+
},
|
|
575
|
+
/**
|
|
576
|
+
* Batch operations (put/delete) on a collection.
|
|
577
|
+
* Maximum 100 operations per request.
|
|
578
|
+
* @param collection - Collection name
|
|
579
|
+
* @param operations - Array of operations
|
|
580
|
+
*/
|
|
581
|
+
batch: async (collection, operations) => {
|
|
582
|
+
return client.fetchApi(`/data/${collection}/batch`, {
|
|
583
|
+
method: "POST",
|
|
584
|
+
body: JSON.stringify({ operations })
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
}), [client]);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// src/components/SignInForm.tsx
|
|
591
|
+
var import_react4 = require("react");
|
|
307
592
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
308
593
|
function SignInForm({ onSuccess, signUpUrl, forgotPasswordUrl }) {
|
|
309
594
|
const { signIn, config } = useAuth();
|
|
310
|
-
const [email, setEmail] = (0,
|
|
311
|
-
const [password, setPassword] = (0,
|
|
312
|
-
const [error, setError] = (0,
|
|
313
|
-
const [loading, setLoading] = (0,
|
|
595
|
+
const [email, setEmail] = (0, import_react4.useState)("");
|
|
596
|
+
const [password, setPassword] = (0, import_react4.useState)("");
|
|
597
|
+
const [error, setError] = (0, import_react4.useState)("");
|
|
598
|
+
const [loading, setLoading] = (0, import_react4.useState)(false);
|
|
314
599
|
const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
315
600
|
const handleSubmit = async (e) => {
|
|
316
601
|
e.preventDefault();
|
|
@@ -396,15 +681,15 @@ function SignInForm({ onSuccess, signUpUrl, forgotPasswordUrl }) {
|
|
|
396
681
|
}
|
|
397
682
|
|
|
398
683
|
// src/components/SignUpForm.tsx
|
|
399
|
-
var
|
|
684
|
+
var import_react5 = require("react");
|
|
400
685
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
401
686
|
function SignUpForm({ onSuccess, signInUrl }) {
|
|
402
687
|
const { signUp, config } = useAuth();
|
|
403
|
-
const [name, setName] = (0,
|
|
404
|
-
const [email, setEmail] = (0,
|
|
405
|
-
const [password, setPassword] = (0,
|
|
406
|
-
const [error, setError] = (0,
|
|
407
|
-
const [loading, setLoading] = (0,
|
|
688
|
+
const [name, setName] = (0, import_react5.useState)("");
|
|
689
|
+
const [email, setEmail] = (0, import_react5.useState)("");
|
|
690
|
+
const [password, setPassword] = (0, import_react5.useState)("");
|
|
691
|
+
const [error, setError] = (0, import_react5.useState)("");
|
|
692
|
+
const [loading, setLoading] = (0, import_react5.useState)(false);
|
|
408
693
|
const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
409
694
|
const passwordValid = password.length >= 8 && /[A-Z]/.test(password) && /[a-z]/.test(password) && /\d/.test(password);
|
|
410
695
|
const handleSubmit = async (e) => {
|
|
@@ -510,31 +795,31 @@ function SignUpForm({ onSuccess, signInUrl }) {
|
|
|
510
795
|
}
|
|
511
796
|
|
|
512
797
|
// src/components/SignInButton.tsx
|
|
513
|
-
var
|
|
798
|
+
var import_react6 = require("react");
|
|
514
799
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
515
800
|
function SignInButton({ className, children, href }) {
|
|
516
|
-
const ctx = (0,
|
|
801
|
+
const ctx = (0, import_react6.useContext)(GitHatContext);
|
|
517
802
|
const url = href || ctx?.config.signInUrl || "/sign-in";
|
|
518
803
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: url, className: className || "githat-button githat-button-primary", "aria-label": "Sign in", children: children || "Sign in" });
|
|
519
804
|
}
|
|
520
805
|
|
|
521
806
|
// src/components/SignUpButton.tsx
|
|
522
|
-
var
|
|
807
|
+
var import_react7 = require("react");
|
|
523
808
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
524
809
|
function SignUpButton({ className, children, href }) {
|
|
525
|
-
const ctx = (0,
|
|
810
|
+
const ctx = (0, import_react7.useContext)(GitHatContext);
|
|
526
811
|
const url = href || ctx?.config.signUpUrl || "/sign-up";
|
|
527
812
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("a", { href: url, className: className || "githat-button githat-button-outline", "aria-label": "Sign up", children: children || "Sign up" });
|
|
528
813
|
}
|
|
529
814
|
|
|
530
815
|
// src/components/UserButton.tsx
|
|
531
|
-
var
|
|
816
|
+
var import_react8 = require("react");
|
|
532
817
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
533
818
|
function UserButton() {
|
|
534
819
|
const { user, org, isSignedIn, signOut } = useAuth();
|
|
535
|
-
const [open, setOpen] = (0,
|
|
536
|
-
const ref = (0,
|
|
537
|
-
(0,
|
|
820
|
+
const [open, setOpen] = (0, import_react8.useState)(false);
|
|
821
|
+
const ref = (0, import_react8.useRef)(null);
|
|
822
|
+
(0, import_react8.useEffect)(() => {
|
|
538
823
|
const handleClickOutside = (e) => {
|
|
539
824
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
540
825
|
};
|
|
@@ -561,23 +846,23 @@ function UserButton() {
|
|
|
561
846
|
}
|
|
562
847
|
|
|
563
848
|
// src/components/OrgSwitcher.tsx
|
|
564
|
-
var
|
|
849
|
+
var import_react9 = require("react");
|
|
565
850
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
566
851
|
function OrgSwitcher() {
|
|
567
852
|
const { org, isSignedIn, switchOrg } = useAuth();
|
|
568
853
|
const githat = useGitHat();
|
|
569
|
-
const [orgs, setOrgs] = (0,
|
|
570
|
-
const [orgsLoading, setOrgsLoading] = (0,
|
|
571
|
-
const [open, setOpen] = (0,
|
|
572
|
-
const ref = (0,
|
|
573
|
-
(0,
|
|
854
|
+
const [orgs, setOrgs] = (0, import_react9.useState)([]);
|
|
855
|
+
const [orgsLoading, setOrgsLoading] = (0, import_react9.useState)(false);
|
|
856
|
+
const [open, setOpen] = (0, import_react9.useState)(false);
|
|
857
|
+
const ref = (0, import_react9.useRef)(null);
|
|
858
|
+
(0, import_react9.useEffect)(() => {
|
|
574
859
|
if (isSignedIn) {
|
|
575
860
|
setOrgsLoading(true);
|
|
576
861
|
githat.getUserOrgs().then((data) => setOrgs(data.orgs || [])).catch(() => {
|
|
577
862
|
}).finally(() => setOrgsLoading(false));
|
|
578
863
|
}
|
|
579
864
|
}, [isSignedIn]);
|
|
580
|
-
(0,
|
|
865
|
+
(0, import_react9.useEffect)(() => {
|
|
581
866
|
const handleClickOutside = (e) => {
|
|
582
867
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
583
868
|
};
|
|
@@ -611,15 +896,15 @@ function OrgSwitcher() {
|
|
|
611
896
|
}
|
|
612
897
|
|
|
613
898
|
// src/components/VerifiedBadge.tsx
|
|
614
|
-
var
|
|
899
|
+
var import_react10 = require("react");
|
|
615
900
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
616
901
|
var CACHE_TTL = 5 * 60 * 1e3;
|
|
617
902
|
var cache = /* @__PURE__ */ new Map();
|
|
618
903
|
function VerifiedBadge({ type, identifier, label }) {
|
|
619
904
|
const githat = useGitHat();
|
|
620
|
-
const [verified, setVerified] = (0,
|
|
621
|
-
const mounted = (0,
|
|
622
|
-
(0,
|
|
905
|
+
const [verified, setVerified] = (0, import_react10.useState)(null);
|
|
906
|
+
const mounted = (0, import_react10.useRef)(true);
|
|
907
|
+
(0, import_react10.useEffect)(() => {
|
|
623
908
|
mounted.current = true;
|
|
624
909
|
const key = `${type}:${identifier}`;
|
|
625
910
|
const cached = cache.get(key);
|
|
@@ -663,18 +948,412 @@ function ProtectedRoute({ children, fallback }) {
|
|
|
663
948
|
}
|
|
664
949
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
|
|
665
950
|
}
|
|
951
|
+
|
|
952
|
+
// src/components/ForgotPasswordForm.tsx
|
|
953
|
+
var import_react11 = require("react");
|
|
954
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
955
|
+
function ForgotPasswordForm({
|
|
956
|
+
onSuccess,
|
|
957
|
+
onError,
|
|
958
|
+
signInUrl = "/sign-in"
|
|
959
|
+
}) {
|
|
960
|
+
const { forgotPassword } = useGitHat();
|
|
961
|
+
const [email, setEmail] = (0, import_react11.useState)("");
|
|
962
|
+
const [isLoading, setIsLoading] = (0, import_react11.useState)(false);
|
|
963
|
+
const [sent, setSent] = (0, import_react11.useState)(false);
|
|
964
|
+
const [error, setError] = (0, import_react11.useState)("");
|
|
965
|
+
const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
966
|
+
const handleSubmit = async (e) => {
|
|
967
|
+
e.preventDefault();
|
|
968
|
+
if (!emailValid) {
|
|
969
|
+
setError("Please enter a valid email address");
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
setIsLoading(true);
|
|
973
|
+
setError("");
|
|
974
|
+
try {
|
|
975
|
+
await forgotPassword(email);
|
|
976
|
+
setSent(true);
|
|
977
|
+
onSuccess?.(email);
|
|
978
|
+
} catch (err) {
|
|
979
|
+
const message = err instanceof Error ? err.message : "Failed to send reset email";
|
|
980
|
+
setError(message);
|
|
981
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
982
|
+
} finally {
|
|
983
|
+
setIsLoading(false);
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
if (sent) {
|
|
987
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "githat-form-container", children: [
|
|
988
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "githat-form-header", children: [
|
|
989
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { className: "githat-form-title", children: "Check your email" }),
|
|
990
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "githat-form-subtitle", children: [
|
|
991
|
+
"We sent a password reset link to ",
|
|
992
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: email })
|
|
993
|
+
] })
|
|
994
|
+
] }),
|
|
995
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("a", { href: signInUrl, className: "githat-link", children: "Back to sign in" }),
|
|
996
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "githat-powered-by", children: [
|
|
997
|
+
"Secured by ",
|
|
998
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "GitHat" })
|
|
999
|
+
] })
|
|
1000
|
+
] });
|
|
1001
|
+
}
|
|
1002
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "githat-form-container", children: [
|
|
1003
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "githat-form-header", children: [
|
|
1004
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { className: "githat-form-title", children: "Forgot password" }),
|
|
1005
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "githat-form-subtitle", children: "Enter your email and we'll send you a reset link" })
|
|
1006
|
+
] }),
|
|
1007
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "githat-alert githat-alert-error", role: "alert", "aria-live": "polite", children: error }),
|
|
1008
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("form", { onSubmit: handleSubmit, className: "githat-form", "aria-label": "Forgot password form", children: [
|
|
1009
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "githat-field", children: [
|
|
1010
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { className: "githat-label", htmlFor: "githat-forgot-email", children: "Email" }),
|
|
1011
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1012
|
+
"input",
|
|
1013
|
+
{
|
|
1014
|
+
id: "githat-forgot-email",
|
|
1015
|
+
className: "githat-input",
|
|
1016
|
+
type: "email",
|
|
1017
|
+
value: email,
|
|
1018
|
+
onChange: (e) => setEmail(e.target.value),
|
|
1019
|
+
placeholder: "you@example.com",
|
|
1020
|
+
autoComplete: "email",
|
|
1021
|
+
disabled: isLoading,
|
|
1022
|
+
required: true
|
|
1023
|
+
}
|
|
1024
|
+
)
|
|
1025
|
+
] }),
|
|
1026
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1027
|
+
"button",
|
|
1028
|
+
{
|
|
1029
|
+
type: "submit",
|
|
1030
|
+
className: "githat-button githat-button-primary",
|
|
1031
|
+
disabled: isLoading || !email || email.length > 0 && !emailValid,
|
|
1032
|
+
children: isLoading ? "Sending..." : "Send reset link"
|
|
1033
|
+
}
|
|
1034
|
+
)
|
|
1035
|
+
] }),
|
|
1036
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "githat-form-footer", children: [
|
|
1037
|
+
"Remember your password? ",
|
|
1038
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("a", { href: signInUrl, className: "githat-link", children: "Sign in" })
|
|
1039
|
+
] }),
|
|
1040
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "githat-powered-by", children: [
|
|
1041
|
+
"Secured by ",
|
|
1042
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "GitHat" })
|
|
1043
|
+
] })
|
|
1044
|
+
] });
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// src/components/ResetPasswordForm.tsx
|
|
1048
|
+
var import_react12 = require("react");
|
|
1049
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1050
|
+
function ResetPasswordForm({
|
|
1051
|
+
token,
|
|
1052
|
+
onSuccess,
|
|
1053
|
+
onError,
|
|
1054
|
+
signInUrl = "/sign-in",
|
|
1055
|
+
minPasswordLength = 8
|
|
1056
|
+
}) {
|
|
1057
|
+
const { resetPassword } = useGitHat();
|
|
1058
|
+
const [password, setPassword] = (0, import_react12.useState)("");
|
|
1059
|
+
const [confirm, setConfirm] = (0, import_react12.useState)("");
|
|
1060
|
+
const [isLoading, setIsLoading] = (0, import_react12.useState)(false);
|
|
1061
|
+
const [success, setSuccess] = (0, import_react12.useState)(false);
|
|
1062
|
+
const [error, setError] = (0, import_react12.useState)("");
|
|
1063
|
+
const handleSubmit = async (e) => {
|
|
1064
|
+
e.preventDefault();
|
|
1065
|
+
if (password !== confirm) {
|
|
1066
|
+
setError("Passwords do not match");
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
if (password.length < minPasswordLength) {
|
|
1070
|
+
setError(`Password must be at least ${minPasswordLength} characters`);
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
setIsLoading(true);
|
|
1074
|
+
setError("");
|
|
1075
|
+
try {
|
|
1076
|
+
await resetPassword(token, password);
|
|
1077
|
+
setSuccess(true);
|
|
1078
|
+
onSuccess?.();
|
|
1079
|
+
} catch (err) {
|
|
1080
|
+
const message = err instanceof Error ? err.message : "Failed to reset password";
|
|
1081
|
+
setError(message);
|
|
1082
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
1083
|
+
} finally {
|
|
1084
|
+
setIsLoading(false);
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
if (success) {
|
|
1088
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "githat-form-container", children: [
|
|
1089
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "githat-form-header", children: [
|
|
1090
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { className: "githat-form-title", children: "Password reset!" }),
|
|
1091
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "githat-form-subtitle", children: "Your password has been successfully reset." })
|
|
1092
|
+
] }),
|
|
1093
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("a", { href: signInUrl, className: "githat-button githat-button-primary", style: { display: "block", textAlign: "center", textDecoration: "none" }, children: "Sign in" }),
|
|
1094
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("p", { className: "githat-powered-by", children: [
|
|
1095
|
+
"Secured by ",
|
|
1096
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: "GitHat" })
|
|
1097
|
+
] })
|
|
1098
|
+
] });
|
|
1099
|
+
}
|
|
1100
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "githat-form-container", children: [
|
|
1101
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "githat-form-header", children: [
|
|
1102
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { className: "githat-form-title", children: "Reset password" }),
|
|
1103
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "githat-form-subtitle", children: "Enter your new password" })
|
|
1104
|
+
] }),
|
|
1105
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "githat-alert githat-alert-error", role: "alert", "aria-live": "polite", children: error }),
|
|
1106
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("form", { onSubmit: handleSubmit, className: "githat-form", "aria-label": "Reset password form", children: [
|
|
1107
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "githat-field", children: [
|
|
1108
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("label", { className: "githat-label", htmlFor: "githat-reset-password", children: "New password" }),
|
|
1109
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1110
|
+
"input",
|
|
1111
|
+
{
|
|
1112
|
+
id: "githat-reset-password",
|
|
1113
|
+
className: "githat-input",
|
|
1114
|
+
type: "password",
|
|
1115
|
+
value: password,
|
|
1116
|
+
onChange: (e) => setPassword(e.target.value),
|
|
1117
|
+
placeholder: "Enter new password",
|
|
1118
|
+
autoComplete: "new-password",
|
|
1119
|
+
disabled: isLoading,
|
|
1120
|
+
required: true,
|
|
1121
|
+
minLength: minPasswordLength
|
|
1122
|
+
}
|
|
1123
|
+
)
|
|
1124
|
+
] }),
|
|
1125
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "githat-field", children: [
|
|
1126
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("label", { className: "githat-label", htmlFor: "githat-reset-confirm", children: "Confirm password" }),
|
|
1127
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1128
|
+
"input",
|
|
1129
|
+
{
|
|
1130
|
+
id: "githat-reset-confirm",
|
|
1131
|
+
className: "githat-input",
|
|
1132
|
+
type: "password",
|
|
1133
|
+
value: confirm,
|
|
1134
|
+
onChange: (e) => setConfirm(e.target.value),
|
|
1135
|
+
placeholder: "Confirm new password",
|
|
1136
|
+
autoComplete: "new-password",
|
|
1137
|
+
disabled: isLoading,
|
|
1138
|
+
required: true
|
|
1139
|
+
}
|
|
1140
|
+
)
|
|
1141
|
+
] }),
|
|
1142
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1143
|
+
"button",
|
|
1144
|
+
{
|
|
1145
|
+
type: "submit",
|
|
1146
|
+
className: "githat-button githat-button-primary",
|
|
1147
|
+
disabled: isLoading || !password || !confirm,
|
|
1148
|
+
children: isLoading ? "Resetting..." : "Reset password"
|
|
1149
|
+
}
|
|
1150
|
+
)
|
|
1151
|
+
] }),
|
|
1152
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("p", { className: "githat-powered-by", children: [
|
|
1153
|
+
"Secured by ",
|
|
1154
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: "GitHat" })
|
|
1155
|
+
] })
|
|
1156
|
+
] });
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
// src/components/VerifyEmailStatus.tsx
|
|
1160
|
+
var import_react13 = require("react");
|
|
1161
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1162
|
+
function VerifyEmailStatus({
|
|
1163
|
+
token,
|
|
1164
|
+
onSuccess,
|
|
1165
|
+
onError,
|
|
1166
|
+
signInUrl = "/sign-in",
|
|
1167
|
+
redirectDelay = 3e3
|
|
1168
|
+
}) {
|
|
1169
|
+
const { verifyEmail } = useGitHat();
|
|
1170
|
+
const [status, setStatus] = (0, import_react13.useState)("loading");
|
|
1171
|
+
const [error, setError] = (0, import_react13.useState)("");
|
|
1172
|
+
(0, import_react13.useEffect)(() => {
|
|
1173
|
+
if (!token) {
|
|
1174
|
+
setStatus("error");
|
|
1175
|
+
setError("Missing verification token");
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
verifyEmail(token).then(() => {
|
|
1179
|
+
setStatus("success");
|
|
1180
|
+
onSuccess?.();
|
|
1181
|
+
if (signInUrl && redirectDelay > 0) {
|
|
1182
|
+
setTimeout(() => {
|
|
1183
|
+
window.location.href = signInUrl;
|
|
1184
|
+
}, redirectDelay);
|
|
1185
|
+
}
|
|
1186
|
+
}).catch((err) => {
|
|
1187
|
+
setStatus("error");
|
|
1188
|
+
const message = err instanceof Error ? err.message : "Verification failed";
|
|
1189
|
+
setError(message);
|
|
1190
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
1191
|
+
});
|
|
1192
|
+
}, [token, verifyEmail, onSuccess, onError, signInUrl, redirectDelay]);
|
|
1193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "githat-form-container", children: [
|
|
1194
|
+
status === "loading" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "githat-form-header", children: [
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { className: "githat-form-title", children: "Verifying email..." }),
|
|
1196
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "githat-form-subtitle", children: "Please wait while we verify your email address." })
|
|
1197
|
+
] }),
|
|
1198
|
+
status === "success" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1199
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "githat-form-header", children: [
|
|
1200
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { className: "githat-form-title", children: "Email verified!" }),
|
|
1201
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "githat-form-subtitle", children: "Your email has been successfully verified. Redirecting to sign in..." })
|
|
1202
|
+
] }),
|
|
1203
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: signInUrl, className: "githat-button githat-button-primary", style: { display: "block", textAlign: "center", textDecoration: "none" }, children: "Sign in now" })
|
|
1204
|
+
] }),
|
|
1205
|
+
status === "error" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1206
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "githat-form-header", children: [
|
|
1207
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { className: "githat-form-title", children: "Verification failed" }),
|
|
1208
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "githat-form-subtitle", children: error })
|
|
1209
|
+
] }),
|
|
1210
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "githat-form-footer", children: [
|
|
1211
|
+
"The link may have expired. ",
|
|
1212
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href: "/sign-up", className: "githat-link", children: "Try signing up again" })
|
|
1213
|
+
] })
|
|
1214
|
+
] }),
|
|
1215
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "githat-powered-by", children: [
|
|
1216
|
+
"Secured by ",
|
|
1217
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "GitHat" })
|
|
1218
|
+
] })
|
|
1219
|
+
] });
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// src/components/ChangePasswordForm.tsx
|
|
1223
|
+
var import_react14 = require("react");
|
|
1224
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1225
|
+
function ChangePasswordForm({
|
|
1226
|
+
onSuccess,
|
|
1227
|
+
onError,
|
|
1228
|
+
minPasswordLength = 8
|
|
1229
|
+
}) {
|
|
1230
|
+
const { changePassword } = useGitHat();
|
|
1231
|
+
const [current, setCurrent] = (0, import_react14.useState)("");
|
|
1232
|
+
const [newPass, setNewPass] = (0, import_react14.useState)("");
|
|
1233
|
+
const [confirm, setConfirm] = (0, import_react14.useState)("");
|
|
1234
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
|
|
1235
|
+
const [error, setError] = (0, import_react14.useState)("");
|
|
1236
|
+
const [success, setSuccess] = (0, import_react14.useState)(false);
|
|
1237
|
+
const handleSubmit = async (e) => {
|
|
1238
|
+
e.preventDefault();
|
|
1239
|
+
if (newPass !== confirm) {
|
|
1240
|
+
setError("Passwords do not match");
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
if (newPass.length < minPasswordLength) {
|
|
1244
|
+
setError(`Password must be at least ${minPasswordLength} characters`);
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
setIsLoading(true);
|
|
1248
|
+
setError("");
|
|
1249
|
+
try {
|
|
1250
|
+
await changePassword(current, newPass);
|
|
1251
|
+
setSuccess(true);
|
|
1252
|
+
setCurrent("");
|
|
1253
|
+
setNewPass("");
|
|
1254
|
+
setConfirm("");
|
|
1255
|
+
onSuccess?.();
|
|
1256
|
+
} catch (err) {
|
|
1257
|
+
const message = err instanceof Error ? err.message : "Failed to change password";
|
|
1258
|
+
setError(message);
|
|
1259
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
1260
|
+
} finally {
|
|
1261
|
+
setIsLoading(false);
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
1264
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "githat-form-container", children: [
|
|
1265
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "githat-form-header", children: [
|
|
1266
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "githat-form-title", children: "Change password" }),
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "githat-form-subtitle", children: "Update your account password" })
|
|
1268
|
+
] }),
|
|
1269
|
+
success && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "githat-alert githat-alert-success", role: "status", "aria-live": "polite", children: "Password changed successfully!" }),
|
|
1270
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "githat-alert githat-alert-error", role: "alert", "aria-live": "polite", children: error }),
|
|
1271
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("form", { onSubmit: handleSubmit, className: "githat-form", "aria-label": "Change password form", children: [
|
|
1272
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "githat-field", children: [
|
|
1273
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { className: "githat-label", htmlFor: "githat-change-current", children: "Current password" }),
|
|
1274
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1275
|
+
"input",
|
|
1276
|
+
{
|
|
1277
|
+
id: "githat-change-current",
|
|
1278
|
+
className: "githat-input",
|
|
1279
|
+
type: "password",
|
|
1280
|
+
value: current,
|
|
1281
|
+
onChange: (e) => setCurrent(e.target.value),
|
|
1282
|
+
placeholder: "Enter current password",
|
|
1283
|
+
autoComplete: "current-password",
|
|
1284
|
+
disabled: isLoading,
|
|
1285
|
+
required: true
|
|
1286
|
+
}
|
|
1287
|
+
)
|
|
1288
|
+
] }),
|
|
1289
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "githat-field", children: [
|
|
1290
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { className: "githat-label", htmlFor: "githat-change-new", children: "New password" }),
|
|
1291
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1292
|
+
"input",
|
|
1293
|
+
{
|
|
1294
|
+
id: "githat-change-new",
|
|
1295
|
+
className: "githat-input",
|
|
1296
|
+
type: "password",
|
|
1297
|
+
value: newPass,
|
|
1298
|
+
onChange: (e) => setNewPass(e.target.value),
|
|
1299
|
+
placeholder: "Enter new password",
|
|
1300
|
+
autoComplete: "new-password",
|
|
1301
|
+
disabled: isLoading,
|
|
1302
|
+
required: true,
|
|
1303
|
+
minLength: minPasswordLength
|
|
1304
|
+
}
|
|
1305
|
+
)
|
|
1306
|
+
] }),
|
|
1307
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "githat-field", children: [
|
|
1308
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { className: "githat-label", htmlFor: "githat-change-confirm", children: "Confirm new password" }),
|
|
1309
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1310
|
+
"input",
|
|
1311
|
+
{
|
|
1312
|
+
id: "githat-change-confirm",
|
|
1313
|
+
className: "githat-input",
|
|
1314
|
+
type: "password",
|
|
1315
|
+
value: confirm,
|
|
1316
|
+
onChange: (e) => setConfirm(e.target.value),
|
|
1317
|
+
placeholder: "Confirm new password",
|
|
1318
|
+
autoComplete: "new-password",
|
|
1319
|
+
disabled: isLoading,
|
|
1320
|
+
required: true
|
|
1321
|
+
}
|
|
1322
|
+
)
|
|
1323
|
+
] }),
|
|
1324
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1325
|
+
"button",
|
|
1326
|
+
{
|
|
1327
|
+
type: "submit",
|
|
1328
|
+
className: "githat-button githat-button-primary",
|
|
1329
|
+
disabled: isLoading || !current || !newPass || !confirm,
|
|
1330
|
+
children: isLoading ? "Changing..." : "Change password"
|
|
1331
|
+
}
|
|
1332
|
+
)
|
|
1333
|
+
] }),
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("p", { className: "githat-powered-by", children: [
|
|
1335
|
+
"Secured by ",
|
|
1336
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: "GitHat" })
|
|
1337
|
+
] })
|
|
1338
|
+
] });
|
|
1339
|
+
}
|
|
666
1340
|
// Annotate the CommonJS export names for ESM import in node:
|
|
667
1341
|
0 && (module.exports = {
|
|
1342
|
+
ChangePasswordForm,
|
|
1343
|
+
ForgotPasswordForm,
|
|
668
1344
|
GitHatProvider,
|
|
669
1345
|
OrgSwitcher,
|
|
670
1346
|
ProtectedRoute,
|
|
1347
|
+
ResetPasswordForm,
|
|
671
1348
|
SignInButton,
|
|
672
1349
|
SignInForm,
|
|
673
1350
|
SignUpButton,
|
|
674
1351
|
SignUpForm,
|
|
675
1352
|
UserButton,
|
|
676
1353
|
VerifiedBadge,
|
|
1354
|
+
VerifyEmailStatus,
|
|
677
1355
|
useAuth,
|
|
1356
|
+
useData,
|
|
678
1357
|
useGitHat
|
|
679
1358
|
});
|
|
680
1359
|
//# sourceMappingURL=index.js.map
|