@urbackend/react 0.1.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,964 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ GuestRoute: () => GuestRoute,
25
+ ProtectedRoute: () => ProtectedRoute,
26
+ UrAuth: () => UrAuth,
27
+ UrProvider: () => UrProvider,
28
+ UrUserButton: () => UrUserButton,
29
+ useAuth: () => useAuth,
30
+ useDb: () => useDb,
31
+ useStorage: () => useStorage,
32
+ useUrContext: () => useUrContext,
33
+ useUser: () => useUser
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/context.tsx
38
+ var import_react = require("react");
39
+ var import_sdk = require("@urbackend/sdk");
40
+ var import_jsx_runtime = require("react/jsx-runtime");
41
+ var UrContext = (0, import_react.createContext)(void 0);
42
+ var UrProvider = ({ apiKey, baseUrl, children }) => {
43
+ const [user, setUser] = (0, import_react.useState)(null);
44
+ const [isInitializing, setIsInitializing] = (0, import_react.useState)(true);
45
+ const [isLoading, setIsLoading] = (0, import_react.useState)(false);
46
+ const [error, setError] = (0, import_react.useState)(null);
47
+ const { client, auth, db, storage } = (0, import_react.useMemo)(() => {
48
+ const _client = new import_sdk.UrBackendClient({ apiKey, baseUrl });
49
+ return {
50
+ client: _client,
51
+ auth: new import_sdk.AuthModule(_client),
52
+ db: new import_sdk.DatabaseModule(_client),
53
+ storage: new import_sdk.StorageModule(_client)
54
+ };
55
+ }, [apiKey, baseUrl]);
56
+ (0, import_react.useEffect)(() => {
57
+ let mounted = true;
58
+ const initAuth = async () => {
59
+ try {
60
+ if (typeof window !== "undefined") {
61
+ const savedToken = localStorage.getItem("ur_auth_token");
62
+ if (savedToken) auth.setToken(savedToken);
63
+ }
64
+ const urlParams = new URLSearchParams(window.location.search);
65
+ const hashParams = new URLSearchParams(window.location.hash.substring(1));
66
+ const token = hashParams.get("token");
67
+ const rtCode = urlParams.get("rtCode");
68
+ const error2 = urlParams.get("error");
69
+ if (error2) {
70
+ console.error("Social Auth Error:", error2);
71
+ if (mounted) setError(error2);
72
+ window.history.replaceState({}, document.title, window.location.pathname);
73
+ } else if (token) {
74
+ auth.setToken(token);
75
+ if (typeof window !== "undefined") localStorage.setItem("ur_auth_token", token);
76
+ if (rtCode) {
77
+ try {
78
+ const exRes = await auth.socialExchange({ token, rtCode });
79
+ const exToken = exRes.accessToken || exRes.token;
80
+ if (exToken && typeof window !== "undefined") localStorage.setItem("ur_auth_token", exToken);
81
+ } catch (err) {
82
+ console.error("Failed to exchange refresh token", err);
83
+ if (mounted) setError(err.message || "Failed to complete social login");
84
+ throw err;
85
+ }
86
+ }
87
+ window.history.replaceState({}, document.title, window.location.pathname);
88
+ } else {
89
+ try {
90
+ const res = await auth.refreshToken();
91
+ const newToken = res.accessToken || res.token;
92
+ if (newToken && typeof window !== "undefined") localStorage.setItem("ur_auth_token", newToken);
93
+ } catch (e) {
94
+ }
95
+ }
96
+ const currentUser = await auth.me();
97
+ if (mounted) {
98
+ setUser(currentUser);
99
+ }
100
+ } catch (error2) {
101
+ if (mounted) {
102
+ setUser(null);
103
+ }
104
+ } finally {
105
+ if (mounted) {
106
+ setIsInitializing(false);
107
+ }
108
+ }
109
+ };
110
+ initAuth();
111
+ return () => {
112
+ mounted = false;
113
+ };
114
+ }, [auth]);
115
+ const value = {
116
+ client,
117
+ auth,
118
+ db,
119
+ storage,
120
+ user,
121
+ setUser,
122
+ isInitializing,
123
+ isLoading,
124
+ setIsLoading,
125
+ error,
126
+ setError
127
+ };
128
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UrContext.Provider, { value, children });
129
+ };
130
+ var useUrContext = () => {
131
+ const context = (0, import_react.useContext)(UrContext);
132
+ if (!context) {
133
+ throw new Error("useUrContext must be used within an UrProvider");
134
+ }
135
+ return context;
136
+ };
137
+
138
+ // src/hooks.ts
139
+ var import_react2 = require("react");
140
+ var useAuth = () => {
141
+ const { auth, user, setUser, isInitializing, isLoading, setIsLoading, error, setError } = useUrContext();
142
+ if (!auth) {
143
+ throw new Error("Auth module not initialized. Make sure you are inside UrProvider.");
144
+ }
145
+ const login = (0, import_react2.useCallback)(async (payload) => {
146
+ try {
147
+ setError(null);
148
+ setIsLoading(true);
149
+ const res = await auth.login(payload);
150
+ const token = res.accessToken || res.token;
151
+ if (token && typeof window !== "undefined") localStorage.setItem("ur_auth_token", token);
152
+ const currentUser = await auth.me();
153
+ setUser(currentUser);
154
+ } catch (err) {
155
+ setError(err.message || "Login failed");
156
+ throw err;
157
+ } finally {
158
+ setIsLoading(false);
159
+ }
160
+ }, [auth, setUser, setIsLoading, setError]);
161
+ const signUp = (0, import_react2.useCallback)(async (payload) => {
162
+ try {
163
+ setError(null);
164
+ setIsLoading(true);
165
+ const newUser = await auth.signUp(payload);
166
+ return newUser;
167
+ } catch (err) {
168
+ setError(err.message || "Sign up failed");
169
+ throw err;
170
+ } finally {
171
+ setIsLoading(false);
172
+ }
173
+ }, [auth, setIsLoading, setError]);
174
+ const logout = (0, import_react2.useCallback)(async () => {
175
+ try {
176
+ setError(null);
177
+ setIsLoading(true);
178
+ await auth.logout();
179
+ if (typeof window !== "undefined") localStorage.removeItem("ur_auth_token");
180
+ setUser(null);
181
+ } catch (err) {
182
+ setError(err.message || "Logout failed");
183
+ throw err;
184
+ } finally {
185
+ setIsLoading(false);
186
+ }
187
+ }, [auth, setUser, setIsLoading, setError]);
188
+ const socialLogin = (0, import_react2.useCallback)((provider) => {
189
+ setError(null);
190
+ const url = auth.socialStart(provider);
191
+ window.location.href = url;
192
+ }, [auth, setError]);
193
+ const verifyEmail = (0, import_react2.useCallback)(async (payload) => {
194
+ try {
195
+ setError(null);
196
+ return await auth.verifyEmail(payload);
197
+ } catch (err) {
198
+ setError(err.message || "Email verification failed");
199
+ throw err;
200
+ }
201
+ }, [auth, setError]);
202
+ const changePassword = (0, import_react2.useCallback)(async (payload) => {
203
+ try {
204
+ setError(null);
205
+ return await auth.changePassword(payload);
206
+ } catch (err) {
207
+ setError(err.message || "Failed to change password");
208
+ throw err;
209
+ }
210
+ }, [auth, setError]);
211
+ const requestPasswordReset = (0, import_react2.useCallback)(async (payload) => {
212
+ try {
213
+ setError(null);
214
+ setIsLoading(true);
215
+ return await auth.requestPasswordReset(payload);
216
+ } catch (err) {
217
+ setError(err.message || "Failed to request password reset");
218
+ throw err;
219
+ } finally {
220
+ setIsLoading(false);
221
+ }
222
+ }, [auth, setError, setIsLoading]);
223
+ const resetPassword = (0, import_react2.useCallback)(async (payload) => {
224
+ try {
225
+ setError(null);
226
+ setIsLoading(true);
227
+ return await auth.resetPassword(payload);
228
+ } catch (err) {
229
+ setError(err.message || "Failed to reset password");
230
+ throw err;
231
+ } finally {
232
+ setIsLoading(false);
233
+ }
234
+ }, [auth, setError, setIsLoading]);
235
+ const clearError = (0, import_react2.useCallback)(() => setError(null), [setError]);
236
+ return {
237
+ user,
238
+ isInitializing,
239
+ isLoading,
240
+ error,
241
+ isAuthenticated: !!user,
242
+ login,
243
+ signUp,
244
+ logout,
245
+ socialLogin,
246
+ verifyEmail,
247
+ changePassword,
248
+ requestPasswordReset,
249
+ resetPassword,
250
+ clearError,
251
+ authApi: auth
252
+ // Escape hatch to underlying SDK
253
+ };
254
+ };
255
+ var useUser = () => {
256
+ const { user, isInitializing, isLoading, error } = useUrContext();
257
+ return {
258
+ user,
259
+ isInitializing,
260
+ isLoading,
261
+ error,
262
+ isAuthenticated: !!user
263
+ };
264
+ };
265
+ var useDb = () => {
266
+ const { db } = useUrContext();
267
+ if (!db) {
268
+ throw new Error("Database module not initialized.");
269
+ }
270
+ return db;
271
+ };
272
+ var useStorage = () => {
273
+ const { storage } = useUrContext();
274
+ if (!storage) {
275
+ throw new Error("Storage module not initialized.");
276
+ }
277
+ return storage;
278
+ };
279
+
280
+ // src/components.tsx
281
+ var import_react3 = require("react");
282
+ var import_jsx_runtime2 = require("react/jsx-runtime");
283
+ var ProtectedRoute = ({
284
+ children,
285
+ redirectTo = "/login",
286
+ fallback = null,
287
+ onRedirect
288
+ }) => {
289
+ const { isAuthenticated, isInitializing } = useUser();
290
+ (0, import_react3.useEffect)(() => {
291
+ if (!isInitializing && !isAuthenticated) {
292
+ if (onRedirect) {
293
+ onRedirect();
294
+ } else if (typeof window !== "undefined") {
295
+ window.location.href = redirectTo;
296
+ }
297
+ }
298
+ }, [isAuthenticated, isInitializing, redirectTo, onRedirect]);
299
+ if (isInitializing) {
300
+ return fallback;
301
+ }
302
+ if (!isAuthenticated) {
303
+ return fallback;
304
+ }
305
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
306
+ };
307
+ var GuestRoute = ({
308
+ children,
309
+ redirectTo = "/dashboard",
310
+ fallback = null,
311
+ onRedirect
312
+ }) => {
313
+ const { isAuthenticated, isInitializing } = useUser();
314
+ (0, import_react3.useEffect)(() => {
315
+ if (!isInitializing && isAuthenticated) {
316
+ if (onRedirect) {
317
+ onRedirect();
318
+ } else if (typeof window !== "undefined") {
319
+ window.location.href = redirectTo;
320
+ }
321
+ }
322
+ }, [isAuthenticated, isInitializing, redirectTo, onRedirect]);
323
+ if (isInitializing) {
324
+ return fallback;
325
+ }
326
+ if (isAuthenticated) {
327
+ return fallback;
328
+ }
329
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
330
+ };
331
+
332
+ // src/components/UrAuth.tsx
333
+ var import_react5 = require("react");
334
+
335
+ // src/components/Toast.tsx
336
+ var import_react4 = require("react");
337
+ var import_jsx_runtime3 = require("react/jsx-runtime");
338
+ var Toast = ({ message, type, onClose, isDark = false }) => {
339
+ const [isVisible, setIsVisible] = (0, import_react4.useState)(false);
340
+ const [isLeaving, setIsLeaving] = (0, import_react4.useState)(false);
341
+ (0, import_react4.useEffect)(() => {
342
+ requestAnimationFrame(() => {
343
+ setIsVisible(true);
344
+ });
345
+ let innerTimer;
346
+ const timer = setTimeout(() => {
347
+ setIsLeaving(true);
348
+ innerTimer = setTimeout(onClose, 300);
349
+ }, 4e3);
350
+ return () => {
351
+ clearTimeout(timer);
352
+ if (innerTimer) clearTimeout(innerTimer);
353
+ };
354
+ }, [onClose]);
355
+ const bgColor = isDark ? "rgba(30, 30, 30, 0.9)" : "rgba(255, 255, 255, 0.9)";
356
+ const borderColor = type === "success" ? "rgba(34, 197, 94, 0.5)" : "rgba(239, 68, 68, 0.5)";
357
+ const iconColor = type === "success" ? "#22c55e" : "#ef4444";
358
+ const textColor = isDark ? "#fff" : "#000";
359
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
360
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: `
361
+ @keyframes slideIn {
362
+ from { transform: translate(-50%, -20px) scale(0.95); opacity: 0; }
363
+ to { transform: translate(-50%, 0) scale(1); opacity: 1; }
364
+ }
365
+ @keyframes slideOut {
366
+ from { transform: translate(-50%, 0) scale(1); opacity: 1; }
367
+ to { transform: translate(-50%, -20px) scale(0.95); opacity: 0; }
368
+ }
369
+ ` }),
370
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
371
+ "div",
372
+ {
373
+ style: {
374
+ position: "fixed",
375
+ top: "24px",
376
+ left: "50%",
377
+ transform: "translateX(-50%)",
378
+ zIndex: 9999,
379
+ display: "flex",
380
+ alignItems: "center",
381
+ gap: "12px",
382
+ padding: "12px 20px",
383
+ borderRadius: "0",
384
+ background: bgColor,
385
+ backdropFilter: "blur(16px)",
386
+ WebkitBackdropFilter: "blur(16px)",
387
+ border: `1px solid ${borderColor}`,
388
+ boxShadow: "0 8px 32px rgba(0,0,0,0.12)",
389
+ color: textColor,
390
+ fontFamily: "system-ui, -apple-system, sans-serif",
391
+ fontSize: "14px",
392
+ fontWeight: 500,
393
+ animation: isLeaving ? "slideOut 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards" : "slideIn 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards"
394
+ },
395
+ children: [
396
+ type === "success" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: iconColor, strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
397
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
398
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "22 4 12 14.01 9 11.01" })
399
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: iconColor, strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
400
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
401
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
402
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
403
+ ] }),
404
+ message
405
+ ]
406
+ }
407
+ )
408
+ ] });
409
+ };
410
+
411
+ // src/components/UrAuth.tsx
412
+ var import_jsx_runtime4 = require("react/jsx-runtime");
413
+ var UrAuth = ({
414
+ providers = ["google", "github"],
415
+ theme = "light",
416
+ onSuccess
417
+ }) => {
418
+ const { login, signUp, socialLogin, requestPasswordReset, resetPassword, isLoading, error, clearError } = useAuth();
419
+ const [mode, setMode] = (0, import_react5.useState)("signin");
420
+ const [email, setEmail] = (0, import_react5.useState)("");
421
+ const [password, setPassword] = (0, import_react5.useState)("");
422
+ const [otp, setOtp] = (0, import_react5.useState)("");
423
+ const [name, setName] = (0, import_react5.useState)("");
424
+ const [toast, setToast] = (0, import_react5.useState)(null);
425
+ (0, import_react5.useEffect)(() => {
426
+ if (error) {
427
+ setToast({ message: error, type: "error" });
428
+ }
429
+ }, [error]);
430
+ const handleSubmit = async (e) => {
431
+ e.preventDefault();
432
+ try {
433
+ if (mode === "signin") {
434
+ await login({ email, password });
435
+ setToast({ message: "Welcome back!", type: "success" });
436
+ if (onSuccess) onSuccess();
437
+ } else if (mode === "signup") {
438
+ await signUp({ email, password, name });
439
+ await login({ email, password });
440
+ setToast({ message: "Account created successfully!", type: "success" });
441
+ if (onSuccess) onSuccess();
442
+ } else if (mode === "forgot") {
443
+ await requestPasswordReset({ email });
444
+ setToast({ message: "Reset code sent to your email", type: "success" });
445
+ setMode("reset");
446
+ } else if (mode === "reset") {
447
+ await resetPassword({ email, otp, newPassword: password });
448
+ setToast({ message: "Password reset successfully", type: "success" });
449
+ setMode("signin");
450
+ setPassword("");
451
+ setOtp("");
452
+ }
453
+ } catch (err) {
454
+ }
455
+ };
456
+ const isDark = theme === "dark";
457
+ const bg = isDark ? "#1a1a1a" : "#ffffff";
458
+ const text = isDark ? "#ffffff" : "#0f172a";
459
+ const textMuted = isDark ? "#a1a1aa" : "#64748b";
460
+ const border = isDark ? "#333" : "#e2e8f0";
461
+ const inputBg = isDark ? "#2a2a2a" : "#ffffff";
462
+ const styles = {
463
+ wrapper: {
464
+ width: "100%",
465
+ maxWidth: "420px",
466
+ margin: "0 auto",
467
+ borderRadius: "0",
468
+ background: bg,
469
+ boxShadow: isDark ? "0 20px 40px rgba(0,0,0,0.5)" : "0 20px 40px rgba(0,0,0,0.06), 0 1px 3px rgba(0,0,0,0.05)",
470
+ border: `1px solid ${border}`,
471
+ overflow: "hidden",
472
+ fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
473
+ color: text
474
+ },
475
+ body: {
476
+ padding: "32px 32px 24px 32px"
477
+ },
478
+ switcherContainer: {
479
+ display: "flex",
480
+ alignItems: "center",
481
+ justifyContent: "center",
482
+ marginBottom: "32px"
483
+ },
484
+ switcher: {
485
+ display: "inline-flex",
486
+ background: isDark ? "#2a2a2a" : "#f1f5f9",
487
+ padding: "4px",
488
+ borderRadius: "0"
489
+ },
490
+ switchBtn: (active) => ({
491
+ display: "flex",
492
+ alignItems: "center",
493
+ gap: "6px",
494
+ padding: "8px 20px",
495
+ borderRadius: "0",
496
+ fontSize: "13px",
497
+ fontWeight: 600,
498
+ cursor: "pointer",
499
+ color: active ? text : textMuted,
500
+ background: active ? isDark ? "#444" : "#ffffff" : "transparent",
501
+ boxShadow: active ? isDark ? "0 2px 4px rgba(0,0,0,0.2)" : "0 2px 8px rgba(0,0,0,0.05)" : "none",
502
+ border: "none",
503
+ transition: "all 0.2s ease"
504
+ }),
505
+ field: {
506
+ marginBottom: "20px"
507
+ },
508
+ labelRow: {
509
+ display: "flex",
510
+ justifyContent: "space-between",
511
+ alignItems: "center",
512
+ marginBottom: "8px"
513
+ },
514
+ label: {
515
+ fontSize: "13px",
516
+ fontWeight: 600,
517
+ color: isDark ? "#ddd" : "#334155"
518
+ },
519
+ forgotLink: {
520
+ fontSize: "12px",
521
+ fontWeight: 600,
522
+ color: text,
523
+ cursor: "pointer",
524
+ textDecoration: "none",
525
+ background: "none",
526
+ border: "none",
527
+ padding: 0
528
+ },
529
+ input: {
530
+ width: "100%",
531
+ padding: "12px 16px",
532
+ borderRadius: "0",
533
+ border: `1px solid ${border}`,
534
+ background: inputBg,
535
+ color: text,
536
+ fontSize: "14px",
537
+ boxSizing: "border-box",
538
+ outline: "none",
539
+ transition: "border-color 0.2s ease"
540
+ },
541
+ primaryBtn: {
542
+ width: "100%",
543
+ padding: "14px",
544
+ borderRadius: "0",
545
+ background: "linear-gradient(180deg, #2a2a2a 0%, #111111 100%)",
546
+ color: "#ffffff",
547
+ fontSize: "15px",
548
+ fontWeight: 600,
549
+ border: "none",
550
+ boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
551
+ cursor: "pointer",
552
+ marginTop: "8px",
553
+ transition: "transform 0.1s ease"
554
+ },
555
+ divider: {
556
+ display: "flex",
557
+ alignItems: "center",
558
+ margin: "24px 0",
559
+ color: "#94a3b8",
560
+ fontSize: "11px",
561
+ fontWeight: 600,
562
+ letterSpacing: "1px"
563
+ },
564
+ dividerLine: {
565
+ flex: 1,
566
+ height: "1px",
567
+ background: border
568
+ },
569
+ dividerText: {
570
+ padding: "0 12px"
571
+ },
572
+ socialBtn: {
573
+ width: "100%",
574
+ padding: "12px",
575
+ borderRadius: "0",
576
+ border: `1px solid ${border}`,
577
+ background: isDark ? "#2a2a2a" : "#ffffff",
578
+ color: text,
579
+ fontSize: "14px",
580
+ fontWeight: 600,
581
+ display: "flex",
582
+ alignItems: "center",
583
+ justifyContent: "center",
584
+ gap: "10px",
585
+ marginBottom: "12px",
586
+ cursor: "pointer",
587
+ boxShadow: isDark ? "none" : "0 1px 2px rgba(0,0,0,0.02)",
588
+ transition: "background 0.2s ease"
589
+ },
590
+ footer: {
591
+ background: isDark ? "#222" : "#f8fafc",
592
+ padding: "24px",
593
+ textAlign: "center",
594
+ borderTop: `1px solid ${border}`,
595
+ fontSize: "13px",
596
+ color: textMuted
597
+ },
598
+ footerLink: {
599
+ color: text,
600
+ fontWeight: 600,
601
+ textDecoration: "underline",
602
+ cursor: "pointer",
603
+ marginLeft: "4px",
604
+ background: "none",
605
+ border: "none",
606
+ padding: 0
607
+ }
608
+ };
609
+ const GoogleIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [
610
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z", fill: "#4285F4" }),
611
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: "#34A853" }),
612
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: "#FBBC05" }),
613
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: "#EA4335" })
614
+ ] });
615
+ const GithubIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: isDark ? "#fff" : "#000", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" }) });
616
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.wrapper, children: [
617
+ toast && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
618
+ Toast,
619
+ {
620
+ message: toast.message,
621
+ type: toast.type,
622
+ isDark,
623
+ onClose: () => {
624
+ setToast(null);
625
+ if (toast.type === "error") clearError();
626
+ }
627
+ }
628
+ ),
629
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.body, children: [
630
+ (mode === "signin" || mode === "signup") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles.switcherContainer, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.switcher, children: [
631
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
632
+ "button",
633
+ {
634
+ type: "button",
635
+ style: styles.switchBtn(mode === "signin"),
636
+ onClick: () => {
637
+ setMode("signin");
638
+ clearError();
639
+ },
640
+ children: [
641
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
642
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4" }),
643
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "10 17 15 12 10 7" }),
644
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "15", y1: "12", x2: "3", y2: "12" })
645
+ ] }),
646
+ "Login"
647
+ ]
648
+ }
649
+ ),
650
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
651
+ "button",
652
+ {
653
+ type: "button",
654
+ style: styles.switchBtn(mode === "signup"),
655
+ onClick: () => {
656
+ setMode("signup");
657
+ clearError();
658
+ },
659
+ children: [
660
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
661
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
662
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "7", r: "4" }),
663
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "19", y1: "8", x2: "19", y2: "14" }),
664
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "22", y1: "11", x2: "16", y2: "11" })
665
+ ] }),
666
+ "Sign Up"
667
+ ]
668
+ }
669
+ )
670
+ ] }) }),
671
+ (mode === "forgot" || mode === "reset") && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginBottom: "24px", textAlign: "center" }, children: [
672
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { style: { margin: "0 0 8px", fontSize: "20px", fontWeight: 700, color: text }, children: mode === "forgot" ? "Reset Password" : "Enter Reset Code" }),
673
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: 0, fontSize: "14px", color: textMuted }, children: mode === "forgot" ? "Enter your email and we'll send a code" : `Enter the code sent to ${email}` })
674
+ ] }),
675
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { onSubmit: handleSubmit, children: [
676
+ mode === "signup" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.field, children: [
677
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles.labelRow, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { style: styles.label, children: "Full Name" }) }),
678
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
679
+ "input",
680
+ {
681
+ style: styles.input,
682
+ type: "text",
683
+ placeholder: "Enter your name",
684
+ value: name,
685
+ onChange: (e) => setName(e.target.value),
686
+ required: true
687
+ }
688
+ )
689
+ ] }),
690
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.field, children: [
691
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles.labelRow, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { style: styles.label, children: "Email address" }) }),
692
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
693
+ "input",
694
+ {
695
+ style: styles.input,
696
+ type: "email",
697
+ placeholder: "Enter your email address",
698
+ value: email,
699
+ onChange: (e) => setEmail(e.target.value),
700
+ required: true,
701
+ readOnly: mode === "reset"
702
+ }
703
+ )
704
+ ] }),
705
+ mode === "reset" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.field, children: [
706
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles.labelRow, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { style: styles.label, children: "6-digit OTP Code" }) }),
707
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
708
+ "input",
709
+ {
710
+ style: styles.input,
711
+ type: "text",
712
+ placeholder: "Enter reset code",
713
+ value: otp,
714
+ onChange: (e) => setOtp(e.target.value),
715
+ required: true
716
+ }
717
+ )
718
+ ] }),
719
+ (mode === "signin" || mode === "signup" || mode === "reset") && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.field, children: [
720
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.labelRow, children: [
721
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { style: styles.label, children: mode === "reset" ? "New Password" : "Password" }),
722
+ mode === "signin" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", style: styles.forgotLink, onClick: () => {
723
+ setMode("forgot");
724
+ clearError();
725
+ }, children: "Forgot password?" })
726
+ ] }),
727
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
728
+ "input",
729
+ {
730
+ style: styles.input,
731
+ type: "password",
732
+ placeholder: mode === "reset" ? "Enter new password" : "Enter your password",
733
+ value: password,
734
+ onChange: (e) => setPassword(e.target.value),
735
+ required: true
736
+ }
737
+ )
738
+ ] }),
739
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
740
+ "button",
741
+ {
742
+ style: styles.primaryBtn,
743
+ type: "submit",
744
+ disabled: isLoading,
745
+ onMouseDown: (e) => e.currentTarget.style.transform = "scale(0.98)",
746
+ onMouseUp: (e) => e.currentTarget.style.transform = "scale(1)",
747
+ onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)",
748
+ children: isLoading ? "Processing..." : mode === "signin" ? "Log In" : mode === "signup" ? "Create Account" : mode === "forgot" ? "Send Reset Code" : "Reset Password"
749
+ }
750
+ )
751
+ ] }),
752
+ (mode === "signin" || mode === "signup") && providers && providers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
753
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.divider, children: [
754
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles.dividerLine }),
755
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: styles.dividerText, children: "OR" }),
756
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles.dividerLine })
757
+ ] }),
758
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
759
+ providers.includes("google") && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { style: styles.socialBtn, onClick: () => socialLogin("google"), type: "button", children: [
760
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GoogleIcon, {}),
761
+ "Continue with Google"
762
+ ] }),
763
+ providers.includes("github") && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { style: styles.socialBtn, onClick: () => socialLogin("github"), type: "button", children: [
764
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GithubIcon, {}),
765
+ "Continue with GitHub"
766
+ ] })
767
+ ] })
768
+ ] })
769
+ ] }),
770
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.footer, children: [
771
+ mode === "signin" ? "Don't have an account yet?" : mode === "signup" ? "Already have an account?" : "Remember your password?",
772
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
773
+ "button",
774
+ {
775
+ type: "button",
776
+ style: styles.footerLink,
777
+ onClick: () => {
778
+ setMode(mode === "signin" ? "signup" : "signin");
779
+ clearError();
780
+ },
781
+ children: mode === "signin" ? "Sign up" : "Log in"
782
+ }
783
+ )
784
+ ] })
785
+ ] });
786
+ };
787
+
788
+ // src/components/UrUserButton.tsx
789
+ var import_react6 = require("react");
790
+ var import_jsx_runtime5 = require("react/jsx-runtime");
791
+ var UrUserButton = ({
792
+ shape = "square",
793
+ position = "top-right",
794
+ onProfileClick,
795
+ onSettingsClick,
796
+ zIndex = 999
797
+ }) => {
798
+ const { user } = useUser();
799
+ const { logout } = useAuth();
800
+ const [isOpen, setIsOpen] = (0, import_react6.useState)(false);
801
+ const containerRef = (0, import_react6.useRef)(null);
802
+ (0, import_react6.useEffect)(() => {
803
+ const handleClickOutside = (event) => {
804
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
805
+ setIsOpen(false);
806
+ }
807
+ };
808
+ document.addEventListener("mousedown", handleClickOutside);
809
+ return () => document.removeEventListener("mousedown", handleClickOutside);
810
+ }, []);
811
+ if (!user) return null;
812
+ const borderRadius = shape === "circle" ? "50%" : "0px";
813
+ const isFixed = position !== "inline";
814
+ const positionStyles = isFixed ? {
815
+ position: "fixed",
816
+ zIndex,
817
+ top: position.includes("top") ? "24px" : "auto",
818
+ bottom: position.includes("bottom") ? "24px" : "auto",
819
+ right: position.includes("right") ? "24px" : "auto",
820
+ left: position.includes("left") ? "24px" : "auto"
821
+ } : { position: "relative" };
822
+ const dropdownStyles = {
823
+ position: "absolute",
824
+ top: position.includes("top") || position === "inline" ? "calc(100% + 8px)" : "auto",
825
+ bottom: position.includes("bottom") ? "calc(100% + 8px)" : "auto",
826
+ right: position.includes("right") || position === "inline" ? "0" : "auto",
827
+ left: position.includes("left") ? "0" : "auto",
828
+ background: "#ffffff",
829
+ border: "1px solid #e2e8f0",
830
+ borderRadius: "0px",
831
+ boxShadow: "0 10px 25px rgba(0,0,0,0.1)",
832
+ width: "220px",
833
+ display: isOpen ? "block" : "none",
834
+ overflow: "hidden",
835
+ fontFamily: "system-ui, -apple-system, sans-serif"
836
+ };
837
+ const getInitials = () => {
838
+ return user.name?.[0]?.toUpperCase() || user.email?.[0]?.toUpperCase() || "U";
839
+ };
840
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: containerRef, style: positionStyles, children: [
841
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
842
+ "button",
843
+ {
844
+ onClick: () => setIsOpen(!isOpen),
845
+ style: {
846
+ width: "40px",
847
+ height: "40px",
848
+ padding: 0,
849
+ border: "1px solid #e2e8f0",
850
+ background: "#f8fafc",
851
+ borderRadius,
852
+ cursor: "pointer",
853
+ display: "flex",
854
+ alignItems: "center",
855
+ justifyContent: "center",
856
+ overflow: "hidden",
857
+ boxShadow: "0 2px 5px rgba(0,0,0,0.05)",
858
+ transition: "transform 0.1s ease"
859
+ },
860
+ children: user.avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: user.avatarUrl, alt: "User", style: { width: "100%", height: "100%", objectFit: "cover" } }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { fontSize: "16px", fontWeight: 600, color: "#475569" }, children: getInitials() })
861
+ }
862
+ ),
863
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: dropdownStyles, children: [
864
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { padding: "16px", borderBottom: "1px solid #e2e8f0", background: "#f8fafc" }, children: [
865
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "14px", fontWeight: 600, color: "#0f172a", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: user.name || "User" }),
866
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: "12px", color: "#64748b", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", marginTop: "2px" }, children: user.email })
867
+ ] }),
868
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { padding: "8px" }, children: [
869
+ onProfileClick && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
870
+ "button",
871
+ {
872
+ onClick: () => {
873
+ setIsOpen(false);
874
+ onProfileClick();
875
+ },
876
+ style: {
877
+ width: "100%",
878
+ textAlign: "left",
879
+ padding: "10px 12px",
880
+ background: "transparent",
881
+ border: "none",
882
+ fontSize: "14px",
883
+ color: "#334155",
884
+ cursor: "pointer",
885
+ borderRadius: "0px",
886
+ display: "block"
887
+ },
888
+ onMouseEnter: (e) => e.currentTarget.style.background = "#f1f5f9",
889
+ onMouseLeave: (e) => e.currentTarget.style.background = "transparent",
890
+ children: "Profile"
891
+ }
892
+ ),
893
+ onSettingsClick && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
894
+ "button",
895
+ {
896
+ onClick: () => {
897
+ setIsOpen(false);
898
+ onSettingsClick();
899
+ },
900
+ style: {
901
+ width: "100%",
902
+ textAlign: "left",
903
+ padding: "10px 12px",
904
+ background: "transparent",
905
+ border: "none",
906
+ fontSize: "14px",
907
+ color: "#334155",
908
+ cursor: "pointer",
909
+ borderRadius: "0px",
910
+ display: "block"
911
+ },
912
+ onMouseEnter: (e) => e.currentTarget.style.background = "#f1f5f9",
913
+ onMouseLeave: (e) => e.currentTarget.style.background = "transparent",
914
+ children: "Settings"
915
+ }
916
+ ),
917
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { height: "1px", background: "#e2e8f0", margin: "4px 0" } }),
918
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
919
+ "button",
920
+ {
921
+ onClick: () => {
922
+ setIsOpen(false);
923
+ logout();
924
+ },
925
+ style: {
926
+ width: "100%",
927
+ textAlign: "left",
928
+ padding: "10px 12px",
929
+ background: "transparent",
930
+ border: "none",
931
+ fontSize: "14px",
932
+ color: "#ef4444",
933
+ fontWeight: 500,
934
+ cursor: "pointer",
935
+ borderRadius: "0px",
936
+ display: "block"
937
+ },
938
+ onMouseEnter: (e) => e.currentTarget.style.background = "#fef2f2",
939
+ onMouseLeave: (e) => e.currentTarget.style.background = "transparent",
940
+ children: "Logout"
941
+ }
942
+ )
943
+ ] })
944
+ ] })
945
+ ] });
946
+ };
947
+
948
+ // src/index.ts
949
+ __reExport(index_exports, require("@urbackend/sdk"), module.exports);
950
+ // Annotate the CommonJS export names for ESM import in node:
951
+ 0 && (module.exports = {
952
+ GuestRoute,
953
+ ProtectedRoute,
954
+ UrAuth,
955
+ UrProvider,
956
+ UrUserButton,
957
+ useAuth,
958
+ useDb,
959
+ useStorage,
960
+ useUrContext,
961
+ useUser,
962
+ ...require("@urbackend/sdk")
963
+ });
964
+ //# sourceMappingURL=index.js.map