acai-ui-library 0.1.13 → 0.1.14

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.
Files changed (63) hide show
  1. package/dist/components/alert.cjs +3 -2
  2. package/dist/components/alert.cjs.map +1 -1
  3. package/dist/components/alert.js +3 -2
  4. package/dist/components/alert.js.map +1 -1
  5. package/dist/components/card.cjs +1 -1
  6. package/dist/components/card.cjs.map +1 -1
  7. package/dist/components/card.js +1 -1
  8. package/dist/components/card.js.map +1 -1
  9. package/dist/components/checkbox.cjs +2 -1
  10. package/dist/components/checkbox.cjs.map +1 -1
  11. package/dist/components/checkbox.js +2 -1
  12. package/dist/components/checkbox.js.map +1 -1
  13. package/dist/components/data-table.cjs +2 -1
  14. package/dist/components/data-table.cjs.map +1 -1
  15. package/dist/components/data-table.js +2 -1
  16. package/dist/components/data-table.js.map +1 -1
  17. package/dist/components/date-picker.cjs.map +1 -1
  18. package/dist/components/date-picker.js.map +1 -1
  19. package/dist/components/impersonation-banner.cjs +137 -0
  20. package/dist/components/impersonation-banner.cjs.map +1 -0
  21. package/dist/components/impersonation-banner.d.cts +36 -0
  22. package/dist/components/impersonation-banner.d.ts +36 -0
  23. package/dist/components/impersonation-banner.js +101 -0
  24. package/dist/components/impersonation-banner.js.map +1 -0
  25. package/dist/components/input.cjs +2 -1
  26. package/dist/components/input.cjs.map +1 -1
  27. package/dist/components/input.js +2 -1
  28. package/dist/components/input.js.map +1 -1
  29. package/dist/components/item.cjs +1 -2
  30. package/dist/components/item.cjs.map +1 -1
  31. package/dist/components/item.js +1 -2
  32. package/dist/components/item.js.map +1 -1
  33. package/dist/components/pagination.cjs +3 -1
  34. package/dist/components/pagination.cjs.map +1 -1
  35. package/dist/components/pagination.d.cts +1 -1
  36. package/dist/components/pagination.d.ts +1 -1
  37. package/dist/components/pagination.js +3 -1
  38. package/dist/components/pagination.js.map +1 -1
  39. package/dist/components/read-only-guard.cjs +103 -0
  40. package/dist/components/read-only-guard.cjs.map +1 -0
  41. package/dist/components/read-only-guard.d.cts +40 -0
  42. package/dist/components/read-only-guard.d.ts +40 -0
  43. package/dist/components/read-only-guard.js +64 -0
  44. package/dist/components/read-only-guard.js.map +1 -0
  45. package/dist/components/stepper.cjs.map +1 -1
  46. package/dist/components/stepper.js.map +1 -1
  47. package/dist/components/typography.cjs +4 -4
  48. package/dist/components/typography.cjs.map +1 -1
  49. package/dist/components/typography.js +4 -4
  50. package/dist/components/typography.js.map +1 -1
  51. package/dist/index.cjs +236 -12
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.d.cts +3 -0
  54. package/dist/index.d.ts +3 -0
  55. package/dist/index.js +224 -12
  56. package/dist/index.js.map +1 -1
  57. package/dist/lib/impersonation.cjs +127 -0
  58. package/dist/lib/impersonation.cjs.map +1 -0
  59. package/dist/lib/impersonation.d.cts +45 -0
  60. package/dist/lib/impersonation.d.ts +45 -0
  61. package/dist/lib/impersonation.js +86 -0
  62. package/dist/lib/impersonation.js.map +1 -0
  63. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -173,7 +173,9 @@ __export(src_exports, {
173
173
  HoverCard: () => HoverCard,
174
174
  HoverCardContent: () => HoverCardContent,
175
175
  HoverCardTrigger: () => HoverCardTrigger,
176
+ INACTIVE_IMPERSONATION: () => INACTIVE_IMPERSONATION,
176
177
  IconInfoLineIcon: () => IconInfoLineIcon,
178
+ ImpersonationBanner: () => ImpersonationBanner,
177
179
  Input: () => Input,
178
180
  InputAddon: () => InputAddon,
179
181
  InputGroup: () => InputGroup,
@@ -215,6 +217,7 @@ __export(src_exports, {
215
217
  NavigationMenuList: () => NavigationMenuList,
216
218
  NavigationMenuTrigger: () => NavigationMenuTrigger,
217
219
  NavigationMenuViewport: () => NavigationMenuViewport,
220
+ OPERATION_CLASSES: () => OPERATION_CLASSES,
218
221
  Pagination: () => Pagination,
219
222
  PaginationContent: () => PaginationContent,
220
223
  PaginationEllipsis: () => PaginationEllipsis,
@@ -227,8 +230,10 @@ __export(src_exports, {
227
230
  PopoverContent: () => PopoverContent,
228
231
  PopoverTrigger: () => PopoverTrigger,
229
232
  Progress: () => Progress,
233
+ READ_ONLY_REASON: () => READ_ONLY_REASON,
230
234
  RadioGroup: () => RadioGroup,
231
235
  RadioGroupItem: () => RadioGroupItem,
236
+ ReadOnlyGuard: () => ReadOnlyGuard,
232
237
  ResizableHandle: () => ResizableHandle,
233
238
  ResizablePanel: () => ResizablePanel,
234
239
  ResizablePanelGroup: () => ResizablePanelGroup,
@@ -299,17 +304,24 @@ __export(src_exports, {
299
304
  TooltipProvider: () => TooltipProvider,
300
305
  TooltipTrigger: () => TooltipTrigger,
301
306
  alertVariants: () => alertVariants,
307
+ approvedOpsOf: () => approvedOpsOf,
302
308
  buttonVariants: () => buttonVariants,
303
309
  checkboxVariants: () => checkboxVariants,
304
310
  cn: () => cn,
311
+ decodeJwtPayload: () => decodeJwtPayload,
305
312
  emptyStateVariants: () => emptyStateVariants,
313
+ formatRemaining: () => formatRemaining,
306
314
  inputVariants: () => inputVariants,
315
+ isGuarded: () => isGuarded,
316
+ modeOfOps: () => modeOfOps,
307
317
  navigationMenuTriggerStyle: () => navigationMenuTriggerStyle,
318
+ readImpersonation: () => readImpersonation,
308
319
  spinnerVariants: () => spinnerVariants,
309
320
  switchVariants: () => switchVariants,
310
321
  toast: () => import_sonner.toast,
311
322
  toggleVariants: () => toggleVariants,
312
323
  useFormField: () => useFormField,
324
+ useImpersonation: () => useImpersonation,
313
325
  useSidebar: () => useSidebar,
314
326
  useTheme: () => import_next_themes3.useTheme
315
327
  });
@@ -443,7 +455,8 @@ var Input = React2.forwardRef(
443
455
  onChange,
444
456
  ...props
445
457
  }, ref) => {
446
- const inputId = id || React2.useId();
458
+ const generatedId = React2.useId();
459
+ const inputId = id || generatedId;
447
460
  const isControlled = value !== void 0;
448
461
  const [internalValue, setInternalValue] = React2.useState(defaultValue);
449
462
  const innerRef = React2.useRef(null);
@@ -816,7 +829,8 @@ var checkboxIconSize = {
816
829
  lg: "size-4"
817
830
  };
818
831
  var Checkbox = React7.forwardRef(({ className, label, id, variant, size = "default", ...props }, ref) => {
819
- const checkboxId = id || React7.useId();
832
+ const generatedId = React7.useId();
833
+ const checkboxId = id || generatedId;
820
834
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "inline-flex items-center gap-2", children: [
821
835
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
822
836
  CheckboxPrimitive.Root,
@@ -1562,12 +1576,13 @@ var Alert = React17.forwardRef(({ className, variant, ...props }, ref) => /* @__
1562
1576
  }
1563
1577
  ));
1564
1578
  Alert.displayName = "Alert";
1565
- var AlertTitle = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1579
+ var AlertTitle = React17.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1566
1580
  "h5",
1567
1581
  {
1568
1582
  ref,
1569
1583
  className: cn("mb-1 font-medium leading-none tracking-tight", className),
1570
- ...props
1584
+ ...props,
1585
+ children
1571
1586
  }
1572
1587
  ));
1573
1588
  AlertTitle.displayName = "AlertTitle";
@@ -1939,7 +1954,7 @@ var Item4 = React24.forwardRef(
1939
1954
  ({ className, clickable, onClick, children, ...props }, ref) => {
1940
1955
  const baseClasses = "flex items-center gap-3 px-4 py-3 rounded-md";
1941
1956
  const interactiveClasses = "cursor-pointer transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--hc-primary-500)] w-full text-start";
1942
- if (clickable) {
1957
+ if (clickable || onClick) {
1943
1958
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1944
1959
  "button",
1945
1960
  {
@@ -1956,7 +1971,6 @@ var Item4 = React24.forwardRef(
1956
1971
  "div",
1957
1972
  {
1958
1973
  ref,
1959
- onClick,
1960
1974
  className: cn(baseClasses, className),
1961
1975
  ...props,
1962
1976
  children
@@ -3522,7 +3536,7 @@ var CardHeader = React39.forwardRef(
3522
3536
  );
3523
3537
  CardHeader.displayName = "CardHeader";
3524
3538
  var CardTitle = React39.forwardRef(
3525
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("h3", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })
3539
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("h3", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props, children })
3526
3540
  );
3527
3541
  CardTitle.displayName = "CardTitle";
3528
3542
  var CardDescription = React39.forwardRef(
@@ -3890,6 +3904,7 @@ var PaginationLink = ({
3890
3904
  className,
3891
3905
  isActive,
3892
3906
  size = "icon",
3907
+ children,
3893
3908
  ...props
3894
3909
  }) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3895
3910
  "a",
@@ -3902,7 +3917,8 @@ var PaginationLink = ({
3902
3917
  }),
3903
3918
  className
3904
3919
  ),
3905
- ...props
3920
+ ...props,
3921
+ children
3906
3922
  }
3907
3923
  );
3908
3924
  PaginationLink.displayName = "PaginationLink";
@@ -4660,19 +4676,19 @@ function resolveColor(color, defaultColorClass) {
4660
4676
  return colorMap[color];
4661
4677
  }
4662
4678
  var H1 = React50.forwardRef(
4663
- ({ className, weight = "semibold", color, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h1", { ref, className: cn("scroll-m-20 text-3xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props })
4679
+ ({ className, weight = "semibold", color, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h1", { ref, className: cn("scroll-m-20 text-3xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props, children })
4664
4680
  );
4665
4681
  H1.displayName = "H1";
4666
4682
  var H2 = React50.forwardRef(
4667
- ({ className, weight = "semibold", color, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h2", { ref, className: cn("scroll-m-20 text-2xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props })
4683
+ ({ className, weight = "semibold", color, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h2", { ref, className: cn("scroll-m-20 text-2xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props, children })
4668
4684
  );
4669
4685
  H2.displayName = "H2";
4670
4686
  var H3 = React50.forwardRef(
4671
- ({ className, weight = "semibold", color, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h3", { ref, className: cn("scroll-m-20 text-xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props })
4687
+ ({ className, weight = "semibold", color, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h3", { ref, className: cn("scroll-m-20 text-xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props, children })
4672
4688
  );
4673
4689
  H3.displayName = "H3";
4674
4690
  var H4 = React50.forwardRef(
4675
- ({ className, weight = "semibold", color, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h4", { ref, className: cn("scroll-m-20 text-lg tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props })
4691
+ ({ className, weight = "semibold", color, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h4", { ref, className: cn("scroll-m-20 text-lg tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props, children })
4676
4692
  );
4677
4693
  H4.displayName = "H4";
4678
4694
  var Body = React50.forwardRef(
@@ -4757,6 +4773,202 @@ var Banner = React51.forwardRef(
4757
4773
  )
4758
4774
  );
4759
4775
  Banner.displayName = "Banner";
4776
+
4777
+ // src/components/impersonation-banner.tsx
4778
+ var React52 = __toESM(require("react"), 1);
4779
+ var import_jsx_runtime61 = require("react/jsx-runtime");
4780
+ function toMs(value) {
4781
+ if (value instanceof Date) return value.getTime();
4782
+ if (typeof value === "number") return value;
4783
+ const parsed = Date.parse(value);
4784
+ return Number.isNaN(parsed) ? 0 : parsed;
4785
+ }
4786
+ function formatRemaining(ms) {
4787
+ const total = Math.max(0, Math.floor(ms / 1e3));
4788
+ const h = Math.floor(total / 3600);
4789
+ const m = Math.floor(total % 3600 / 60);
4790
+ const s = total % 60;
4791
+ const pad = (n) => String(n).padStart(2, "0");
4792
+ return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${m}:${pad(s)}`;
4793
+ }
4794
+ var ImpersonationBanner = React52.forwardRef(
4795
+ ({ actorLabel, mode, expiresAt, onExit, targetLabel, ops, inline = false, onExpire, className }, ref) => {
4796
+ const endMs = toMs(expiresAt);
4797
+ const [now, setNow] = React52.useState(() => Date.now());
4798
+ const remaining = endMs - now;
4799
+ const expired = remaining <= 0;
4800
+ const onExpireRef = React52.useRef(onExpire);
4801
+ onExpireRef.current = onExpire;
4802
+ React52.useEffect(() => {
4803
+ if (expired) return void 0;
4804
+ const timer = setInterval(() => setNow(Date.now()), 1e3);
4805
+ return () => clearInterval(timer);
4806
+ }, [expired]);
4807
+ const firedFor = React52.useRef(null);
4808
+ React52.useEffect(() => {
4809
+ if (expired && firedFor.current !== endMs) {
4810
+ firedFor.current = endMs;
4811
+ onExpireRef.current?.();
4812
+ }
4813
+ }, [expired, endMs]);
4814
+ const isRead = mode === "READ";
4815
+ const modeText = isRead ? "Read-only" : "Changes allowed";
4816
+ const opsText = ops && ops.length > 0 ? ops.join(", ") : null;
4817
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_jsx_runtime61.Fragment, { children: [
4818
+ inline ? null : /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { "aria-hidden": "true", className: "h-12", "data-impersonation-spacer": "" }),
4819
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
4820
+ "div",
4821
+ {
4822
+ ref,
4823
+ role: "alert",
4824
+ "data-impersonation-banner": "",
4825
+ "data-mode": mode,
4826
+ className: cn(
4827
+ inline ? "relative" : "fixed inset-x-0 top-0 z-[2147483000]",
4828
+ "flex h-12 items-center gap-3 border-b-2 px-4 text-sm font-medium shadow-md",
4829
+ isRead ? "border-black bg-[#FDE047] text-black" : "border-white bg-[#991B1B] text-white",
4830
+ className
4831
+ ),
4832
+ children: [
4833
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "shrink-0 rounded px-2 py-0.5 text-xs font-bold uppercase tracking-wide ring-1 ring-current", children: "Support session" }),
4834
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("p", { className: "min-w-0 flex-1 truncate", children: [
4835
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "font-semibold", children: actorLabel }),
4836
+ targetLabel ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_jsx_runtime61.Fragment, { children: [
4837
+ " is acting as ",
4838
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "font-semibold", children: targetLabel })
4839
+ ] }) : " is acting as this user",
4840
+ " \xB7 ",
4841
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { "data-testid": "impersonation-mode", children: modeText }),
4842
+ opsText ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "hidden sm:inline", children: ` (${opsText})` }) : null
4843
+ ] }),
4844
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "shrink-0 tabular-nums", "aria-live": "off", title: "Time left in this support session", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("time", { "data-testid": "impersonation-countdown", dateTime: new Date(endMs).toISOString(), children: expired ? "Expired" : formatRemaining(remaining) }) }),
4845
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
4846
+ "button",
4847
+ {
4848
+ type: "button",
4849
+ onClick: onExit,
4850
+ className: cn(
4851
+ "shrink-0 rounded-md px-3 py-1 text-sm font-semibold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
4852
+ isRead ? "bg-black text-[#FDE047] hover:bg-black/85 focus-visible:ring-black focus-visible:ring-offset-[#FDE047]" : "bg-white text-[#991B1B] hover:bg-white/90 focus-visible:ring-white focus-visible:ring-offset-[#991B1B]"
4853
+ ),
4854
+ children: "Exit"
4855
+ }
4856
+ )
4857
+ ]
4858
+ }
4859
+ )
4860
+ ] });
4861
+ }
4862
+ );
4863
+ ImpersonationBanner.displayName = "ImpersonationBanner";
4864
+
4865
+ // src/components/read-only-guard.tsx
4866
+ var import_jsx_runtime62 = require("react/jsx-runtime");
4867
+ var READ_ONLY_REASON = "Read-only support session: this action is turned off.";
4868
+ function isGuarded({ mode, ops, op = "WRITE" }) {
4869
+ if (ops) return !ops.includes(op);
4870
+ return mode === "READ";
4871
+ }
4872
+ function ReadOnlyGuard({ mode, ops, op = "WRITE", reason = READ_ONLY_REASON, className, children }) {
4873
+ if (!isGuarded({ mode, ops, op })) return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_jsx_runtime62.Fragment, { children });
4874
+ const swallow = (e) => {
4875
+ e.preventDefault();
4876
+ e.stopPropagation();
4877
+ };
4878
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(TooltipProvider, { delayDuration: 150, children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(Tooltip, { children: [
4879
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
4880
+ "span",
4881
+ {
4882
+ tabIndex: 0,
4883
+ "data-read-only": "",
4884
+ "aria-disabled": "true",
4885
+ className: cn("inline-flex cursor-not-allowed", className),
4886
+ onClickCapture: swallow,
4887
+ onSubmitCapture: swallow,
4888
+ children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("fieldset", { disabled: true, className: "contents", children })
4889
+ }
4890
+ ) }),
4891
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(TooltipContent, { children: reason })
4892
+ ] }) });
4893
+ }
4894
+ ReadOnlyGuard.displayName = "ReadOnlyGuard";
4895
+
4896
+ // src/lib/impersonation.ts
4897
+ var React53 = __toESM(require("react"), 1);
4898
+ var OPERATION_CLASSES = ["READ", "WRITE", "DESTRUCTIVE", "FINANCIAL", "SECURITY"];
4899
+ var PLATFORM_BLOCKED = /* @__PURE__ */ new Set(["FINANCIAL", "SECURITY"]);
4900
+ var INACTIVE_IMPERSONATION = Object.freeze({
4901
+ active: false,
4902
+ mode: null,
4903
+ ops: [],
4904
+ actorSub: null,
4905
+ actorUserType: null,
4906
+ sessionId: null,
4907
+ expiresAt: null
4908
+ });
4909
+ function base64UrlDecode(segment) {
4910
+ const b64 = segment.replace(/-/g, "+").replace(/_/g, "/");
4911
+ const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
4912
+ const binary = atob(padded);
4913
+ const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
4914
+ return new TextDecoder().decode(bytes);
4915
+ }
4916
+ function decodeJwtPayload(token) {
4917
+ if (typeof token !== "string") return null;
4918
+ const parts = token.split(".");
4919
+ if (parts.length !== 3 || !parts[1]) return null;
4920
+ try {
4921
+ const payload = JSON.parse(base64UrlDecode(parts[1]));
4922
+ return payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
4923
+ } catch {
4924
+ return null;
4925
+ }
4926
+ }
4927
+ var nonEmpty = (v) => typeof v === "string" && v.trim() !== "" ? v : null;
4928
+ function approvedOpsOf(claims) {
4929
+ let ops;
4930
+ if (Array.isArray(claims.imp_ops)) ops = claims.imp_ops.filter((v) => typeof v === "string");
4931
+ else if (claims.imp_mode === "WRITE") ops = ["READ", "WRITE"];
4932
+ else ops = ["READ"];
4933
+ const set = new Set(ops.filter((op) => !PLATFORM_BLOCKED.has(op)));
4934
+ return OPERATION_CLASSES.filter((c) => set.has(c));
4935
+ }
4936
+ function modeOfOps(ops) {
4937
+ return ops.every((op) => op === "READ") ? "READ" : "WRITE";
4938
+ }
4939
+ function readImpersonation(token, now = Date.now()) {
4940
+ const claims = decodeJwtPayload(token);
4941
+ if (!claims) return INACTIVE_IMPERSONATION;
4942
+ const amr = Array.isArray(claims.amr) ? claims.amr : [];
4943
+ if (!amr.includes("impersonation")) return INACTIVE_IMPERSONATION;
4944
+ const act = claims.act !== null && typeof claims.act === "object" ? claims.act : {};
4945
+ const actorSub = nonEmpty(act.sub);
4946
+ const sessionId = nonEmpty(claims.imp_sid);
4947
+ const expiresAt = typeof claims.exp === "number" ? new Date(claims.exp * 1e3) : null;
4948
+ if (!actorSub || !sessionId || !expiresAt || expiresAt.getTime() <= now) return INACTIVE_IMPERSONATION;
4949
+ const ops = approvedOpsOf(claims);
4950
+ return {
4951
+ active: true,
4952
+ mode: modeOfOps(ops),
4953
+ ops,
4954
+ actorSub,
4955
+ actorUserType: nonEmpty(act.userType),
4956
+ sessionId,
4957
+ expiresAt
4958
+ };
4959
+ }
4960
+ function useImpersonation(token) {
4961
+ const [tick, setTick] = React53.useState(0);
4962
+ const state = React53.useMemo(() => readImpersonation(token), [token, tick]);
4963
+ const expiresAtMs = state.expiresAt?.getTime() ?? null;
4964
+ React53.useEffect(() => {
4965
+ if (expiresAtMs === null) return void 0;
4966
+ const delay = Math.max(0, expiresAtMs - Date.now());
4967
+ const timer = setTimeout(() => setTick((t) => t + 1), Math.min(delay + 50, 2147e6));
4968
+ return () => clearTimeout(timer);
4969
+ }, [expiresAtMs]);
4970
+ return state;
4971
+ }
4760
4972
  // Annotate the CommonJS export names for ESM import in node:
4761
4973
  0 && (module.exports = {
4762
4974
  Accordion,
@@ -4902,7 +5114,9 @@ Banner.displayName = "Banner";
4902
5114
  HoverCard,
4903
5115
  HoverCardContent,
4904
5116
  HoverCardTrigger,
5117
+ INACTIVE_IMPERSONATION,
4905
5118
  IconInfoLineIcon,
5119
+ ImpersonationBanner,
4906
5120
  Input,
4907
5121
  InputAddon,
4908
5122
  InputGroup,
@@ -4944,6 +5158,7 @@ Banner.displayName = "Banner";
4944
5158
  NavigationMenuList,
4945
5159
  NavigationMenuTrigger,
4946
5160
  NavigationMenuViewport,
5161
+ OPERATION_CLASSES,
4947
5162
  Pagination,
4948
5163
  PaginationContent,
4949
5164
  PaginationEllipsis,
@@ -4956,8 +5171,10 @@ Banner.displayName = "Banner";
4956
5171
  PopoverContent,
4957
5172
  PopoverTrigger,
4958
5173
  Progress,
5174
+ READ_ONLY_REASON,
4959
5175
  RadioGroup,
4960
5176
  RadioGroupItem,
5177
+ ReadOnlyGuard,
4961
5178
  ResizableHandle,
4962
5179
  ResizablePanel,
4963
5180
  ResizablePanelGroup,
@@ -5028,17 +5245,24 @@ Banner.displayName = "Banner";
5028
5245
  TooltipProvider,
5029
5246
  TooltipTrigger,
5030
5247
  alertVariants,
5248
+ approvedOpsOf,
5031
5249
  buttonVariants,
5032
5250
  checkboxVariants,
5033
5251
  cn,
5252
+ decodeJwtPayload,
5034
5253
  emptyStateVariants,
5254
+ formatRemaining,
5035
5255
  inputVariants,
5256
+ isGuarded,
5257
+ modeOfOps,
5036
5258
  navigationMenuTriggerStyle,
5259
+ readImpersonation,
5037
5260
  spinnerVariants,
5038
5261
  switchVariants,
5039
5262
  toast,
5040
5263
  toggleVariants,
5041
5264
  useFormField,
5265
+ useImpersonation,
5042
5266
  useSidebar,
5043
5267
  useTheme
5044
5268
  });