cilantro-react 0.1.6 → 0.1.7

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.
@@ -0,0 +1,19 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { c as AuthGuardProps } from './AuthGuard-siMJeYPD.mjs';
3
+ export { a as AuthGuardClassNames, b as AuthGuardLayout } from './AuthGuard-siMJeYPD.mjs';
4
+ import 'react';
5
+
6
+ /**
7
+ * AuthGuard integrated with Next.js App Router.
8
+ * Uses `useRouter().replace()` for redirects (no full page reload).
9
+ * Requires `next` to be installed.
10
+ *
11
+ * @example
12
+ * // app/dashboard/layout.tsx or page.tsx
13
+ * <NextAuthGuard redirectTo="/login" layout="fullscreen">
14
+ * <DashboardContent />
15
+ * </NextAuthGuard>
16
+ */
17
+ declare function NextAuthGuard(props: Omit<AuthGuardProps, "onRedirect">): react_jsx_runtime.JSX.Element;
18
+
19
+ export { AuthGuardProps, NextAuthGuard };
package/dist/next.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { c as AuthGuardProps } from './AuthGuard-siMJeYPD.js';
3
+ export { a as AuthGuardClassNames, b as AuthGuardLayout } from './AuthGuard-siMJeYPD.js';
4
+ import 'react';
5
+
6
+ /**
7
+ * AuthGuard integrated with Next.js App Router.
8
+ * Uses `useRouter().replace()` for redirects (no full page reload).
9
+ * Requires `next` to be installed.
10
+ *
11
+ * @example
12
+ * // app/dashboard/layout.tsx or page.tsx
13
+ * <NextAuthGuard redirectTo="/login" layout="fullscreen">
14
+ * <DashboardContent />
15
+ * </NextAuthGuard>
16
+ */
17
+ declare function NextAuthGuard(props: Omit<AuthGuardProps, "onRedirect">): react_jsx_runtime.JSX.Element;
18
+
19
+ export { AuthGuardProps, NextAuthGuard };
package/dist/next.js ADDED
@@ -0,0 +1,494 @@
1
+ 'use client';
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/next.ts
32
+ var next_exports = {};
33
+ __export(next_exports, {
34
+ NextAuthGuard: () => NextAuthGuard
35
+ });
36
+ module.exports = __toCommonJS(next_exports);
37
+
38
+ // src/components/auth/NextAuthGuard.tsx
39
+ var import_navigation = require("next/navigation");
40
+
41
+ // src/components/auth/AuthGuard.tsx
42
+ var import_react4 = require("react");
43
+
44
+ // src/context/CilantroContext.tsx
45
+ var import_react = require("react");
46
+ var import_cilantro_sdk2 = require("cilantro-sdk");
47
+ var import_auth = require("cilantro-sdk/auth");
48
+ var import_user = require("cilantro-sdk/user");
49
+ var import_wallet = require("cilantro-sdk/wallet");
50
+
51
+ // src/core/auth.ts
52
+ var import_cilantro_sdk = require("cilantro-sdk");
53
+
54
+ // src/core/storage-adapter.ts
55
+ var import_helpers = require("cilantro-sdk/helpers");
56
+
57
+ // src/context/CilantroContext.tsx
58
+ var import_jsx_runtime = require("react/jsx-runtime");
59
+ var CilantroContext = (0, import_react.createContext)(void 0);
60
+ function useCilantroContext() {
61
+ const ctx = (0, import_react.useContext)(CilantroContext);
62
+ if (ctx === void 0) {
63
+ throw new Error("useCilantroContext must be used within CilantroContextProvider");
64
+ }
65
+ return ctx;
66
+ }
67
+
68
+ // src/providers/CilantroAuthProvider.tsx
69
+ function useCilantroAuth() {
70
+ const ctx = useCilantroContext();
71
+ return {
72
+ user: ctx.user,
73
+ jwt: ctx.jwt,
74
+ token: ctx.jwt,
75
+ isAuthenticated: ctx.isAuthenticated,
76
+ login: (usernameOrEmail, password) => ctx.login({ usernameOrEmail, password }),
77
+ register: ctx.register,
78
+ logout: ctx.logout,
79
+ clearSessionDueToAuthError: ctx.clearSessionDueToAuthError,
80
+ isLoading: ctx.isLoading
81
+ };
82
+ }
83
+
84
+ // src/components/auth/LoginForm.tsx
85
+ var import_react3 = require("react");
86
+
87
+ // src/hooks/useReturnUrl.ts
88
+ var import_react2 = require("react");
89
+ function useReturnUrl(options = {}) {
90
+ const {
91
+ param = "returnUrl",
92
+ defaultPath = "/",
93
+ allowRelativeOnly = true
94
+ } = options;
95
+ const rawReturnUrl = (0, import_react2.useMemo)(() => {
96
+ if (typeof window === "undefined") return null;
97
+ const params = new URLSearchParams(window.location.search);
98
+ return params.get(param);
99
+ }, [param]);
100
+ const returnPath = (0, import_react2.useMemo)(() => {
101
+ if (!rawReturnUrl) return defaultPath;
102
+ if (allowRelativeOnly) {
103
+ const trimmed = rawReturnUrl.trim();
104
+ if (trimmed.startsWith("//") || /^https?:\/\//i.test(trimmed)) {
105
+ return defaultPath;
106
+ }
107
+ if (trimmed.startsWith("/")) return trimmed;
108
+ return `/${trimmed}`;
109
+ }
110
+ return rawReturnUrl;
111
+ }, [rawReturnUrl, defaultPath, allowRelativeOnly]);
112
+ const redirect = (0, import_react2.useCallback)(
113
+ (customRedirect) => {
114
+ const path = returnPath;
115
+ if (customRedirect) {
116
+ customRedirect(path);
117
+ } else if (typeof window !== "undefined") {
118
+ window.location.href = path;
119
+ }
120
+ },
121
+ [returnPath]
122
+ );
123
+ return { returnPath, redirect, rawReturnUrl };
124
+ }
125
+
126
+ // src/ui/button.tsx
127
+ var React = __toESM(require("react"));
128
+ var import_react_slot = require("@radix-ui/react-slot");
129
+ var import_class_variance_authority = require("class-variance-authority");
130
+
131
+ // src/ui/cn.ts
132
+ var import_clsx = require("clsx");
133
+ var import_tailwind_merge = require("tailwind-merge");
134
+ function cn(...inputs) {
135
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
136
+ }
137
+
138
+ // src/ui/button.tsx
139
+ var import_jsx_runtime2 = require("react/jsx-runtime");
140
+ var buttonVariants = (0, import_class_variance_authority.cva)(
141
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
142
+ {
143
+ variants: {
144
+ variant: {
145
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
146
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
147
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
148
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
149
+ ghost: "hover:bg-accent hover:text-accent-foreground",
150
+ link: "text-primary underline-offset-4 hover:underline"
151
+ },
152
+ size: {
153
+ default: "h-10 px-4 py-2",
154
+ sm: "h-9 rounded-md px-3",
155
+ lg: "h-11 rounded-md px-8",
156
+ icon: "h-10 w-10",
157
+ touch: "h-12 min-h-[44px] min-w-[44px] rounded-md px-4"
158
+ }
159
+ },
160
+ defaultVariants: {
161
+ variant: "default",
162
+ size: "default"
163
+ }
164
+ }
165
+ );
166
+ var Button = React.forwardRef(
167
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
168
+ const Comp = asChild ? import_react_slot.Slot : "button";
169
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
170
+ }
171
+ );
172
+ Button.displayName = "Button";
173
+
174
+ // src/ui/input.tsx
175
+ var React2 = __toESM(require("react"));
176
+ var import_jsx_runtime3 = require("react/jsx-runtime");
177
+ var Input = React2.forwardRef(
178
+ ({ className, type, ...props }, ref) => {
179
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
180
+ "input",
181
+ {
182
+ type,
183
+ className: cn(
184
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
185
+ className
186
+ ),
187
+ ref,
188
+ ...props
189
+ }
190
+ );
191
+ }
192
+ );
193
+ Input.displayName = "Input";
194
+
195
+ // src/ui/label.tsx
196
+ var React3 = __toESM(require("react"));
197
+ var LabelPrimitive = __toESM(require("@radix-ui/react-label"));
198
+ var import_class_variance_authority2 = require("class-variance-authority");
199
+ var import_jsx_runtime4 = require("react/jsx-runtime");
200
+ var labelVariants = (0, import_class_variance_authority2.cva)(
201
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
202
+ );
203
+ var Label = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LabelPrimitive.Root, { ref, className: cn(labelVariants(), className), ...props }));
204
+ Label.displayName = LabelPrimitive.Root.displayName;
205
+
206
+ // src/ui/card.tsx
207
+ var React4 = __toESM(require("react"));
208
+ var import_jsx_runtime5 = require("react/jsx-runtime");
209
+ var Card = React4.forwardRef(
210
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
211
+ "div",
212
+ {
213
+ ref,
214
+ className: cn("rounded-xl border bg-card text-card-foreground shadow", className),
215
+ ...props
216
+ }
217
+ )
218
+ );
219
+ Card.displayName = "Card";
220
+ var CardHeader = React4.forwardRef(
221
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
222
+ );
223
+ CardHeader.displayName = "CardHeader";
224
+ var CardTitle = React4.forwardRef(
225
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
226
+ "h3",
227
+ {
228
+ ref,
229
+ className: cn("font-semibold leading-none tracking-tight", className),
230
+ ...props
231
+ }
232
+ )
233
+ );
234
+ CardTitle.displayName = "CardTitle";
235
+ var CardDescription = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
236
+ CardDescription.displayName = "CardDescription";
237
+ var CardContent = React4.forwardRef(
238
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref, className: cn("p-6 pt-0", className), ...props })
239
+ );
240
+ CardContent.displayName = "CardContent";
241
+ var CardFooter = React4.forwardRef(
242
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref, className: cn("flex items-center p-6 pt-0", className), ...props })
243
+ );
244
+ CardFooter.displayName = "CardFooter";
245
+
246
+ // src/components/auth/LoginForm.tsx
247
+ var import_jsx_runtime6 = require("react/jsx-runtime");
248
+ function LoginForm({
249
+ className,
250
+ classNames,
251
+ style,
252
+ onSuccess,
253
+ onError,
254
+ redirectAfterSuccess,
255
+ onRedirect,
256
+ returnUrlParam = "returnUrl",
257
+ submitLabel = "Sign in",
258
+ title = "Sign in",
259
+ description,
260
+ renderSwitchToRegister
261
+ }) {
262
+ const { login, isLoading } = useCilantroAuth();
263
+ const { returnPath } = useReturnUrl({ param: returnUrlParam, defaultPath: "/" });
264
+ const [usernameOrEmail, setUsernameOrEmail] = (0, import_react3.useState)("");
265
+ const [password, setPassword] = (0, import_react3.useState)("");
266
+ const [error, setError] = (0, import_react3.useState)(null);
267
+ const pathToRedirect = redirectAfterSuccess ?? returnPath;
268
+ const handleSubmit = async (e) => {
269
+ e.preventDefault();
270
+ setError(null);
271
+ try {
272
+ await login(usernameOrEmail.trim(), password);
273
+ onSuccess?.();
274
+ if (pathToRedirect) {
275
+ if (onRedirect) {
276
+ onRedirect(pathToRedirect);
277
+ } else if (typeof window !== "undefined") {
278
+ window.location.href = pathToRedirect;
279
+ }
280
+ }
281
+ } catch (err) {
282
+ const message = err instanceof Error ? err.message : String(err);
283
+ setError(message);
284
+ onError?.(err instanceof Error ? err : new Error(message));
285
+ }
286
+ };
287
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Card, { className: cn(className, classNames?.root), style, "data-cilantro-login-form": true, children: [
288
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(CardHeader, { className: classNames?.header, children: [
289
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardTitle, { className: classNames?.title, children: title }),
290
+ description != null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardDescription, { className: classNames?.description, children: description })
291
+ ] }),
292
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardContent, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className: cn("space-y-4", classNames?.form), children: [
293
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
294
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Label, { htmlFor: "cilantro-login-username", className: classNames?.label, children: "Username or email" }),
295
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
296
+ Input,
297
+ {
298
+ id: "cilantro-login-username",
299
+ type: "text",
300
+ autoComplete: "username",
301
+ className: classNames?.input,
302
+ value: usernameOrEmail,
303
+ onChange: (e) => setUsernameOrEmail(e.target.value),
304
+ placeholder: "Username or email",
305
+ required: true,
306
+ disabled: isLoading
307
+ }
308
+ )
309
+ ] }),
310
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
311
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Label, { htmlFor: "cilantro-login-password", className: classNames?.label, children: "Password" }),
312
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
313
+ Input,
314
+ {
315
+ id: "cilantro-login-password",
316
+ type: "password",
317
+ autoComplete: "current-password",
318
+ className: classNames?.input,
319
+ value: password,
320
+ onChange: (e) => setPassword(e.target.value),
321
+ placeholder: "Password",
322
+ required: true,
323
+ disabled: isLoading
324
+ }
325
+ )
326
+ ] }),
327
+ error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
328
+ "div",
329
+ {
330
+ className: cn(
331
+ "rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive",
332
+ classNames?.error
333
+ ),
334
+ role: "alert",
335
+ children: error
336
+ }
337
+ ),
338
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
339
+ Button,
340
+ {
341
+ type: "submit",
342
+ size: "touch",
343
+ className: cn("w-full", classNames?.submitButton),
344
+ disabled: isLoading || !usernameOrEmail.trim() || !password,
345
+ children: isLoading ? "Signing in..." : submitLabel
346
+ }
347
+ ),
348
+ renderSwitchToRegister && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-center text-sm text-muted-foreground", children: renderSwitchToRegister() })
349
+ ] }) })
350
+ ] });
351
+ }
352
+
353
+ // src/ui/skeleton.tsx
354
+ var React5 = __toESM(require("react"));
355
+ var import_jsx_runtime7 = require("react/jsx-runtime");
356
+ var Skeleton = React5.forwardRef(
357
+ ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
358
+ "div",
359
+ {
360
+ ref,
361
+ className: cn("rounded-md bg-muted animate-pulse", className),
362
+ ...props
363
+ }
364
+ )
365
+ );
366
+ Skeleton.displayName = "Skeleton";
367
+
368
+ // src/components/auth/AuthGuard.tsx
369
+ var import_jsx_runtime8 = require("react/jsx-runtime");
370
+ var LAYOUT_CLASSES = {
371
+ inline: "",
372
+ centered: "flex min-h-[280px] items-center justify-center p-6",
373
+ fullscreen: "fixed inset-0 z-50 flex min-h-screen items-center justify-center bg-background p-4"
374
+ };
375
+ function getCurrentReturnPath(returnUrlParam) {
376
+ if (typeof window === "undefined") return "/";
377
+ const params = new URLSearchParams(window.location.search);
378
+ const existing = params.get(returnUrlParam);
379
+ if (existing && existing.startsWith("/")) return existing;
380
+ const path = window.location.pathname + window.location.search;
381
+ return path || "/";
382
+ }
383
+ function AuthGuard({
384
+ children,
385
+ fallback,
386
+ redirectTo,
387
+ onRedirect,
388
+ returnUrlParam = "returnUrl",
389
+ layout = "inline",
390
+ className,
391
+ classNames,
392
+ showFallback = true,
393
+ useSkeleton = false
394
+ }) {
395
+ const { isAuthenticated, isLoading } = useCilantroAuth();
396
+ const redirectPath = (0, import_react4.useMemo)(() => {
397
+ if (!redirectTo) return null;
398
+ const returnPath = getCurrentReturnPath(returnUrlParam);
399
+ const sep = redirectTo.includes("?") ? "&" : "?";
400
+ return `${redirectTo}${sep}${returnUrlParam}=${encodeURIComponent(returnPath)}`;
401
+ }, [redirectTo, returnUrlParam]);
402
+ if (isLoading) {
403
+ const loadingContent = useSkeleton ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: cn("rounded-lg border border-input p-6 space-y-4 w-full max-w-sm", classNames?.fallback), children: [
404
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Skeleton, { className: cn("h-7 w-2/3 rounded", classNames?.skeleton) }),
405
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Skeleton, { className: cn("h-4 w-full rounded", classNames?.skeleton) }),
406
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Skeleton, { className: cn("h-10 w-full rounded", classNames?.skeleton) }),
407
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Skeleton, { className: cn("h-10 w-full rounded", classNames?.skeleton) })
408
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col items-center gap-3", children: [
409
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
410
+ "div",
411
+ {
412
+ className: "h-8 w-8 animate-spin rounded-full border-2 border-primary border-t-transparent",
413
+ "aria-hidden": true
414
+ }
415
+ ),
416
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-sm text-muted-foreground", children: "Loading..." })
417
+ ] });
418
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
419
+ "div",
420
+ {
421
+ className: cn(
422
+ LAYOUT_CLASSES[layout],
423
+ className,
424
+ classNames?.root,
425
+ classNames?.loading
426
+ ),
427
+ "data-cilantro-auth-guard": true,
428
+ "aria-busy": "true",
429
+ "aria-live": "polite",
430
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn(layout !== "inline" && "w-full max-w-sm", classNames?.layout), children: loadingContent })
431
+ }
432
+ );
433
+ }
434
+ if (!isAuthenticated) {
435
+ if (!showFallback && redirectPath) {
436
+ if (onRedirect) {
437
+ onRedirect(redirectPath);
438
+ } else if (typeof window !== "undefined") {
439
+ window.location.href = redirectPath;
440
+ }
441
+ return null;
442
+ }
443
+ if (!showFallback) return null;
444
+ if (redirectPath) {
445
+ if (onRedirect) {
446
+ onRedirect(redirectPath);
447
+ } else if (typeof window !== "undefined") {
448
+ window.location.href = redirectPath;
449
+ }
450
+ return null;
451
+ }
452
+ const returnPath = getCurrentReturnPath(returnUrlParam);
453
+ const fallbackContent = fallback ?? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
454
+ LoginForm,
455
+ {
456
+ className: classNames?.fallback,
457
+ redirectAfterSuccess: returnPath,
458
+ returnUrlParam,
459
+ onRedirect
460
+ }
461
+ );
462
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
463
+ "div",
464
+ {
465
+ className: cn(
466
+ LAYOUT_CLASSES[layout],
467
+ className,
468
+ classNames?.root
469
+ ),
470
+ "data-cilantro-auth-guard": true,
471
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn(layout !== "inline" && "w-full max-w-sm", classNames?.layout), children: fallbackContent })
472
+ }
473
+ );
474
+ }
475
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children });
476
+ }
477
+
478
+ // src/components/auth/NextAuthGuard.tsx
479
+ var import_jsx_runtime9 = require("react/jsx-runtime");
480
+ function NextAuthGuard(props) {
481
+ const router = (0, import_navigation.useRouter)();
482
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
483
+ AuthGuard,
484
+ {
485
+ ...props,
486
+ onRedirect: (path) => router.replace(path)
487
+ }
488
+ );
489
+ }
490
+ // Annotate the CommonJS export names for ESM import in node:
491
+ 0 && (module.exports = {
492
+ NextAuthGuard
493
+ });
494
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/next.ts","../src/components/auth/NextAuthGuard.tsx","../src/components/auth/AuthGuard.tsx","../src/context/CilantroContext.tsx","../src/core/auth.ts","../src/core/storage-adapter.ts","../src/providers/CilantroAuthProvider.tsx","../src/components/auth/LoginForm.tsx","../src/hooks/useReturnUrl.ts","../src/ui/button.tsx","../src/ui/cn.ts","../src/ui/input.tsx","../src/ui/label.tsx","../src/ui/card.tsx","../src/ui/skeleton.tsx"],"sourcesContent":["/**\n * cilantro-react/next - Next.js App Router integration\n * Requires: next >= 13\n */\n\nexport { NextAuthGuard, type AuthGuardProps, type AuthGuardClassNames, type AuthGuardLayout } from \"./components/auth/NextAuthGuard\";\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useRouter } from \"next/navigation\";\nimport type { AuthGuardProps } from \"./AuthGuard\";\nimport { AuthGuard } from \"./AuthGuard\";\n\nexport type { AuthGuardProps, AuthGuardClassNames, AuthGuardLayout } from \"./AuthGuard\";\n\n/**\n * AuthGuard integrated with Next.js App Router.\n * Uses `useRouter().replace()` for redirects (no full page reload).\n * Requires `next` to be installed.\n *\n * @example\n * // app/dashboard/layout.tsx or page.tsx\n * <NextAuthGuard redirectTo=\"/login\" layout=\"fullscreen\">\n * <DashboardContent />\n * </NextAuthGuard>\n */\nexport function NextAuthGuard(props: Omit<AuthGuardProps, \"onRedirect\">) {\n const router = useRouter();\n return (\n <AuthGuard\n {...props}\n onRedirect={(path) => router.replace(path)}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo, type ReactNode } from \"react\";\nimport { useCilantroAuth } from \"../../providers/CilantroAuthProvider\";\nimport { LoginForm } from \"./LoginForm\";\nimport { Skeleton } from \"../../ui/skeleton\";\nimport { cn } from \"../../ui/cn\";\n\nexport interface AuthGuardClassNames {\n root?: string;\n fallback?: string;\n skeleton?: string;\n loading?: string;\n /** Centered/fullscreen layout wrapper */\n layout?: string;\n}\n\nexport type AuthGuardLayout = \"inline\" | \"centered\" | \"fullscreen\";\n\nexport interface AuthGuardProps {\n children: ReactNode;\n /** Shown when not authenticated. Default: <LoginForm /> */\n fallback?: ReactNode;\n /** Redirect unauthenticated users to this path (e.g. \"/login\"). Uses onRedirect if provided, else window.location. */\n redirectTo?: string;\n /** Custom redirect function for SPA routers (Next.js, React Router). e.g. (path) => router.replace(path) */\n onRedirect?: (path: string) => void;\n /** Query param for return URL when redirecting. Default: \"returnUrl\" */\n returnUrlParam?: string;\n /** Layout for fallback content. \"centered\" and \"fullscreen\" give polished auth UX. */\n layout?: AuthGuardLayout;\n /** Root class when showing fallback */\n className?: string;\n classNames?: AuthGuardClassNames;\n /** When true, show fallback (login) instead of redirecting. When false, redirect when redirectTo is set, else render null. */\n showFallback?: boolean;\n /** When true, show skeleton while loading. When false, show \"Loading...\" text. */\n useSkeleton?: boolean;\n}\n\nconst LAYOUT_CLASSES: Record<AuthGuardLayout, string> = {\n inline: \"\",\n centered: \"flex min-h-[280px] items-center justify-center p-6\",\n fullscreen: \"fixed inset-0 z-50 flex min-h-screen items-center justify-center bg-background p-4\",\n};\n\nfunction getCurrentReturnPath(returnUrlParam: string): string {\n if (typeof window === \"undefined\") return \"/\";\n const params = new URLSearchParams(window.location.search);\n const existing = params.get(returnUrlParam);\n if (existing && existing.startsWith(\"/\")) return existing;\n const path = window.location.pathname + window.location.search;\n return path || \"/\";\n}\n\n/**\n * Wraps content and shows fallback (e.g. LoginForm) when the user is not authenticated.\n * Use inside CilantroProvider.\n *\n * For Next.js: pass onRedirect={(path) => router.replace(path)} and redirectTo=\"/login\".\n * For return-after-login flow: set redirectTo=\"/login\"; AuthGuard will redirect with ?returnUrl=currentPath.\n */\nexport function AuthGuard({\n children,\n fallback,\n redirectTo,\n onRedirect,\n returnUrlParam = \"returnUrl\",\n layout = \"inline\",\n className,\n classNames,\n showFallback = true,\n useSkeleton = false,\n}: AuthGuardProps) {\n const { isAuthenticated, isLoading } = useCilantroAuth();\n\n const redirectPath = useMemo(() => {\n if (!redirectTo) return null;\n const returnPath = getCurrentReturnPath(returnUrlParam);\n const sep = redirectTo.includes(\"?\") ? \"&\" : \"?\";\n return `${redirectTo}${sep}${returnUrlParam}=${encodeURIComponent(returnPath)}`;\n }, [redirectTo, returnUrlParam]);\n\n if (isLoading) {\n const loadingContent = useSkeleton ? (\n <div className={cn(\"rounded-lg border border-input p-6 space-y-4 w-full max-w-sm\", classNames?.fallback)}>\n <Skeleton className={cn(\"h-7 w-2/3 rounded\", classNames?.skeleton)} />\n <Skeleton className={cn(\"h-4 w-full rounded\", classNames?.skeleton)} />\n <Skeleton className={cn(\"h-10 w-full rounded\", classNames?.skeleton)} />\n <Skeleton className={cn(\"h-10 w-full rounded\", classNames?.skeleton)} />\n </div>\n ) : (\n <div className=\"flex flex-col items-center gap-3\">\n <div\n className=\"h-8 w-8 animate-spin rounded-full border-2 border-primary border-t-transparent\"\n aria-hidden\n />\n <p className=\"text-sm text-muted-foreground\">Loading...</p>\n </div>\n );\n\n return (\n <div\n className={cn(\n LAYOUT_CLASSES[layout],\n className,\n classNames?.root,\n classNames?.loading\n )}\n data-cilantro-auth-guard\n aria-busy=\"true\"\n aria-live=\"polite\"\n >\n <div className={cn(layout !== \"inline\" && \"w-full max-w-sm\", classNames?.layout)}>\n {loadingContent}\n </div>\n </div>\n );\n }\n\n if (!isAuthenticated) {\n if (!showFallback && redirectPath) {\n if (onRedirect) {\n onRedirect(redirectPath);\n } else if (typeof window !== \"undefined\") {\n window.location.href = redirectPath;\n }\n return null;\n }\n if (!showFallback) return null;\n\n // Redirect mode: send user to login page with returnUrl\n if (redirectPath) {\n if (onRedirect) {\n onRedirect(redirectPath);\n } else if (typeof window !== \"undefined\") {\n window.location.href = redirectPath;\n }\n return null;\n }\n\n // Show fallback (login form) - pass returnPath for post-login redirect\n const returnPath = getCurrentReturnPath(returnUrlParam);\n const fallbackContent =\n fallback ??\n (\n <LoginForm\n className={classNames?.fallback}\n redirectAfterSuccess={returnPath}\n returnUrlParam={returnUrlParam}\n onRedirect={onRedirect}\n />\n );\n\n return (\n <div\n className={cn(\n LAYOUT_CLASSES[layout],\n className,\n classNames?.root\n )}\n data-cilantro-auth-guard\n >\n <div className={cn(layout !== \"inline\" && \"w-full max-w-sm\", classNames?.layout)}>\n {fallbackContent}\n </div>\n </div>\n );\n }\n\n return <>{children}</>;\n}\n","\"use client\";\n\nimport {\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { clearAuth } from \"cilantro-sdk\";\nimport { login as cilantroLogin } from \"cilantro-sdk/auth\";\nimport type { AuthControllerLogin200Data } from \"cilantro-sdk/auth\";\nimport { create as createUser } from \"cilantro-sdk/user\";\nimport { create as createWalletSDK, findAll as findAllWallets } from \"cilantro-sdk/wallet\";\nimport type {\n WalletControllerFindAllResult,\n WalletControllerCreateResult,\n} from \"cilantro-sdk/wallet\";\nimport { setAuthConfig, setSdkAuth, getPlatformApiKey, isJwtExpired } from \"../core/auth\";\nimport { setStorageAdapter } from \"../core/storage-adapter\";\nimport type { DeviceKeyStorage } from \"../core/storage-adapter\";\nimport { extractResponseData } from \"../core/types\";\nimport { extractErrorMessage, isAuthError } from \"../core/error-utils\";\nimport { normalizeWallet } from \"../core/normalize\";\n\nconst DEFAULT_BASE_URL = \"https://api.cilantro.gg\";\nconst DEFAULT_JWT_STORAGE_KEY = \"cilantro_jwt\";\nconst DEFAULT_WALLET_STORAGE_KEY = \"cilantro_selected_wallet_id\";\n\n/** Minimal user view; populated from SDK login result data.user when available. */\nexport interface User {\n username?: string;\n email?: string;\n userType?: string;\n}\n\n/** SDK wallet list item type. */\nexport type WalletDataDto = WalletControllerFindAllResult[\"data\"] extends readonly (infer E)[]\n ? E\n : WalletControllerFindAllResult[\"data\"] extends (infer E)[]\n ? E\n : never;\n\n/** Wallet with backward-compat aliases (id, address, active). */\nexport type WalletData = WalletDataDto & {\n id?: string;\n address?: string;\n active?: boolean;\n};\n\nexport interface CilantroConfig {\n apiKey?: string;\n baseURL: string;\n jwt?: string | null;\n}\n\nexport interface CilantroContextValue {\n config: CilantroConfig;\n storage: DeviceKeyStorage | null;\n // Auth\n user: User | null;\n jwt: string | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n login: (params: { usernameOrEmail: string; password: string }) => Promise<void>;\n logout: () => void;\n register: (\n username: string,\n email: string,\n password: string,\n isActive?: boolean\n ) => Promise<void>;\n clearSessionDueToAuthError: () => void;\n // Wallet\n wallet: WalletData | null;\n wallets: WalletData[];\n createWallet: (params: { name: string; userId?: string }) => Promise<WalletControllerCreateResult>;\n selectWallet: (walletId: string) => void;\n refreshWallets: () => Promise<void>;\n walletError: string | null;\n walletsLoading: boolean;\n}\n\nconst CilantroContext = createContext<CilantroContextValue | undefined>(undefined);\n\nexport interface CilantroContextProviderProps {\n children: ReactNode;\n apiKey?: string;\n baseURL?: string;\n storageAdapter?: DeviceKeyStorage | null;\n jwtStorageKey?: string;\n walletStorageKey?: string;\n /** When true, sync JWT to a cookie (same name as jwtStorageKey) for Next.js/middleware. Default: false. */\n syncJwtToCookie?: boolean;\n /** Cookie name for JWT when syncJwtToCookie is true. Default: cilantro_jwt. */\n jwtCookieName?: string;\n onLoginSuccess?: () => void;\n onLogout?: () => void;\n onRegisterSuccess?: () => void;\n onSessionExpired?: () => void;\n}\n\nconst DEFAULT_JWT_COOKIE_NAME = \"cilantro_jwt\";\n\nfunction setJwtCookie(name: string, token: string | null): void {\n if (typeof document === \"undefined\") return;\n const value = token ?? \"\";\n if (!value) {\n document.cookie = `${name}=; path=/; SameSite=Lax; max-age=0`;\n return;\n }\n // Set cookie with long expiry (JWT has its own exp; middleware will validate).\n const maxAge = 60 * 60 * 24 * 7; // 7 days\n document.cookie = `${name}=${encodeURIComponent(value)}; path=/; SameSite=Lax; max-age=${maxAge}`;\n}\n\nexport function CilantroContextProvider({\n children,\n apiKey,\n baseURL = DEFAULT_BASE_URL,\n storageAdapter = null,\n jwtStorageKey = DEFAULT_JWT_STORAGE_KEY,\n walletStorageKey = DEFAULT_WALLET_STORAGE_KEY,\n syncJwtToCookie = false,\n jwtCookieName = DEFAULT_JWT_COOKIE_NAME,\n onLoginSuccess,\n onLogout,\n onRegisterSuccess,\n onSessionExpired,\n}: CilantroContextProviderProps) {\n const [user, setUser] = useState<User | null>(null);\n const [jwt, setJwt] = useState<string | null>(null);\n const [authLoading, setAuthLoading] = useState(true);\n const [wallets, setWallets] = useState<WalletData[]>([]);\n const [selectedWallet, setSelectedWallet] = useState<WalletData | null>(null);\n const [walletsLoading, setWalletsLoading] = useState(true);\n const [walletError, setWalletError] = useState<string | null>(null);\n\n const config = useMemo<CilantroConfig>(\n () => ({\n apiKey,\n baseURL,\n jwt: jwt ?? undefined,\n }),\n [apiKey, baseURL, jwt]\n );\n\n // Inject storage adapter into core so signer creation uses it\n useEffect(() => {\n setStorageAdapter(storageAdapter ?? null);\n return () => setStorageAdapter(null);\n }, [storageAdapter]);\n\n // Set SDK auth config and restore session from storage\n useEffect(() => {\n setAuthConfig({ apiKey, baseURL });\n const storedToken =\n typeof window !== \"undefined\" ? localStorage.getItem(jwtStorageKey) : null;\n if (storedToken) {\n if (isJwtExpired(storedToken)) {\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(jwtStorageKey);\n const keys = Object.keys(localStorage);\n keys.forEach((key) => {\n if (key.startsWith(\"delegated-key-\")) localStorage.removeItem(key);\n });\n }\n setSdkAuth(null);\n } else {\n setJwt(storedToken);\n setSdkAuth(storedToken);\n try {\n const payload = JSON.parse(atob(storedToken.split(\".\")[1]));\n setUser({\n username: payload.username,\n email: payload.email,\n userType: payload.userType,\n });\n } catch {\n // ignore\n }\n }\n } else {\n setSdkAuth(null);\n }\n setAuthLoading(false);\n }, [apiKey, baseURL, jwtStorageKey]);\n\n // Sync JWT to cookie for Next.js/middleware when enabled\n useEffect(() => {\n if (syncJwtToCookie && typeof document !== \"undefined\") {\n setJwtCookie(jwtCookieName, jwt);\n }\n }, [jwt, syncJwtToCookie, jwtCookieName]);\n\n const login = useCallback(\n async (params: { usernameOrEmail: string; password: string }) => {\n const result = await cilantroLogin(params);\n const data: AuthControllerLogin200Data | undefined =\n result && typeof result === \"object\" && \"data\" in result\n ? (result as { data: AuthControllerLogin200Data }).data\n : undefined;\n const token =\n (data && \"jwt\" in data ? (data as { jwt?: string }).jwt : undefined) ??\n (data && \"accessToken\" in data ? (data as { accessToken?: string }).accessToken : undefined);\n if (!token) throw new Error(\"No JWT token received from server\");\n const userType = data?.userType;\n setJwt(token);\n setSdkAuth(token);\n if (typeof window !== \"undefined\") {\n localStorage.setItem(jwtStorageKey, token);\n if (syncJwtToCookie) setJwtCookie(jwtCookieName, token);\n }\n if (data?.user && typeof data.user === \"object\") {\n const u = data.user as Record<string, unknown>;\n setUser({\n username: u.username as string | undefined,\n email: u.email as string | undefined,\n userType: (userType ?? u.userType) as string | undefined,\n });\n } else {\n try {\n const payload = JSON.parse(atob(token.split(\".\")[1])) as Record<string, unknown>;\n setUser({\n username: payload.username as string | undefined,\n email: payload.email as string | undefined,\n userType: (userType ?? payload.userType) as string | undefined,\n });\n } catch {\n setUser({ userType: userType as string | undefined });\n }\n }\n onLoginSuccess?.();\n },\n [jwtStorageKey, jwtCookieName, syncJwtToCookie, onLoginSuccess]\n );\n\n const logout = useCallback(() => {\n setUser(null);\n setJwt(null);\n clearAuth();\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(jwtStorageKey);\n if (syncJwtToCookie) setJwtCookie(jwtCookieName, null);\n const keys = Object.keys(localStorage);\n keys.forEach((key) => {\n if (key.startsWith(\"delegated-key-\")) localStorage.removeItem(key);\n });\n }\n setSdkAuth(null);\n onLogout?.();\n }, [jwtStorageKey, jwtCookieName, syncJwtToCookie, onLogout]);\n\n const register = useCallback(\n async (username: string, email: string, password: string, isActive = true) => {\n setSdkAuth(null);\n const platformKey = getPlatformApiKey();\n const userData: {\n username: string;\n email: string;\n password: string;\n isActive: boolean;\n platformApiKey?: string;\n } = { username, email, password, isActive };\n if (platformKey) userData.platformApiKey = platformKey;\n await createUser(userData);\n await login({ usernameOrEmail: username, password });\n onRegisterSuccess?.();\n },\n [login, onRegisterSuccess]\n );\n\n const clearSessionDueToAuthError = useCallback(() => {\n setUser(null);\n setJwt(null);\n clearAuth();\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(jwtStorageKey);\n if (syncJwtToCookie) setJwtCookie(jwtCookieName, null);\n const keys = Object.keys(localStorage);\n keys.forEach((key) => {\n if (key.startsWith(\"delegated-key-\")) localStorage.removeItem(key);\n });\n }\n setSdkAuth(null);\n onSessionExpired?.();\n }, [jwtStorageKey, jwtCookieName, syncJwtToCookie, onSessionExpired]);\n\n const loadWallets = useCallback(async () => {\n if (!jwt) return;\n setWalletsLoading(true);\n setWalletError(null);\n try {\n setSdkAuth(jwt);\n const result = await findAllWallets();\n const walletsList = extractResponseData<WalletDataDto[]>(result) ?? [];\n const list = Array.isArray(walletsList) ? walletsList : [];\n const formatted: WalletData[] = list.map((w) =>\n normalizeWallet(w as unknown as Record<string, unknown>) as unknown as WalletData\n );\n setWallets(formatted);\n } catch (err) {\n if (isAuthError(err)) {\n clearSessionDueToAuthError();\n setWalletError(\"Session expired. Please sign in again.\");\n } else {\n setWalletError(extractErrorMessage(err));\n }\n setWallets([]);\n } finally {\n setWalletsLoading(false);\n }\n }, [jwt, clearSessionDueToAuthError]);\n\n useEffect(() => {\n if (jwt) {\n loadWallets();\n } else {\n setWallets([]);\n setSelectedWallet(null);\n setWalletError(null);\n setWalletsLoading(false);\n }\n }, [jwt, loadWallets]);\n\n useEffect(() => {\n if (wallets.length > 0 && !selectedWallet) {\n const storedId =\n typeof window !== \"undefined\" ? localStorage.getItem(walletStorageKey) : null;\n if (storedId) {\n const w = wallets.find((x) => x.id === storedId || x.walletId === storedId);\n if (w) setSelectedWallet(w);\n else {\n setSelectedWallet(wallets[0]);\n if (typeof window !== \"undefined\")\n localStorage.setItem(walletStorageKey, wallets[0].id ?? wallets[0].walletId);\n }\n } else {\n setSelectedWallet(wallets[0]);\n if (typeof window !== \"undefined\")\n localStorage.setItem(walletStorageKey, wallets[0].id ?? wallets[0].walletId);\n }\n } else if (wallets.length === 0) {\n setSelectedWallet(null);\n if (typeof window !== \"undefined\") localStorage.removeItem(walletStorageKey);\n }\n }, [wallets, walletStorageKey]);\n\n const selectWallet = useCallback(\n (walletId: string) => {\n const w = wallets.find((x) => x.id === walletId || x.walletId === walletId);\n if (w) {\n setSelectedWallet(w);\n if (typeof window !== \"undefined\")\n localStorage.setItem(walletStorageKey, w.id ?? w.walletId);\n }\n },\n [wallets, walletStorageKey]\n );\n\n const createWallet = useCallback(\n async (params: { name: string; userId?: string }) => {\n setSdkAuth(jwt ?? undefined);\n const dto = { walletName: params.name, chain: \"solana\" as const };\n const result = await createWalletSDK(dto);\n await loadWallets();\n return result as WalletControllerCreateResult;\n },\n [jwt, loadWallets]\n );\n\n const value: CilantroContextValue = useMemo(\n () => ({\n config,\n storage: storageAdapter ?? null,\n user,\n jwt,\n isAuthenticated: !!jwt,\n isLoading: authLoading,\n login,\n logout,\n register,\n clearSessionDueToAuthError,\n wallet: selectedWallet,\n wallets,\n createWallet,\n selectWallet,\n refreshWallets: loadWallets,\n walletError,\n walletsLoading,\n }),\n [\n config,\n storageAdapter,\n user,\n jwt,\n authLoading,\n login,\n logout,\n register,\n clearSessionDueToAuthError,\n selectedWallet,\n wallets,\n createWallet,\n selectWallet,\n loadWallets,\n walletError,\n walletsLoading,\n ]\n );\n\n return (\n <CilantroContext.Provider value={value}>{children}</CilantroContext.Provider>\n );\n}\n\nexport function useCilantroContext(): CilantroContextValue {\n const ctx = useContext(CilantroContext);\n if (ctx === undefined) {\n throw new Error(\"useCilantroContext must be used within CilantroContextProvider\");\n }\n return ctx;\n}\n","import { setAuth } from \"cilantro-sdk\";\n\nlet platformApiKey = \"\";\nlet apiUrl: string | undefined;\n\nexport interface AuthConfig {\n platformApiKey?: string;\n apiUrl?: string;\n /** Guide-aligned alias for platformApiKey */\n apiKey?: string;\n /** Guide-aligned alias for apiUrl */\n baseURL?: string;\n jwt?: string | null;\n}\n\n/**\n * Set SDK authentication config. Call with apiKey/baseURL (or platformApiKey/apiUrl) from provider/config.\n * Do not read process.env in library code.\n */\nexport function setAuthConfig(config: AuthConfig): void {\n platformApiKey = config.apiKey ?? config.platformApiKey ?? \"\";\n apiUrl = config.baseURL ?? config.apiUrl;\n const authPayload: { jwt?: string; platformApiKey?: string; apiUrl?: string } = {};\n if (config.jwt) {\n authPayload.jwt = config.jwt;\n }\n if (platformApiKey) {\n authPayload.platformApiKey = platformApiKey;\n }\n if (apiUrl) {\n authPayload.apiUrl = apiUrl;\n }\n setAuth(authPayload);\n}\n\n/**\n * Set SDK auth with JWT (assumes platformApiKey already set via setAuthConfig).\n */\nexport function setSdkAuth(jwt?: string | null): void {\n const authConfig: { jwt?: string; platformApiKey?: string; apiUrl?: string } = {};\n if (jwt) {\n authConfig.jwt = jwt;\n }\n if (platformApiKey) {\n authConfig.platformApiKey = platformApiKey;\n }\n if (apiUrl) {\n authConfig.apiUrl = apiUrl;\n }\n setAuth(authConfig);\n}\n\n/**\n * Get the platform API key (set via setAuthConfig).\n */\nexport function getPlatformApiKey(): string {\n return platformApiKey;\n}\n\n/**\n * Get the optional API URL (set via setAuthConfig).\n */\nexport function getApiUrl(): string | undefined {\n return apiUrl;\n}\n\n/**\n * Check if a JWT is expired using the payload `exp` claim.\n * @param token - JWT string (assumes 3 segments separated by dots).\n * @param bufferSeconds - Optional buffer in seconds; if exp is within this many seconds of now, treat as expired (default 60).\n * @returns true if token is expired or invalid/not a JWT.\n */\nexport function isJwtExpired(token: string, bufferSeconds = 60): boolean {\n if (!token || typeof token !== \"string\") return true;\n const parts = token.split(\".\");\n if (parts.length !== 3) return true;\n try {\n const payload = JSON.parse(atob(parts[1])) as { exp?: number };\n const exp = payload.exp;\n if (exp == null || typeof exp !== \"number\") return false;\n const now = Math.floor(Date.now() / 1000);\n return exp - bufferSeconds <= now;\n } catch {\n return true;\n }\n}\n","import { createIndexedDBAdapter } from \"cilantro-sdk/helpers\";\n\nexport type DeviceKeyStorage = ReturnType<typeof createIndexedDBAdapter>;\n\nlet storageAdapterInstance: DeviceKeyStorage | null = null;\nlet contextProvidedAdapter: DeviceKeyStorage | null = null;\nlet initializationPromise: Promise<DeviceKeyStorage> | null = null;\n\n/**\n * Set the storage adapter from CilantroProvider (context). When set, getStorageAdapter() returns this.\n */\nexport function setStorageAdapter(adapter: DeviceKeyStorage | null): void {\n contextProvidedAdapter = adapter;\n}\n\nexport async function initializeStorageAdapter(): Promise<DeviceKeyStorage> {\n if (contextProvidedAdapter) return contextProvidedAdapter;\n if (storageAdapterInstance) return storageAdapterInstance;\n if (initializationPromise) return initializationPromise;\n if (typeof window === \"undefined\") {\n throw new Error(\"Storage adapter can only be initialized in browser environment.\");\n }\n initializationPromise = (async () => {\n try {\n storageAdapterInstance = createIndexedDBAdapter();\n return storageAdapterInstance;\n } catch (error) {\n initializationPromise = null;\n throw error;\n }\n })();\n return initializationPromise;\n}\n\nexport function getStorageAdapter(): DeviceKeyStorage {\n if (contextProvidedAdapter) return contextProvidedAdapter;\n if (storageAdapterInstance) return storageAdapterInstance;\n if (typeof window === \"undefined\") {\n throw new Error(\"Storage adapter can only be initialized in browser environment.\");\n }\n storageAdapterInstance = createIndexedDBAdapter();\n return storageAdapterInstance;\n}\n\nexport function getStorageAdapterType(): \"IndexedDB\" | \"LocalStorage\" | \"Memory\" | \"Unknown\" {\n if (typeof window === \"undefined\") return \"Memory\";\n if (\"indexedDB\" in window) return \"IndexedDB\";\n return \"Unknown\";\n}\n\nexport function clearStorageAdapter(): void {\n storageAdapterInstance = null;\n}\n","\"use client\";\n\nimport { useCilantroContext } from \"../context/CilantroContext\";\nimport type { User } from \"../context/CilantroContext\";\n\nexport interface CilantroAuthContextType {\n user: User | null;\n /** JWT token. Alias for token. */\n jwt: string | null;\n token: string | null;\n isAuthenticated: boolean;\n login: (usernameOrEmail: string, password: string) => Promise<void>;\n register: (username: string, email: string, password: string, isActive?: boolean) => Promise<void>;\n logout: () => void;\n clearSessionDueToAuthError: () => void;\n isLoading: boolean;\n}\n\nexport function useCilantroAuth(): CilantroAuthContextType {\n const ctx = useCilantroContext();\n return {\n user: ctx.user,\n jwt: ctx.jwt,\n token: ctx.jwt,\n isAuthenticated: ctx.isAuthenticated,\n login: (usernameOrEmail: string, password: string) =>\n ctx.login({ usernameOrEmail, password }),\n register: ctx.register,\n logout: ctx.logout,\n clearSessionDueToAuthError: ctx.clearSessionDueToAuthError,\n isLoading: ctx.isLoading,\n };\n}\n\nexport type { User };\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { useCilantroAuth } from \"../../providers/CilantroAuthProvider\";\nimport { useReturnUrl } from \"../../hooks/useReturnUrl\";\nimport { Button } from \"../../ui/button\";\nimport { Input } from \"../../ui/input\";\nimport { Label } from \"../../ui/label\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"../../ui/card\";\nimport { cn } from \"../../ui/cn\";\n\nexport interface LoginFormClassNames {\n root?: string;\n header?: string;\n title?: string;\n description?: string;\n form?: string;\n label?: string;\n input?: string;\n submitButton?: string;\n error?: string;\n}\n\nexport interface LoginFormProps {\n className?: string;\n classNames?: LoginFormClassNames;\n style?: React.CSSProperties;\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n /** Redirect to this path after successful login. If not set, reads from URL ?returnUrl= (when returnUrlParam provided). */\n redirectAfterSuccess?: string;\n /** Custom redirect function for SPA routers. e.g. (path) => router.replace(path) */\n onRedirect?: (path: string) => void;\n /** Query param to read returnUrl from URL. Default: \"returnUrl\". Used when redirectAfterSuccess not set. */\n returnUrlParam?: string;\n rememberMe?: boolean;\n /** Override submit button label */\n submitLabel?: string;\n /** Override title */\n title?: string;\n /** Override description */\n description?: string;\n /** Render \"Create account\" link (e.g. to switch to register). Shown below submit. */\n renderSwitchToRegister?: () => React.ReactNode;\n}\n\nexport function LoginForm({\n className,\n classNames,\n style,\n onSuccess,\n onError,\n redirectAfterSuccess,\n onRedirect,\n returnUrlParam = \"returnUrl\",\n submitLabel = \"Sign in\",\n title = \"Sign in\",\n description,\n renderSwitchToRegister,\n}: LoginFormProps) {\n const { login, isLoading } = useCilantroAuth();\n const { returnPath } = useReturnUrl({ param: returnUrlParam, defaultPath: \"/\" });\n const [usernameOrEmail, setUsernameOrEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n\n const pathToRedirect = redirectAfterSuccess ?? returnPath;\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n try {\n await login(usernameOrEmail.trim(), password);\n onSuccess?.();\n if (pathToRedirect) {\n if (onRedirect) {\n onRedirect(pathToRedirect);\n } else if (typeof window !== \"undefined\") {\n window.location.href = pathToRedirect;\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n setError(message);\n onError?.(err instanceof Error ? err : new Error(message));\n }\n };\n\n return (\n <Card className={cn(className, classNames?.root)} style={style} data-cilantro-login-form>\n <CardHeader className={classNames?.header}>\n <CardTitle className={classNames?.title}>{title}</CardTitle>\n {description != null && (\n <CardDescription className={classNames?.description}>{description}</CardDescription>\n )}\n </CardHeader>\n <CardContent>\n <form onSubmit={handleSubmit} className={cn(\"space-y-4\", classNames?.form)}>\n <div className=\"space-y-2\">\n <Label htmlFor=\"cilantro-login-username\" className={classNames?.label}>\n Username or email\n </Label>\n <Input\n id=\"cilantro-login-username\"\n type=\"text\"\n autoComplete=\"username\"\n className={classNames?.input}\n value={usernameOrEmail}\n onChange={(e) => setUsernameOrEmail(e.target.value)}\n placeholder=\"Username or email\"\n required\n disabled={isLoading}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"cilantro-login-password\" className={classNames?.label}>\n Password\n </Label>\n <Input\n id=\"cilantro-login-password\"\n type=\"password\"\n autoComplete=\"current-password\"\n className={classNames?.input}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder=\"Password\"\n required\n disabled={isLoading}\n />\n </div>\n {error && (\n <div\n className={cn(\n \"rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive\",\n classNames?.error\n )}\n role=\"alert\"\n >\n {error}\n </div>\n )}\n <Button\n type=\"submit\"\n size=\"touch\"\n className={cn(\"w-full\", classNames?.submitButton)}\n disabled={isLoading || !usernameOrEmail.trim() || !password}\n >\n {isLoading ? \"Signing in...\" : submitLabel}\n </Button>\n {renderSwitchToRegister && (\n <div className=\"text-center text-sm text-muted-foreground\">{renderSwitchToRegister()}</div>\n )}\n </form>\n </CardContent>\n </Card>\n );\n}\n","\"use client\";\n\nimport { useCallback, useMemo } from \"react\";\n\nexport interface UseReturnUrlOptions {\n /** Query param name for return URL. Default: \"returnUrl\" */\n param?: string;\n /** Default path when no returnUrl in URL. Default: \"/\" */\n defaultPath?: string;\n /** Only allow relative paths (no protocol). Default: true */\n allowRelativeOnly?: boolean;\n}\n\n/**\n * Read returnUrl from URL search params and provide a safe redirect path.\n * Use with LoginForm/RegisterForm to redirect users back after auth.\n *\n * @example\n * // In LoginForm wrapper - redirect to returnUrl after login\n * const { returnPath, redirect } = useReturnUrl();\n * <LoginForm onSuccess={() => redirect()} redirectAfterSuccess={returnPath} onRedirect={router.replace} />\n */\nexport function useReturnUrl(options: UseReturnUrlOptions = {}): {\n /** Safe path to redirect to (from URL or defaultPath) */\n returnPath: string;\n /** Redirect to returnPath using window.location (or pass custom fn) */\n redirect: (customRedirect?: (path: string) => void) => void;\n /** Raw value from URL (may be empty) */\n rawReturnUrl: string | null;\n} {\n const {\n param = \"returnUrl\",\n defaultPath = \"/\",\n allowRelativeOnly = true,\n } = options;\n\n const rawReturnUrl = useMemo(() => {\n if (typeof window === \"undefined\") return null;\n const params = new URLSearchParams(window.location.search);\n return params.get(param);\n }, [param]);\n\n const returnPath = useMemo(() => {\n if (!rawReturnUrl) return defaultPath;\n if (allowRelativeOnly) {\n // Reject absolute URLs (protocol-relative or http(s))\n const trimmed = rawReturnUrl.trim();\n if (trimmed.startsWith(\"//\") || /^https?:\\/\\//i.test(trimmed)) {\n return defaultPath;\n }\n if (trimmed.startsWith(\"/\")) return trimmed;\n // Relative path without leading slash - make absolute\n return `/${trimmed}`;\n }\n return rawReturnUrl;\n }, [rawReturnUrl, defaultPath, allowRelativeOnly]);\n\n const redirect = useCallback(\n (customRedirect?: (path: string) => void) => {\n const path = returnPath;\n if (customRedirect) {\n customRedirect(path);\n } else if (typeof window !== \"undefined\") {\n window.location.href = path;\n }\n },\n [returnPath]\n );\n\n return { returnPath, redirect, rawReturnUrl };\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"./cn\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive: \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n touch: \"h-12 min-h-[44px] min-w-[44px] rounded-md px-4\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;\n }\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"./cn\";\n\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n className\n )}\n ref={ref}\n {...props}\n />\n );\n }\n);\nInput.displayName = \"Input\";\n\nexport { Input };\n","\"use client\";\n\nimport * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"./cn\";\n\nconst labelVariants = cva(\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n);\n\nconst Label = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>\n>(({ className, ...props }, ref) => (\n <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />\n));\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"./cn\";\n\nconst Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"rounded-xl border bg-card text-card-foreground shadow\", className)}\n {...props}\n />\n )\n);\nCard.displayName = \"Card\";\n\nconst CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex flex-col space-y-1.5 p-6\", className)} {...props} />\n )\n);\nCardHeader.displayName = \"CardHeader\";\n\nconst CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(\n ({ className, ...props }, ref) => (\n <h3\n ref={ref}\n className={cn(\"font-semibold leading-none tracking-tight\", className)}\n {...props}\n />\n )\n);\nCardTitle.displayName = \"CardTitle\";\n\nconst CardDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <p ref={ref} className={cn(\"text-sm text-muted-foreground\", className)} {...props} />\n));\nCardDescription.displayName = \"CardDescription\";\n\nconst CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"p-6 pt-0\", className)} {...props} />\n )\n);\nCardContent.displayName = \"CardContent\";\n\nconst CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex items-center p-6 pt-0\", className)} {...props} />\n )\n);\nCardFooter.displayName = \"CardFooter\";\n\nexport { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"./cn\";\n\nexport interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"rounded-md bg-muted animate-pulse\", className)}\n {...props}\n />\n )\n);\nSkeleton.displayName = \"Skeleton\";\n\nexport { Skeleton };\n"],"mappings":"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","names":["import_react","import_cilantro_sdk","import_react","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_class_variance_authority","import_jsx_runtime","React","import_jsx_runtime","import_jsx_runtime","React","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}