@githat/nextjs 0.2.0 → 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 +584 -48
- package/dist/githat.css +41 -0
- package/dist/index.d.mts +213 -2
- package/dist/index.d.ts +213 -2
- package/dist/index.js +792 -96
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +786 -95
- 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 +23 -3
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,36 +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;
|
|
121
|
+
try {
|
|
122
|
+
response = await fetch(url, {
|
|
123
|
+
...fetchOptions,
|
|
124
|
+
headers,
|
|
125
|
+
credentials: useCookies ? "include" : "same-origin"
|
|
126
|
+
});
|
|
127
|
+
} catch (networkError) {
|
|
128
|
+
if (networkError instanceof TypeError) {
|
|
129
|
+
const isMissingKey = !appKey || !appKey.startsWith("pk_live_") && !appKey.startsWith("pk_test_");
|
|
130
|
+
const isLocalhost = typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1");
|
|
131
|
+
if (isMissingKey && !isLocalhost) {
|
|
132
|
+
throw new Error(
|
|
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."
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
throw new Error(
|
|
142
|
+
"GitHat: API request failed. Verify your publishable key and app domain at https://githat.io/dashboard/apps"
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
throw networkError;
|
|
146
|
+
}
|
|
108
147
|
if (response.status === 401) {
|
|
109
148
|
if (!_refreshPromise) {
|
|
110
|
-
_refreshPromise = refreshTokens(apiUrl, appKey).finally(() => {
|
|
149
|
+
_refreshPromise = refreshTokens(apiUrl, appKey, useCookies).finally(() => {
|
|
111
150
|
_refreshPromise = null;
|
|
112
151
|
});
|
|
113
152
|
}
|
|
114
153
|
const refreshed = await _refreshPromise;
|
|
115
154
|
if (refreshed) {
|
|
116
|
-
const newToken = localStorage.getItem(TOKEN_KEYS.accessToken);
|
|
155
|
+
const newToken = !useCookies && typeof window !== "undefined" ? localStorage.getItem(TOKEN_KEYS.accessToken) : null;
|
|
117
156
|
const retryResponse = await fetch(url, {
|
|
118
|
-
...
|
|
157
|
+
...fetchOptions,
|
|
119
158
|
headers: {
|
|
120
159
|
...headers,
|
|
121
160
|
...newToken && { Authorization: `Bearer ${newToken}` }
|
|
122
|
-
}
|
|
161
|
+
},
|
|
162
|
+
credentials: useCookies ? "include" : "same-origin"
|
|
123
163
|
});
|
|
124
164
|
const retryData = await retryResponse.json();
|
|
125
165
|
if (!retryResponse.ok) throw new Error(retryData.error || "Request failed");
|
|
@@ -138,40 +178,108 @@ function createClient(apiUrl, appKey) {
|
|
|
138
178
|
// src/provider.tsx
|
|
139
179
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
140
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
|
+
}
|
|
141
212
|
function GitHatProvider({ config: rawConfig, children }) {
|
|
142
213
|
const config = (0, import_react.useMemo)(() => resolveConfig(rawConfig), [rawConfig]);
|
|
143
|
-
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
|
+
}, []);
|
|
144
234
|
const [user, setUser] = (0, import_react.useState)(null);
|
|
145
235
|
const [org, setOrg] = (0, import_react.useState)(null);
|
|
146
236
|
const [isSignedIn, setIsSignedIn] = (0, import_react.useState)(false);
|
|
147
237
|
const [isLoading, setIsLoading] = (0, import_react.useState)(true);
|
|
148
238
|
const [authError, setAuthError] = (0, import_react.useState)(null);
|
|
149
239
|
(0, import_react.useEffect)(() => {
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
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") {
|
|
162
266
|
clientRef.current.clearAuth();
|
|
163
|
-
} else {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
+
}
|
|
167
275
|
}
|
|
168
|
-
setAuthError(
|
|
276
|
+
setAuthError(error.message || "Failed to verify session");
|
|
169
277
|
}
|
|
170
|
-
}
|
|
171
|
-
} else {
|
|
278
|
+
}
|
|
172
279
|
setIsLoading(false);
|
|
173
|
-
}
|
|
174
|
-
|
|
280
|
+
};
|
|
281
|
+
validateSession();
|
|
282
|
+
}, [useCookies]);
|
|
175
283
|
(0, import_react.useEffect)(() => {
|
|
176
284
|
const handleAuthChanged = (e) => {
|
|
177
285
|
const detail = e.detail;
|
|
@@ -189,30 +297,36 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
189
297
|
return () => window.removeEventListener("githat:auth-changed", handleAuthChanged);
|
|
190
298
|
}, []);
|
|
191
299
|
const signIn = (0, import_react.useCallback)(async (email, password) => {
|
|
192
|
-
const
|
|
300
|
+
const loginUrl = useCookies ? "/auth/login?setCookie=true" : "/auth/login";
|
|
301
|
+
const data = await clientRef.current.fetchApi(loginUrl, {
|
|
193
302
|
method: "POST",
|
|
194
303
|
body: JSON.stringify({ email, password })
|
|
195
304
|
});
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
+
}
|
|
200
311
|
setUser(data.user);
|
|
201
312
|
setOrg(data.org || null);
|
|
202
313
|
setIsSignedIn(true);
|
|
203
314
|
window.dispatchEvent(new CustomEvent("githat:auth-changed", {
|
|
204
315
|
detail: { user: data.user, org: data.org, signedIn: true }
|
|
205
316
|
}));
|
|
206
|
-
}, []);
|
|
317
|
+
}, [useCookies]);
|
|
207
318
|
const signUp = (0, import_react.useCallback)(async (signUpData) => {
|
|
208
|
-
const
|
|
319
|
+
const registerUrl = useCookies ? "/auth/register?setCookie=true" : "/auth/register";
|
|
320
|
+
const data = await clientRef.current.fetchApi(registerUrl, {
|
|
209
321
|
method: "POST",
|
|
210
322
|
body: JSON.stringify(signUpData)
|
|
211
323
|
});
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
+
}
|
|
216
330
|
setUser(data.user);
|
|
217
331
|
setOrg(data.org || null);
|
|
218
332
|
setIsSignedIn(true);
|
|
@@ -220,10 +334,11 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
220
334
|
detail: { user: data.user, org: data.org, signedIn: true }
|
|
221
335
|
}));
|
|
222
336
|
return { requiresVerification: !data.user.emailVerified, email: signUpData.email };
|
|
223
|
-
}, []);
|
|
337
|
+
}, [useCookies]);
|
|
224
338
|
const signOut = (0, import_react.useCallback)(async () => {
|
|
225
339
|
try {
|
|
226
|
-
|
|
340
|
+
const logoutUrl = useCookies ? "/auth/logout?setCookie=true" : "/auth/logout";
|
|
341
|
+
await clientRef.current.fetchApi(logoutUrl, { method: "POST" });
|
|
227
342
|
} catch {
|
|
228
343
|
}
|
|
229
344
|
clientRef.current.clearAuth();
|
|
@@ -233,22 +348,24 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
233
348
|
if (typeof window !== "undefined" && config.afterSignOutUrl) {
|
|
234
349
|
window.location.href = config.afterSignOutUrl;
|
|
235
350
|
}
|
|
236
|
-
}, [config.afterSignOutUrl]);
|
|
351
|
+
}, [config.afterSignOutUrl, useCookies]);
|
|
237
352
|
const switchOrg = (0, import_react.useCallback)(async (orgId) => {
|
|
238
353
|
try {
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
if (
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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);
|
|
245
362
|
window.dispatchEvent(new CustomEvent("githat:auth-changed", {
|
|
246
|
-
detail: { user, org:
|
|
363
|
+
detail: { user, org: data.org, signedIn: true }
|
|
247
364
|
}));
|
|
248
365
|
} catch (e) {
|
|
249
366
|
console.error("Org switch failed:", e);
|
|
250
367
|
}
|
|
251
|
-
}, [user]);
|
|
368
|
+
}, [user, useCookies]);
|
|
252
369
|
const value = (0, import_react.useMemo)(() => ({
|
|
253
370
|
user,
|
|
254
371
|
org,
|
|
@@ -261,7 +378,10 @@ function GitHatProvider({ config: rawConfig, children }) {
|
|
|
261
378
|
signOut,
|
|
262
379
|
switchOrg
|
|
263
380
|
}), [user, org, isSignedIn, isLoading, authError, config, signIn, signUp, signOut, switchOrg]);
|
|
264
|
-
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
|
+
] });
|
|
265
385
|
}
|
|
266
386
|
|
|
267
387
|
// src/hooks.ts
|
|
@@ -277,23 +397,205 @@ function useGitHat() {
|
|
|
277
397
|
() => createClient(ctx.config.apiUrl, ctx.config.publishableKey),
|
|
278
398
|
[ctx.config.apiUrl, ctx.config.publishableKey]
|
|
279
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
|
+
);
|
|
280
495
|
return {
|
|
281
496
|
fetch: client.fetchApi,
|
|
282
497
|
getUserOrgs: () => client.fetchApi("/user/orgs"),
|
|
283
498
|
verifyMCP: (domain) => client.fetchApi(`/verify/mcp/${domain}`),
|
|
284
|
-
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
|
|
285
509
|
};
|
|
286
510
|
}
|
|
287
511
|
|
|
288
|
-
// src/
|
|
512
|
+
// src/data.ts
|
|
289
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");
|
|
290
592
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
291
593
|
function SignInForm({ onSuccess, signUpUrl, forgotPasswordUrl }) {
|
|
292
594
|
const { signIn, config } = useAuth();
|
|
293
|
-
const [email, setEmail] = (0,
|
|
294
|
-
const [password, setPassword] = (0,
|
|
295
|
-
const [error, setError] = (0,
|
|
296
|
-
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);
|
|
297
599
|
const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
298
600
|
const handleSubmit = async (e) => {
|
|
299
601
|
e.preventDefault();
|
|
@@ -379,15 +681,15 @@ function SignInForm({ onSuccess, signUpUrl, forgotPasswordUrl }) {
|
|
|
379
681
|
}
|
|
380
682
|
|
|
381
683
|
// src/components/SignUpForm.tsx
|
|
382
|
-
var
|
|
684
|
+
var import_react5 = require("react");
|
|
383
685
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
384
686
|
function SignUpForm({ onSuccess, signInUrl }) {
|
|
385
687
|
const { signUp, config } = useAuth();
|
|
386
|
-
const [name, setName] = (0,
|
|
387
|
-
const [email, setEmail] = (0,
|
|
388
|
-
const [password, setPassword] = (0,
|
|
389
|
-
const [error, setError] = (0,
|
|
390
|
-
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);
|
|
391
693
|
const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
392
694
|
const passwordValid = password.length >= 8 && /[A-Z]/.test(password) && /[a-z]/.test(password) && /\d/.test(password);
|
|
393
695
|
const handleSubmit = async (e) => {
|
|
@@ -493,31 +795,31 @@ function SignUpForm({ onSuccess, signInUrl }) {
|
|
|
493
795
|
}
|
|
494
796
|
|
|
495
797
|
// src/components/SignInButton.tsx
|
|
496
|
-
var
|
|
798
|
+
var import_react6 = require("react");
|
|
497
799
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
498
800
|
function SignInButton({ className, children, href }) {
|
|
499
|
-
const ctx = (0,
|
|
801
|
+
const ctx = (0, import_react6.useContext)(GitHatContext);
|
|
500
802
|
const url = href || ctx?.config.signInUrl || "/sign-in";
|
|
501
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" });
|
|
502
804
|
}
|
|
503
805
|
|
|
504
806
|
// src/components/SignUpButton.tsx
|
|
505
|
-
var
|
|
807
|
+
var import_react7 = require("react");
|
|
506
808
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
507
809
|
function SignUpButton({ className, children, href }) {
|
|
508
|
-
const ctx = (0,
|
|
810
|
+
const ctx = (0, import_react7.useContext)(GitHatContext);
|
|
509
811
|
const url = href || ctx?.config.signUpUrl || "/sign-up";
|
|
510
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" });
|
|
511
813
|
}
|
|
512
814
|
|
|
513
815
|
// src/components/UserButton.tsx
|
|
514
|
-
var
|
|
816
|
+
var import_react8 = require("react");
|
|
515
817
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
516
818
|
function UserButton() {
|
|
517
819
|
const { user, org, isSignedIn, signOut } = useAuth();
|
|
518
|
-
const [open, setOpen] = (0,
|
|
519
|
-
const ref = (0,
|
|
520
|
-
(0,
|
|
820
|
+
const [open, setOpen] = (0, import_react8.useState)(false);
|
|
821
|
+
const ref = (0, import_react8.useRef)(null);
|
|
822
|
+
(0, import_react8.useEffect)(() => {
|
|
521
823
|
const handleClickOutside = (e) => {
|
|
522
824
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
523
825
|
};
|
|
@@ -544,23 +846,23 @@ function UserButton() {
|
|
|
544
846
|
}
|
|
545
847
|
|
|
546
848
|
// src/components/OrgSwitcher.tsx
|
|
547
|
-
var
|
|
849
|
+
var import_react9 = require("react");
|
|
548
850
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
549
851
|
function OrgSwitcher() {
|
|
550
852
|
const { org, isSignedIn, switchOrg } = useAuth();
|
|
551
853
|
const githat = useGitHat();
|
|
552
|
-
const [orgs, setOrgs] = (0,
|
|
553
|
-
const [orgsLoading, setOrgsLoading] = (0,
|
|
554
|
-
const [open, setOpen] = (0,
|
|
555
|
-
const ref = (0,
|
|
556
|
-
(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)(() => {
|
|
557
859
|
if (isSignedIn) {
|
|
558
860
|
setOrgsLoading(true);
|
|
559
861
|
githat.getUserOrgs().then((data) => setOrgs(data.orgs || [])).catch(() => {
|
|
560
862
|
}).finally(() => setOrgsLoading(false));
|
|
561
863
|
}
|
|
562
864
|
}, [isSignedIn]);
|
|
563
|
-
(0,
|
|
865
|
+
(0, import_react9.useEffect)(() => {
|
|
564
866
|
const handleClickOutside = (e) => {
|
|
565
867
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
566
868
|
};
|
|
@@ -594,15 +896,15 @@ function OrgSwitcher() {
|
|
|
594
896
|
}
|
|
595
897
|
|
|
596
898
|
// src/components/VerifiedBadge.tsx
|
|
597
|
-
var
|
|
899
|
+
var import_react10 = require("react");
|
|
598
900
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
599
901
|
var CACHE_TTL = 5 * 60 * 1e3;
|
|
600
902
|
var cache = /* @__PURE__ */ new Map();
|
|
601
903
|
function VerifiedBadge({ type, identifier, label }) {
|
|
602
904
|
const githat = useGitHat();
|
|
603
|
-
const [verified, setVerified] = (0,
|
|
604
|
-
const mounted = (0,
|
|
605
|
-
(0,
|
|
905
|
+
const [verified, setVerified] = (0, import_react10.useState)(null);
|
|
906
|
+
const mounted = (0, import_react10.useRef)(true);
|
|
907
|
+
(0, import_react10.useEffect)(() => {
|
|
606
908
|
mounted.current = true;
|
|
607
909
|
const key = `${type}:${identifier}`;
|
|
608
910
|
const cached = cache.get(key);
|
|
@@ -646,18 +948,412 @@ function ProtectedRoute({ children, fallback }) {
|
|
|
646
948
|
}
|
|
647
949
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
|
|
648
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
|
+
}
|
|
649
1340
|
// Annotate the CommonJS export names for ESM import in node:
|
|
650
1341
|
0 && (module.exports = {
|
|
1342
|
+
ChangePasswordForm,
|
|
1343
|
+
ForgotPasswordForm,
|
|
651
1344
|
GitHatProvider,
|
|
652
1345
|
OrgSwitcher,
|
|
653
1346
|
ProtectedRoute,
|
|
1347
|
+
ResetPasswordForm,
|
|
654
1348
|
SignInButton,
|
|
655
1349
|
SignInForm,
|
|
656
1350
|
SignUpButton,
|
|
657
1351
|
SignUpForm,
|
|
658
1352
|
UserButton,
|
|
659
1353
|
VerifiedBadge,
|
|
1354
|
+
VerifyEmailStatus,
|
|
660
1355
|
useAuth,
|
|
1356
|
+
useData,
|
|
661
1357
|
useGitHat
|
|
662
1358
|
});
|
|
663
1359
|
//# sourceMappingURL=index.js.map
|