@githat/nextjs 0.2.1 → 0.2.3
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 +779 -100
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +773 -99
- 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 +32 -4
package/dist/index.mjs
CHANGED
|
@@ -18,15 +18,16 @@ function resolveConfig(config) {
|
|
|
18
18
|
signInUrl: config.signInUrl || "/sign-in",
|
|
19
19
|
signUpUrl: config.signUpUrl || "/sign-up",
|
|
20
20
|
afterSignInUrl: config.afterSignInUrl || "/dashboard",
|
|
21
|
-
afterSignOutUrl: config.afterSignOutUrl || "/"
|
|
21
|
+
afterSignOutUrl: config.afterSignOutUrl || "/",
|
|
22
|
+
tokenStorage: config.tokenStorage || "localStorage"
|
|
22
23
|
};
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
// src/client.ts
|
|
26
27
|
var _refreshPromise = null;
|
|
27
|
-
async function refreshTokens(apiUrl, appKey) {
|
|
28
|
-
const refreshToken = typeof window !== "undefined" ? localStorage.getItem(TOKEN_KEYS.refreshToken) : null;
|
|
29
|
-
if (!refreshToken) return false;
|
|
28
|
+
async function refreshTokens(apiUrl, appKey, useCookies) {
|
|
29
|
+
const refreshToken = typeof window !== "undefined" && !useCookies ? localStorage.getItem(TOKEN_KEYS.refreshToken) : null;
|
|
30
|
+
if (!useCookies && !refreshToken) return false;
|
|
30
31
|
let orgId = null;
|
|
31
32
|
try {
|
|
32
33
|
const orgStr = localStorage.getItem(TOKEN_KEYS.org);
|
|
@@ -34,18 +35,22 @@ async function refreshTokens(apiUrl, appKey) {
|
|
|
34
35
|
} catch {
|
|
35
36
|
}
|
|
36
37
|
try {
|
|
37
|
-
const
|
|
38
|
+
const refreshUrl = useCookies ? `${apiUrl}/auth/refresh?setCookie=true` : `${apiUrl}/auth/refresh`;
|
|
39
|
+
const res = await fetch(refreshUrl, {
|
|
38
40
|
method: "POST",
|
|
39
41
|
headers: {
|
|
40
42
|
"Content-Type": "application/json",
|
|
41
43
|
"X-GitHat-App-Key": appKey
|
|
42
44
|
},
|
|
43
|
-
|
|
45
|
+
credentials: useCookies ? "include" : "same-origin",
|
|
46
|
+
body: JSON.stringify(useCookies ? { orgId } : { refreshToken, orgId })
|
|
44
47
|
});
|
|
45
48
|
if (!res.ok) return false;
|
|
46
49
|
const data = await res.json();
|
|
47
|
-
if (
|
|
48
|
-
|
|
50
|
+
if (!useCookies) {
|
|
51
|
+
if (data.accessToken) localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
|
|
52
|
+
if (data.refreshToken) localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
|
|
53
|
+
}
|
|
49
54
|
if (data.org) localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
|
|
50
55
|
return true;
|
|
51
56
|
} catch {
|
|
@@ -55,53 +60,66 @@ async function refreshTokens(apiUrl, appKey) {
|
|
|
55
60
|
function clearAuth() {
|
|
56
61
|
if (typeof window === "undefined") return;
|
|
57
62
|
Object.values(TOKEN_KEYS).forEach((key) => localStorage.removeItem(key));
|
|
58
|
-
window.dispatchEvent(
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
window.dispatchEvent(
|
|
64
|
+
new CustomEvent("githat:auth-changed", {
|
|
65
|
+
detail: { user: null, org: null, signedIn: false }
|
|
66
|
+
})
|
|
67
|
+
);
|
|
61
68
|
}
|
|
62
|
-
function createClient(apiUrl, appKey) {
|
|
63
|
-
|
|
69
|
+
function createClient(apiUrl, appKey, options = {}) {
|
|
70
|
+
const { useCookies = false } = options;
|
|
71
|
+
async function fetchApi(endpoint, fetchOptions = {}) {
|
|
64
72
|
const url = `${apiUrl}${endpoint}`;
|
|
65
|
-
const token = typeof window !== "undefined" ? localStorage.getItem(TOKEN_KEYS.accessToken) : null;
|
|
73
|
+
const token = typeof window !== "undefined" && !useCookies ? localStorage.getItem(TOKEN_KEYS.accessToken) : null;
|
|
66
74
|
const headers = {
|
|
67
75
|
"Content-Type": "application/json",
|
|
68
76
|
"X-GitHat-App-Key": appKey,
|
|
69
77
|
...token && { Authorization: `Bearer ${token}` },
|
|
70
|
-
...
|
|
78
|
+
...fetchOptions.headers
|
|
71
79
|
};
|
|
72
80
|
let response;
|
|
73
81
|
try {
|
|
74
|
-
response = await fetch(url, {
|
|
82
|
+
response = await fetch(url, {
|
|
83
|
+
...fetchOptions,
|
|
84
|
+
headers,
|
|
85
|
+
credentials: useCookies ? "include" : "same-origin"
|
|
86
|
+
});
|
|
75
87
|
} catch (networkError) {
|
|
76
88
|
if (networkError instanceof TypeError) {
|
|
77
|
-
const isMissingKey = !appKey || !appKey.startsWith("pk_live_");
|
|
89
|
+
const isMissingKey = !appKey || !appKey.startsWith("pk_live_") && !appKey.startsWith("pk_test_");
|
|
78
90
|
const isLocalhost = typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1");
|
|
79
91
|
if (isMissingKey && !isLocalhost) {
|
|
80
92
|
throw new Error(
|
|
81
|
-
"Missing
|
|
93
|
+
"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"
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (isLocalhost) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
"GitHat: Cannot reach api.githat.io. Check your internet connection."
|
|
82
99
|
);
|
|
83
100
|
}
|
|
84
101
|
throw new Error(
|
|
85
|
-
"
|
|
102
|
+
"GitHat: API request failed. Verify your publishable key and app domain at https://githat.io/dashboard/apps"
|
|
86
103
|
);
|
|
87
104
|
}
|
|
88
105
|
throw networkError;
|
|
89
106
|
}
|
|
90
107
|
if (response.status === 401) {
|
|
91
108
|
if (!_refreshPromise) {
|
|
92
|
-
_refreshPromise = refreshTokens(apiUrl, appKey).finally(() => {
|
|
109
|
+
_refreshPromise = refreshTokens(apiUrl, appKey, useCookies).finally(() => {
|
|
93
110
|
_refreshPromise = null;
|
|
94
111
|
});
|
|
95
112
|
}
|
|
96
113
|
const refreshed = await _refreshPromise;
|
|
97
114
|
if (refreshed) {
|
|
98
|
-
const newToken = localStorage.getItem(TOKEN_KEYS.accessToken);
|
|
115
|
+
const newToken = !useCookies && typeof window !== "undefined" ? localStorage.getItem(TOKEN_KEYS.accessToken) : null;
|
|
99
116
|
const retryResponse = await fetch(url, {
|
|
100
|
-
...
|
|
117
|
+
...fetchOptions,
|
|
101
118
|
headers: {
|
|
102
119
|
...headers,
|
|
103
120
|
...newToken && { Authorization: `Bearer ${newToken}` }
|
|
104
|
-
}
|
|
121
|
+
},
|
|
122
|
+
credentials: useCookies ? "include" : "same-origin"
|
|
105
123
|
});
|
|
106
124
|
const retryData = await retryResponse.json();
|
|
107
125
|
if (!retryResponse.ok) throw new Error(retryData.error || "Request failed");
|
|
@@ -118,42 +136,110 @@ function createClient(apiUrl, appKey) {
|
|
|
118
136
|
}
|
|
119
137
|
|
|
120
138
|
// src/provider.tsx
|
|
121
|
-
import { jsx } from "react/jsx-runtime";
|
|
139
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
122
140
|
var GitHatContext = createContext(null);
|
|
141
|
+
function isDevMode(key) {
|
|
142
|
+
return !key || !key.startsWith("pk_live_") && !key.startsWith("pk_test_");
|
|
143
|
+
}
|
|
144
|
+
function DevModeBanner() {
|
|
145
|
+
const [dismissed, setDismissed] = useState(() => {
|
|
146
|
+
if (typeof window === "undefined") return true;
|
|
147
|
+
return localStorage.getItem("githat_dev_banner_dismissed") === "1";
|
|
148
|
+
});
|
|
149
|
+
if (dismissed || typeof window === "undefined") return null;
|
|
150
|
+
const hostname = window.location.hostname;
|
|
151
|
+
if (hostname !== "localhost" && hostname !== "127.0.0.1") return null;
|
|
152
|
+
return /* @__PURE__ */ jsxs("div", { className: "githat-dev-banner", role: "status", children: [
|
|
153
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
154
|
+
/* @__PURE__ */ jsx("strong", { children: "GitHat Dev Mode" }),
|
|
155
|
+
" \u2014 No publishable key. Auth works on localhost.",
|
|
156
|
+
" ",
|
|
157
|
+
/* @__PURE__ */ jsx("a", { href: "https://githat.io/dashboard/apps", target: "_blank", rel: "noopener noreferrer", children: "Get your key" })
|
|
158
|
+
] }),
|
|
159
|
+
/* @__PURE__ */ jsx(
|
|
160
|
+
"button",
|
|
161
|
+
{
|
|
162
|
+
onClick: () => {
|
|
163
|
+
setDismissed(true);
|
|
164
|
+
localStorage.setItem("githat_dev_banner_dismissed", "1");
|
|
165
|
+
},
|
|
166
|
+
"aria-label": "Dismiss",
|
|
167
|
+
children: "\xD7"
|
|
168
|
+
}
|
|
169
|
+
)
|
|
170
|
+
] });
|
|
171
|
+
}
|
|
123
172
|
function GitHatProvider({ config: rawConfig, children }) {
|
|
124
173
|
const config = useMemo(() => resolveConfig(rawConfig), [rawConfig]);
|
|
125
|
-
const
|
|
174
|
+
const useCookies = config.tokenStorage === "cookie";
|
|
175
|
+
const devMode = isDevMode(config.publishableKey);
|
|
176
|
+
const clientRef = useRef(createClient(config.apiUrl, config.publishableKey, { useCookies }));
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
if (!devMode || typeof window === "undefined") return;
|
|
179
|
+
const hostname = window.location.hostname;
|
|
180
|
+
if (hostname === "localhost" || hostname === "127.0.0.1") {
|
|
181
|
+
console.warn(
|
|
182
|
+
"%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",
|
|
183
|
+
"background: #f59e0b; color: #000; font-weight: bold; padding: 2px 6px; border-radius: 3px;",
|
|
184
|
+
"color: #f59e0b;"
|
|
185
|
+
);
|
|
186
|
+
} else {
|
|
187
|
+
console.error(
|
|
188
|
+
"%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",
|
|
189
|
+
"background: #ef4444; color: #fff; font-weight: bold; padding: 2px 6px; border-radius: 3px;",
|
|
190
|
+
"color: #ef4444;"
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}, []);
|
|
126
194
|
const [user, setUser] = useState(null);
|
|
127
195
|
const [org, setOrg] = useState(null);
|
|
128
196
|
const [isSignedIn, setIsSignedIn] = useState(false);
|
|
129
197
|
const [isLoading, setIsLoading] = useState(true);
|
|
130
198
|
const [authError, setAuthError] = useState(null);
|
|
131
199
|
useEffect(() => {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (
|
|
200
|
+
const validateSession = async () => {
|
|
201
|
+
try {
|
|
202
|
+
if (!useCookies) {
|
|
203
|
+
const token = localStorage.getItem(TOKEN_KEYS.accessToken);
|
|
204
|
+
const storedUser = localStorage.getItem(TOKEN_KEYS.user);
|
|
205
|
+
if (!token || !storedUser) {
|
|
206
|
+
setIsLoading(false);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const data = await clientRef.current.fetchApi("/auth/me");
|
|
211
|
+
if (data.user) {
|
|
212
|
+
setUser(data.user);
|
|
213
|
+
setOrg(data.currentOrg || null);
|
|
214
|
+
setIsSignedIn(true);
|
|
215
|
+
setAuthError(null);
|
|
216
|
+
if (!useCookies) {
|
|
217
|
+
localStorage.setItem(TOKEN_KEYS.user, JSON.stringify(data.user));
|
|
218
|
+
if (data.currentOrg) {
|
|
219
|
+
localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.currentOrg));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} catch (err) {
|
|
224
|
+
const error = err;
|
|
225
|
+
if (error.message === "Session expired") {
|
|
144
226
|
clientRef.current.clearAuth();
|
|
145
|
-
} else {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
227
|
+
} else if (!useCookies) {
|
|
228
|
+
const storedUser = localStorage.getItem(TOKEN_KEYS.user);
|
|
229
|
+
if (storedUser) {
|
|
230
|
+
try {
|
|
231
|
+
setUser(JSON.parse(storedUser));
|
|
232
|
+
setIsSignedIn(true);
|
|
233
|
+
} catch {
|
|
234
|
+
}
|
|
149
235
|
}
|
|
150
|
-
setAuthError(
|
|
236
|
+
setAuthError(error.message || "Failed to verify session");
|
|
151
237
|
}
|
|
152
|
-
}
|
|
153
|
-
} else {
|
|
238
|
+
}
|
|
154
239
|
setIsLoading(false);
|
|
155
|
-
}
|
|
156
|
-
|
|
240
|
+
};
|
|
241
|
+
validateSession();
|
|
242
|
+
}, [useCookies]);
|
|
157
243
|
useEffect(() => {
|
|
158
244
|
const handleAuthChanged = (e) => {
|
|
159
245
|
const detail = e.detail;
|
|
@@ -171,30 +257,36 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
171
257
|
return () => window.removeEventListener("githat:auth-changed", handleAuthChanged);
|
|
172
258
|
}, []);
|
|
173
259
|
const signIn = useCallback(async (email, password) => {
|
|
174
|
-
const
|
|
260
|
+
const loginUrl = useCookies ? "/auth/login?setCookie=true" : "/auth/login";
|
|
261
|
+
const data = await clientRef.current.fetchApi(loginUrl, {
|
|
175
262
|
method: "POST",
|
|
176
263
|
body: JSON.stringify({ email, password })
|
|
177
264
|
});
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
265
|
+
if (!useCookies && data.accessToken && data.refreshToken) {
|
|
266
|
+
localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
|
|
267
|
+
localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
|
|
268
|
+
localStorage.setItem(TOKEN_KEYS.user, JSON.stringify(data.user));
|
|
269
|
+
if (data.org) localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
|
|
270
|
+
}
|
|
182
271
|
setUser(data.user);
|
|
183
272
|
setOrg(data.org || null);
|
|
184
273
|
setIsSignedIn(true);
|
|
185
274
|
window.dispatchEvent(new CustomEvent("githat:auth-changed", {
|
|
186
275
|
detail: { user: data.user, org: data.org, signedIn: true }
|
|
187
276
|
}));
|
|
188
|
-
}, []);
|
|
277
|
+
}, [useCookies]);
|
|
189
278
|
const signUp = useCallback(async (signUpData) => {
|
|
190
|
-
const
|
|
279
|
+
const registerUrl = useCookies ? "/auth/register?setCookie=true" : "/auth/register";
|
|
280
|
+
const data = await clientRef.current.fetchApi(registerUrl, {
|
|
191
281
|
method: "POST",
|
|
192
282
|
body: JSON.stringify(signUpData)
|
|
193
283
|
});
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
284
|
+
if (!useCookies && data.accessToken && data.refreshToken) {
|
|
285
|
+
localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
|
|
286
|
+
localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
|
|
287
|
+
localStorage.setItem(TOKEN_KEYS.user, JSON.stringify(data.user));
|
|
288
|
+
if (data.org) localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
|
|
289
|
+
}
|
|
198
290
|
setUser(data.user);
|
|
199
291
|
setOrg(data.org || null);
|
|
200
292
|
setIsSignedIn(true);
|
|
@@ -202,10 +294,11 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
202
294
|
detail: { user: data.user, org: data.org, signedIn: true }
|
|
203
295
|
}));
|
|
204
296
|
return { requiresVerification: !data.user.emailVerified, email: signUpData.email };
|
|
205
|
-
}, []);
|
|
297
|
+
}, [useCookies]);
|
|
206
298
|
const signOut = useCallback(async () => {
|
|
207
299
|
try {
|
|
208
|
-
|
|
300
|
+
const logoutUrl = useCookies ? "/auth/logout?setCookie=true" : "/auth/logout";
|
|
301
|
+
await clientRef.current.fetchApi(logoutUrl, { method: "POST" });
|
|
209
302
|
} catch {
|
|
210
303
|
}
|
|
211
304
|
clientRef.current.clearAuth();
|
|
@@ -215,22 +308,24 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
215
308
|
if (typeof window !== "undefined" && config.afterSignOutUrl) {
|
|
216
309
|
window.location.href = config.afterSignOutUrl;
|
|
217
310
|
}
|
|
218
|
-
}, [config.afterSignOutUrl]);
|
|
311
|
+
}, [config.afterSignOutUrl, useCookies]);
|
|
219
312
|
const switchOrg = useCallback(async (orgId) => {
|
|
220
313
|
try {
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
if (
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
314
|
+
const switchUrl = useCookies ? `/user/orgs/${orgId}/switch?setCookie=true` : `/user/orgs/${orgId}/switch`;
|
|
315
|
+
const data = await clientRef.current.fetchApi(switchUrl, { method: "POST" });
|
|
316
|
+
if (!useCookies) {
|
|
317
|
+
if (data.accessToken) localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
|
|
318
|
+
if (data.refreshToken) localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
|
|
319
|
+
localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
|
|
320
|
+
}
|
|
321
|
+
setOrg(data.org);
|
|
227
322
|
window.dispatchEvent(new CustomEvent("githat:auth-changed", {
|
|
228
|
-
detail: { user, org:
|
|
323
|
+
detail: { user, org: data.org, signedIn: true }
|
|
229
324
|
}));
|
|
230
325
|
} catch (e) {
|
|
231
326
|
console.error("Org switch failed:", e);
|
|
232
327
|
}
|
|
233
|
-
}, [user]);
|
|
328
|
+
}, [user, useCookies]);
|
|
234
329
|
const value = useMemo(() => ({
|
|
235
330
|
user,
|
|
236
331
|
org,
|
|
@@ -243,11 +338,14 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
243
338
|
signOut,
|
|
244
339
|
switchOrg
|
|
245
340
|
}), [user, org, isSignedIn, isLoading, authError, config, signIn, signUp, signOut, switchOrg]);
|
|
246
|
-
return /* @__PURE__ */
|
|
341
|
+
return /* @__PURE__ */ jsxs(GitHatContext.Provider, { value, children: [
|
|
342
|
+
devMode && /* @__PURE__ */ jsx(DevModeBanner, {}),
|
|
343
|
+
children
|
|
344
|
+
] });
|
|
247
345
|
}
|
|
248
346
|
|
|
249
347
|
// src/hooks.ts
|
|
250
|
-
import { useContext, useMemo as useMemo2 } from "react";
|
|
348
|
+
import { useContext, useMemo as useMemo2, useCallback as useCallback2 } from "react";
|
|
251
349
|
function useAuth() {
|
|
252
350
|
const ctx = useContext(GitHatContext);
|
|
253
351
|
if (!ctx) throw new Error("useAuth must be used within a <GitHatProvider>");
|
|
@@ -259,17 +357,199 @@ function useGitHat() {
|
|
|
259
357
|
() => createClient(ctx.config.apiUrl, ctx.config.publishableKey),
|
|
260
358
|
[ctx.config.apiUrl, ctx.config.publishableKey]
|
|
261
359
|
);
|
|
360
|
+
const getOrgMetadata = useCallback2(async () => {
|
|
361
|
+
if (!ctx.org?.id) {
|
|
362
|
+
throw new Error("No active organization");
|
|
363
|
+
}
|
|
364
|
+
const response = await client.fetchApi(
|
|
365
|
+
`/orgs/${ctx.org.id}/metadata`
|
|
366
|
+
);
|
|
367
|
+
return response.metadata || {};
|
|
368
|
+
}, [client, ctx.org?.id]);
|
|
369
|
+
const updateOrgMetadata = useCallback2(
|
|
370
|
+
async (updates) => {
|
|
371
|
+
if (!ctx.org?.id) {
|
|
372
|
+
throw new Error("No active organization");
|
|
373
|
+
}
|
|
374
|
+
const response = await client.fetchApi(
|
|
375
|
+
`/orgs/${ctx.org.id}/metadata`,
|
|
376
|
+
{
|
|
377
|
+
method: "PATCH",
|
|
378
|
+
body: JSON.stringify(updates)
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
return response.metadata || {};
|
|
382
|
+
},
|
|
383
|
+
[client, ctx.org?.id]
|
|
384
|
+
);
|
|
385
|
+
const forgotPassword = useCallback2(
|
|
386
|
+
async (email) => {
|
|
387
|
+
const response = await fetch(`${ctx.config.apiUrl}/auth/forgot-password`, {
|
|
388
|
+
method: "POST",
|
|
389
|
+
headers: { "Content-Type": "application/json" },
|
|
390
|
+
body: JSON.stringify({ email })
|
|
391
|
+
});
|
|
392
|
+
if (!response.ok) {
|
|
393
|
+
const error = await response.json().catch(() => ({}));
|
|
394
|
+
throw new Error(error.message || "Failed to send reset email");
|
|
395
|
+
}
|
|
396
|
+
return { success: true };
|
|
397
|
+
},
|
|
398
|
+
[ctx.config.apiUrl]
|
|
399
|
+
);
|
|
400
|
+
const resetPassword = useCallback2(
|
|
401
|
+
async (token, newPassword) => {
|
|
402
|
+
const response = await fetch(`${ctx.config.apiUrl}/auth/reset-password`, {
|
|
403
|
+
method: "POST",
|
|
404
|
+
headers: { "Content-Type": "application/json" },
|
|
405
|
+
body: JSON.stringify({ token, password: newPassword })
|
|
406
|
+
});
|
|
407
|
+
if (!response.ok) {
|
|
408
|
+
const error = await response.json().catch(() => ({}));
|
|
409
|
+
throw new Error(error.message || "Failed to reset password");
|
|
410
|
+
}
|
|
411
|
+
return { success: true };
|
|
412
|
+
},
|
|
413
|
+
[ctx.config.apiUrl]
|
|
414
|
+
);
|
|
415
|
+
const changePassword = useCallback2(
|
|
416
|
+
async (currentPassword, newPassword) => {
|
|
417
|
+
await client.fetchApi("/auth/change-password", {
|
|
418
|
+
method: "POST",
|
|
419
|
+
body: JSON.stringify({ currentPassword, newPassword })
|
|
420
|
+
});
|
|
421
|
+
return { success: true };
|
|
422
|
+
},
|
|
423
|
+
[client]
|
|
424
|
+
);
|
|
425
|
+
const verifyEmail = useCallback2(
|
|
426
|
+
async (token) => {
|
|
427
|
+
const response = await fetch(`${ctx.config.apiUrl}/auth/verify-email`, {
|
|
428
|
+
method: "POST",
|
|
429
|
+
headers: { "Content-Type": "application/json" },
|
|
430
|
+
body: JSON.stringify({ token })
|
|
431
|
+
});
|
|
432
|
+
if (!response.ok) {
|
|
433
|
+
const error = await response.json().catch(() => ({}));
|
|
434
|
+
throw new Error(error.message || "Failed to verify email");
|
|
435
|
+
}
|
|
436
|
+
return { success: true };
|
|
437
|
+
},
|
|
438
|
+
[ctx.config.apiUrl]
|
|
439
|
+
);
|
|
440
|
+
const resendVerificationEmail = useCallback2(
|
|
441
|
+
async (email) => {
|
|
442
|
+
const response = await fetch(`${ctx.config.apiUrl}/auth/resend-verification`, {
|
|
443
|
+
method: "POST",
|
|
444
|
+
headers: { "Content-Type": "application/json" },
|
|
445
|
+
body: JSON.stringify({ email })
|
|
446
|
+
});
|
|
447
|
+
if (!response.ok) {
|
|
448
|
+
const error = await response.json().catch(() => ({}));
|
|
449
|
+
throw new Error(error.message || "Failed to resend verification email");
|
|
450
|
+
}
|
|
451
|
+
return { success: true };
|
|
452
|
+
},
|
|
453
|
+
[ctx.config.apiUrl]
|
|
454
|
+
);
|
|
262
455
|
return {
|
|
263
456
|
fetch: client.fetchApi,
|
|
264
457
|
getUserOrgs: () => client.fetchApi("/user/orgs"),
|
|
265
458
|
verifyMCP: (domain) => client.fetchApi(`/verify/mcp/${domain}`),
|
|
266
|
-
verifyAgent: (wallet) => client.fetchApi(`/verify/agent/${wallet}`)
|
|
459
|
+
verifyAgent: (wallet) => client.fetchApi(`/verify/agent/${wallet}`),
|
|
460
|
+
getOrgMetadata,
|
|
461
|
+
updateOrgMetadata,
|
|
462
|
+
// Password management
|
|
463
|
+
forgotPassword,
|
|
464
|
+
resetPassword,
|
|
465
|
+
changePassword,
|
|
466
|
+
// Email verification
|
|
467
|
+
verifyEmail,
|
|
468
|
+
resendVerificationEmail
|
|
267
469
|
};
|
|
268
470
|
}
|
|
269
471
|
|
|
472
|
+
// src/data.ts
|
|
473
|
+
import { useMemo as useMemo3 } from "react";
|
|
474
|
+
function useData() {
|
|
475
|
+
const ctx = useAuth();
|
|
476
|
+
const client = useMemo3(
|
|
477
|
+
() => createClient(ctx.config.apiUrl, ctx.config.publishableKey),
|
|
478
|
+
[ctx.config.apiUrl, ctx.config.publishableKey]
|
|
479
|
+
);
|
|
480
|
+
return useMemo3(() => ({
|
|
481
|
+
/**
|
|
482
|
+
* Store an item in a collection. If the item exists, it will be updated.
|
|
483
|
+
* @param collection - Collection name (e.g., 'orders', 'users')
|
|
484
|
+
* @param data - Data object with required `id` field
|
|
485
|
+
*/
|
|
486
|
+
put: async (collection, data) => {
|
|
487
|
+
if (!data.id) {
|
|
488
|
+
throw new Error('Data must include an "id" field');
|
|
489
|
+
}
|
|
490
|
+
return client.fetchApi(`/data/${collection}/${data.id}`, {
|
|
491
|
+
method: "PUT",
|
|
492
|
+
body: JSON.stringify(data)
|
|
493
|
+
});
|
|
494
|
+
},
|
|
495
|
+
/**
|
|
496
|
+
* Get a single item from a collection.
|
|
497
|
+
* @param collection - Collection name
|
|
498
|
+
* @param id - Item ID
|
|
499
|
+
*/
|
|
500
|
+
get: async (collection, id) => {
|
|
501
|
+
try {
|
|
502
|
+
const result = await client.fetchApi(`/data/${collection}/${id}`);
|
|
503
|
+
return result.item;
|
|
504
|
+
} catch (err) {
|
|
505
|
+
if (err instanceof Error && err.message === "Item not found") {
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
throw err;
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
/**
|
|
512
|
+
* Query items from a collection with optional filters and pagination.
|
|
513
|
+
* @param collection - Collection name
|
|
514
|
+
* @param options - Query options (limit, cursor, filter)
|
|
515
|
+
*/
|
|
516
|
+
query: async (collection, options = {}) => {
|
|
517
|
+
const params = new URLSearchParams();
|
|
518
|
+
if (options.limit) params.set("limit", options.limit.toString());
|
|
519
|
+
if (options.cursor) params.set("cursor", options.cursor);
|
|
520
|
+
if (options.filter) params.set("filter", JSON.stringify(options.filter));
|
|
521
|
+
const queryString = params.toString();
|
|
522
|
+
const url = `/data/${collection}${queryString ? `?${queryString}` : ""}`;
|
|
523
|
+
return client.fetchApi(url);
|
|
524
|
+
},
|
|
525
|
+
/**
|
|
526
|
+
* Delete an item from a collection.
|
|
527
|
+
* @param collection - Collection name
|
|
528
|
+
* @param id - Item ID
|
|
529
|
+
*/
|
|
530
|
+
remove: async (collection, id) => {
|
|
531
|
+
return client.fetchApi(`/data/${collection}/${id}`, {
|
|
532
|
+
method: "DELETE"
|
|
533
|
+
});
|
|
534
|
+
},
|
|
535
|
+
/**
|
|
536
|
+
* Batch operations (put/delete) on a collection.
|
|
537
|
+
* Maximum 100 operations per request.
|
|
538
|
+
* @param collection - Collection name
|
|
539
|
+
* @param operations - Array of operations
|
|
540
|
+
*/
|
|
541
|
+
batch: async (collection, operations) => {
|
|
542
|
+
return client.fetchApi(`/data/${collection}/batch`, {
|
|
543
|
+
method: "POST",
|
|
544
|
+
body: JSON.stringify({ operations })
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
}), [client]);
|
|
548
|
+
}
|
|
549
|
+
|
|
270
550
|
// src/components/SignInForm.tsx
|
|
271
551
|
import { useState as useState2 } from "react";
|
|
272
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
552
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
273
553
|
function SignInForm({ onSuccess, signUpUrl, forgotPasswordUrl }) {
|
|
274
554
|
const { signIn, config } = useAuth();
|
|
275
555
|
const [email, setEmail] = useState2("");
|
|
@@ -299,14 +579,14 @@ function SignInForm({ onSuccess, signUpUrl, forgotPasswordUrl }) {
|
|
|
299
579
|
setLoading(false);
|
|
300
580
|
}
|
|
301
581
|
};
|
|
302
|
-
return /* @__PURE__ */
|
|
303
|
-
/* @__PURE__ */
|
|
582
|
+
return /* @__PURE__ */ jsxs2("div", { className: "githat-form-container", children: [
|
|
583
|
+
/* @__PURE__ */ jsxs2("div", { className: "githat-form-header", children: [
|
|
304
584
|
/* @__PURE__ */ jsx2("h2", { className: "githat-form-title", children: "Sign in" }),
|
|
305
585
|
/* @__PURE__ */ jsx2("p", { className: "githat-form-subtitle", children: "Welcome back to GitHat" })
|
|
306
586
|
] }),
|
|
307
587
|
error && /* @__PURE__ */ jsx2("div", { className: "githat-alert githat-alert-error", role: "alert", "aria-live": "polite", children: error }),
|
|
308
|
-
/* @__PURE__ */
|
|
309
|
-
/* @__PURE__ */
|
|
588
|
+
/* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className: "githat-form", "aria-label": "Sign in form", children: [
|
|
589
|
+
/* @__PURE__ */ jsxs2("div", { className: "githat-field", children: [
|
|
310
590
|
/* @__PURE__ */ jsx2("label", { className: "githat-label", htmlFor: "githat-signin-email", children: "Email" }),
|
|
311
591
|
/* @__PURE__ */ jsx2(
|
|
312
592
|
"input",
|
|
@@ -322,7 +602,7 @@ function SignInForm({ onSuccess, signUpUrl, forgotPasswordUrl }) {
|
|
|
322
602
|
}
|
|
323
603
|
)
|
|
324
604
|
] }),
|
|
325
|
-
/* @__PURE__ */
|
|
605
|
+
/* @__PURE__ */ jsxs2("div", { className: "githat-field", children: [
|
|
326
606
|
/* @__PURE__ */ jsx2("label", { className: "githat-label", htmlFor: "githat-signin-password", children: "Password" }),
|
|
327
607
|
/* @__PURE__ */ jsx2(
|
|
328
608
|
"input",
|
|
@@ -349,11 +629,11 @@ function SignInForm({ onSuccess, signUpUrl, forgotPasswordUrl }) {
|
|
|
349
629
|
}
|
|
350
630
|
)
|
|
351
631
|
] }),
|
|
352
|
-
signUpUrl && /* @__PURE__ */
|
|
632
|
+
signUpUrl && /* @__PURE__ */ jsxs2("p", { className: "githat-form-footer", children: [
|
|
353
633
|
"Don't have an account? ",
|
|
354
634
|
/* @__PURE__ */ jsx2("a", { href: signUpUrl, className: "githat-link", children: "Sign up" })
|
|
355
635
|
] }),
|
|
356
|
-
/* @__PURE__ */
|
|
636
|
+
/* @__PURE__ */ jsxs2("p", { className: "githat-powered-by", children: [
|
|
357
637
|
"Secured by ",
|
|
358
638
|
/* @__PURE__ */ jsx2("strong", { children: "GitHat" })
|
|
359
639
|
] })
|
|
@@ -362,7 +642,7 @@ function SignInForm({ onSuccess, signUpUrl, forgotPasswordUrl }) {
|
|
|
362
642
|
|
|
363
643
|
// src/components/SignUpForm.tsx
|
|
364
644
|
import { useState as useState3 } from "react";
|
|
365
|
-
import { jsx as jsx3, jsxs as
|
|
645
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
366
646
|
function SignUpForm({ onSuccess, signInUrl }) {
|
|
367
647
|
const { signUp, config } = useAuth();
|
|
368
648
|
const [name, setName] = useState3("");
|
|
@@ -379,7 +659,7 @@ function SignUpForm({ onSuccess, signInUrl }) {
|
|
|
379
659
|
return;
|
|
380
660
|
}
|
|
381
661
|
if (!passwordValid) {
|
|
382
|
-
setError("Password must be 8+ characters with uppercase, lowercase,
|
|
662
|
+
setError("Password must be 8+ characters with uppercase, lowercase, and number");
|
|
383
663
|
return;
|
|
384
664
|
}
|
|
385
665
|
setError("");
|
|
@@ -397,14 +677,14 @@ function SignUpForm({ onSuccess, signInUrl }) {
|
|
|
397
677
|
setLoading(false);
|
|
398
678
|
}
|
|
399
679
|
};
|
|
400
|
-
return /* @__PURE__ */
|
|
401
|
-
/* @__PURE__ */
|
|
680
|
+
return /* @__PURE__ */ jsxs3("div", { className: "githat-form-container", children: [
|
|
681
|
+
/* @__PURE__ */ jsxs3("div", { className: "githat-form-header", children: [
|
|
402
682
|
/* @__PURE__ */ jsx3("h2", { className: "githat-form-title", children: "Create an account" }),
|
|
403
683
|
/* @__PURE__ */ jsx3("p", { className: "githat-form-subtitle", children: "Get started with GitHat" })
|
|
404
684
|
] }),
|
|
405
685
|
error && /* @__PURE__ */ jsx3("div", { className: "githat-alert githat-alert-error", role: "alert", "aria-live": "polite", children: error }),
|
|
406
|
-
/* @__PURE__ */
|
|
407
|
-
/* @__PURE__ */
|
|
686
|
+
/* @__PURE__ */ jsxs3("form", { onSubmit: handleSubmit, className: "githat-form", "aria-label": "Sign up form", children: [
|
|
687
|
+
/* @__PURE__ */ jsxs3("div", { className: "githat-field", children: [
|
|
408
688
|
/* @__PURE__ */ jsx3("label", { className: "githat-label", htmlFor: "githat-signup-name", children: "Full name" }),
|
|
409
689
|
/* @__PURE__ */ jsx3(
|
|
410
690
|
"input",
|
|
@@ -420,7 +700,7 @@ function SignUpForm({ onSuccess, signInUrl }) {
|
|
|
420
700
|
}
|
|
421
701
|
)
|
|
422
702
|
] }),
|
|
423
|
-
/* @__PURE__ */
|
|
703
|
+
/* @__PURE__ */ jsxs3("div", { className: "githat-field", children: [
|
|
424
704
|
/* @__PURE__ */ jsx3("label", { className: "githat-label", htmlFor: "githat-signup-email", children: "Email" }),
|
|
425
705
|
/* @__PURE__ */ jsx3(
|
|
426
706
|
"input",
|
|
@@ -436,7 +716,7 @@ function SignUpForm({ onSuccess, signInUrl }) {
|
|
|
436
716
|
}
|
|
437
717
|
)
|
|
438
718
|
] }),
|
|
439
|
-
/* @__PURE__ */
|
|
719
|
+
/* @__PURE__ */ jsxs3("div", { className: "githat-field", children: [
|
|
440
720
|
/* @__PURE__ */ jsx3("label", { className: "githat-label", htmlFor: "githat-signup-password", children: "Password" }),
|
|
441
721
|
/* @__PURE__ */ jsx3(
|
|
442
722
|
"input",
|
|
@@ -463,11 +743,11 @@ function SignUpForm({ onSuccess, signInUrl }) {
|
|
|
463
743
|
}
|
|
464
744
|
)
|
|
465
745
|
] }),
|
|
466
|
-
signInUrl && /* @__PURE__ */
|
|
746
|
+
signInUrl && /* @__PURE__ */ jsxs3("p", { className: "githat-form-footer", children: [
|
|
467
747
|
"Already have an account? ",
|
|
468
748
|
/* @__PURE__ */ jsx3("a", { href: signInUrl, className: "githat-link", children: "Sign in" })
|
|
469
749
|
] }),
|
|
470
|
-
/* @__PURE__ */
|
|
750
|
+
/* @__PURE__ */ jsxs3("p", { className: "githat-powered-by", children: [
|
|
471
751
|
"Secured by ",
|
|
472
752
|
/* @__PURE__ */ jsx3("strong", { children: "GitHat" })
|
|
473
753
|
] })
|
|
@@ -494,7 +774,7 @@ function SignUpButton({ className, children, href }) {
|
|
|
494
774
|
|
|
495
775
|
// src/components/UserButton.tsx
|
|
496
776
|
import { useState as useState4, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
497
|
-
import { jsx as jsx6, jsxs as
|
|
777
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
498
778
|
function UserButton() {
|
|
499
779
|
const { user, org, isSignedIn, signOut } = useAuth();
|
|
500
780
|
const [open, setOpen] = useState4(false);
|
|
@@ -508,10 +788,10 @@ function UserButton() {
|
|
|
508
788
|
}, []);
|
|
509
789
|
if (!isSignedIn || !user) return null;
|
|
510
790
|
const initials = user.name ? user.name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2) : user.email[0].toUpperCase();
|
|
511
|
-
return /* @__PURE__ */
|
|
791
|
+
return /* @__PURE__ */ jsxs4("div", { className: "githat-user-button", ref, children: [
|
|
512
792
|
/* @__PURE__ */ jsx6("button", { className: "githat-avatar-trigger", onClick: () => setOpen(!open), "aria-label": "User menu", "aria-expanded": open, "aria-haspopup": "true", children: user.avatarUrl ? /* @__PURE__ */ jsx6("img", { src: user.avatarUrl, alt: user.name || "User avatar", className: "githat-avatar-img" }) : /* @__PURE__ */ jsx6("span", { className: "githat-avatar-initials", children: initials }) }),
|
|
513
|
-
open && /* @__PURE__ */
|
|
514
|
-
/* @__PURE__ */
|
|
793
|
+
open && /* @__PURE__ */ jsxs4("div", { className: "githat-dropdown", role: "menu", children: [
|
|
794
|
+
/* @__PURE__ */ jsxs4("div", { className: "githat-dropdown-header", children: [
|
|
515
795
|
/* @__PURE__ */ jsx6("p", { className: "githat-dropdown-name", children: user.name }),
|
|
516
796
|
/* @__PURE__ */ jsx6("p", { className: "githat-dropdown-email", children: user.email }),
|
|
517
797
|
org && /* @__PURE__ */ jsx6("p", { className: "githat-dropdown-org", children: org.name })
|
|
@@ -527,7 +807,7 @@ function UserButton() {
|
|
|
527
807
|
|
|
528
808
|
// src/components/OrgSwitcher.tsx
|
|
529
809
|
import { useState as useState5, useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
530
|
-
import { jsx as jsx7, jsxs as
|
|
810
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
531
811
|
function OrgSwitcher() {
|
|
532
812
|
const { org, isSignedIn, switchOrg } = useAuth();
|
|
533
813
|
const githat = useGitHat();
|
|
@@ -550,12 +830,12 @@ function OrgSwitcher() {
|
|
|
550
830
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
551
831
|
}, []);
|
|
552
832
|
if (!isSignedIn || !org || orgs.length < 2 && !orgsLoading) return null;
|
|
553
|
-
return /* @__PURE__ */
|
|
554
|
-
/* @__PURE__ */
|
|
833
|
+
return /* @__PURE__ */ jsxs5("div", { className: "githat-org-switcher", ref, children: [
|
|
834
|
+
/* @__PURE__ */ jsxs5("button", { className: "githat-org-trigger", onClick: () => setOpen(!open), "aria-label": "Switch organization", "aria-expanded": open, "aria-haspopup": "true", children: [
|
|
555
835
|
/* @__PURE__ */ jsx7("span", { className: "githat-org-name", children: org.name }),
|
|
556
836
|
/* @__PURE__ */ jsx7("span", { className: "githat-chevron", children: open ? "\u25B2" : "\u25BC" })
|
|
557
837
|
] }),
|
|
558
|
-
open && /* @__PURE__ */ jsx7("div", { className: "githat-dropdown", role: "menu", children: orgsLoading ? /* @__PURE__ */ jsx7("div", { className: "githat-dropdown-item", "aria-busy": "true", children: "Loading..." }) : orgs.map((o) => /* @__PURE__ */
|
|
838
|
+
open && /* @__PURE__ */ jsx7("div", { className: "githat-dropdown", role: "menu", children: orgsLoading ? /* @__PURE__ */ jsx7("div", { className: "githat-dropdown-item", "aria-busy": "true", children: "Loading..." }) : orgs.map((o) => /* @__PURE__ */ jsxs5(
|
|
559
839
|
"button",
|
|
560
840
|
{
|
|
561
841
|
className: `githat-dropdown-item ${o.id === org.id ? "githat-dropdown-item-active" : ""}`,
|
|
@@ -577,7 +857,7 @@ function OrgSwitcher() {
|
|
|
577
857
|
|
|
578
858
|
// src/components/VerifiedBadge.tsx
|
|
579
859
|
import { useState as useState6, useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
580
|
-
import { jsxs as
|
|
860
|
+
import { jsxs as jsxs6 } from "react/jsx-runtime";
|
|
581
861
|
var CACHE_TTL = 5 * 60 * 1e3;
|
|
582
862
|
var cache = /* @__PURE__ */ new Map();
|
|
583
863
|
function VerifiedBadge({ type, identifier, label }) {
|
|
@@ -606,7 +886,7 @@ function VerifiedBadge({ type, identifier, label }) {
|
|
|
606
886
|
};
|
|
607
887
|
}, [type, identifier]);
|
|
608
888
|
if (verified === null) return null;
|
|
609
|
-
return /* @__PURE__ */
|
|
889
|
+
return /* @__PURE__ */ jsxs6("span", { className: `githat-badge ${verified ? "githat-badge-verified" : "githat-badge-unverified"}`, children: [
|
|
610
890
|
verified ? "\u2713" : "\u2717",
|
|
611
891
|
" ",
|
|
612
892
|
label || (verified ? "Verified" : "Unverified")
|
|
@@ -628,17 +908,411 @@ function ProtectedRoute({ children, fallback }) {
|
|
|
628
908
|
}
|
|
629
909
|
return /* @__PURE__ */ jsx8(Fragment, { children });
|
|
630
910
|
}
|
|
911
|
+
|
|
912
|
+
// src/components/ForgotPasswordForm.tsx
|
|
913
|
+
import { useState as useState7 } from "react";
|
|
914
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
915
|
+
function ForgotPasswordForm({
|
|
916
|
+
onSuccess,
|
|
917
|
+
onError,
|
|
918
|
+
signInUrl = "/sign-in"
|
|
919
|
+
}) {
|
|
920
|
+
const { forgotPassword } = useGitHat();
|
|
921
|
+
const [email, setEmail] = useState7("");
|
|
922
|
+
const [isLoading, setIsLoading] = useState7(false);
|
|
923
|
+
const [sent, setSent] = useState7(false);
|
|
924
|
+
const [error, setError] = useState7("");
|
|
925
|
+
const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
926
|
+
const handleSubmit = async (e) => {
|
|
927
|
+
e.preventDefault();
|
|
928
|
+
if (!emailValid) {
|
|
929
|
+
setError("Please enter a valid email address");
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
setIsLoading(true);
|
|
933
|
+
setError("");
|
|
934
|
+
try {
|
|
935
|
+
await forgotPassword(email);
|
|
936
|
+
setSent(true);
|
|
937
|
+
onSuccess?.(email);
|
|
938
|
+
} catch (err) {
|
|
939
|
+
const message = err instanceof Error ? err.message : "Failed to send reset email";
|
|
940
|
+
setError(message);
|
|
941
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
942
|
+
} finally {
|
|
943
|
+
setIsLoading(false);
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
if (sent) {
|
|
947
|
+
return /* @__PURE__ */ jsxs7("div", { className: "githat-form-container", children: [
|
|
948
|
+
/* @__PURE__ */ jsxs7("div", { className: "githat-form-header", children: [
|
|
949
|
+
/* @__PURE__ */ jsx9("h2", { className: "githat-form-title", children: "Check your email" }),
|
|
950
|
+
/* @__PURE__ */ jsxs7("p", { className: "githat-form-subtitle", children: [
|
|
951
|
+
"We sent a password reset link to ",
|
|
952
|
+
/* @__PURE__ */ jsx9("strong", { children: email })
|
|
953
|
+
] })
|
|
954
|
+
] }),
|
|
955
|
+
/* @__PURE__ */ jsx9("a", { href: signInUrl, className: "githat-link", children: "Back to sign in" }),
|
|
956
|
+
/* @__PURE__ */ jsxs7("p", { className: "githat-powered-by", children: [
|
|
957
|
+
"Secured by ",
|
|
958
|
+
/* @__PURE__ */ jsx9("strong", { children: "GitHat" })
|
|
959
|
+
] })
|
|
960
|
+
] });
|
|
961
|
+
}
|
|
962
|
+
return /* @__PURE__ */ jsxs7("div", { className: "githat-form-container", children: [
|
|
963
|
+
/* @__PURE__ */ jsxs7("div", { className: "githat-form-header", children: [
|
|
964
|
+
/* @__PURE__ */ jsx9("h2", { className: "githat-form-title", children: "Forgot password" }),
|
|
965
|
+
/* @__PURE__ */ jsx9("p", { className: "githat-form-subtitle", children: "Enter your email and we'll send you a reset link" })
|
|
966
|
+
] }),
|
|
967
|
+
error && /* @__PURE__ */ jsx9("div", { className: "githat-alert githat-alert-error", role: "alert", "aria-live": "polite", children: error }),
|
|
968
|
+
/* @__PURE__ */ jsxs7("form", { onSubmit: handleSubmit, className: "githat-form", "aria-label": "Forgot password form", children: [
|
|
969
|
+
/* @__PURE__ */ jsxs7("div", { className: "githat-field", children: [
|
|
970
|
+
/* @__PURE__ */ jsx9("label", { className: "githat-label", htmlFor: "githat-forgot-email", children: "Email" }),
|
|
971
|
+
/* @__PURE__ */ jsx9(
|
|
972
|
+
"input",
|
|
973
|
+
{
|
|
974
|
+
id: "githat-forgot-email",
|
|
975
|
+
className: "githat-input",
|
|
976
|
+
type: "email",
|
|
977
|
+
value: email,
|
|
978
|
+
onChange: (e) => setEmail(e.target.value),
|
|
979
|
+
placeholder: "you@example.com",
|
|
980
|
+
autoComplete: "email",
|
|
981
|
+
disabled: isLoading,
|
|
982
|
+
required: true
|
|
983
|
+
}
|
|
984
|
+
)
|
|
985
|
+
] }),
|
|
986
|
+
/* @__PURE__ */ jsx9(
|
|
987
|
+
"button",
|
|
988
|
+
{
|
|
989
|
+
type: "submit",
|
|
990
|
+
className: "githat-button githat-button-primary",
|
|
991
|
+
disabled: isLoading || !email || email.length > 0 && !emailValid,
|
|
992
|
+
children: isLoading ? "Sending..." : "Send reset link"
|
|
993
|
+
}
|
|
994
|
+
)
|
|
995
|
+
] }),
|
|
996
|
+
/* @__PURE__ */ jsxs7("p", { className: "githat-form-footer", children: [
|
|
997
|
+
"Remember your password? ",
|
|
998
|
+
/* @__PURE__ */ jsx9("a", { href: signInUrl, className: "githat-link", children: "Sign in" })
|
|
999
|
+
] }),
|
|
1000
|
+
/* @__PURE__ */ jsxs7("p", { className: "githat-powered-by", children: [
|
|
1001
|
+
"Secured by ",
|
|
1002
|
+
/* @__PURE__ */ jsx9("strong", { children: "GitHat" })
|
|
1003
|
+
] })
|
|
1004
|
+
] });
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// src/components/ResetPasswordForm.tsx
|
|
1008
|
+
import { useState as useState8 } from "react";
|
|
1009
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1010
|
+
function ResetPasswordForm({
|
|
1011
|
+
token,
|
|
1012
|
+
onSuccess,
|
|
1013
|
+
onError,
|
|
1014
|
+
signInUrl = "/sign-in",
|
|
1015
|
+
minPasswordLength = 8
|
|
1016
|
+
}) {
|
|
1017
|
+
const { resetPassword } = useGitHat();
|
|
1018
|
+
const [password, setPassword] = useState8("");
|
|
1019
|
+
const [confirm, setConfirm] = useState8("");
|
|
1020
|
+
const [isLoading, setIsLoading] = useState8(false);
|
|
1021
|
+
const [success, setSuccess] = useState8(false);
|
|
1022
|
+
const [error, setError] = useState8("");
|
|
1023
|
+
const handleSubmit = async (e) => {
|
|
1024
|
+
e.preventDefault();
|
|
1025
|
+
if (password !== confirm) {
|
|
1026
|
+
setError("Passwords do not match");
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
if (password.length < minPasswordLength) {
|
|
1030
|
+
setError(`Password must be at least ${minPasswordLength} characters`);
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
setIsLoading(true);
|
|
1034
|
+
setError("");
|
|
1035
|
+
try {
|
|
1036
|
+
await resetPassword(token, password);
|
|
1037
|
+
setSuccess(true);
|
|
1038
|
+
onSuccess?.();
|
|
1039
|
+
} catch (err) {
|
|
1040
|
+
const message = err instanceof Error ? err.message : "Failed to reset password";
|
|
1041
|
+
setError(message);
|
|
1042
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
1043
|
+
} finally {
|
|
1044
|
+
setIsLoading(false);
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
if (success) {
|
|
1048
|
+
return /* @__PURE__ */ jsxs8("div", { className: "githat-form-container", children: [
|
|
1049
|
+
/* @__PURE__ */ jsxs8("div", { className: "githat-form-header", children: [
|
|
1050
|
+
/* @__PURE__ */ jsx10("h2", { className: "githat-form-title", children: "Password reset!" }),
|
|
1051
|
+
/* @__PURE__ */ jsx10("p", { className: "githat-form-subtitle", children: "Your password has been successfully reset." })
|
|
1052
|
+
] }),
|
|
1053
|
+
/* @__PURE__ */ jsx10("a", { href: signInUrl, className: "githat-button githat-button-primary", style: { display: "block", textAlign: "center", textDecoration: "none" }, children: "Sign in" }),
|
|
1054
|
+
/* @__PURE__ */ jsxs8("p", { className: "githat-powered-by", children: [
|
|
1055
|
+
"Secured by ",
|
|
1056
|
+
/* @__PURE__ */ jsx10("strong", { children: "GitHat" })
|
|
1057
|
+
] })
|
|
1058
|
+
] });
|
|
1059
|
+
}
|
|
1060
|
+
return /* @__PURE__ */ jsxs8("div", { className: "githat-form-container", children: [
|
|
1061
|
+
/* @__PURE__ */ jsxs8("div", { className: "githat-form-header", children: [
|
|
1062
|
+
/* @__PURE__ */ jsx10("h2", { className: "githat-form-title", children: "Reset password" }),
|
|
1063
|
+
/* @__PURE__ */ jsx10("p", { className: "githat-form-subtitle", children: "Enter your new password" })
|
|
1064
|
+
] }),
|
|
1065
|
+
error && /* @__PURE__ */ jsx10("div", { className: "githat-alert githat-alert-error", role: "alert", "aria-live": "polite", children: error }),
|
|
1066
|
+
/* @__PURE__ */ jsxs8("form", { onSubmit: handleSubmit, className: "githat-form", "aria-label": "Reset password form", children: [
|
|
1067
|
+
/* @__PURE__ */ jsxs8("div", { className: "githat-field", children: [
|
|
1068
|
+
/* @__PURE__ */ jsx10("label", { className: "githat-label", htmlFor: "githat-reset-password", children: "New password" }),
|
|
1069
|
+
/* @__PURE__ */ jsx10(
|
|
1070
|
+
"input",
|
|
1071
|
+
{
|
|
1072
|
+
id: "githat-reset-password",
|
|
1073
|
+
className: "githat-input",
|
|
1074
|
+
type: "password",
|
|
1075
|
+
value: password,
|
|
1076
|
+
onChange: (e) => setPassword(e.target.value),
|
|
1077
|
+
placeholder: "Enter new password",
|
|
1078
|
+
autoComplete: "new-password",
|
|
1079
|
+
disabled: isLoading,
|
|
1080
|
+
required: true,
|
|
1081
|
+
minLength: minPasswordLength
|
|
1082
|
+
}
|
|
1083
|
+
)
|
|
1084
|
+
] }),
|
|
1085
|
+
/* @__PURE__ */ jsxs8("div", { className: "githat-field", children: [
|
|
1086
|
+
/* @__PURE__ */ jsx10("label", { className: "githat-label", htmlFor: "githat-reset-confirm", children: "Confirm password" }),
|
|
1087
|
+
/* @__PURE__ */ jsx10(
|
|
1088
|
+
"input",
|
|
1089
|
+
{
|
|
1090
|
+
id: "githat-reset-confirm",
|
|
1091
|
+
className: "githat-input",
|
|
1092
|
+
type: "password",
|
|
1093
|
+
value: confirm,
|
|
1094
|
+
onChange: (e) => setConfirm(e.target.value),
|
|
1095
|
+
placeholder: "Confirm new password",
|
|
1096
|
+
autoComplete: "new-password",
|
|
1097
|
+
disabled: isLoading,
|
|
1098
|
+
required: true
|
|
1099
|
+
}
|
|
1100
|
+
)
|
|
1101
|
+
] }),
|
|
1102
|
+
/* @__PURE__ */ jsx10(
|
|
1103
|
+
"button",
|
|
1104
|
+
{
|
|
1105
|
+
type: "submit",
|
|
1106
|
+
className: "githat-button githat-button-primary",
|
|
1107
|
+
disabled: isLoading || !password || !confirm,
|
|
1108
|
+
children: isLoading ? "Resetting..." : "Reset password"
|
|
1109
|
+
}
|
|
1110
|
+
)
|
|
1111
|
+
] }),
|
|
1112
|
+
/* @__PURE__ */ jsxs8("p", { className: "githat-powered-by", children: [
|
|
1113
|
+
"Secured by ",
|
|
1114
|
+
/* @__PURE__ */ jsx10("strong", { children: "GitHat" })
|
|
1115
|
+
] })
|
|
1116
|
+
] });
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// src/components/VerifyEmailStatus.tsx
|
|
1120
|
+
import { useEffect as useEffect5, useState as useState9 } from "react";
|
|
1121
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1122
|
+
function VerifyEmailStatus({
|
|
1123
|
+
token,
|
|
1124
|
+
onSuccess,
|
|
1125
|
+
onError,
|
|
1126
|
+
signInUrl = "/sign-in",
|
|
1127
|
+
redirectDelay = 3e3
|
|
1128
|
+
}) {
|
|
1129
|
+
const { verifyEmail } = useGitHat();
|
|
1130
|
+
const [status, setStatus] = useState9("loading");
|
|
1131
|
+
const [error, setError] = useState9("");
|
|
1132
|
+
useEffect5(() => {
|
|
1133
|
+
if (!token) {
|
|
1134
|
+
setStatus("error");
|
|
1135
|
+
setError("Missing verification token");
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
verifyEmail(token).then(() => {
|
|
1139
|
+
setStatus("success");
|
|
1140
|
+
onSuccess?.();
|
|
1141
|
+
if (signInUrl && redirectDelay > 0) {
|
|
1142
|
+
setTimeout(() => {
|
|
1143
|
+
window.location.href = signInUrl;
|
|
1144
|
+
}, redirectDelay);
|
|
1145
|
+
}
|
|
1146
|
+
}).catch((err) => {
|
|
1147
|
+
setStatus("error");
|
|
1148
|
+
const message = err instanceof Error ? err.message : "Verification failed";
|
|
1149
|
+
setError(message);
|
|
1150
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
1151
|
+
});
|
|
1152
|
+
}, [token, verifyEmail, onSuccess, onError, signInUrl, redirectDelay]);
|
|
1153
|
+
return /* @__PURE__ */ jsxs9("div", { className: "githat-form-container", children: [
|
|
1154
|
+
status === "loading" && /* @__PURE__ */ jsxs9("div", { className: "githat-form-header", children: [
|
|
1155
|
+
/* @__PURE__ */ jsx11("h2", { className: "githat-form-title", children: "Verifying email..." }),
|
|
1156
|
+
/* @__PURE__ */ jsx11("p", { className: "githat-form-subtitle", children: "Please wait while we verify your email address." })
|
|
1157
|
+
] }),
|
|
1158
|
+
status === "success" && /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1159
|
+
/* @__PURE__ */ jsxs9("div", { className: "githat-form-header", children: [
|
|
1160
|
+
/* @__PURE__ */ jsx11("h2", { className: "githat-form-title", children: "Email verified!" }),
|
|
1161
|
+
/* @__PURE__ */ jsx11("p", { className: "githat-form-subtitle", children: "Your email has been successfully verified. Redirecting to sign in..." })
|
|
1162
|
+
] }),
|
|
1163
|
+
/* @__PURE__ */ jsx11("a", { href: signInUrl, className: "githat-button githat-button-primary", style: { display: "block", textAlign: "center", textDecoration: "none" }, children: "Sign in now" })
|
|
1164
|
+
] }),
|
|
1165
|
+
status === "error" && /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1166
|
+
/* @__PURE__ */ jsxs9("div", { className: "githat-form-header", children: [
|
|
1167
|
+
/* @__PURE__ */ jsx11("h2", { className: "githat-form-title", children: "Verification failed" }),
|
|
1168
|
+
/* @__PURE__ */ jsx11("p", { className: "githat-form-subtitle", children: error })
|
|
1169
|
+
] }),
|
|
1170
|
+
/* @__PURE__ */ jsxs9("p", { className: "githat-form-footer", children: [
|
|
1171
|
+
"The link may have expired. ",
|
|
1172
|
+
/* @__PURE__ */ jsx11("a", { href: "/sign-up", className: "githat-link", children: "Try signing up again" })
|
|
1173
|
+
] })
|
|
1174
|
+
] }),
|
|
1175
|
+
/* @__PURE__ */ jsxs9("p", { className: "githat-powered-by", children: [
|
|
1176
|
+
"Secured by ",
|
|
1177
|
+
/* @__PURE__ */ jsx11("strong", { children: "GitHat" })
|
|
1178
|
+
] })
|
|
1179
|
+
] });
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// src/components/ChangePasswordForm.tsx
|
|
1183
|
+
import { useState as useState10 } from "react";
|
|
1184
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1185
|
+
function ChangePasswordForm({
|
|
1186
|
+
onSuccess,
|
|
1187
|
+
onError,
|
|
1188
|
+
minPasswordLength = 8
|
|
1189
|
+
}) {
|
|
1190
|
+
const { changePassword } = useGitHat();
|
|
1191
|
+
const [current, setCurrent] = useState10("");
|
|
1192
|
+
const [newPass, setNewPass] = useState10("");
|
|
1193
|
+
const [confirm, setConfirm] = useState10("");
|
|
1194
|
+
const [isLoading, setIsLoading] = useState10(false);
|
|
1195
|
+
const [error, setError] = useState10("");
|
|
1196
|
+
const [success, setSuccess] = useState10(false);
|
|
1197
|
+
const handleSubmit = async (e) => {
|
|
1198
|
+
e.preventDefault();
|
|
1199
|
+
if (newPass !== confirm) {
|
|
1200
|
+
setError("Passwords do not match");
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
if (newPass.length < minPasswordLength) {
|
|
1204
|
+
setError(`Password must be at least ${minPasswordLength} characters`);
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
setIsLoading(true);
|
|
1208
|
+
setError("");
|
|
1209
|
+
try {
|
|
1210
|
+
await changePassword(current, newPass);
|
|
1211
|
+
setSuccess(true);
|
|
1212
|
+
setCurrent("");
|
|
1213
|
+
setNewPass("");
|
|
1214
|
+
setConfirm("");
|
|
1215
|
+
onSuccess?.();
|
|
1216
|
+
} catch (err) {
|
|
1217
|
+
const message = err instanceof Error ? err.message : "Failed to change password";
|
|
1218
|
+
setError(message);
|
|
1219
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
1220
|
+
} finally {
|
|
1221
|
+
setIsLoading(false);
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
return /* @__PURE__ */ jsxs10("div", { className: "githat-form-container", children: [
|
|
1225
|
+
/* @__PURE__ */ jsxs10("div", { className: "githat-form-header", children: [
|
|
1226
|
+
/* @__PURE__ */ jsx12("h2", { className: "githat-form-title", children: "Change password" }),
|
|
1227
|
+
/* @__PURE__ */ jsx12("p", { className: "githat-form-subtitle", children: "Update your account password" })
|
|
1228
|
+
] }),
|
|
1229
|
+
success && /* @__PURE__ */ jsx12("div", { className: "githat-alert githat-alert-success", role: "status", "aria-live": "polite", children: "Password changed successfully!" }),
|
|
1230
|
+
error && /* @__PURE__ */ jsx12("div", { className: "githat-alert githat-alert-error", role: "alert", "aria-live": "polite", children: error }),
|
|
1231
|
+
/* @__PURE__ */ jsxs10("form", { onSubmit: handleSubmit, className: "githat-form", "aria-label": "Change password form", children: [
|
|
1232
|
+
/* @__PURE__ */ jsxs10("div", { className: "githat-field", children: [
|
|
1233
|
+
/* @__PURE__ */ jsx12("label", { className: "githat-label", htmlFor: "githat-change-current", children: "Current password" }),
|
|
1234
|
+
/* @__PURE__ */ jsx12(
|
|
1235
|
+
"input",
|
|
1236
|
+
{
|
|
1237
|
+
id: "githat-change-current",
|
|
1238
|
+
className: "githat-input",
|
|
1239
|
+
type: "password",
|
|
1240
|
+
value: current,
|
|
1241
|
+
onChange: (e) => setCurrent(e.target.value),
|
|
1242
|
+
placeholder: "Enter current password",
|
|
1243
|
+
autoComplete: "current-password",
|
|
1244
|
+
disabled: isLoading,
|
|
1245
|
+
required: true
|
|
1246
|
+
}
|
|
1247
|
+
)
|
|
1248
|
+
] }),
|
|
1249
|
+
/* @__PURE__ */ jsxs10("div", { className: "githat-field", children: [
|
|
1250
|
+
/* @__PURE__ */ jsx12("label", { className: "githat-label", htmlFor: "githat-change-new", children: "New password" }),
|
|
1251
|
+
/* @__PURE__ */ jsx12(
|
|
1252
|
+
"input",
|
|
1253
|
+
{
|
|
1254
|
+
id: "githat-change-new",
|
|
1255
|
+
className: "githat-input",
|
|
1256
|
+
type: "password",
|
|
1257
|
+
value: newPass,
|
|
1258
|
+
onChange: (e) => setNewPass(e.target.value),
|
|
1259
|
+
placeholder: "Enter new password",
|
|
1260
|
+
autoComplete: "new-password",
|
|
1261
|
+
disabled: isLoading,
|
|
1262
|
+
required: true,
|
|
1263
|
+
minLength: minPasswordLength
|
|
1264
|
+
}
|
|
1265
|
+
)
|
|
1266
|
+
] }),
|
|
1267
|
+
/* @__PURE__ */ jsxs10("div", { className: "githat-field", children: [
|
|
1268
|
+
/* @__PURE__ */ jsx12("label", { className: "githat-label", htmlFor: "githat-change-confirm", children: "Confirm new password" }),
|
|
1269
|
+
/* @__PURE__ */ jsx12(
|
|
1270
|
+
"input",
|
|
1271
|
+
{
|
|
1272
|
+
id: "githat-change-confirm",
|
|
1273
|
+
className: "githat-input",
|
|
1274
|
+
type: "password",
|
|
1275
|
+
value: confirm,
|
|
1276
|
+
onChange: (e) => setConfirm(e.target.value),
|
|
1277
|
+
placeholder: "Confirm new password",
|
|
1278
|
+
autoComplete: "new-password",
|
|
1279
|
+
disabled: isLoading,
|
|
1280
|
+
required: true
|
|
1281
|
+
}
|
|
1282
|
+
)
|
|
1283
|
+
] }),
|
|
1284
|
+
/* @__PURE__ */ jsx12(
|
|
1285
|
+
"button",
|
|
1286
|
+
{
|
|
1287
|
+
type: "submit",
|
|
1288
|
+
className: "githat-button githat-button-primary",
|
|
1289
|
+
disabled: isLoading || !current || !newPass || !confirm,
|
|
1290
|
+
children: isLoading ? "Changing..." : "Change password"
|
|
1291
|
+
}
|
|
1292
|
+
)
|
|
1293
|
+
] }),
|
|
1294
|
+
/* @__PURE__ */ jsxs10("p", { className: "githat-powered-by", children: [
|
|
1295
|
+
"Secured by ",
|
|
1296
|
+
/* @__PURE__ */ jsx12("strong", { children: "GitHat" })
|
|
1297
|
+
] })
|
|
1298
|
+
] });
|
|
1299
|
+
}
|
|
631
1300
|
export {
|
|
1301
|
+
ChangePasswordForm,
|
|
1302
|
+
ForgotPasswordForm,
|
|
632
1303
|
GitHatProvider,
|
|
633
1304
|
OrgSwitcher,
|
|
634
1305
|
ProtectedRoute,
|
|
1306
|
+
ResetPasswordForm,
|
|
635
1307
|
SignInButton,
|
|
636
1308
|
SignInForm,
|
|
637
1309
|
SignUpButton,
|
|
638
1310
|
SignUpForm,
|
|
639
1311
|
UserButton,
|
|
640
1312
|
VerifiedBadge,
|
|
1313
|
+
VerifyEmailStatus,
|
|
641
1314
|
useAuth,
|
|
1315
|
+
useData,
|
|
642
1316
|
useGitHat
|
|
643
1317
|
};
|
|
644
1318
|
//# sourceMappingURL=index.mjs.map
|