@githat/nextjs 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,663 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var src_exports = {};
23
+ __export(src_exports, {
24
+ GitHatProvider: () => GitHatProvider,
25
+ OrgSwitcher: () => OrgSwitcher,
26
+ ProtectedRoute: () => ProtectedRoute,
27
+ SignInButton: () => SignInButton,
28
+ SignInForm: () => SignInForm,
29
+ SignUpButton: () => SignUpButton,
30
+ SignUpForm: () => SignUpForm,
31
+ UserButton: () => UserButton,
32
+ VerifiedBadge: () => VerifiedBadge,
33
+ useAuth: () => useAuth,
34
+ useGitHat: () => useGitHat
35
+ });
36
+ module.exports = __toCommonJS(src_exports);
37
+
38
+ // src/provider.tsx
39
+ var import_react = require("react");
40
+
41
+ // src/config.ts
42
+ var DEFAULT_API_URL = "https://api.githat.io";
43
+ var TOKEN_KEYS = {
44
+ accessToken: "githat_access_token",
45
+ refreshToken: "githat_refresh_token",
46
+ user: "githat_user",
47
+ org: "githat_org"
48
+ };
49
+ function resolveConfig(config) {
50
+ return {
51
+ publishableKey: config.publishableKey,
52
+ apiUrl: config.apiUrl || DEFAULT_API_URL,
53
+ signInUrl: config.signInUrl || "/sign-in",
54
+ signUpUrl: config.signUpUrl || "/sign-up",
55
+ afterSignInUrl: config.afterSignInUrl || "/dashboard",
56
+ afterSignOutUrl: config.afterSignOutUrl || "/"
57
+ };
58
+ }
59
+
60
+ // src/client.ts
61
+ 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;
65
+ let orgId = null;
66
+ try {
67
+ const orgStr = localStorage.getItem(TOKEN_KEYS.org);
68
+ if (orgStr) orgId = JSON.parse(orgStr).id;
69
+ } catch {
70
+ }
71
+ try {
72
+ const res = await fetch(`${apiUrl}/auth/refresh`, {
73
+ method: "POST",
74
+ headers: {
75
+ "Content-Type": "application/json",
76
+ "X-GitHat-App-Key": appKey
77
+ },
78
+ body: JSON.stringify({ refreshToken, orgId })
79
+ });
80
+ if (!res.ok) return false;
81
+ const data = await res.json();
82
+ if (data.accessToken) localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
83
+ if (data.refreshToken) localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
84
+ if (data.org) localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
85
+ return true;
86
+ } catch {
87
+ return false;
88
+ }
89
+ }
90
+ function clearAuth() {
91
+ if (typeof window === "undefined") return;
92
+ Object.values(TOKEN_KEYS).forEach((key) => localStorage.removeItem(key));
93
+ window.dispatchEvent(new CustomEvent("githat:auth-changed", {
94
+ detail: { user: null, org: null, signedIn: false }
95
+ }));
96
+ }
97
+ function createClient(apiUrl, appKey) {
98
+ async function fetchApi(endpoint, options = {}) {
99
+ const url = `${apiUrl}${endpoint}`;
100
+ const token = typeof window !== "undefined" ? localStorage.getItem(TOKEN_KEYS.accessToken) : null;
101
+ const headers = {
102
+ "Content-Type": "application/json",
103
+ "X-GitHat-App-Key": appKey,
104
+ ...token && { Authorization: `Bearer ${token}` },
105
+ ...options.headers
106
+ };
107
+ const response = await fetch(url, { ...options, headers });
108
+ if (response.status === 401) {
109
+ if (!_refreshPromise) {
110
+ _refreshPromise = refreshTokens(apiUrl, appKey).finally(() => {
111
+ _refreshPromise = null;
112
+ });
113
+ }
114
+ const refreshed = await _refreshPromise;
115
+ if (refreshed) {
116
+ const newToken = localStorage.getItem(TOKEN_KEYS.accessToken);
117
+ const retryResponse = await fetch(url, {
118
+ ...options,
119
+ headers: {
120
+ ...headers,
121
+ ...newToken && { Authorization: `Bearer ${newToken}` }
122
+ }
123
+ });
124
+ const retryData = await retryResponse.json();
125
+ if (!retryResponse.ok) throw new Error(retryData.error || "Request failed");
126
+ return retryData;
127
+ }
128
+ clearAuth();
129
+ throw new Error("Session expired");
130
+ }
131
+ const data = await response.json();
132
+ if (!response.ok) throw new Error(data.error || "Request failed");
133
+ return data;
134
+ }
135
+ return { fetchApi, clearAuth };
136
+ }
137
+
138
+ // src/provider.tsx
139
+ var import_jsx_runtime = require("react/jsx-runtime");
140
+ var GitHatContext = (0, import_react.createContext)(null);
141
+ function GitHatProvider({ config: rawConfig, children }) {
142
+ const config = (0, import_react.useMemo)(() => resolveConfig(rawConfig), [rawConfig]);
143
+ const clientRef = (0, import_react.useRef)(createClient(config.apiUrl, config.publishableKey));
144
+ const [user, setUser] = (0, import_react.useState)(null);
145
+ const [org, setOrg] = (0, import_react.useState)(null);
146
+ const [isSignedIn, setIsSignedIn] = (0, import_react.useState)(false);
147
+ const [isLoading, setIsLoading] = (0, import_react.useState)(true);
148
+ const [authError, setAuthError] = (0, import_react.useState)(null);
149
+ (0, import_react.useEffect)(() => {
150
+ const token = localStorage.getItem(TOKEN_KEYS.accessToken);
151
+ const storedUser = localStorage.getItem(TOKEN_KEYS.user);
152
+ if (token && storedUser) {
153
+ clientRef.current.fetchApi("/auth/me").then((data) => {
154
+ const u = data.user || JSON.parse(storedUser);
155
+ setUser(u);
156
+ const storedOrg = localStorage.getItem(TOKEN_KEYS.org);
157
+ setOrg(data.currentOrg || (storedOrg ? JSON.parse(storedOrg) : null));
158
+ setIsSignedIn(true);
159
+ setAuthError(null);
160
+ }).catch((err) => {
161
+ if (err.message === "Session expired") {
162
+ clientRef.current.clearAuth();
163
+ } else {
164
+ try {
165
+ setUser(JSON.parse(storedUser));
166
+ } catch {
167
+ }
168
+ setAuthError(err.message || "Failed to verify session");
169
+ }
170
+ }).finally(() => setIsLoading(false));
171
+ } else {
172
+ setIsLoading(false);
173
+ }
174
+ }, []);
175
+ (0, import_react.useEffect)(() => {
176
+ const handleAuthChanged = (e) => {
177
+ const detail = e.detail;
178
+ if (detail?.signedIn === false) {
179
+ setIsSignedIn(false);
180
+ setUser(null);
181
+ setOrg(null);
182
+ } else if (detail?.signedIn === true && detail?.user) {
183
+ setUser(detail.user);
184
+ setIsSignedIn(true);
185
+ if (detail.org) setOrg(detail.org);
186
+ }
187
+ };
188
+ window.addEventListener("githat:auth-changed", handleAuthChanged);
189
+ return () => window.removeEventListener("githat:auth-changed", handleAuthChanged);
190
+ }, []);
191
+ const signIn = (0, import_react.useCallback)(async (email, password) => {
192
+ const data = await clientRef.current.fetchApi("/auth/login", {
193
+ method: "POST",
194
+ body: JSON.stringify({ email, password })
195
+ });
196
+ localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
197
+ localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
198
+ localStorage.setItem(TOKEN_KEYS.user, JSON.stringify(data.user));
199
+ if (data.org) localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
200
+ setUser(data.user);
201
+ setOrg(data.org || null);
202
+ setIsSignedIn(true);
203
+ window.dispatchEvent(new CustomEvent("githat:auth-changed", {
204
+ detail: { user: data.user, org: data.org, signedIn: true }
205
+ }));
206
+ }, []);
207
+ const signUp = (0, import_react.useCallback)(async (signUpData) => {
208
+ const data = await clientRef.current.fetchApi("/auth/register", {
209
+ method: "POST",
210
+ body: JSON.stringify(signUpData)
211
+ });
212
+ localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
213
+ localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
214
+ localStorage.setItem(TOKEN_KEYS.user, JSON.stringify(data.user));
215
+ if (data.org) localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(data.org));
216
+ setUser(data.user);
217
+ setOrg(data.org || null);
218
+ setIsSignedIn(true);
219
+ window.dispatchEvent(new CustomEvent("githat:auth-changed", {
220
+ detail: { user: data.user, org: data.org, signedIn: true }
221
+ }));
222
+ return { requiresVerification: !data.user.emailVerified, email: signUpData.email };
223
+ }, []);
224
+ const signOut = (0, import_react.useCallback)(async () => {
225
+ try {
226
+ await clientRef.current.fetchApi("/auth/logout", { method: "POST" });
227
+ } catch {
228
+ }
229
+ clientRef.current.clearAuth();
230
+ setIsSignedIn(false);
231
+ setUser(null);
232
+ setOrg(null);
233
+ if (typeof window !== "undefined" && config.afterSignOutUrl) {
234
+ window.location.href = config.afterSignOutUrl;
235
+ }
236
+ }, [config.afterSignOutUrl]);
237
+ const switchOrg = (0, import_react.useCallback)(async (orgId) => {
238
+ try {
239
+ const data = await clientRef.current.fetchApi(`/user/orgs/${orgId}/switch`, { method: "POST" });
240
+ if (data.accessToken) localStorage.setItem(TOKEN_KEYS.accessToken, data.accessToken);
241
+ if (data.refreshToken) localStorage.setItem(TOKEN_KEYS.refreshToken, data.refreshToken);
242
+ const orgData = data.org;
243
+ localStorage.setItem(TOKEN_KEYS.org, JSON.stringify(orgData));
244
+ setOrg(orgData);
245
+ window.dispatchEvent(new CustomEvent("githat:auth-changed", {
246
+ detail: { user, org: orgData, signedIn: true }
247
+ }));
248
+ } catch (e) {
249
+ console.error("Org switch failed:", e);
250
+ }
251
+ }, [user]);
252
+ const value = (0, import_react.useMemo)(() => ({
253
+ user,
254
+ org,
255
+ isSignedIn,
256
+ isLoading,
257
+ authError,
258
+ config,
259
+ signIn,
260
+ signUp,
261
+ signOut,
262
+ switchOrg
263
+ }), [user, org, isSignedIn, isLoading, authError, config, signIn, signUp, signOut, switchOrg]);
264
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitHatContext.Provider, { value, children });
265
+ }
266
+
267
+ // src/hooks.ts
268
+ var import_react2 = require("react");
269
+ function useAuth() {
270
+ const ctx = (0, import_react2.useContext)(GitHatContext);
271
+ if (!ctx) throw new Error("useAuth must be used within a <GitHatProvider>");
272
+ return ctx;
273
+ }
274
+ function useGitHat() {
275
+ const ctx = useAuth();
276
+ const client = (0, import_react2.useMemo)(
277
+ () => createClient(ctx.config.apiUrl, ctx.config.publishableKey),
278
+ [ctx.config.apiUrl, ctx.config.publishableKey]
279
+ );
280
+ return {
281
+ fetch: client.fetchApi,
282
+ getUserOrgs: () => client.fetchApi("/user/orgs"),
283
+ verifyMCP: (domain) => client.fetchApi(`/verify/mcp/${domain}`),
284
+ verifyAgent: (wallet) => client.fetchApi(`/verify/agent/${wallet}`)
285
+ };
286
+ }
287
+
288
+ // src/components/SignInForm.tsx
289
+ var import_react3 = require("react");
290
+ var import_jsx_runtime2 = require("react/jsx-runtime");
291
+ function SignInForm({ onSuccess, signUpUrl, forgotPasswordUrl }) {
292
+ const { signIn, config } = useAuth();
293
+ const [email, setEmail] = (0, import_react3.useState)("");
294
+ const [password, setPassword] = (0, import_react3.useState)("");
295
+ const [error, setError] = (0, import_react3.useState)("");
296
+ const [loading, setLoading] = (0, import_react3.useState)(false);
297
+ const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
298
+ const handleSubmit = async (e) => {
299
+ e.preventDefault();
300
+ if (!emailValid) {
301
+ setError("Please enter a valid email address");
302
+ return;
303
+ }
304
+ setError("");
305
+ setLoading(true);
306
+ try {
307
+ await signIn(email, password);
308
+ if (onSuccess) {
309
+ onSuccess();
310
+ } else if (typeof window !== "undefined") {
311
+ const params = new URLSearchParams(window.location.search);
312
+ window.location.href = params.get("redirect_url") || config.afterSignInUrl;
313
+ }
314
+ } catch (err) {
315
+ setError(err.message || "Sign in failed");
316
+ } finally {
317
+ setLoading(false);
318
+ }
319
+ };
320
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "githat-form-container", children: [
321
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "githat-form-header", children: [
322
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "githat-form-title", children: "Sign in" }),
323
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "githat-form-subtitle", children: "Welcome back to GitHat" })
324
+ ] }),
325
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "githat-alert githat-alert-error", role: "alert", "aria-live": "polite", children: error }),
326
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleSubmit, className: "githat-form", "aria-label": "Sign in form", children: [
327
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "githat-field", children: [
328
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "githat-label", htmlFor: "githat-signin-email", children: "Email" }),
329
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
330
+ "input",
331
+ {
332
+ id: "githat-signin-email",
333
+ className: "githat-input",
334
+ type: "email",
335
+ value: email,
336
+ onChange: (e) => setEmail(e.target.value),
337
+ placeholder: "you@example.com",
338
+ autoComplete: "email",
339
+ required: true
340
+ }
341
+ )
342
+ ] }),
343
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "githat-field", children: [
344
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "githat-label", htmlFor: "githat-signin-password", children: "Password" }),
345
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
346
+ "input",
347
+ {
348
+ id: "githat-signin-password",
349
+ className: "githat-input",
350
+ type: "password",
351
+ value: password,
352
+ onChange: (e) => setPassword(e.target.value),
353
+ placeholder: "Enter your password",
354
+ autoComplete: "current-password",
355
+ required: true
356
+ }
357
+ )
358
+ ] }),
359
+ forgotPasswordUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: forgotPasswordUrl, className: "githat-link githat-forgot-link", children: "Forgot password?" }),
360
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
361
+ "button",
362
+ {
363
+ type: "submit",
364
+ className: "githat-button githat-button-primary",
365
+ disabled: loading || !email || !password || email.length > 0 && !emailValid,
366
+ children: loading ? "Signing in..." : "Sign in"
367
+ }
368
+ )
369
+ ] }),
370
+ signUpUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "githat-form-footer", children: [
371
+ "Don't have an account? ",
372
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: signUpUrl, className: "githat-link", children: "Sign up" })
373
+ ] }),
374
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "githat-powered-by", children: [
375
+ "Secured by ",
376
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: "GitHat" })
377
+ ] })
378
+ ] });
379
+ }
380
+
381
+ // src/components/SignUpForm.tsx
382
+ var import_react4 = require("react");
383
+ var import_jsx_runtime3 = require("react/jsx-runtime");
384
+ function SignUpForm({ onSuccess, signInUrl }) {
385
+ const { signUp, config } = useAuth();
386
+ const [name, setName] = (0, import_react4.useState)("");
387
+ const [email, setEmail] = (0, import_react4.useState)("");
388
+ const [password, setPassword] = (0, import_react4.useState)("");
389
+ const [error, setError] = (0, import_react4.useState)("");
390
+ const [loading, setLoading] = (0, import_react4.useState)(false);
391
+ const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
392
+ const passwordValid = password.length >= 8 && /[A-Z]/.test(password) && /[a-z]/.test(password) && /\d/.test(password);
393
+ const handleSubmit = async (e) => {
394
+ e.preventDefault();
395
+ if (!emailValid) {
396
+ setError("Please enter a valid email address");
397
+ return;
398
+ }
399
+ if (!passwordValid) {
400
+ setError("Password must be 8+ characters with uppercase, lowercase, number, and special character");
401
+ return;
402
+ }
403
+ setError("");
404
+ setLoading(true);
405
+ try {
406
+ const result = await signUp({ email, password, name });
407
+ if (onSuccess) {
408
+ onSuccess(result);
409
+ } else if (typeof window !== "undefined") {
410
+ window.location.href = config.afterSignInUrl;
411
+ }
412
+ } catch (err) {
413
+ setError(err.message || "Sign up failed");
414
+ } finally {
415
+ setLoading(false);
416
+ }
417
+ };
418
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "githat-form-container", children: [
419
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "githat-form-header", children: [
420
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { className: "githat-form-title", children: "Create an account" }),
421
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "githat-form-subtitle", children: "Get started with GitHat" })
422
+ ] }),
423
+ error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "githat-alert githat-alert-error", role: "alert", "aria-live": "polite", children: error }),
424
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { onSubmit: handleSubmit, className: "githat-form", "aria-label": "Sign up form", children: [
425
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "githat-field", children: [
426
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "githat-label", htmlFor: "githat-signup-name", children: "Full name" }),
427
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
428
+ "input",
429
+ {
430
+ id: "githat-signup-name",
431
+ className: "githat-input",
432
+ type: "text",
433
+ value: name,
434
+ onChange: (e) => setName(e.target.value),
435
+ placeholder: "Your name",
436
+ autoComplete: "name",
437
+ required: true
438
+ }
439
+ )
440
+ ] }),
441
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "githat-field", children: [
442
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "githat-label", htmlFor: "githat-signup-email", children: "Email" }),
443
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
444
+ "input",
445
+ {
446
+ id: "githat-signup-email",
447
+ className: "githat-input",
448
+ type: "email",
449
+ value: email,
450
+ onChange: (e) => setEmail(e.target.value),
451
+ placeholder: "you@example.com",
452
+ autoComplete: "email",
453
+ required: true
454
+ }
455
+ )
456
+ ] }),
457
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "githat-field", children: [
458
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "githat-label", htmlFor: "githat-signup-password", children: "Password" }),
459
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
460
+ "input",
461
+ {
462
+ id: "githat-signup-password",
463
+ className: "githat-input",
464
+ type: "password",
465
+ value: password,
466
+ onChange: (e) => setPassword(e.target.value),
467
+ placeholder: "8+ characters",
468
+ autoComplete: "new-password",
469
+ required: true
470
+ }
471
+ ),
472
+ password && !passwordValid && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "githat-field-error", children: "Must be 8+ characters with uppercase, lowercase, and number" })
473
+ ] }),
474
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
475
+ "button",
476
+ {
477
+ type: "submit",
478
+ className: "githat-button githat-button-primary",
479
+ disabled: loading || !email || !password || !name || !emailValid,
480
+ children: loading ? "Creating account..." : "Sign up"
481
+ }
482
+ )
483
+ ] }),
484
+ signInUrl && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "githat-form-footer", children: [
485
+ "Already have an account? ",
486
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { href: signInUrl, className: "githat-link", children: "Sign in" })
487
+ ] }),
488
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "githat-powered-by", children: [
489
+ "Secured by ",
490
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "GitHat" })
491
+ ] })
492
+ ] });
493
+ }
494
+
495
+ // src/components/SignInButton.tsx
496
+ var import_react5 = require("react");
497
+ var import_jsx_runtime4 = require("react/jsx-runtime");
498
+ function SignInButton({ className, children, href }) {
499
+ const ctx = (0, import_react5.useContext)(GitHatContext);
500
+ const url = href || ctx?.config.signInUrl || "/sign-in";
501
+ 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
+ }
503
+
504
+ // src/components/SignUpButton.tsx
505
+ var import_react6 = require("react");
506
+ var import_jsx_runtime5 = require("react/jsx-runtime");
507
+ function SignUpButton({ className, children, href }) {
508
+ const ctx = (0, import_react6.useContext)(GitHatContext);
509
+ const url = href || ctx?.config.signUpUrl || "/sign-up";
510
+ 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
+ }
512
+
513
+ // src/components/UserButton.tsx
514
+ var import_react7 = require("react");
515
+ var import_jsx_runtime6 = require("react/jsx-runtime");
516
+ function UserButton() {
517
+ const { user, org, isSignedIn, signOut } = useAuth();
518
+ const [open, setOpen] = (0, import_react7.useState)(false);
519
+ const ref = (0, import_react7.useRef)(null);
520
+ (0, import_react7.useEffect)(() => {
521
+ const handleClickOutside = (e) => {
522
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
523
+ };
524
+ document.addEventListener("mousedown", handleClickOutside);
525
+ return () => document.removeEventListener("mousedown", handleClickOutside);
526
+ }, []);
527
+ if (!isSignedIn || !user) return null;
528
+ const initials = user.name ? user.name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2) : user.email[0].toUpperCase();
529
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "githat-user-button", ref, children: [
530
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "githat-avatar-trigger", onClick: () => setOpen(!open), "aria-label": "User menu", "aria-expanded": open, "aria-haspopup": "true", children: user.avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: user.avatarUrl, alt: user.name || "User avatar", className: "githat-avatar-img" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "githat-avatar-initials", children: initials }) }),
531
+ open && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "githat-dropdown", role: "menu", children: [
532
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "githat-dropdown-header", children: [
533
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "githat-dropdown-name", children: user.name }),
534
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "githat-dropdown-email", children: user.email }),
535
+ org && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "githat-dropdown-org", children: org.name })
536
+ ] }),
537
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "githat-dropdown-divider" }),
538
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "githat-dropdown-item", role: "menuitem", onClick: () => {
539
+ signOut();
540
+ setOpen(false);
541
+ }, children: "Sign out" })
542
+ ] })
543
+ ] });
544
+ }
545
+
546
+ // src/components/OrgSwitcher.tsx
547
+ var import_react8 = require("react");
548
+ var import_jsx_runtime7 = require("react/jsx-runtime");
549
+ function OrgSwitcher() {
550
+ const { org, isSignedIn, switchOrg } = useAuth();
551
+ const githat = useGitHat();
552
+ const [orgs, setOrgs] = (0, import_react8.useState)([]);
553
+ const [orgsLoading, setOrgsLoading] = (0, import_react8.useState)(false);
554
+ const [open, setOpen] = (0, import_react8.useState)(false);
555
+ const ref = (0, import_react8.useRef)(null);
556
+ (0, import_react8.useEffect)(() => {
557
+ if (isSignedIn) {
558
+ setOrgsLoading(true);
559
+ githat.getUserOrgs().then((data) => setOrgs(data.orgs || [])).catch(() => {
560
+ }).finally(() => setOrgsLoading(false));
561
+ }
562
+ }, [isSignedIn]);
563
+ (0, import_react8.useEffect)(() => {
564
+ const handleClickOutside = (e) => {
565
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
566
+ };
567
+ document.addEventListener("mousedown", handleClickOutside);
568
+ return () => document.removeEventListener("mousedown", handleClickOutside);
569
+ }, []);
570
+ if (!isSignedIn || !org || orgs.length < 2 && !orgsLoading) return null;
571
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "githat-org-switcher", ref, children: [
572
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { className: "githat-org-trigger", onClick: () => setOpen(!open), "aria-label": "Switch organization", "aria-expanded": open, "aria-haspopup": "true", children: [
573
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "githat-org-name", children: org.name }),
574
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "githat-chevron", children: open ? "\u25B2" : "\u25BC" })
575
+ ] }),
576
+ open && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "githat-dropdown", role: "menu", children: orgsLoading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "githat-dropdown-item", "aria-busy": "true", children: "Loading..." }) : orgs.map((o) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
577
+ "button",
578
+ {
579
+ className: `githat-dropdown-item ${o.id === org.id ? "githat-dropdown-item-active" : ""}`,
580
+ role: "menuitem",
581
+ "aria-current": o.id === org.id ? "true" : void 0,
582
+ onClick: () => {
583
+ switchOrg(o.id);
584
+ setOpen(false);
585
+ },
586
+ children: [
587
+ o.name,
588
+ o.id === org.id && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "githat-check", children: "\u2713" })
589
+ ]
590
+ },
591
+ o.id
592
+ )) })
593
+ ] });
594
+ }
595
+
596
+ // src/components/VerifiedBadge.tsx
597
+ var import_react9 = require("react");
598
+ var import_jsx_runtime8 = require("react/jsx-runtime");
599
+ var CACHE_TTL = 5 * 60 * 1e3;
600
+ var cache = /* @__PURE__ */ new Map();
601
+ function VerifiedBadge({ type, identifier, label }) {
602
+ const githat = useGitHat();
603
+ const [verified, setVerified] = (0, import_react9.useState)(null);
604
+ const mounted = (0, import_react9.useRef)(true);
605
+ (0, import_react9.useEffect)(() => {
606
+ mounted.current = true;
607
+ const key = `${type}:${identifier}`;
608
+ const cached = cache.get(key);
609
+ if (cached && Date.now() - cached.ts < CACHE_TTL) {
610
+ setVerified(cached.verified);
611
+ return;
612
+ }
613
+ const verify = type === "mcp" ? githat.verifyMCP : githat.verifyAgent;
614
+ verify(identifier).then((data) => {
615
+ if (mounted.current) {
616
+ setVerified(data.verified);
617
+ cache.set(key, { verified: data.verified, ts: Date.now() });
618
+ }
619
+ }).catch(() => {
620
+ if (mounted.current) setVerified(false);
621
+ });
622
+ return () => {
623
+ mounted.current = false;
624
+ };
625
+ }, [type, identifier]);
626
+ if (verified === null) return null;
627
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: `githat-badge ${verified ? "githat-badge-verified" : "githat-badge-unverified"}`, children: [
628
+ verified ? "\u2713" : "\u2717",
629
+ " ",
630
+ label || (verified ? "Verified" : "Unverified")
631
+ ] });
632
+ }
633
+
634
+ // src/components/ProtectedRoute.tsx
635
+ var import_jsx_runtime9 = require("react/jsx-runtime");
636
+ function ProtectedRoute({ children, fallback }) {
637
+ const { isSignedIn, isLoading, config } = useAuth();
638
+ if (isLoading) {
639
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: fallback || /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "githat-loading", children: "Loading..." }) });
640
+ }
641
+ if (!isSignedIn) {
642
+ if (typeof window !== "undefined") {
643
+ window.location.href = config.signInUrl;
644
+ }
645
+ return null;
646
+ }
647
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
648
+ }
649
+ // Annotate the CommonJS export names for ESM import in node:
650
+ 0 && (module.exports = {
651
+ GitHatProvider,
652
+ OrgSwitcher,
653
+ ProtectedRoute,
654
+ SignInButton,
655
+ SignInForm,
656
+ SignUpButton,
657
+ SignUpForm,
658
+ UserButton,
659
+ VerifiedBadge,
660
+ useAuth,
661
+ useGitHat
662
+ });
663
+ //# sourceMappingURL=index.js.map