@brokr/sdk 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -34,6 +34,7 @@ var index_exports = {};
34
34
  __export(index_exports, {
35
35
  AIChat: () => AIChat,
36
36
  AccountPanel: () => AccountPanel,
37
+ ActivityFeed: () => ActivityFeed,
37
38
  AuthPageShell: () => AuthPageShell,
38
39
  AuthWall: () => AuthWall,
39
40
  AutoReloadToggle: () => AutoReloadToggle,
@@ -63,8 +64,10 @@ __export(index_exports, {
63
64
  UpdateBilling: () => UpdateBilling,
64
65
  UpgradePrompt: () => UpgradePrompt,
65
66
  UsageGate: () => UsageGate,
67
+ UsageGrid: () => UsageGrid,
66
68
  UserButton: () => UserButton,
67
69
  defineAccount: () => defineAccount,
70
+ defineBrokrTheme: () => defineBrokrTheme,
68
71
  defineChat: () => defineChat,
69
72
  useBrokr: () => useBrokr,
70
73
  useBrokrTheme: () => useBrokrTheme,
@@ -6328,15 +6331,32 @@ function CancelSubscription({ onCancel }) {
6328
6331
  return /* @__PURE__ */ import_react29.default.createElement("div", { className: "brokr-section", style: { gap: "0.75rem" } }, confirming ? /* @__PURE__ */ import_react29.default.createElement("div", { className: "brokr-inline-message" }, "Subscription changes are confirmed in billing. Continue?") : null, /* @__PURE__ */ import_react29.default.createElement("div", { className: "brokr-brand-row" }, /* @__PURE__ */ import_react29.default.createElement("button", { className: "brokr-button-ghost", disabled: isPending, onClick: handlePrimaryClick, type: "button" }, isPending ? "Opening billing" : confirming ? "Continue" : "Cancel subscription"), confirming ? /* @__PURE__ */ import_react29.default.createElement("button", { className: "brokr-button-secondary", onClick: handleDismiss, type: "button" }, "Keep subscription") : null));
6329
6332
  }
6330
6333
 
6334
+ // src/react/payments/UsageGrid.tsx
6335
+ var import_react30 = __toESM(require("react"));
6336
+ function UsageGrid() {
6337
+ const { entitlements, isLoaded } = useBrokr();
6338
+ const meteredFeatures = (0, import_react30.useMemo)(() => {
6339
+ if (!entitlements?.features) return [];
6340
+ return Object.entries(entitlements.features).filter(([_, check]) => check.limitType === "numeric").map(([slug]) => slug);
6341
+ }, [entitlements]);
6342
+ if (!isLoaded) {
6343
+ return /* @__PURE__ */ import_react30.default.createElement("div", { className: "brokr-usage-grid" }, /* @__PURE__ */ import_react30.default.createElement(Skeleton, { height: 72 }), /* @__PURE__ */ import_react30.default.createElement(Skeleton, { height: 72 }));
6344
+ }
6345
+ if (meteredFeatures.length === 0) {
6346
+ return null;
6347
+ }
6348
+ return /* @__PURE__ */ import_react30.default.createElement("div", { className: "brokr-usage-grid" }, meteredFeatures.map((slug) => /* @__PURE__ */ import_react30.default.createElement(FeatureMeter, { key: slug, feature: slug })));
6349
+ }
6350
+
6331
6351
  // src/react/chat/AIChat.tsx
6332
- var import_react38 = __toESM(require("react"));
6352
+ var import_react39 = __toESM(require("react"));
6333
6353
 
6334
6354
  // src/react/chat/ChatContext.tsx
6335
- var import_react30 = require("react");
6336
- var InternalChatContext = (0, import_react30.createContext)(null);
6355
+ var import_react31 = require("react");
6356
+ var InternalChatContext = (0, import_react31.createContext)(null);
6337
6357
  var ChatProvider = InternalChatContext.Provider;
6338
6358
  function useChatState() {
6339
- const ctx = (0, import_react30.useContext)(InternalChatContext);
6359
+ const ctx = (0, import_react31.useContext)(InternalChatContext);
6340
6360
  if (!ctx) {
6341
6361
  throw new Error("useChatState must be used within <AIChat>");
6342
6362
  }
@@ -6344,7 +6364,7 @@ function useChatState() {
6344
6364
  }
6345
6365
 
6346
6366
  // src/react/chat/useChat.ts
6347
- var import_react31 = require("react");
6367
+ var import_react32 = require("react");
6348
6368
 
6349
6369
  // src/ai/types.ts
6350
6370
  function contentToText(content) {
@@ -6519,24 +6539,24 @@ function useChat(config) {
6519
6539
  userId
6520
6540
  } = config;
6521
6541
  const isPersist = persist && !isControlled;
6522
- const [memConversations, setMemConversations] = (0, import_react31.useState)([]);
6523
- const [memActiveId, setMemActiveId] = (0, import_react31.useState)(null);
6524
- const [serverThreads, setServerThreads] = (0, import_react31.useState)([]);
6525
- const [serverActiveId, setServerActiveId] = (0, import_react31.useState)(null);
6526
- const [serverMessages, setServerMessages] = (0, import_react31.useState)([]);
6527
- const [input, setInput] = (0, import_react31.useState)("");
6528
- const [isSubmitting, setIsSubmitting] = (0, import_react31.useState)(false);
6529
- const [error, setError] = (0, import_react31.useState)(null);
6530
- const [threadsLoading, setThreadsLoading] = (0, import_react31.useState)(false);
6531
- const [renamingId, setRenamingId] = (0, import_react31.useState)(null);
6532
- const [renameValue, setRenameValue] = (0, import_react31.useState)("");
6533
- const [hasMoreMessages, setHasMoreMessages] = (0, import_react31.useState)(false);
6534
- const [loadingOlder, setLoadingOlder] = (0, import_react31.useState)(false);
6535
- const textareaRef = (0, import_react31.useRef)(null);
6536
- const bottomRef = (0, import_react31.useRef)(null);
6537
- const scrollContainerRef = (0, import_react31.useRef)(null);
6538
- const sentinelRef = (0, import_react31.useRef)(null);
6539
- const displaySidebarItems = (0, import_react31.useMemo)(() => {
6542
+ const [memConversations, setMemConversations] = (0, import_react32.useState)([]);
6543
+ const [memActiveId, setMemActiveId] = (0, import_react32.useState)(null);
6544
+ const [serverThreads, setServerThreads] = (0, import_react32.useState)([]);
6545
+ const [serverActiveId, setServerActiveId] = (0, import_react32.useState)(null);
6546
+ const [serverMessages, setServerMessages] = (0, import_react32.useState)([]);
6547
+ const [input, setInput] = (0, import_react32.useState)("");
6548
+ const [isSubmitting, setIsSubmitting] = (0, import_react32.useState)(false);
6549
+ const [error, setError] = (0, import_react32.useState)(null);
6550
+ const [threadsLoading, setThreadsLoading] = (0, import_react32.useState)(false);
6551
+ const [renamingId, setRenamingId] = (0, import_react32.useState)(null);
6552
+ const [renameValue, setRenameValue] = (0, import_react32.useState)("");
6553
+ const [hasMoreMessages, setHasMoreMessages] = (0, import_react32.useState)(false);
6554
+ const [loadingOlder, setLoadingOlder] = (0, import_react32.useState)(false);
6555
+ const textareaRef = (0, import_react32.useRef)(null);
6556
+ const bottomRef = (0, import_react32.useRef)(null);
6557
+ const scrollContainerRef = (0, import_react32.useRef)(null);
6558
+ const sentinelRef = (0, import_react32.useRef)(null);
6559
+ const displaySidebarItems = (0, import_react32.useMemo)(() => {
6540
6560
  if (isControlled) {
6541
6561
  return threadsProp?.map((t) => ({
6542
6562
  id: t.id,
@@ -6557,26 +6577,26 @@ function useChat(config) {
6557
6577
  updatedAt: new Date(c.updatedAt).toISOString()
6558
6578
  }));
6559
6579
  }, [isControlled, isPersist, threadsProp, serverThreads, memConversations]);
6560
- const activeId = (0, import_react31.useMemo)(() => {
6580
+ const activeId = (0, import_react32.useMemo)(() => {
6561
6581
  if (isControlled) return activeThreadIdProp ?? null;
6562
6582
  if (isPersist) return serverActiveId;
6563
6583
  return memActiveId;
6564
6584
  }, [isControlled, isPersist, activeThreadIdProp, serverActiveId, memActiveId]);
6565
- const displayMessages = (0, import_react31.useMemo)(() => {
6585
+ const displayMessages = (0, import_react32.useMemo)(() => {
6566
6586
  if (isControlled) return messagesProp ?? [];
6567
6587
  if (isPersist) return serverMessages;
6568
6588
  return memConversations.find((c) => c.id === memActiveId)?.messages ?? [];
6569
6589
  }, [isControlled, isPersist, messagesProp, serverMessages, memConversations, memActiveId]);
6570
- const activeMemConv = (0, import_react31.useMemo)(
6590
+ const activeMemConv = (0, import_react32.useMemo)(
6571
6591
  () => memConversations.find((c) => c.id === memActiveId) ?? null,
6572
6592
  [memConversations, memActiveId]
6573
6593
  );
6574
- const activeThread = (0, import_react31.useMemo)(() => {
6594
+ const activeThread = (0, import_react32.useMemo)(() => {
6575
6595
  if (isControlled) return threadsProp?.find((t) => t.id === activeId) ?? null;
6576
6596
  if (isPersist) return serverThreads.find((t) => t.id === activeId) ?? null;
6577
6597
  return null;
6578
6598
  }, [isControlled, isPersist, threadsProp, serverThreads, activeId]);
6579
- const renderedTitle = (0, import_react31.useMemo)(() => {
6599
+ const renderedTitle = (0, import_react32.useMemo)(() => {
6580
6600
  if (isPersist && activeThread) return activeThread.title;
6581
6601
  if (!isPersist && activeMemConv) {
6582
6602
  if (activeMemConv.titleState === "loading") return "Naming conversation";
@@ -6585,10 +6605,10 @@ function useChat(config) {
6585
6605
  return "New chat";
6586
6606
  }, [isPersist, activeThread, activeMemConv]);
6587
6607
  const isTitleLoading = !isPersist && activeMemConv?.titleState === "loading";
6588
- (0, import_react31.useEffect)(() => {
6608
+ (0, import_react32.useEffect)(() => {
6589
6609
  bottomRef.current?.scrollIntoView({ behavior: "smooth" });
6590
6610
  }, [displayMessages, activeId]);
6591
- (0, import_react31.useEffect)(() => {
6611
+ (0, import_react32.useEffect)(() => {
6592
6612
  if (!isPersist) return;
6593
6613
  setThreadsLoading(true);
6594
6614
  const base = getBaseEndpoint(endpoint);
@@ -6597,7 +6617,7 @@ function useChat(config) {
6597
6617
  fetch(`${base}/threads?${params}`, { credentials: "include" }).then((r) => r.json()).then((data) => setServerThreads(data.threads ?? [])).catch(() => {
6598
6618
  }).finally(() => setThreadsLoading(false));
6599
6619
  }, [isPersist, endpoint, surface, subject]);
6600
- (0, import_react31.useEffect)(() => {
6620
+ (0, import_react32.useEffect)(() => {
6601
6621
  if (!isPersist || !serverActiveId || isSubmitting) return;
6602
6622
  const base = getBaseEndpoint(endpoint);
6603
6623
  fetch(`${base}/threads/${serverActiveId}/messages?limit=30&offset=0`, { credentials: "include" }).then((r) => r.json()).then((data) => {
@@ -6606,7 +6626,7 @@ function useChat(config) {
6606
6626
  }).catch(() => {
6607
6627
  });
6608
6628
  }, [isPersist, serverActiveId, endpoint, isSubmitting]);
6609
- const loadOlderMessages = (0, import_react31.useCallback)(async () => {
6629
+ const loadOlderMessages = (0, import_react32.useCallback)(async () => {
6610
6630
  if (!isPersist || !serverActiveId || loadingOlder || !hasMoreMessages) return;
6611
6631
  setLoadingOlder(true);
6612
6632
  const base = getBaseEndpoint(endpoint);
@@ -6636,7 +6656,7 @@ function useChat(config) {
6636
6656
  setLoadingOlder(false);
6637
6657
  }
6638
6658
  }, [isPersist, serverActiveId, loadingOlder, hasMoreMessages, endpoint, serverMessages.length]);
6639
- (0, import_react31.useEffect)(() => {
6659
+ (0, import_react32.useEffect)(() => {
6640
6660
  if (!isPersist || !hasMoreMessages) return;
6641
6661
  const sentinel = sentinelRef.current;
6642
6662
  if (!sentinel) return;
@@ -6649,15 +6669,15 @@ function useChat(config) {
6649
6669
  observer.observe(sentinel);
6650
6670
  return () => observer.disconnect();
6651
6671
  }, [isPersist, hasMoreMessages, loadOlderMessages]);
6652
- const notificationsCtx = (0, import_react31.useContext)(NotificationsContext);
6653
- (0, import_react31.useEffect)(() => {
6672
+ const notificationsCtx = (0, import_react32.useContext)(NotificationsContext);
6673
+ (0, import_react32.useEffect)(() => {
6654
6674
  if (!notificationsCtx || !serverActiveId) return;
6655
6675
  notificationsCtx.registerViewingThread(serverActiveId);
6656
6676
  return () => {
6657
6677
  notificationsCtx.unregisterViewingThread(serverActiveId);
6658
6678
  };
6659
6679
  }, [notificationsCtx, serverActiveId]);
6660
- (0, import_react31.useEffect)(() => {
6680
+ (0, import_react32.useEffect)(() => {
6661
6681
  if (!onThreadChange) return;
6662
6682
  if (isControlled || isPersist) {
6663
6683
  onThreadChange(activeThread);
@@ -6678,23 +6698,23 @@ function useChat(config) {
6678
6698
  }
6679
6699
  }
6680
6700
  }, [activeThread, onThreadChange, isControlled, isPersist, memConversations, memActiveId, surface, subject]);
6681
- const updateMemMessages = (0, import_react31.useCallback)((convId, msgs) => {
6701
+ const updateMemMessages = (0, import_react32.useCallback)((convId, msgs) => {
6682
6702
  setMemConversations((prev) => prev.map((c) => c.id === convId ? { ...c, messages: msgs, updatedAt: Date.now() } : c).sort((a, b) => b.updatedAt - a.updatedAt));
6683
6703
  }, []);
6684
- const updateMemTitle = (0, import_react31.useCallback)((convId, t) => {
6704
+ const updateMemTitle = (0, import_react32.useCallback)((convId, t) => {
6685
6705
  setMemConversations((prev) => prev.map((c) => c.id === convId ? { ...c, title: t, titleState: t ? "ready" : c.titleState, updatedAt: Date.now() } : c));
6686
6706
  }, []);
6687
- const setMemTitleState = (0, import_react31.useCallback)((convId, state) => {
6707
+ const setMemTitleState = (0, import_react32.useCallback)((convId, state) => {
6688
6708
  setMemConversations((prev) => prev.map((c) => c.id === convId ? { ...c, titleState: state, updatedAt: Date.now() } : c));
6689
6709
  }, []);
6690
- const appendMemDelta = (0, import_react31.useCallback)((convId, msgId, delta) => {
6710
+ const appendMemDelta = (0, import_react32.useCallback)((convId, msgId, delta) => {
6691
6711
  setMemConversations((prev) => prev.map((c) => c.id === convId ? {
6692
6712
  ...c,
6693
6713
  messages: c.messages.map((m) => m.id === msgId ? { ...m, content: `${m.content}${delta}` } : m),
6694
6714
  updatedAt: Date.now()
6695
6715
  } : c));
6696
6716
  }, []);
6697
- const animateTitle = (0, import_react31.useCallback)(async (convId, raw) => {
6717
+ const animateTitle = (0, import_react32.useCallback)(async (convId, raw) => {
6698
6718
  const safe = sanitizeTitle(raw);
6699
6719
  setMemTitleState(convId, "loading");
6700
6720
  updateMemTitle(convId, "");
@@ -6706,7 +6726,7 @@ function useChat(config) {
6706
6726
  }
6707
6727
  setMemTitleState(convId, "ready");
6708
6728
  }, [setMemTitleState, updateMemTitle]);
6709
- const ensureMemConversation = (0, import_react31.useCallback)(() => {
6729
+ const ensureMemConversation = (0, import_react32.useCallback)(() => {
6710
6730
  if (memActiveId) return memActiveId;
6711
6731
  const id = makeId("conv");
6712
6732
  setMemConversations((prev) => [{
@@ -6719,7 +6739,7 @@ function useChat(config) {
6719
6739
  setMemActiveId(id);
6720
6740
  return id;
6721
6741
  }, [memActiveId]);
6722
- const sendMemoryMessage = (0, import_react31.useCallback)(async (content) => {
6742
+ const sendMemoryMessage = (0, import_react32.useCallback)(async (content) => {
6723
6743
  const convId = ensureMemConversation();
6724
6744
  const userMsg = { id: makeId("msg"), role: "user", content };
6725
6745
  const assistantMsg = { id: makeId("msg"), role: "assistant", content: "", model: activeModel };
@@ -6796,7 +6816,7 @@ function useChat(config) {
6796
6816
  setMemTitleState,
6797
6817
  onMessage
6798
6818
  ]);
6799
- const sendPersistMessage = (0, import_react31.useCallback)(async (content) => {
6819
+ const sendPersistMessage = (0, import_react32.useCallback)(async (content) => {
6800
6820
  const userMsg = { id: makeId("msg"), role: "user", content, status: "complete" };
6801
6821
  const assistantMsg = { id: makeId("msg"), role: "assistant", content: "", model: activeModel, status: "pending" };
6802
6822
  setServerMessages((prev) => [...prev, userMsg, assistantMsg]);
@@ -6881,7 +6901,7 @@ function useChat(config) {
6881
6901
  onMessage,
6882
6902
  onThreadCreate
6883
6903
  ]);
6884
- const sendMessage = (0, import_react31.useCallback)(async (rawText) => {
6904
+ const sendMessage = (0, import_react32.useCallback)(async (rawText) => {
6885
6905
  const content = (rawText ?? input).trim();
6886
6906
  if (!content || isSubmitting) return;
6887
6907
  setInput("");
@@ -6921,7 +6941,7 @@ function useChat(config) {
6921
6941
  setIsSubmitting(false);
6922
6942
  }
6923
6943
  }, [input, isSubmitting, isControlled, isPersist, onSendMessage, activeId, sendPersistMessage, sendMemoryMessage, memActiveId]);
6924
- const startNewChat = (0, import_react31.useCallback)(() => {
6944
+ const startNewChat = (0, import_react32.useCallback)(() => {
6925
6945
  if (isControlled) {
6926
6946
  onThreadSelect?.(null);
6927
6947
  } else if (isPersist) {
@@ -6936,7 +6956,7 @@ function useChat(config) {
6936
6956
  textareaRef.current?.focus();
6937
6957
  });
6938
6958
  }, [isControlled, isPersist, onThreadSelect]);
6939
- const selectThread = (0, import_react31.useCallback)((id) => {
6959
+ const selectThread = (0, import_react32.useCallback)((id) => {
6940
6960
  if (isControlled) {
6941
6961
  onThreadSelect?.(id);
6942
6962
  } else if (isPersist) {
@@ -6947,7 +6967,7 @@ function useChat(config) {
6947
6967
  setError(null);
6948
6968
  }
6949
6969
  }, [isControlled, isPersist, onThreadSelect]);
6950
- const deleteThread = (0, import_react31.useCallback)(async (threadId) => {
6970
+ const deleteThread = (0, import_react32.useCallback)(async (threadId) => {
6951
6971
  if (isControlled) {
6952
6972
  onThreadDelete?.(threadId);
6953
6973
  return;
@@ -6966,12 +6986,12 @@ function useChat(config) {
6966
6986
  if (memActiveId === threadId) setMemActiveId(null);
6967
6987
  }
6968
6988
  }, [isControlled, isPersist, serverActiveId, endpoint, memActiveId, onThreadDelete]);
6969
- const startRename = (0, import_react31.useCallback)((threadId) => {
6989
+ const startRename = (0, import_react32.useCallback)((threadId) => {
6970
6990
  const item = displaySidebarItems.find((t) => t.id === threadId);
6971
6991
  setRenamingId(threadId);
6972
6992
  setRenameValue(item?.title ?? "");
6973
6993
  }, [displaySidebarItems]);
6974
- const submitRename = (0, import_react31.useCallback)(async () => {
6994
+ const submitRename = (0, import_react32.useCallback)(async () => {
6975
6995
  if (!renamingId || !renameValue.trim()) {
6976
6996
  setRenamingId(null);
6977
6997
  return;
@@ -7030,7 +7050,7 @@ function useChat(config) {
7030
7050
  }
7031
7051
 
7032
7052
  // src/react/chat/ModelSelector.tsx
7033
- var import_react32 = __toESM(require("react"));
7053
+ var import_react33 = __toESM(require("react"));
7034
7054
  function ModelOption({
7035
7055
  provider,
7036
7056
  isActive,
@@ -7038,14 +7058,14 @@ function ModelOption({
7038
7058
  onSelect,
7039
7059
  onCheckout
7040
7060
  }) {
7041
- const handleClick = (0, import_react32.useCallback)(() => {
7061
+ const handleClick = (0, import_react33.useCallback)(() => {
7042
7062
  if (isLocked) {
7043
7063
  void onCheckout({ plan: "pro" });
7044
7064
  } else {
7045
7065
  onSelect(provider.model);
7046
7066
  }
7047
7067
  }, [isLocked, onCheckout, onSelect, provider.model]);
7048
- return /* @__PURE__ */ import_react32.default.createElement(
7068
+ return /* @__PURE__ */ import_react33.default.createElement(
7049
7069
  "button",
7050
7070
  {
7051
7071
  "aria-selected": isActive,
@@ -7057,9 +7077,9 @@ function ModelOption({
7057
7077
  title: isLocked ? "Add credits to unlock" : void 0,
7058
7078
  type: "button"
7059
7079
  },
7060
- /* @__PURE__ */ import_react32.default.createElement("img", { alt: "", className: "brokr-model-logo", src: provider.logo }),
7061
- /* @__PURE__ */ import_react32.default.createElement("span", { className: "brokr-model-option-label" }, provider.label),
7062
- isLocked ? /* @__PURE__ */ import_react32.default.createElement("span", { className: "brokr-model-lock", "aria-hidden": "true" }, /* @__PURE__ */ import_react32.default.createElement(LockIcon, { size: 13 })) : null
7080
+ /* @__PURE__ */ import_react33.default.createElement("img", { alt: "", className: "brokr-model-logo", src: provider.logo }),
7081
+ /* @__PURE__ */ import_react33.default.createElement("span", { className: "brokr-model-option-label" }, provider.label),
7082
+ isLocked ? /* @__PURE__ */ import_react33.default.createElement("span", { className: "brokr-model-lock", "aria-hidden": "true" }, /* @__PURE__ */ import_react33.default.createElement(LockIcon, { size: 13 })) : null
7063
7083
  );
7064
7084
  }
7065
7085
  function ModelSelector({
@@ -7068,22 +7088,22 @@ function ModelSelector({
7068
7088
  availableProviders,
7069
7089
  checkout
7070
7090
  }) {
7071
- const [selectorOpen, setSelectorOpen] = (0, import_react32.useState)(false);
7072
- const selectorRef = (0, import_react32.useRef)(null);
7091
+ const [selectorOpen, setSelectorOpen] = (0, import_react33.useState)(false);
7092
+ const selectorRef = (0, import_react33.useRef)(null);
7073
7093
  const isAuto = activeModel === STACK_DEFAULT || !providers.some((p) => p.model === activeModel);
7074
- const activeProvider = (0, import_react32.useMemo)(
7094
+ const activeProvider = (0, import_react33.useMemo)(
7075
7095
  () => isAuto ? void 0 : providers.find((p) => p.model === activeModel) ?? providers[0],
7076
7096
  [activeModel, isAuto]
7077
7097
  );
7078
- const handleModelSelect = (0, import_react32.useCallback)((model) => {
7098
+ const handleModelSelect = (0, import_react33.useCallback)((model) => {
7079
7099
  setSelectedModel(model === STACK_DEFAULT ? null : model);
7080
7100
  setSelectorOpen(false);
7081
7101
  }, [setSelectedModel]);
7082
- const handleAutoSelect = (0, import_react32.useCallback)(() => {
7102
+ const handleAutoSelect = (0, import_react33.useCallback)(() => {
7083
7103
  setSelectedModel(null);
7084
7104
  setSelectorOpen(false);
7085
7105
  }, [setSelectedModel]);
7086
- (0, import_react32.useEffect)(() => {
7106
+ (0, import_react33.useEffect)(() => {
7087
7107
  if (!selectorOpen) return;
7088
7108
  const onMouseDown = (e) => {
7089
7109
  if (!selectorRef.current?.contains(e.target)) setSelectorOpen(false);
@@ -7098,10 +7118,10 @@ function ModelSelector({
7098
7118
  document.removeEventListener("keydown", onKeyDown);
7099
7119
  };
7100
7120
  }, [selectorOpen]);
7101
- const handleToggle = (0, import_react32.useCallback)(() => {
7121
+ const handleToggle = (0, import_react33.useCallback)(() => {
7102
7122
  setSelectorOpen((v) => !v);
7103
7123
  }, []);
7104
- return /* @__PURE__ */ import_react32.default.createElement("div", { className: "brokr-model-selector", ref: selectorRef }, /* @__PURE__ */ import_react32.default.createElement(
7124
+ return /* @__PURE__ */ import_react33.default.createElement("div", { className: "brokr-model-selector", ref: selectorRef }, /* @__PURE__ */ import_react33.default.createElement(
7105
7125
  "button",
7106
7126
  {
7107
7127
  "aria-expanded": selectorOpen,
@@ -7110,10 +7130,10 @@ function ModelSelector({
7110
7130
  onClick: handleToggle,
7111
7131
  type: "button"
7112
7132
  },
7113
- activeProvider ? /* @__PURE__ */ import_react32.default.createElement("img", { alt: "", className: "brokr-model-logo", src: activeProvider.logo }) : /* @__PURE__ */ import_react32.default.createElement("span", { className: "brokr-model-dot", style: { background: "#6B7280" } }),
7133
+ activeProvider ? /* @__PURE__ */ import_react33.default.createElement("img", { alt: "", className: "brokr-model-logo", src: activeProvider.logo }) : /* @__PURE__ */ import_react33.default.createElement("span", { className: "brokr-model-dot", style: { background: "#6B7280" } }),
7114
7134
  isAuto ? "Auto" : activeProvider?.label ?? "Model",
7115
- /* @__PURE__ */ import_react32.default.createElement(ChevronDownIcon, { size: 13 })
7116
- ), selectorOpen ? /* @__PURE__ */ import_react32.default.createElement("div", { className: "brokr-model-dropdown", role: "listbox" }, /* @__PURE__ */ import_react32.default.createElement(
7135
+ /* @__PURE__ */ import_react33.default.createElement(ChevronDownIcon, { size: 13 })
7136
+ ), selectorOpen ? /* @__PURE__ */ import_react33.default.createElement("div", { className: "brokr-model-dropdown", role: "listbox" }, /* @__PURE__ */ import_react33.default.createElement(
7117
7137
  "button",
7118
7138
  {
7119
7139
  "aria-selected": isAuto,
@@ -7122,9 +7142,9 @@ function ModelSelector({
7122
7142
  onClick: handleAutoSelect,
7123
7143
  type: "button"
7124
7144
  },
7125
- /* @__PURE__ */ import_react32.default.createElement("span", { className: "brokr-model-dot", style: { background: "#6B7280" } }),
7126
- /* @__PURE__ */ import_react32.default.createElement("span", { className: "brokr-model-option-label" }, "Stack Default")
7127
- ), providers.map((p) => /* @__PURE__ */ import_react32.default.createElement(
7145
+ /* @__PURE__ */ import_react33.default.createElement("span", { className: "brokr-model-dot", style: { background: "#6B7280" } }),
7146
+ /* @__PURE__ */ import_react33.default.createElement("span", { className: "brokr-model-option-label" }, "Stack Default")
7147
+ ), providers.map((p) => /* @__PURE__ */ import_react33.default.createElement(
7128
7148
  ModelOption,
7129
7149
  {
7130
7150
  key: p.id,
@@ -7138,10 +7158,10 @@ function ModelSelector({
7138
7158
  }
7139
7159
 
7140
7160
  // src/react/chat/ThreadSidebar.tsx
7141
- var import_react33 = __toESM(require("react"));
7161
+ var import_react34 = __toESM(require("react"));
7142
7162
  function ThreadItemButton({ id, title, isActive, onSelect }) {
7143
- const handleClick = (0, import_react33.useCallback)(() => onSelect(id), [id, onSelect]);
7144
- return /* @__PURE__ */ import_react33.default.createElement(
7163
+ const handleClick = (0, import_react34.useCallback)(() => onSelect(id), [id, onSelect]);
7164
+ return /* @__PURE__ */ import_react34.default.createElement(
7145
7165
  "button",
7146
7166
  {
7147
7167
  className: "brokr-ai-chat-conversation",
@@ -7149,8 +7169,8 @@ function ThreadItemButton({ id, title, isActive, onSelect }) {
7149
7169
  onClick: handleClick,
7150
7170
  type: "button"
7151
7171
  },
7152
- /* @__PURE__ */ import_react33.default.createElement(MessageIcon, { size: 12 }),
7153
- /* @__PURE__ */ import_react33.default.createElement("span", { className: "brokr-ai-chat-conversation-label" }, title)
7172
+ /* @__PURE__ */ import_react34.default.createElement(MessageIcon, { size: 12 }),
7173
+ /* @__PURE__ */ import_react34.default.createElement("span", { className: "brokr-ai-chat-conversation-label" }, title)
7154
7174
  );
7155
7175
  }
7156
7176
  var SIDEBAR_GROUP_ORDER = [
@@ -7196,11 +7216,11 @@ function ThreadSidebar() {
7196
7216
  activeId,
7197
7217
  selectThreadAndCloseSidebar
7198
7218
  } = useChatState();
7199
- const handleNewChat = (0, import_react33.useCallback)(() => {
7219
+ const handleNewChat = (0, import_react34.useCallback)(() => {
7200
7220
  startNewChat();
7201
7221
  closeSidebar();
7202
7222
  }, [startNewChat, closeSidebar]);
7203
- const handleRenameKeyDown = (0, import_react33.useCallback)((e) => {
7223
+ const handleRenameKeyDown = (0, import_react34.useCallback)((e) => {
7204
7224
  if (e.key === "Enter") {
7205
7225
  e.preventDefault();
7206
7226
  void submitRename();
@@ -7208,13 +7228,13 @@ function ThreadSidebar() {
7208
7228
  if (e.key === "Escape") {
7209
7229
  }
7210
7230
  }, [submitRename]);
7211
- const handleRenameBlur = (0, import_react33.useCallback)(() => {
7231
+ const handleRenameBlur = (0, import_react34.useCallback)(() => {
7212
7232
  void submitRename();
7213
7233
  }, [submitRename]);
7214
- const handleRenameChange = (0, import_react33.useCallback)((e) => {
7234
+ const handleRenameChange = (0, import_react34.useCallback)((e) => {
7215
7235
  setRenameValue(e.target.value);
7216
7236
  }, [setRenameValue]);
7217
- const groupedSidebarItems = (0, import_react33.useMemo)(() => {
7237
+ const groupedSidebarItems = (0, import_react34.useMemo)(() => {
7218
7238
  const grouped = /* @__PURE__ */ new Map();
7219
7239
  for (const item of displaySidebarItems) {
7220
7240
  const key = resolveSidebarDateGroup(item.updatedAt);
@@ -7231,14 +7251,14 @@ function ThreadSidebar() {
7231
7251
  items: grouped.get(key) ?? []
7232
7252
  })).filter((group) => group.items.length > 0);
7233
7253
  }, [displaySidebarItems]);
7234
- const content = (0, import_react33.useMemo)(() => {
7254
+ const content = (0, import_react34.useMemo)(() => {
7235
7255
  if (threadsLoading && displaySidebarItems.length === 0) {
7236
- return /* @__PURE__ */ import_react33.default.createElement("div", { className: "brokr-ai-chat-sidebar-skeleton" }, /* @__PURE__ */ import_react33.default.createElement(Skeleton, { width: "75%", height: 14, radius: 6 }), /* @__PURE__ */ import_react33.default.createElement(Skeleton, { width: "60%", height: 14, radius: 6 }), /* @__PURE__ */ import_react33.default.createElement(Skeleton, { width: "85%", height: 14, radius: 6 }));
7256
+ return /* @__PURE__ */ import_react34.default.createElement("div", { className: "brokr-ai-chat-sidebar-skeleton" }, /* @__PURE__ */ import_react34.default.createElement(Skeleton, { width: "75%", height: 14, radius: 6 }), /* @__PURE__ */ import_react34.default.createElement(Skeleton, { width: "60%", height: 14, radius: 6 }), /* @__PURE__ */ import_react34.default.createElement(Skeleton, { width: "85%", height: 14, radius: 6 }));
7237
7257
  }
7238
7258
  if (displaySidebarItems.length === 0) {
7239
- return /* @__PURE__ */ import_react33.default.createElement("div", { className: "brokr-ai-chat-sidebar-empty" }, /* @__PURE__ */ import_react33.default.createElement("p", { className: "brokr-ai-chat-sidebar-empty-text" }, "No conversations yet. Start one above."));
7259
+ return /* @__PURE__ */ import_react34.default.createElement("div", { className: "brokr-ai-chat-sidebar-empty" }, /* @__PURE__ */ import_react34.default.createElement("p", { className: "brokr-ai-chat-sidebar-empty-text" }, "No conversations yet. Start one above."));
7240
7260
  }
7241
- return /* @__PURE__ */ import_react33.default.createElement("div", { className: "brokr-ai-chat-sidebar-groups" }, groupedSidebarItems.map((group) => /* @__PURE__ */ import_react33.default.createElement("section", { className: "brokr-ai-chat-sidebar-group", key: group.key }, /* @__PURE__ */ import_react33.default.createElement("span", { className: "brokr-ai-chat-sidebar-kicker" }, group.label), /* @__PURE__ */ import_react33.default.createElement("div", { className: "brokr-ai-chat-conversations" }, group.items.map((item) => renamingId === item.id ? /* @__PURE__ */ import_react33.default.createElement(
7261
+ return /* @__PURE__ */ import_react34.default.createElement("div", { className: "brokr-ai-chat-sidebar-groups" }, groupedSidebarItems.map((group) => /* @__PURE__ */ import_react34.default.createElement("section", { className: "brokr-ai-chat-sidebar-group", key: group.key }, /* @__PURE__ */ import_react34.default.createElement("span", { className: "brokr-ai-chat-sidebar-kicker" }, group.label), /* @__PURE__ */ import_react34.default.createElement("div", { className: "brokr-ai-chat-conversations" }, group.items.map((item) => renamingId === item.id ? /* @__PURE__ */ import_react34.default.createElement(
7242
7262
  "input",
7243
7263
  {
7244
7264
  autoFocus: true,
@@ -7249,7 +7269,7 @@ function ThreadSidebar() {
7249
7269
  onKeyDown: handleRenameKeyDown,
7250
7270
  value: renameValue
7251
7271
  }
7252
- ) : /* @__PURE__ */ import_react33.default.createElement(
7272
+ ) : /* @__PURE__ */ import_react34.default.createElement(
7253
7273
  ThreadItemButton,
7254
7274
  {
7255
7275
  key: item.id,
@@ -7271,17 +7291,17 @@ function ThreadSidebar() {
7271
7291
  handleRenameChange,
7272
7292
  handleRenameKeyDown
7273
7293
  ]);
7274
- return /* @__PURE__ */ import_react33.default.createElement(import_react33.default.Fragment, null, /* @__PURE__ */ import_react33.default.createElement("button", { className: "brokr-ai-chat-sidebar-new-chat", onClick: handleNewChat, type: "button" }, /* @__PURE__ */ import_react33.default.createElement(MessageIcon, { size: 16 }), "New chat"), content);
7294
+ return /* @__PURE__ */ import_react34.default.createElement(import_react34.default.Fragment, null, /* @__PURE__ */ import_react34.default.createElement("button", { className: "brokr-ai-chat-sidebar-new-chat", onClick: handleNewChat, type: "button" }, /* @__PURE__ */ import_react34.default.createElement(MessageIcon, { size: 16 }), "New chat"), content);
7275
7295
  }
7276
7296
 
7277
7297
  // src/react/chat/MessagePane.tsx
7278
- var import_react36 = __toESM(require("react"));
7298
+ var import_react37 = __toESM(require("react"));
7279
7299
 
7280
7300
  // src/react/chat/MessageBubble.tsx
7281
- var import_react35 = __toESM(require("react"));
7301
+ var import_react36 = __toESM(require("react"));
7282
7302
 
7283
7303
  // src/react/chat/MarkdownRenderer.tsx
7284
- var import_react34 = __toESM(require("react"));
7304
+ var import_react35 = __toESM(require("react"));
7285
7305
  function parseInline(text) {
7286
7306
  const nodes = [];
7287
7307
  let remaining = text;
@@ -7289,25 +7309,25 @@ function parseInline(text) {
7289
7309
  while (remaining) {
7290
7310
  const codeMatch = remaining.match(/^`([^`]+)`/);
7291
7311
  if (codeMatch) {
7292
- nodes.push(/* @__PURE__ */ import_react34.default.createElement("code", { className: "brokr-md-inline-code", key: key++ }, codeMatch[1]));
7312
+ nodes.push(/* @__PURE__ */ import_react35.default.createElement("code", { className: "brokr-md-inline-code", key: key++ }, codeMatch[1]));
7293
7313
  remaining = remaining.slice(codeMatch[0].length);
7294
7314
  continue;
7295
7315
  }
7296
7316
  const boldMatch = remaining.match(/^\*\*(.+?)\*\*/);
7297
7317
  if (boldMatch) {
7298
- nodes.push(/* @__PURE__ */ import_react34.default.createElement("strong", { key: key++ }, boldMatch[1]));
7318
+ nodes.push(/* @__PURE__ */ import_react35.default.createElement("strong", { key: key++ }, boldMatch[1]));
7299
7319
  remaining = remaining.slice(boldMatch[0].length);
7300
7320
  continue;
7301
7321
  }
7302
7322
  const strikethroughMatch = remaining.match(/^~~(.+?)~~/);
7303
7323
  if (strikethroughMatch) {
7304
- nodes.push(/* @__PURE__ */ import_react34.default.createElement("del", { key: key++ }, strikethroughMatch[1]));
7324
+ nodes.push(/* @__PURE__ */ import_react35.default.createElement("del", { key: key++ }, strikethroughMatch[1]));
7305
7325
  remaining = remaining.slice(strikethroughMatch[0].length);
7306
7326
  continue;
7307
7327
  }
7308
7328
  const italicMatch = remaining.match(/^\*(.+?)\*/);
7309
7329
  if (italicMatch) {
7310
- nodes.push(/* @__PURE__ */ import_react34.default.createElement("em", { key: key++ }, italicMatch[1]));
7330
+ nodes.push(/* @__PURE__ */ import_react35.default.createElement("em", { key: key++ }, italicMatch[1]));
7311
7331
  remaining = remaining.slice(italicMatch[0].length);
7312
7332
  continue;
7313
7333
  }
@@ -7316,7 +7336,7 @@ function parseInline(text) {
7316
7336
  const rawHref = linkMatch[2];
7317
7337
  const isSafe = /^https?:\/\//i.test(rawHref) || /^mailto:/i.test(rawHref);
7318
7338
  nodes.push(
7319
- /* @__PURE__ */ import_react34.default.createElement("a", { className: "brokr-md-link", href: isSafe ? rawHref : "#", key: key++, rel: "noopener noreferrer", target: "_blank" }, linkMatch[1])
7339
+ /* @__PURE__ */ import_react35.default.createElement("a", { className: "brokr-md-link", href: isSafe ? rawHref : "#", key: key++, rel: "noopener noreferrer", target: "_blank" }, linkMatch[1])
7320
7340
  );
7321
7341
  remaining = remaining.slice(linkMatch[0].length);
7322
7342
  continue;
@@ -7337,10 +7357,10 @@ function parseInline(text) {
7337
7357
  return nodes;
7338
7358
  }
7339
7359
  function CodeBlock({ code, language }) {
7340
- const handleCopy = (0, import_react34.useCallback)(() => {
7360
+ const handleCopy = (0, import_react35.useCallback)(() => {
7341
7361
  void navigator.clipboard?.writeText(code);
7342
7362
  }, [code]);
7343
- return /* @__PURE__ */ import_react34.default.createElement("div", { className: "brokr-md-codeblock" }, /* @__PURE__ */ import_react34.default.createElement("div", { className: "brokr-md-codeblock-header" }, /* @__PURE__ */ import_react34.default.createElement("span", { className: "brokr-md-codeblock-lang" }, language || "code"), /* @__PURE__ */ import_react34.default.createElement(
7363
+ return /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-md-codeblock" }, /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-md-codeblock-header" }, /* @__PURE__ */ import_react35.default.createElement("span", { className: "brokr-md-codeblock-lang" }, language || "code"), /* @__PURE__ */ import_react35.default.createElement(
7344
7364
  "button",
7345
7365
  {
7346
7366
  "aria-label": "Copy code",
@@ -7348,9 +7368,9 @@ function CodeBlock({ code, language }) {
7348
7368
  onClick: handleCopy,
7349
7369
  type: "button"
7350
7370
  },
7351
- /* @__PURE__ */ import_react34.default.createElement(CopyIcon, { size: 13 }),
7371
+ /* @__PURE__ */ import_react35.default.createElement(CopyIcon, { size: 13 }),
7352
7372
  "Copy"
7353
- )), /* @__PURE__ */ import_react34.default.createElement("pre", { className: "brokr-md-codeblock-pre" }, /* @__PURE__ */ import_react34.default.createElement("code", null, code)));
7373
+ )), /* @__PURE__ */ import_react35.default.createElement("pre", { className: "brokr-md-codeblock-pre" }, /* @__PURE__ */ import_react35.default.createElement("code", null, code)));
7354
7374
  }
7355
7375
  function looksLikeTableSeparator(line) {
7356
7376
  const trimmed = line.trim();
@@ -7448,48 +7468,48 @@ function renderBlocks(blocks) {
7448
7468
  return blocks.map((block, idx) => {
7449
7469
  switch (block.type) {
7450
7470
  case "code":
7451
- return /* @__PURE__ */ import_react34.default.createElement(CodeBlock, { code: block.content, key: idx, language: block.language });
7471
+ return /* @__PURE__ */ import_react35.default.createElement(CodeBlock, { code: block.content, key: idx, language: block.language });
7452
7472
  case "divider":
7453
- return /* @__PURE__ */ import_react34.default.createElement("hr", { className: "brokr-md-divider", key: idx });
7473
+ return /* @__PURE__ */ import_react35.default.createElement("hr", { className: "brokr-md-divider", key: idx });
7454
7474
  case "heading": {
7455
7475
  const Tag = `h${Math.min(block.level ?? 3, 6)}`;
7456
- return /* @__PURE__ */ import_react34.default.createElement(Tag, { className: `brokr-md-heading brokr-md-h${block.level}`, key: idx }, parseInline(block.content));
7476
+ return /* @__PURE__ */ import_react35.default.createElement(Tag, { className: `brokr-md-heading brokr-md-h${block.level}`, key: idx }, parseInline(block.content));
7457
7477
  }
7458
7478
  case "list":
7459
7479
  if (block.ordered) {
7460
- return /* @__PURE__ */ import_react34.default.createElement("ol", { className: "brokr-md-list brokr-md-list-ordered", key: idx }, block.items?.map((item, li) => /* @__PURE__ */ import_react34.default.createElement("li", { key: li }, parseInline(item))));
7480
+ return /* @__PURE__ */ import_react35.default.createElement("ol", { className: "brokr-md-list brokr-md-list-ordered", key: idx }, block.items?.map((item, li) => /* @__PURE__ */ import_react35.default.createElement("li", { key: li }, parseInline(item))));
7461
7481
  }
7462
- return /* @__PURE__ */ import_react34.default.createElement("ul", { className: "brokr-md-list brokr-md-list-unordered", key: idx }, block.items?.map((item, li) => /* @__PURE__ */ import_react34.default.createElement("li", { key: li }, parseInline(item))));
7482
+ return /* @__PURE__ */ import_react35.default.createElement("ul", { className: "brokr-md-list brokr-md-list-unordered", key: idx }, block.items?.map((item, li) => /* @__PURE__ */ import_react35.default.createElement("li", { key: li }, parseInline(item))));
7463
7483
  case "quote":
7464
- return /* @__PURE__ */ import_react34.default.createElement("blockquote", { className: "brokr-md-quote", key: idx }, block.items?.map((line, lineIndex) => /* @__PURE__ */ import_react34.default.createElement("p", { className: "brokr-md-quote-line", key: lineIndex }, parseInline(line))));
7484
+ return /* @__PURE__ */ import_react35.default.createElement("blockquote", { className: "brokr-md-quote", key: idx }, block.items?.map((line, lineIndex) => /* @__PURE__ */ import_react35.default.createElement("p", { className: "brokr-md-quote-line", key: lineIndex }, parseInline(line))));
7465
7485
  case "table":
7466
- return /* @__PURE__ */ import_react34.default.createElement("div", { className: "brokr-md-table-wrap", key: idx }, /* @__PURE__ */ import_react34.default.createElement("table", { className: "brokr-md-table" }, /* @__PURE__ */ import_react34.default.createElement("thead", null, /* @__PURE__ */ import_react34.default.createElement("tr", null, block.headers?.map((header, headerIndex) => /* @__PURE__ */ import_react34.default.createElement("th", { key: headerIndex }, parseInline(header))))), /* @__PURE__ */ import_react34.default.createElement("tbody", null, block.rows?.map((row, rowIndex) => /* @__PURE__ */ import_react34.default.createElement("tr", { key: rowIndex }, row.map((cell, cellIndex) => /* @__PURE__ */ import_react34.default.createElement("td", { key: cellIndex }, parseInline(cell))))))));
7486
+ return /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-md-table-wrap", key: idx }, /* @__PURE__ */ import_react35.default.createElement("table", { className: "brokr-md-table" }, /* @__PURE__ */ import_react35.default.createElement("thead", null, /* @__PURE__ */ import_react35.default.createElement("tr", null, block.headers?.map((header, headerIndex) => /* @__PURE__ */ import_react35.default.createElement("th", { key: headerIndex }, parseInline(header))))), /* @__PURE__ */ import_react35.default.createElement("tbody", null, block.rows?.map((row, rowIndex) => /* @__PURE__ */ import_react35.default.createElement("tr", { key: rowIndex }, row.map((cell, cellIndex) => /* @__PURE__ */ import_react35.default.createElement("td", { key: cellIndex }, parseInline(cell))))))));
7467
7487
  case "paragraph":
7468
7488
  default:
7469
- return /* @__PURE__ */ import_react34.default.createElement("p", { className: "brokr-md-paragraph", key: idx }, parseInline(block.content));
7489
+ return /* @__PURE__ */ import_react35.default.createElement("p", { className: "brokr-md-paragraph", key: idx }, parseInline(block.content));
7470
7490
  }
7471
7491
  });
7472
7492
  }
7473
7493
  function MarkdownRenderer({ content }) {
7474
- const rendered = (0, import_react34.useMemo)(() => {
7494
+ const rendered = (0, import_react35.useMemo)(() => {
7475
7495
  if (!content) return null;
7476
7496
  const blocks = parseBlocks(content);
7477
7497
  return renderBlocks(blocks);
7478
7498
  }, [content]);
7479
- return /* @__PURE__ */ import_react34.default.createElement("div", { className: "brokr-md" }, rendered);
7499
+ return /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-md" }, rendered);
7480
7500
  }
7481
7501
 
7482
7502
  // src/react/chat/MessageBubble.tsx
7483
7503
  function MessageBubble({ message, isTyping, user }) {
7484
- const handleCopy = (0, import_react35.useCallback)(() => {
7504
+ const handleCopy = (0, import_react36.useCallback)(() => {
7485
7505
  navigator.clipboard.writeText(message.content).catch(() => {
7486
7506
  });
7487
7507
  }, [message.content]);
7488
7508
  if (message.role === "user") {
7489
- return /* @__PURE__ */ import_react35.default.createElement("article", { className: "brokr-ai-chat-message", "data-role": "user" }, /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-ai-chat-message-row", "data-role": "user" }, /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-ai-chat-message-bubble" }, /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-ai-chat-message-content brokr-ai-chat-message-content-user" }, message.content)), /* @__PURE__ */ import_react35.default.createElement(Avatar, { email: user?.email, name: user?.name, src: user?.image })));
7509
+ return /* @__PURE__ */ import_react36.default.createElement("article", { className: "brokr-ai-chat-message", "data-role": "user" }, /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-message-row", "data-role": "user" }, /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-message-bubble" }, /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-message-content brokr-ai-chat-message-content-user" }, message.content)), /* @__PURE__ */ import_react36.default.createElement(Avatar, { email: user?.email, name: user?.name, src: user?.image })));
7490
7510
  }
7491
7511
  const mp = message.model ? resolveProviderByModel(message.model) : null;
7492
- return /* @__PURE__ */ import_react35.default.createElement("article", { className: "brokr-ai-chat-message", "data-role": "assistant" }, /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-ai-chat-message-row", "data-role": "assistant" }, mp ? /* @__PURE__ */ import_react35.default.createElement("img", { alt: mp.label, className: "brokr-ai-chat-model-avatar", src: mp.logo }) : null, isTyping ? /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-ai-chat-typing", "aria-label": "AI is typing" }, /* @__PURE__ */ import_react35.default.createElement("span", null), /* @__PURE__ */ import_react35.default.createElement("span", null), /* @__PURE__ */ import_react35.default.createElement("span", null)) : message.status === "error" && !message.content ? /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-ai-chat-message-wrap" }, /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-ai-chat-message-error" }, "Something went wrong generating a reply.")) : /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-ai-chat-message-wrap" }, /* @__PURE__ */ import_react35.default.createElement("div", { className: "brokr-ai-chat-message-content" }, /* @__PURE__ */ import_react35.default.createElement(MarkdownRenderer, { content: message.content })), message.content ? /* @__PURE__ */ import_react35.default.createElement(
7512
+ return /* @__PURE__ */ import_react36.default.createElement("article", { className: "brokr-ai-chat-message", "data-role": "assistant" }, /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-message-row", "data-role": "assistant" }, mp ? /* @__PURE__ */ import_react36.default.createElement("img", { alt: mp.label, className: "brokr-ai-chat-model-avatar", src: mp.logo }) : null, isTyping ? /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-typing", "aria-label": "AI is typing" }, /* @__PURE__ */ import_react36.default.createElement("span", null), /* @__PURE__ */ import_react36.default.createElement("span", null), /* @__PURE__ */ import_react36.default.createElement("span", null)) : message.status === "error" && !message.content ? /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-message-wrap" }, /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-message-error" }, "Something went wrong generating a reply.")) : /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-message-wrap" }, /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-message-content" }, /* @__PURE__ */ import_react36.default.createElement(MarkdownRenderer, { content: message.content })), message.content ? /* @__PURE__ */ import_react36.default.createElement(
7493
7513
  "button",
7494
7514
  {
7495
7515
  "aria-label": "Copy message",
@@ -7497,16 +7517,16 @@ function MessageBubble({ message, isTyping, user }) {
7497
7517
  onClick: handleCopy,
7498
7518
  type: "button"
7499
7519
  },
7500
- /* @__PURE__ */ import_react35.default.createElement(CopyIcon, { size: 13 })
7520
+ /* @__PURE__ */ import_react36.default.createElement(CopyIcon, { size: 13 })
7501
7521
  ) : null)));
7502
7522
  }
7503
7523
 
7504
7524
  // src/react/chat/MessagePane.tsx
7505
7525
  function StarterPromptButton({ prompt, onSend }) {
7506
- const handleClick = (0, import_react36.useCallback)(() => {
7526
+ const handleClick = (0, import_react37.useCallback)(() => {
7507
7527
  void onSend(prompt);
7508
7528
  }, [prompt, onSend]);
7509
- return /* @__PURE__ */ import_react36.default.createElement("button", { className: "brokr-ai-chat-starter", onClick: handleClick, type: "button" }, prompt);
7529
+ return /* @__PURE__ */ import_react37.default.createElement("button", { className: "brokr-ai-chat-starter", onClick: handleClick, type: "button" }, prompt);
7510
7530
  }
7511
7531
  function MessagePane({ starterPrompts, emptyTitle, emptyCopy, subtitle }) {
7512
7532
  const {
@@ -7524,10 +7544,10 @@ function MessagePane({ starterPrompts, emptyTitle, emptyCopy, subtitle }) {
7524
7544
  user
7525
7545
  } = useChatState();
7526
7546
  const isEmpty = displayMessages.length === 0;
7527
- const messageElements = (0, import_react36.useMemo)(() => {
7547
+ const messageElements = (0, import_react37.useMemo)(() => {
7528
7548
  return visibleMessages.map((message, index) => {
7529
7549
  const isTyping = message.role === "assistant" && !message.content && (isSubmitting && index === visibleMessages.length - 1 || message.status === "pending" || message.status === "streaming");
7530
- return /* @__PURE__ */ import_react36.default.createElement(
7550
+ return /* @__PURE__ */ import_react37.default.createElement(
7531
7551
  MessageBubble,
7532
7552
  {
7533
7553
  isTyping,
@@ -7538,16 +7558,16 @@ function MessagePane({ starterPrompts, emptyTitle, emptyCopy, subtitle }) {
7538
7558
  );
7539
7559
  });
7540
7560
  }, [visibleMessages, isSubmitting, user]);
7541
- return /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-thread", "data-empty": isEmpty, ref: scrollContainerRef }, isEmpty ? /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-empty" }, /* @__PURE__ */ import_react36.default.createElement(SparkIcon, { size: 28 }), /* @__PURE__ */ import_react36.default.createElement("h2", { className: "brokr-title" }, emptyTitle), subtitle ?? emptyCopy ? /* @__PURE__ */ import_react36.default.createElement("p", { className: "brokr-copy" }, subtitle ?? emptyCopy) : null, starterPrompts.length > 0 ? /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-starters" }, starterPrompts.map((sp) => /* @__PURE__ */ import_react36.default.createElement(StarterPromptButton, { key: sp, prompt: sp, onSend: sendMessage }))) : null) : /* @__PURE__ */ import_react36.default.createElement("div", { className: "brokr-ai-chat-thread-inner" }, (isPersist ? hasMoreMessages : memHasMore) ? /* @__PURE__ */ import_react36.default.createElement("div", { ref: sentinelRef, className: "brokr-ai-chat-sentinel" }, loadingOlder ? /* @__PURE__ */ import_react36.default.createElement("div", { style: { display: "flex", justifyContent: "center", padding: "0.5rem" } }, /* @__PURE__ */ import_react36.default.createElement(Skeleton, { width: 120, height: 12, radius: 6 })) : null) : null, messageElements, /* @__PURE__ */ import_react36.default.createElement("div", { ref: bottomRef })));
7561
+ return /* @__PURE__ */ import_react37.default.createElement("div", { className: "brokr-ai-chat-thread", "data-empty": isEmpty, ref: scrollContainerRef }, isEmpty ? /* @__PURE__ */ import_react37.default.createElement("div", { className: "brokr-ai-chat-empty" }, /* @__PURE__ */ import_react37.default.createElement(SparkIcon, { size: 28 }), /* @__PURE__ */ import_react37.default.createElement("h2", { className: "brokr-title" }, emptyTitle), subtitle ?? emptyCopy ? /* @__PURE__ */ import_react37.default.createElement("p", { className: "brokr-copy" }, subtitle ?? emptyCopy) : null, starterPrompts.length > 0 ? /* @__PURE__ */ import_react37.default.createElement("div", { className: "brokr-ai-chat-starters" }, starterPrompts.map((sp) => /* @__PURE__ */ import_react37.default.createElement(StarterPromptButton, { key: sp, prompt: sp, onSend: sendMessage }))) : null) : /* @__PURE__ */ import_react37.default.createElement("div", { className: "brokr-ai-chat-thread-inner" }, (isPersist ? hasMoreMessages : memHasMore) ? /* @__PURE__ */ import_react37.default.createElement("div", { ref: sentinelRef, className: "brokr-ai-chat-sentinel" }, loadingOlder ? /* @__PURE__ */ import_react37.default.createElement("div", { style: { display: "flex", justifyContent: "center", padding: "0.5rem" } }, /* @__PURE__ */ import_react37.default.createElement(Skeleton, { width: 120, height: 12, radius: 6 })) : null) : null, messageElements, /* @__PURE__ */ import_react37.default.createElement("div", { ref: bottomRef })));
7542
7562
  }
7543
7563
 
7544
7564
  // src/react/chat/ChatInput.tsx
7545
- var import_react37 = __toESM(require("react"));
7565
+ var import_react38 = __toESM(require("react"));
7546
7566
  function CommandButton({ cmd, chatContext }) {
7547
- const handleClick = (0, import_react37.useCallback)(() => {
7567
+ const handleClick = (0, import_react38.useCallback)(() => {
7548
7568
  void cmd.run(chatContext);
7549
7569
  }, [cmd, chatContext]);
7550
- return /* @__PURE__ */ import_react37.default.createElement("button", { className: "brokr-ai-chat-sidebar-button", key: cmd.id, onClick: handleClick, type: "button" }, cmd.text);
7570
+ return /* @__PURE__ */ import_react38.default.createElement("button", { className: "brokr-ai-chat-sidebar-button", key: cmd.id, onClick: handleClick, type: "button" }, cmd.text);
7551
7571
  }
7552
7572
  function ChatInput() {
7553
7573
  const {
@@ -7560,26 +7580,26 @@ function ChatInput() {
7560
7580
  composerCommands,
7561
7581
  chatContext
7562
7582
  } = useChatState();
7563
- (0, import_react37.useEffect)(() => {
7583
+ (0, import_react38.useEffect)(() => {
7564
7584
  const el = textareaRef.current;
7565
7585
  if (!el) return;
7566
7586
  el.style.height = "auto";
7567
7587
  el.style.height = `${Math.min(el.scrollHeight, 168)}px`;
7568
7588
  }, [input, textareaRef]);
7569
- const handleSubmit = (0, import_react37.useCallback)((e) => {
7589
+ const handleSubmit = (0, import_react38.useCallback)((e) => {
7570
7590
  e.preventDefault();
7571
7591
  void sendMessage();
7572
7592
  }, [sendMessage]);
7573
- const handleKeyDown = (0, import_react37.useCallback)((e) => {
7593
+ const handleKeyDown = (0, import_react38.useCallback)((e) => {
7574
7594
  if (e.key === "Enter" && !e.shiftKey) {
7575
7595
  e.preventDefault();
7576
7596
  void sendMessage();
7577
7597
  }
7578
7598
  }, [sendMessage]);
7579
- const handleChange = (0, import_react37.useCallback)((e) => {
7599
+ const handleChange = (0, import_react38.useCallback)((e) => {
7580
7600
  setInput(e.target.value);
7581
7601
  }, [setInput]);
7582
- return /* @__PURE__ */ import_react37.default.createElement("form", { className: "brokr-ai-chat-input-area", onSubmit: handleSubmit }, /* @__PURE__ */ import_react37.default.createElement("div", { className: "brokr-ai-chat-input-container" }, composerCommands.length > 0 ? /* @__PURE__ */ import_react37.default.createElement("div", { className: "brokr-ai-chat-composer-actions" }, composerCommands.map((cmd) => /* @__PURE__ */ import_react37.default.createElement(CommandButton, { key: cmd.id, cmd, chatContext }))) : null, /* @__PURE__ */ import_react37.default.createElement("div", { className: "brokr-ai-chat-input-row" }, /* @__PURE__ */ import_react37.default.createElement(
7602
+ return /* @__PURE__ */ import_react38.default.createElement("form", { className: "brokr-ai-chat-input-area", onSubmit: handleSubmit }, /* @__PURE__ */ import_react38.default.createElement("div", { className: "brokr-ai-chat-input-container" }, composerCommands.length > 0 ? /* @__PURE__ */ import_react38.default.createElement("div", { className: "brokr-ai-chat-composer-actions" }, composerCommands.map((cmd) => /* @__PURE__ */ import_react38.default.createElement(CommandButton, { key: cmd.id, cmd, chatContext }))) : null, /* @__PURE__ */ import_react38.default.createElement("div", { className: "brokr-ai-chat-input-row" }, /* @__PURE__ */ import_react38.default.createElement(
7583
7603
  "textarea",
7584
7604
  {
7585
7605
  className: "brokr-ai-chat-textarea",
@@ -7590,15 +7610,15 @@ function ChatInput() {
7590
7610
  rows: 1,
7591
7611
  value: input
7592
7612
  }
7593
- ), /* @__PURE__ */ import_react37.default.createElement(
7613
+ ), /* @__PURE__ */ import_react38.default.createElement(
7594
7614
  "button",
7595
7615
  {
7596
7616
  className: "brokr-ai-chat-send",
7597
7617
  disabled: isSubmitting || !input.trim(),
7598
7618
  type: "submit"
7599
7619
  },
7600
- isSubmitting ? /* @__PURE__ */ import_react37.default.createElement(SparkIcon, { size: 16 }) : /* @__PURE__ */ import_react37.default.createElement(ArrowRightIcon, { size: 16 })
7601
- ))), error ? /* @__PURE__ */ import_react37.default.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null);
7620
+ isSubmitting ? /* @__PURE__ */ import_react38.default.createElement(SparkIcon, { size: 16 }) : /* @__PURE__ */ import_react38.default.createElement(ArrowRightIcon, { size: 16 })
7621
+ ))), error ? /* @__PURE__ */ import_react38.default.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null);
7602
7622
  }
7603
7623
 
7604
7624
  // src/react/chat/AIChat.tsx
@@ -7644,19 +7664,19 @@ function AIChat(inlineProps) {
7644
7664
  const headerVisible = variant !== 3;
7645
7665
  const threadMenuVisible = threadMenuProp !== void 0 ? threadMenuProp : variant !== 3;
7646
7666
  const modelSelectorVisible = (modelSelector !== void 0 ? modelSelector : true) && !modelProp;
7647
- const [userSelectedModel, setUserSelectedModel] = (0, import_react38.useState)(null);
7667
+ const [userSelectedModel, setUserSelectedModel] = (0, import_react39.useState)(null);
7648
7668
  const explicitModel = modelProp ?? userSelectedModel ?? void 0;
7649
7669
  const displayModel = explicitModel ?? providers.find((p) => p.free)?.model ?? providers[0]?.model ?? "";
7650
7670
  const activeModel = explicitModel ?? STACK_DEFAULT;
7651
- const activeProvider = (0, import_react38.useMemo)(
7671
+ const activeProvider = (0, import_react39.useMemo)(
7652
7672
  () => activeModel === STACK_DEFAULT ? void 0 : providers.find((p) => p.model === activeModel) ?? providers[0],
7653
7673
  [activeModel]
7654
7674
  );
7655
- const hasBalance = (0, import_react38.useMemo)(
7675
+ const hasBalance = (0, import_react39.useMemo)(
7656
7676
  () => billing === null || billing.balanceCents === null || billing.balanceCents > 0 || billing.hasPaymentMethod,
7657
7677
  [billing]
7658
7678
  );
7659
- const availableProviders = (0, import_react38.useMemo)(
7679
+ const availableProviders = (0, import_react39.useMemo)(
7660
7680
  () => hasBalance ? providers : providers.filter((p) => p.free),
7661
7681
  [hasBalance]
7662
7682
  );
@@ -7682,8 +7702,8 @@ function AIChat(inlineProps) {
7682
7702
  onThreadChange,
7683
7703
  userId: user?.id
7684
7704
  });
7685
- const shellRef = (0, import_react38.useRef)(null);
7686
- (0, import_react38.useEffect)(() => {
7705
+ const shellRef = (0, import_react39.useRef)(null);
7706
+ (0, import_react39.useEffect)(() => {
7687
7707
  const el = shellRef.current;
7688
7708
  if (!el) return;
7689
7709
  let raf = 0;
@@ -7709,23 +7729,23 @@ function AIChat(inlineProps) {
7709
7729
  ro?.disconnect();
7710
7730
  };
7711
7731
  }, []);
7712
- const [sidebarOpen, setSidebarOpen] = (0, import_react38.useState)(false);
7713
- const [threadMenuOpenId, setThreadMenuOpenId] = (0, import_react38.useState)(null);
7714
- const threadMenuRef = (0, import_react38.useRef)(null);
7715
- const closeSidebar = (0, import_react38.useCallback)(() => setSidebarOpen(false), []);
7716
- const selectThreadAndCloseSidebar = (0, import_react38.useCallback)((id) => {
7732
+ const [sidebarOpen, setSidebarOpen] = (0, import_react39.useState)(false);
7733
+ const [threadMenuOpenId, setThreadMenuOpenId] = (0, import_react39.useState)(null);
7734
+ const threadMenuRef = (0, import_react39.useRef)(null);
7735
+ const closeSidebar = (0, import_react39.useCallback)(() => setSidebarOpen(false), []);
7736
+ const selectThreadAndCloseSidebar = (0, import_react39.useCallback)((id) => {
7717
7737
  chat.selectThread(id);
7718
7738
  setSidebarOpen(false);
7719
7739
  }, [chat.selectThread]);
7720
- const handleCopy = (0, import_react38.useCallback)((content) => {
7740
+ const handleCopy = (0, import_react39.useCallback)((content) => {
7721
7741
  navigator.clipboard.writeText(content).catch(() => {
7722
7742
  });
7723
7743
  }, []);
7724
- const handleStartRename = (0, import_react38.useCallback)((threadId) => {
7744
+ const handleStartRename = (0, import_react39.useCallback)((threadId) => {
7725
7745
  setThreadMenuOpenId(null);
7726
7746
  chat.startRename(threadId);
7727
7747
  }, [chat.startRename]);
7728
- (0, import_react38.useEffect)(() => {
7748
+ (0, import_react39.useEffect)(() => {
7729
7749
  if (!threadMenuOpenId) return;
7730
7750
  const onMouseDown = (e) => {
7731
7751
  if (!threadMenuRef.current?.contains(e.target)) setThreadMenuOpenId(null);
@@ -7733,7 +7753,7 @@ function AIChat(inlineProps) {
7733
7753
  document.addEventListener("mousedown", onMouseDown);
7734
7754
  return () => document.removeEventListener("mousedown", onMouseDown);
7735
7755
  }, [threadMenuOpenId]);
7736
- (0, import_react38.useEffect)(() => {
7756
+ (0, import_react39.useEffect)(() => {
7737
7757
  if (!sidebarOpen) return;
7738
7758
  const onKeyDown = (e) => {
7739
7759
  if (e.key === "Escape") setSidebarOpen(false);
@@ -7741,10 +7761,10 @@ function AIChat(inlineProps) {
7741
7761
  document.addEventListener("keydown", onKeyDown);
7742
7762
  return () => document.removeEventListener("keydown", onKeyDown);
7743
7763
  }, [sidebarOpen]);
7744
- const finalTitle = (0, import_react38.useMemo)(() => {
7764
+ const finalTitle = (0, import_react39.useMemo)(() => {
7745
7765
  return chat.renderedTitle || title;
7746
7766
  }, [chat.renderedTitle, title]);
7747
- const chatContext = (0, import_react38.useMemo)(() => ({
7767
+ const chatContext = (0, import_react39.useMemo)(() => ({
7748
7768
  thread: chat.activeThread,
7749
7769
  messages: chat.displayMessages,
7750
7770
  user,
@@ -7752,19 +7772,19 @@ function AIChat(inlineProps) {
7752
7772
  newThread: chat.startNewChat,
7753
7773
  setThread: chat.selectThread
7754
7774
  }), [chat.activeThread, chat.displayMessages, user, chat.sendMessage, chat.startNewChat, chat.selectThread]);
7755
- const headerCommands = (0, import_react38.useMemo)(
7775
+ const headerCommands = (0, import_react39.useMemo)(
7756
7776
  () => commands.filter((c) => c.location === "header" && (!c.show || c.show(chatContext))),
7757
7777
  [commands, chatContext]
7758
7778
  );
7759
- const composerCommands = (0, import_react38.useMemo)(
7779
+ const composerCommands = (0, import_react39.useMemo)(
7760
7780
  () => commands.filter((c) => c.location === "composer" && (!c.show || c.show(chatContext))),
7761
7781
  [commands, chatContext]
7762
7782
  );
7763
- const threadMenuCommands = (0, import_react38.useMemo)(
7783
+ const threadMenuCommands = (0, import_react39.useMemo)(
7764
7784
  () => commands.filter((c) => c.location === "threadMenu" && (!c.show || c.show(chatContext))),
7765
7785
  [commands, chatContext]
7766
7786
  );
7767
- const chatState = (0, import_react38.useMemo)(() => ({
7787
+ const chatState = (0, import_react39.useMemo)(() => ({
7768
7788
  displayMessages: chat.displayMessages,
7769
7789
  visibleMessages: chat.displayMessages,
7770
7790
  isSubmitting: chat.isSubmitting,
@@ -7831,16 +7851,16 @@ function AIChat(inlineProps) {
7831
7851
  checkout,
7832
7852
  user
7833
7853
  ]);
7834
- return /* @__PURE__ */ import_react38.default.createElement(ChatProvider, { value: chatState }, /* @__PURE__ */ import_react38.default.createElement(
7854
+ return /* @__PURE__ */ import_react39.default.createElement(ChatProvider, { value: chatState }, /* @__PURE__ */ import_react39.default.createElement(
7835
7855
  "section",
7836
7856
  {
7837
7857
  className: "brokr-ai-chat-shell",
7838
7858
  "data-sidebar": sidebarVisible,
7839
7859
  ref: shellRef
7840
7860
  },
7841
- sidebarVisible ? /* @__PURE__ */ import_react38.default.createElement("aside", { className: "brokr-ai-chat-sidebar brokr-ai-chat-sidebar-desktop" }, /* @__PURE__ */ import_react38.default.createElement(ThreadSidebar, null)) : null,
7842
- sidebarOpen ? /* @__PURE__ */ import_react38.default.createElement(import_react38.default.Fragment, null, /* @__PURE__ */ import_react38.default.createElement("div", { className: "brokr-ai-chat-drawer-backdrop", onClick: closeSidebar }), /* @__PURE__ */ import_react38.default.createElement("aside", { className: "brokr-ai-chat-drawer" }, /* @__PURE__ */ import_react38.default.createElement(ThreadSidebar, null))) : null,
7843
- /* @__PURE__ */ import_react38.default.createElement("div", { className: "brokr-ai-chat-stage", "data-noheader": !headerVisible }, headerVisible ? /* @__PURE__ */ import_react38.default.createElement(
7861
+ sidebarVisible ? /* @__PURE__ */ import_react39.default.createElement("aside", { className: "brokr-ai-chat-sidebar brokr-ai-chat-sidebar-desktop" }, /* @__PURE__ */ import_react39.default.createElement(ThreadSidebar, null)) : null,
7862
+ sidebarOpen ? /* @__PURE__ */ import_react39.default.createElement(import_react39.default.Fragment, null, /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-ai-chat-drawer-backdrop", onClick: closeSidebar }), /* @__PURE__ */ import_react39.default.createElement("aside", { className: "brokr-ai-chat-drawer" }, /* @__PURE__ */ import_react39.default.createElement(ThreadSidebar, null))) : null,
7863
+ /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-ai-chat-stage", "data-noheader": !headerVisible }, headerVisible ? /* @__PURE__ */ import_react39.default.createElement(
7844
7864
  ChatHeader,
7845
7865
  {
7846
7866
  activeId: chat.activeId,
@@ -7861,7 +7881,7 @@ function AIChat(inlineProps) {
7861
7881
  startRename: chatState.startRename,
7862
7882
  deleteThread: chat.deleteThread
7863
7883
  }
7864
- ) : null, /* @__PURE__ */ import_react38.default.createElement(
7884
+ ) : null, /* @__PURE__ */ import_react39.default.createElement(
7865
7885
  MessagePane,
7866
7886
  {
7867
7887
  starterPrompts,
@@ -7869,21 +7889,21 @@ function AIChat(inlineProps) {
7869
7889
  emptyCopy,
7870
7890
  subtitle
7871
7891
  }
7872
- ), /* @__PURE__ */ import_react38.default.createElement(ChatInput, null))
7892
+ ), /* @__PURE__ */ import_react39.default.createElement(ChatInput, null))
7873
7893
  ));
7874
7894
  }
7875
7895
  function CommandButton2({ cmd, chatContext }) {
7876
- const handleClick = (0, import_react38.useCallback)(() => {
7896
+ const handleClick = (0, import_react39.useCallback)(() => {
7877
7897
  void cmd.run(chatContext);
7878
7898
  }, [cmd, chatContext]);
7879
- return /* @__PURE__ */ import_react38.default.createElement("button", { className: "brokr-ai-chat-sidebar-button", onClick: handleClick, type: "button" }, cmd.text);
7899
+ return /* @__PURE__ */ import_react39.default.createElement("button", { className: "brokr-ai-chat-sidebar-button", onClick: handleClick, type: "button" }, cmd.text);
7880
7900
  }
7881
7901
  function MenuCommandItem({ cmd, chatContext, onClose }) {
7882
- const handleClick = (0, import_react38.useCallback)(() => {
7902
+ const handleClick = (0, import_react39.useCallback)(() => {
7883
7903
  onClose();
7884
7904
  void cmd.run(chatContext);
7885
7905
  }, [cmd, chatContext, onClose]);
7886
- return /* @__PURE__ */ import_react38.default.createElement("button", { className: "brokr-ai-chat-thread-dropdown-item", onClick: handleClick, type: "button" }, cmd.text);
7906
+ return /* @__PURE__ */ import_react39.default.createElement("button", { className: "brokr-ai-chat-thread-dropdown-item", onClick: handleClick, type: "button" }, cmd.text);
7887
7907
  }
7888
7908
  function ChatHeader({
7889
7909
  activeId,
@@ -7904,21 +7924,21 @@ function ChatHeader({
7904
7924
  startRename,
7905
7925
  deleteThread
7906
7926
  }) {
7907
- const handleOpenSidebar = (0, import_react38.useCallback)(() => setSidebarOpen(true), [setSidebarOpen]);
7908
- const handleToggleMenu = (0, import_react38.useCallback)(() => {
7927
+ const handleOpenSidebar = (0, import_react39.useCallback)(() => setSidebarOpen(true), [setSidebarOpen]);
7928
+ const handleToggleMenu = (0, import_react39.useCallback)(() => {
7909
7929
  setThreadMenuOpenId(threadMenuOpenId ? null : activeId);
7910
7930
  }, [setThreadMenuOpenId, threadMenuOpenId, activeId]);
7911
- const closeMenu = (0, import_react38.useCallback)(() => setThreadMenuOpenId(null), [setThreadMenuOpenId]);
7912
- const handleRename = (0, import_react38.useCallback)(() => {
7931
+ const closeMenu = (0, import_react39.useCallback)(() => setThreadMenuOpenId(null), [setThreadMenuOpenId]);
7932
+ const handleRename = (0, import_react39.useCallback)(() => {
7913
7933
  if (activeId) startRename(activeId);
7914
7934
  }, [activeId, startRename]);
7915
- const handleDelete = (0, import_react38.useCallback)(() => {
7935
+ const handleDelete = (0, import_react39.useCallback)(() => {
7916
7936
  if (activeId) {
7917
7937
  setThreadMenuOpenId(null);
7918
7938
  void deleteThread(activeId);
7919
7939
  }
7920
7940
  }, [activeId, deleteThread, setThreadMenuOpenId]);
7921
- return /* @__PURE__ */ import_react38.default.createElement("header", { className: "brokr-ai-chat-topbar" }, /* @__PURE__ */ import_react38.default.createElement("div", { className: "brokr-ai-chat-topbar-left" }, sidebarVisible ? /* @__PURE__ */ import_react38.default.createElement(
7941
+ return /* @__PURE__ */ import_react39.default.createElement("header", { className: "brokr-ai-chat-topbar" }, /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-ai-chat-topbar-left" }, sidebarVisible ? /* @__PURE__ */ import_react39.default.createElement(
7922
7942
  "button",
7923
7943
  {
7924
7944
  "aria-label": "Open sidebar",
@@ -7926,8 +7946,8 @@ function ChatHeader({
7926
7946
  onClick: handleOpenSidebar,
7927
7947
  type: "button"
7928
7948
  },
7929
- /* @__PURE__ */ import_react38.default.createElement(MenuIcon, { size: 18 })
7930
- ) : null), /* @__PURE__ */ import_react38.default.createElement("div", { className: "brokr-ai-chat-topbar-actions" }, headerCommands.map((cmd) => /* @__PURE__ */ import_react38.default.createElement(CommandButton2, { key: cmd.id, cmd, chatContext })), modelSelectorVisible ? /* @__PURE__ */ import_react38.default.createElement(
7949
+ /* @__PURE__ */ import_react39.default.createElement(MenuIcon, { size: 18 })
7950
+ ) : null), /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-ai-chat-topbar-actions" }, headerCommands.map((cmd) => /* @__PURE__ */ import_react39.default.createElement(CommandButton2, { key: cmd.id, cmd, chatContext })), modelSelectorVisible ? /* @__PURE__ */ import_react39.default.createElement(
7931
7951
  ModelSelector,
7932
7952
  {
7933
7953
  activeModel,
@@ -7935,7 +7955,7 @@ function ChatHeader({
7935
7955
  checkout,
7936
7956
  setSelectedModel
7937
7957
  }
7938
- ) : null, activeId && threadMenuVisible ? /* @__PURE__ */ import_react38.default.createElement("div", { className: "brokr-ai-chat-thread-menu-wrap", ref: threadMenuRef }, /* @__PURE__ */ import_react38.default.createElement(
7958
+ ) : null, activeId && threadMenuVisible ? /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-ai-chat-thread-menu-wrap", ref: threadMenuRef }, /* @__PURE__ */ import_react39.default.createElement(
7939
7959
  "button",
7940
7960
  {
7941
7961
  "aria-label": "Thread actions",
@@ -7943,17 +7963,17 @@ function ChatHeader({
7943
7963
  onClick: handleToggleMenu,
7944
7964
  type: "button"
7945
7965
  },
7946
- /* @__PURE__ */ import_react38.default.createElement(MoreHorizontalIcon, { size: 14 })
7947
- ), threadMenuOpenId ? /* @__PURE__ */ import_react38.default.createElement("div", { className: "brokr-ai-chat-thread-dropdown" }, /* @__PURE__ */ import_react38.default.createElement(
7966
+ /* @__PURE__ */ import_react39.default.createElement(MoreHorizontalIcon, { size: 14 })
7967
+ ), threadMenuOpenId ? /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-ai-chat-thread-dropdown" }, /* @__PURE__ */ import_react39.default.createElement(
7948
7968
  "button",
7949
7969
  {
7950
7970
  className: "brokr-ai-chat-thread-dropdown-item",
7951
7971
  onClick: handleRename,
7952
7972
  type: "button"
7953
7973
  },
7954
- /* @__PURE__ */ import_react38.default.createElement(PencilIcon, { size: 13 }),
7974
+ /* @__PURE__ */ import_react39.default.createElement(PencilIcon, { size: 13 }),
7955
7975
  "Rename"
7956
- ), threadMenuCommands.map((cmd) => /* @__PURE__ */ import_react38.default.createElement(
7976
+ ), threadMenuCommands.map((cmd) => /* @__PURE__ */ import_react39.default.createElement(
7957
7977
  MenuCommandItem,
7958
7978
  {
7959
7979
  key: cmd.id,
@@ -7961,7 +7981,7 @@ function ChatHeader({
7961
7981
  chatContext,
7962
7982
  onClose: closeMenu
7963
7983
  }
7964
- )), /* @__PURE__ */ import_react38.default.createElement(
7984
+ )), /* @__PURE__ */ import_react39.default.createElement(
7965
7985
  "button",
7966
7986
  {
7967
7987
  className: "brokr-ai-chat-thread-dropdown-item",
@@ -7969,13 +7989,13 @@ function ChatHeader({
7969
7989
  onClick: handleDelete,
7970
7990
  type: "button"
7971
7991
  },
7972
- /* @__PURE__ */ import_react38.default.createElement(TrashIcon, { size: 13 }),
7992
+ /* @__PURE__ */ import_react39.default.createElement(TrashIcon, { size: 13 }),
7973
7993
  "Delete"
7974
7994
  )) : null) : null));
7975
7995
  }
7976
7996
 
7977
7997
  // src/react/composites/FabAI.tsx
7978
- var import_react39 = __toESM(require("react"));
7998
+ var import_react40 = __toESM(require("react"));
7979
7999
 
7980
8000
  // src/react/composites/fab-context.ts
7981
8001
  function buildFabSystemPrompt(appContext, brandName, existingPrompt) {
@@ -8026,34 +8046,34 @@ function FabAI({
8026
8046
  }) {
8027
8047
  const { can, user, theme } = useBrokr();
8028
8048
  const brandName = theme?.brand?.name;
8029
- const [isOpen, setIsOpen] = (0, import_react39.useState)(false);
8030
- const [input, setInput] = (0, import_react39.useState)("");
8031
- const [error, setError] = (0, import_react39.useState)(null);
8032
- const [isSending, setIsSending] = (0, import_react39.useState)(false);
8033
- const [messages, setMessages] = (0, import_react39.useState)([]);
8034
- const conversationIdRef = (0, import_react39.useRef)(`fab_${crypto.randomUUID()}`);
8035
- const launcherStyle = (0, import_react39.useMemo)(
8049
+ const [isOpen, setIsOpen] = (0, import_react40.useState)(false);
8050
+ const [input, setInput] = (0, import_react40.useState)("");
8051
+ const [error, setError] = (0, import_react40.useState)(null);
8052
+ const [isSending, setIsSending] = (0, import_react40.useState)(false);
8053
+ const [messages, setMessages] = (0, import_react40.useState)([]);
8054
+ const conversationIdRef = (0, import_react40.useRef)(`fab_${crypto.randomUUID()}`);
8055
+ const launcherStyle = (0, import_react40.useMemo)(
8036
8056
  () => ({
8037
8057
  left: position === "bottom-left" ? "var(--brokr-space-6)" : void 0,
8038
8058
  right: position === "bottom-right" ? "var(--brokr-space-6)" : void 0
8039
8059
  }),
8040
8060
  [position]
8041
8061
  );
8042
- const canChat = (0, import_react39.useMemo)(() => can("ai.chat"), [can]);
8043
- const toggleOpen = (0, import_react39.useCallback)(() => {
8062
+ const canChat = (0, import_react40.useMemo)(() => can("ai.chat"), [can]);
8063
+ const toggleOpen = (0, import_react40.useCallback)(() => {
8044
8064
  if (!canChat) {
8045
8065
  redirectTo("/pricing");
8046
8066
  return;
8047
8067
  }
8048
8068
  setIsOpen((current) => !current);
8049
8069
  }, [canChat]);
8050
- const handleInputChange = (0, import_react39.useCallback)((event) => {
8070
+ const handleInputChange = (0, import_react40.useCallback)((event) => {
8051
8071
  setInput(event.target.value);
8052
8072
  }, []);
8053
- const handleClose = (0, import_react39.useCallback)(() => {
8073
+ const handleClose = (0, import_react40.useCallback)(() => {
8054
8074
  setIsOpen(false);
8055
8075
  }, []);
8056
- const sendPrompt = (0, import_react39.useCallback)(async (prompt) => {
8076
+ const sendPrompt = (0, import_react40.useCallback)(async (prompt) => {
8057
8077
  const nextPrompt = prompt.trim();
8058
8078
  if (!nextPrompt || isSending) return;
8059
8079
  const userMessage = { role: "user", content: nextPrompt };
@@ -8124,17 +8144,17 @@ function FabAI({
8124
8144
  setIsSending(false);
8125
8145
  }
8126
8146
  }, [isSending, messages, model, onSendMessage, systemPrompt]);
8127
- const handleSubmit = (0, import_react39.useCallback)(async (event) => {
8147
+ const handleSubmit = (0, import_react40.useCallback)(async (event) => {
8128
8148
  event.preventDefault();
8129
8149
  await sendPrompt(input);
8130
8150
  }, [input, sendPrompt]);
8131
- const handleKeyDown = (0, import_react39.useCallback)((event) => {
8151
+ const handleKeyDown = (0, import_react40.useCallback)((event) => {
8132
8152
  if (event.key === "Enter" && !event.shiftKey) {
8133
8153
  event.preventDefault();
8134
8154
  void sendPrompt(input);
8135
8155
  }
8136
8156
  }, [input, sendPrompt]);
8137
- return /* @__PURE__ */ import_react39.default.createElement(import_react39.default.Fragment, null, /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-chat-fab", style: launcherStyle }, /* @__PURE__ */ import_react39.default.createElement(
8157
+ return /* @__PURE__ */ import_react40.default.createElement(import_react40.default.Fragment, null, /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-chat-fab", style: launcherStyle }, /* @__PURE__ */ import_react40.default.createElement(
8138
8158
  "button",
8139
8159
  {
8140
8160
  "aria-label": isOpen ? "Close AI chat" : "Open AI chat",
@@ -8144,21 +8164,21 @@ function FabAI({
8144
8164
  onClick: toggleOpen,
8145
8165
  type: "button"
8146
8166
  },
8147
- /* @__PURE__ */ import_react39.default.createElement(SparkIcon, { size: 18 })
8148
- )), isOpen ? /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-panel brokr-chat-panel", role: "dialog" }, /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ import_react39.default.createElement("strong", null, "AI Chat"), user?.name ? /* @__PURE__ */ import_react39.default.createElement("span", { className: "brokr-copy" }, user.name) : null), /* @__PURE__ */ import_react39.default.createElement("button", { className: "brokr-button-ghost", onClick: handleClose, type: "button" }, /* @__PURE__ */ import_react39.default.createElement(CloseIcon, { size: 16 }))), /* @__PURE__ */ import_react39.default.createElement(
8167
+ /* @__PURE__ */ import_react40.default.createElement(SparkIcon, { size: 18 })
8168
+ )), isOpen ? /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-panel brokr-chat-panel", role: "dialog" }, /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ import_react40.default.createElement("strong", null, "AI Chat"), user?.name ? /* @__PURE__ */ import_react40.default.createElement("span", { className: "brokr-copy" }, user.name) : null), /* @__PURE__ */ import_react40.default.createElement("button", { className: "brokr-button-ghost", onClick: handleClose, type: "button" }, /* @__PURE__ */ import_react40.default.createElement(CloseIcon, { size: 16 }))), /* @__PURE__ */ import_react40.default.createElement(
8149
8169
  "div",
8150
8170
  {
8151
8171
  className: "brokr-chat-messages",
8152
8172
  "data-empty": messages.length === 0
8153
8173
  },
8154
- messages.length === 0 ? /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-chat-empty" }, /* @__PURE__ */ import_react39.default.createElement(SparkIcon, { size: 18 }), /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ import_react39.default.createElement("strong", null, "Send a message to chat with the AI."), /* @__PURE__ */ import_react39.default.createElement("span", { className: "brokr-copy" }, "Ask a question or drop in a starter prompt below."))) : null,
8174
+ messages.length === 0 ? /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-chat-empty" }, /* @__PURE__ */ import_react40.default.createElement(SparkIcon, { size: 18 }), /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ import_react40.default.createElement("strong", null, "Send a message to chat with the AI."), /* @__PURE__ */ import_react40.default.createElement("span", { className: "brokr-copy" }, "Ask a question or drop in a starter prompt below."))) : null,
8155
8175
  messages.map((message, index) => {
8156
8176
  const text = contentToText(message.content);
8157
8177
  const isTyping = message.role === "assistant" && !text && isSending && index === messages.length - 1;
8158
- return /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-chat-bubble", "data-role": message.role, key: `${message.role}-${index}` }, isTyping ? /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-ai-chat-typing", "aria-label": "AI is typing" }, /* @__PURE__ */ import_react39.default.createElement("span", null), /* @__PURE__ */ import_react39.default.createElement("span", null), /* @__PURE__ */ import_react39.default.createElement("span", null)) : message.role === "assistant" ? /* @__PURE__ */ import_react39.default.createElement(MarkdownRenderer, { content: text }) : text);
8178
+ return /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-chat-bubble", "data-role": message.role, key: `${message.role}-${index}` }, isTyping ? /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-ai-chat-typing", "aria-label": "AI is typing" }, /* @__PURE__ */ import_react40.default.createElement("span", null), /* @__PURE__ */ import_react40.default.createElement("span", null), /* @__PURE__ */ import_react40.default.createElement("span", null)) : message.role === "assistant" ? /* @__PURE__ */ import_react40.default.createElement(MarkdownRenderer, { content: text }) : text);
8159
8179
  }),
8160
- error ? /* @__PURE__ */ import_react39.default.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null
8161
- ), /* @__PURE__ */ import_react39.default.createElement("form", { className: "brokr-section", onSubmit: handleSubmit, style: { gap: "var(--brokr-space-3)" } }, /* @__PURE__ */ import_react39.default.createElement(
8180
+ error ? /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null
8181
+ ), /* @__PURE__ */ import_react40.default.createElement("form", { className: "brokr-section", onSubmit: handleSubmit, style: { gap: "var(--brokr-space-3)" } }, /* @__PURE__ */ import_react40.default.createElement(
8162
8182
  "textarea",
8163
8183
  {
8164
8184
  className: "brokr-textarea brokr-chat-input",
@@ -8168,11 +8188,11 @@ function FabAI({
8168
8188
  rows: 2,
8169
8189
  value: input
8170
8190
  }
8171
- ), /* @__PURE__ */ import_react39.default.createElement("button", { className: "brokr-button", disabled: isSending || !input.trim(), type: "submit" }, isSending ? "Thinking" : "Send"))) : null);
8191
+ ), /* @__PURE__ */ import_react40.default.createElement("button", { className: "brokr-button", disabled: isSending || !input.trim(), type: "submit" }, isSending ? "Thinking" : "Send"))) : null);
8172
8192
  }
8173
8193
 
8174
8194
  // src/react/composites/SmartUpload.tsx
8175
- var import_react40 = __toESM(require("react"));
8195
+ var import_react41 = __toESM(require("react"));
8176
8196
  function SmartUpload({
8177
8197
  accept,
8178
8198
  maxSize = 500 * 1024 * 1024,
@@ -8180,17 +8200,17 @@ function SmartUpload({
8180
8200
  purpose = "general"
8181
8201
  }) {
8182
8202
  const { paymentsMode } = useBrokr();
8183
- const inputId = (0, import_react40.useId)();
8184
- const inputRef = (0, import_react40.useRef)(null);
8185
- const [dragActive, setDragActive] = (0, import_react40.useState)(false);
8186
- const [error, setError] = (0, import_react40.useState)(null);
8187
- const [fileName, setFileName] = (0, import_react40.useState)(null);
8188
- const [progress, setProgress] = (0, import_react40.useState)(0);
8189
- const [isUploading, setIsUploading] = (0, import_react40.useState)(false);
8190
- const helperText = (0, import_react40.useMemo)(() => {
8203
+ const inputId = (0, import_react41.useId)();
8204
+ const inputRef = (0, import_react41.useRef)(null);
8205
+ const [dragActive, setDragActive] = (0, import_react41.useState)(false);
8206
+ const [error, setError] = (0, import_react41.useState)(null);
8207
+ const [fileName, setFileName] = (0, import_react41.useState)(null);
8208
+ const [progress, setProgress] = (0, import_react41.useState)(0);
8209
+ const [isUploading, setIsUploading] = (0, import_react41.useState)(false);
8210
+ const helperText = (0, import_react41.useMemo)(() => {
8191
8211
  return `${Math.round(maxSize / (1024 * 1024))} MB max file size.`;
8192
8212
  }, [maxSize]);
8193
- const beginUpload = (0, import_react40.useCallback)((file) => {
8213
+ const beginUpload = (0, import_react41.useCallback)((file) => {
8194
8214
  if (file.size > maxSize) {
8195
8215
  setError(`That file is larger than ${Math.round(maxSize / (1024 * 1024))} MB.`);
8196
8216
  return;
@@ -8227,31 +8247,31 @@ function SmartUpload({
8227
8247
  body.append("purpose", purpose);
8228
8248
  request.send(body);
8229
8249
  }, [maxSize, onUpload, purpose]);
8230
- const handleInputChange = (0, import_react40.useCallback)((event) => {
8250
+ const handleInputChange = (0, import_react41.useCallback)((event) => {
8231
8251
  const file = event.target.files?.[0];
8232
8252
  event.target.value = "";
8233
8253
  if (!file) return;
8234
8254
  beginUpload(file);
8235
8255
  }, [beginUpload]);
8236
- const handleDrop = (0, import_react40.useCallback)((event) => {
8256
+ const handleDrop = (0, import_react41.useCallback)((event) => {
8237
8257
  event.preventDefault();
8238
8258
  setDragActive(false);
8239
8259
  const file = event.dataTransfer.files?.[0];
8240
8260
  if (!file) return;
8241
8261
  beginUpload(file);
8242
8262
  }, [beginUpload]);
8243
- const handleDragEnter = (0, import_react40.useCallback)((event) => {
8263
+ const handleDragEnter = (0, import_react41.useCallback)((event) => {
8244
8264
  event.preventDefault();
8245
8265
  setDragActive(true);
8246
8266
  }, []);
8247
- const handleDragLeave = (0, import_react40.useCallback)((event) => {
8267
+ const handleDragLeave = (0, import_react41.useCallback)((event) => {
8248
8268
  event.preventDefault();
8249
8269
  setDragActive(false);
8250
8270
  }, []);
8251
- const handleBrowse = (0, import_react40.useCallback)(() => {
8271
+ const handleBrowse = (0, import_react41.useCallback)(() => {
8252
8272
  inputRef.current?.click();
8253
8273
  }, []);
8254
- return /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-card brokr-upload-shell" }, /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ import_react40.default.createElement("strong", null, "Upload files"), /* @__PURE__ */ import_react40.default.createElement("span", { className: "brokr-copy" }, "Drop a file and let Brokr handle the boring part.")), paymentsMode === "sandbox" ? /* @__PURE__ */ import_react40.default.createElement("span", { className: "brokr-badge brokr-badge-sandbox" }, "Sandbox") : null), /* @__PURE__ */ import_react40.default.createElement(
8274
+ return /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-card brokr-upload-shell" }, /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ import_react41.default.createElement("strong", null, "Upload files"), /* @__PURE__ */ import_react41.default.createElement("span", { className: "brokr-copy" }, "Drop a file and let Brokr handle the boring part.")), paymentsMode === "sandbox" ? /* @__PURE__ */ import_react41.default.createElement("span", { className: "brokr-badge brokr-badge-sandbox" }, "Sandbox") : null), /* @__PURE__ */ import_react41.default.createElement(
8255
8275
  "label",
8256
8276
  {
8257
8277
  className: "brokr-upload-dropzone",
@@ -8262,11 +8282,11 @@ function SmartUpload({
8262
8282
  onDragOver: handleDragEnter,
8263
8283
  onDrop: handleDrop
8264
8284
  },
8265
- /* @__PURE__ */ import_react40.default.createElement(UploadIcon, { size: 24 }),
8266
- /* @__PURE__ */ import_react40.default.createElement("strong", null, "Drag and drop a file here or choose one"),
8267
- /* @__PURE__ */ import_react40.default.createElement("span", { className: "brokr-copy" }, helperText),
8268
- /* @__PURE__ */ import_react40.default.createElement("button", { className: "brokr-button-secondary", onClick: handleBrowse, type: "button" }, "Choose file")
8269
- ), /* @__PURE__ */ import_react40.default.createElement(
8285
+ /* @__PURE__ */ import_react41.default.createElement(UploadIcon, { size: 24 }),
8286
+ /* @__PURE__ */ import_react41.default.createElement("strong", null, "Drag and drop a file here or choose one"),
8287
+ /* @__PURE__ */ import_react41.default.createElement("span", { className: "brokr-copy" }, helperText),
8288
+ /* @__PURE__ */ import_react41.default.createElement("button", { className: "brokr-button-secondary", onClick: handleBrowse, type: "button" }, "Choose file")
8289
+ ), /* @__PURE__ */ import_react41.default.createElement(
8270
8290
  "input",
8271
8291
  {
8272
8292
  accept,
@@ -8276,31 +8296,31 @@ function SmartUpload({
8276
8296
  ref: inputRef,
8277
8297
  type: "file"
8278
8298
  }
8279
- ), fileName ? /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-card brokr-upload-file" }, /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ import_react40.default.createElement("strong", null, fileName), /* @__PURE__ */ import_react40.default.createElement("span", { className: "brokr-copy" }, isUploading ? `Uploading ${progress}%` : progress === 100 ? "Processed" : "Queued")), /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-meter-bar" }, /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-meter-fill", style: { width: `${progress}%` } }))) : null, error ? /* @__PURE__ */ import_react40.default.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null);
8299
+ ), fileName ? /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-card brokr-upload-file" }, /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ import_react41.default.createElement("strong", null, fileName), /* @__PURE__ */ import_react41.default.createElement("span", { className: "brokr-copy" }, isUploading ? `Uploading ${progress}%` : progress === 100 ? "Processed" : "Queued")), /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-meter-bar" }, /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-meter-fill", style: { width: `${progress}%` } }))) : null, error ? /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null);
8280
8300
  }
8281
8301
 
8282
8302
  // src/react/composites/FeedbackWidget.tsx
8283
- var import_react41 = __toESM(require("react"));
8303
+ var import_react42 = __toESM(require("react"));
8284
8304
  function FeedbackWidget({
8285
8305
  context,
8286
8306
  onSubmit
8287
8307
  }) {
8288
8308
  const { user } = useBrokr();
8289
- const [rating, setRating] = (0, import_react41.useState)(null);
8290
- const [text, setText] = (0, import_react41.useState)("");
8291
- const [error, setError] = (0, import_react41.useState)(null);
8292
- const [message, setMessage] = (0, import_react41.useState)(null);
8293
- const [isPending, setIsPending] = (0, import_react41.useState)(false);
8294
- const handleTextChange = (0, import_react41.useCallback)((event) => {
8309
+ const [rating, setRating] = (0, import_react42.useState)(null);
8310
+ const [text, setText] = (0, import_react42.useState)("");
8311
+ const [error, setError] = (0, import_react42.useState)(null);
8312
+ const [message, setMessage] = (0, import_react42.useState)(null);
8313
+ const [isPending, setIsPending] = (0, import_react42.useState)(false);
8314
+ const handleTextChange = (0, import_react42.useCallback)((event) => {
8295
8315
  setText(event.target.value);
8296
8316
  }, []);
8297
- const handleRateUp = (0, import_react41.useCallback)(() => {
8317
+ const handleRateUp = (0, import_react42.useCallback)(() => {
8298
8318
  setRating("up");
8299
8319
  }, []);
8300
- const handleRateDown = (0, import_react41.useCallback)(() => {
8320
+ const handleRateDown = (0, import_react42.useCallback)(() => {
8301
8321
  setRating("down");
8302
8322
  }, []);
8303
- const handleSubmit = (0, import_react41.useCallback)(async (event) => {
8323
+ const handleSubmit = (0, import_react42.useCallback)(async (event) => {
8304
8324
  event.preventDefault();
8305
8325
  if (!rating) {
8306
8326
  setError("Choose a direction first.");
@@ -8330,7 +8350,7 @@ function FeedbackWidget({
8330
8350
  setIsPending(false);
8331
8351
  }
8332
8352
  }, [context, onSubmit, rating, text, user?.id]);
8333
- return /* @__PURE__ */ import_react41.default.createElement("form", { className: "brokr-card brokr-feedback-shell", onSubmit: handleSubmit }, /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-section", style: { gap: "0.5rem" } }, /* @__PURE__ */ import_react41.default.createElement("strong", null, "How did this feel?"), /* @__PURE__ */ import_react41.default.createElement("p", { className: "brokr-copy" }, "Tight signal only. Tell us what helped or what felt off.")), /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-feedback-rating" }, /* @__PURE__ */ import_react41.default.createElement(
8353
+ return /* @__PURE__ */ import_react42.default.createElement("form", { className: "brokr-card brokr-feedback-shell", onSubmit: handleSubmit }, /* @__PURE__ */ import_react42.default.createElement("div", { className: "brokr-section", style: { gap: "0.5rem" } }, /* @__PURE__ */ import_react42.default.createElement("strong", null, "How did this feel?"), /* @__PURE__ */ import_react42.default.createElement("p", { className: "brokr-copy" }, "Tight signal only. Tell us what helped or what felt off.")), /* @__PURE__ */ import_react42.default.createElement("div", { className: "brokr-feedback-rating" }, /* @__PURE__ */ import_react42.default.createElement(
8334
8354
  "button",
8335
8355
  {
8336
8356
  className: "brokr-rating-button",
@@ -8339,7 +8359,7 @@ function FeedbackWidget({
8339
8359
  type: "button"
8340
8360
  },
8341
8361
  "This worked"
8342
- ), /* @__PURE__ */ import_react41.default.createElement(
8362
+ ), /* @__PURE__ */ import_react42.default.createElement(
8343
8363
  "button",
8344
8364
  {
8345
8365
  className: "brokr-rating-button",
@@ -8348,7 +8368,7 @@ function FeedbackWidget({
8348
8368
  type: "button"
8349
8369
  },
8350
8370
  "Needs work"
8351
- )), /* @__PURE__ */ import_react41.default.createElement(
8371
+ )), /* @__PURE__ */ import_react42.default.createElement(
8352
8372
  "textarea",
8353
8373
  {
8354
8374
  className: "brokr-textarea",
@@ -8357,11 +8377,11 @@ function FeedbackWidget({
8357
8377
  rows: 4,
8358
8378
  value: text
8359
8379
  }
8360
- ), error ? /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null, message ? /* @__PURE__ */ import_react41.default.createElement("div", { className: "brokr-inline-message" }, message) : null, /* @__PURE__ */ import_react41.default.createElement("button", { className: "brokr-button", disabled: isPending, type: "submit" }, isPending ? "Sending" : "Send feedback"));
8380
+ ), error ? /* @__PURE__ */ import_react42.default.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null, message ? /* @__PURE__ */ import_react42.default.createElement("div", { className: "brokr-inline-message" }, message) : null, /* @__PURE__ */ import_react42.default.createElement("button", { className: "brokr-button", disabled: isPending, type: "submit" }, isPending ? "Sending" : "Send feedback"));
8361
8381
  }
8362
8382
 
8363
8383
  // src/react/BrokrErrorBoundary.tsx
8364
- var import_react42 = __toESM(require("react"));
8384
+ var import_react43 = __toESM(require("react"));
8365
8385
 
8366
8386
  // src/fix-registry.ts
8367
8387
  var FIX_REGISTRY = {
@@ -8585,7 +8605,7 @@ var BrokrError = class extends Error {
8585
8605
  };
8586
8606
 
8587
8607
  // src/react/BrokrErrorBoundary.tsx
8588
- var BrokrErrorBoundary = class extends import_react42.default.Component {
8608
+ var BrokrErrorBoundary = class extends import_react43.default.Component {
8589
8609
  constructor() {
8590
8610
  super(...arguments);
8591
8611
  this.state = { hasError: false, error: null };
@@ -8597,11 +8617,11 @@ var BrokrErrorBoundary = class extends import_react42.default.Component {
8597
8617
  if (this.state.hasError) {
8598
8618
  if (this.props.fallback) return this.props.fallback;
8599
8619
  const message = this.state.error instanceof BrokrError ? this.state.error.toUserMessage() : "Something went wrong.";
8600
- return import_react42.default.createElement(
8620
+ return import_react43.default.createElement(
8601
8621
  "div",
8602
8622
  { style: { padding: 24, textAlign: "center" } },
8603
- import_react42.default.createElement("p", null, message),
8604
- import_react42.default.createElement(
8623
+ import_react43.default.createElement("p", null, message),
8624
+ import_react43.default.createElement(
8605
8625
  "button",
8606
8626
  {
8607
8627
  onClick: () => this.setState({ hasError: false, error: null }),
@@ -8615,13 +8635,13 @@ var BrokrErrorBoundary = class extends import_react42.default.Component {
8615
8635
  }
8616
8636
  };
8617
8637
 
8618
- // src/react/notifications/NotificationBell.tsx
8619
- var import_react44 = __toESM(require("react"));
8638
+ // src/react/notifications/ActivityFeed.tsx
8639
+ var import_react45 = __toESM(require("react"));
8620
8640
 
8621
8641
  // src/react/notifications/use-notifications.ts
8622
- var import_react43 = require("react");
8642
+ var import_react44 = require("react");
8623
8643
  function useNotifications() {
8624
- const ctx = (0, import_react43.useContext)(NotificationsContext);
8644
+ const ctx = (0, import_react44.useContext)(NotificationsContext);
8625
8645
  if (!ctx) {
8626
8646
  throw new Error(
8627
8647
  "useNotifications() requires <BrokrProvider notifications> or <BrokrProvider notifications={config}>. Pass the notifications prop to enable the notification system."
@@ -8630,7 +8650,7 @@ function useNotifications() {
8630
8650
  return ctx;
8631
8651
  }
8632
8652
 
8633
- // src/react/notifications/NotificationBell.tsx
8653
+ // src/react/notifications/ActivityFeed.tsx
8634
8654
  function timeAgo(iso) {
8635
8655
  const diff = Date.now() - new Date(iso).getTime();
8636
8656
  const mins = Math.floor(diff / 6e4);
@@ -8641,16 +8661,79 @@ function timeAgo(iso) {
8641
8661
  const days = Math.floor(hours / 24);
8642
8662
  return `${days}d ago`;
8643
8663
  }
8664
+ function FeedItem({
8665
+ item,
8666
+ formatter
8667
+ }) {
8668
+ if (formatter) {
8669
+ return /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-feed-item" }, formatter(item));
8670
+ }
8671
+ return /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-feed-item" }, /* @__PURE__ */ import_react45.default.createElement("span", { className: `brokr-feed-dot brokr-feed-dot--${item.variant}` }), /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-feed-content" }, /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-feed-title" }, item.title), item.message ? /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-feed-message" }, item.message) : null), /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-feed-time" }, timeAgo(item.createdAt)));
8672
+ }
8673
+ function ActivityFeed({
8674
+ filter,
8675
+ maxItems = 20,
8676
+ formatters,
8677
+ emptyState
8678
+ }) {
8679
+ const { notifications, isLoading } = useNotifications();
8680
+ const items = (0, import_react45.useMemo)(() => {
8681
+ let filtered = notifications;
8682
+ if (filter && filter.length > 0) {
8683
+ const set = new Set(filter);
8684
+ filtered = notifications.filter(
8685
+ (n) => set.has(n.variant) || n.type && set.has(n.type)
8686
+ );
8687
+ }
8688
+ return [...filtered].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()).slice(0, maxItems);
8689
+ }, [notifications, filter, maxItems]);
8690
+ const getFormatter = (0, import_react45.useCallback)(
8691
+ (item) => {
8692
+ if (!formatters) return void 0;
8693
+ if (item.type && formatters[item.type]) return formatters[item.type];
8694
+ if (formatters[item.variant]) return formatters[item.variant];
8695
+ return void 0;
8696
+ },
8697
+ [formatters]
8698
+ );
8699
+ if (isLoading) {
8700
+ return /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-feed" }, [1, 2, 3].map((i) => /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-feed-item", key: i }, /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-feed-dot" }), /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-feed-content" }, /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-skeleton", style: { width: "60%", height: 12 } }), /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-skeleton", style: { width: "80%", height: 12 } })), /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-skeleton", style: { width: 40, height: 12 } }))));
8701
+ }
8702
+ if (items.length === 0) {
8703
+ return /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-feed" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-feed-empty" }, emptyState ?? /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-copy" }, "No activity yet.")));
8704
+ }
8705
+ return /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-feed" }, items.map((item) => /* @__PURE__ */ import_react45.default.createElement(
8706
+ FeedItem,
8707
+ {
8708
+ key: item.id,
8709
+ item,
8710
+ formatter: getFormatter(item)
8711
+ }
8712
+ )));
8713
+ }
8714
+
8715
+ // src/react/notifications/NotificationBell.tsx
8716
+ var import_react46 = __toESM(require("react"));
8717
+ function timeAgo2(iso) {
8718
+ const diff = Date.now() - new Date(iso).getTime();
8719
+ const mins = Math.floor(diff / 6e4);
8720
+ if (mins < 1) return "just now";
8721
+ if (mins < 60) return `${mins}m ago`;
8722
+ const hours = Math.floor(mins / 60);
8723
+ if (hours < 24) return `${hours}h ago`;
8724
+ const days = Math.floor(hours / 24);
8725
+ return `${days}d ago`;
8726
+ }
8644
8727
  function NotifDropdownItem({
8645
8728
  notif,
8646
8729
  registry,
8647
8730
  onClick
8648
8731
  }) {
8649
- const handleClick = (0, import_react44.useCallback)(() => onClick(notif), [notif, onClick]);
8732
+ const handleClick = (0, import_react46.useCallback)(() => onClick(notif), [notif, onClick]);
8650
8733
  const notifData = notif.data ?? {};
8651
8734
  const notifType = notifData.type ?? "default";
8652
8735
  const resolved = resolveNotificationType(registry, notifType, notifData);
8653
- return /* @__PURE__ */ import_react44.default.createElement(
8736
+ return /* @__PURE__ */ import_react46.default.createElement(
8654
8737
  "button",
8655
8738
  {
8656
8739
  type: "button",
@@ -8658,18 +8741,18 @@ function NotifDropdownItem({
8658
8741
  onClick: handleClick,
8659
8742
  role: "menuitem"
8660
8743
  },
8661
- resolved.image ? /* @__PURE__ */ import_react44.default.createElement("img", { src: resolved.image.url, alt: resolved.image.alt, className: "brokr-notif-item-logo" }) : /* @__PURE__ */ import_react44.default.createElement("span", { className: `brokr-notif-item-dot brokr-notif-item-dot--${notif.variant}` }),
8662
- /* @__PURE__ */ import_react44.default.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ import_react44.default.createElement("span", { className: "brokr-notif-item-title" }, notif.title), /* @__PURE__ */ import_react44.default.createElement("span", { className: "brokr-notif-item-message" }, notif.message)),
8663
- /* @__PURE__ */ import_react44.default.createElement("span", { className: "brokr-notif-item-time" }, timeAgo(notif.createdAt))
8744
+ resolved.image ? /* @__PURE__ */ import_react46.default.createElement("img", { src: resolved.image.url, alt: resolved.image.alt, className: "brokr-notif-item-logo" }) : /* @__PURE__ */ import_react46.default.createElement("span", { className: `brokr-notif-item-dot brokr-notif-item-dot--${notif.variant}` }),
8745
+ /* @__PURE__ */ import_react46.default.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ import_react46.default.createElement("span", { className: "brokr-notif-item-title" }, notif.title), /* @__PURE__ */ import_react46.default.createElement("span", { className: "brokr-notif-item-message" }, notif.message)),
8746
+ /* @__PURE__ */ import_react46.default.createElement("span", { className: "brokr-notif-item-time" }, timeAgo2(notif.createdAt))
8664
8747
  );
8665
8748
  }
8666
8749
  function NotificationBell() {
8667
8750
  const { notifications, unreadCount, markRead, markAllRead, isLoading, registry } = useNotifications();
8668
- const [open, setOpen] = (0, import_react44.useState)(false);
8669
- const containerRef = (0, import_react44.useRef)(null);
8670
- const markReadTimerRef = (0, import_react44.useRef)(null);
8671
- const toggle = (0, import_react44.useCallback)(() => setOpen((o) => !o), []);
8672
- (0, import_react44.useEffect)(() => {
8751
+ const [open, setOpen] = (0, import_react46.useState)(false);
8752
+ const containerRef = (0, import_react46.useRef)(null);
8753
+ const markReadTimerRef = (0, import_react46.useRef)(null);
8754
+ const toggle = (0, import_react46.useCallback)(() => setOpen((o) => !o), []);
8755
+ (0, import_react46.useEffect)(() => {
8673
8756
  if (markReadTimerRef.current) {
8674
8757
  clearTimeout(markReadTimerRef.current);
8675
8758
  markReadTimerRef.current = null;
@@ -8686,7 +8769,7 @@ function NotificationBell() {
8686
8769
  }
8687
8770
  };
8688
8771
  }, [open, unreadCount, markAllRead]);
8689
- (0, import_react44.useEffect)(() => {
8772
+ (0, import_react46.useEffect)(() => {
8690
8773
  if (!open) return;
8691
8774
  function handleClick(e) {
8692
8775
  if (containerRef.current && !containerRef.current.contains(e.target)) {
@@ -8696,7 +8779,7 @@ function NotificationBell() {
8696
8779
  document.addEventListener("mousedown", handleClick);
8697
8780
  return () => document.removeEventListener("mousedown", handleClick);
8698
8781
  }, [open]);
8699
- (0, import_react44.useEffect)(() => {
8782
+ (0, import_react46.useEffect)(() => {
8700
8783
  if (!open) return;
8701
8784
  function handleKey(e) {
8702
8785
  if (e.key === "Escape") setOpen(false);
@@ -8704,13 +8787,13 @@ function NotificationBell() {
8704
8787
  document.addEventListener("keydown", handleKey);
8705
8788
  return () => document.removeEventListener("keydown", handleKey);
8706
8789
  }, [open]);
8707
- const sorted = (0, import_react44.useMemo)(
8790
+ const sorted = (0, import_react46.useMemo)(
8708
8791
  () => [...notifications].sort(
8709
8792
  (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
8710
8793
  ),
8711
8794
  [notifications]
8712
8795
  );
8713
- const handleItemClick = (0, import_react44.useCallback)((notif) => {
8796
+ const handleItemClick = (0, import_react46.useCallback)((notif) => {
8714
8797
  if (!notif.read) markRead(notif.id);
8715
8798
  const notifData = notif.data ?? {};
8716
8799
  const notifType = notif.type ?? notifData.type ?? "default";
@@ -8720,7 +8803,7 @@ function NotificationBell() {
8720
8803
  window.location.assign(href);
8721
8804
  }
8722
8805
  }, [markRead, registry]);
8723
- return /* @__PURE__ */ import_react44.default.createElement("div", { className: "brokr-notif-bell-wrap", ref: containerRef }, /* @__PURE__ */ import_react44.default.createElement(
8806
+ return /* @__PURE__ */ import_react46.default.createElement("div", { className: "brokr-notif-bell-wrap", ref: containerRef }, /* @__PURE__ */ import_react46.default.createElement(
8724
8807
  "button",
8725
8808
  {
8726
8809
  type: "button",
@@ -8730,9 +8813,9 @@ function NotificationBell() {
8730
8813
  "aria-expanded": open,
8731
8814
  "aria-haspopup": "menu"
8732
8815
  },
8733
- /* @__PURE__ */ import_react44.default.createElement("svg", { "aria-hidden": "true", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react44.default.createElement("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }), /* @__PURE__ */ import_react44.default.createElement("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })),
8734
- unreadCount > 0 && /* @__PURE__ */ import_react44.default.createElement("span", { className: "brokr-notif-badge" }, unreadCount > 99 ? "99+" : unreadCount)
8735
- ), open && /* @__PURE__ */ import_react44.default.createElement("div", { className: "brokr-notif-dropdown", role: "menu" }, /* @__PURE__ */ import_react44.default.createElement("div", { className: "brokr-notif-dropdown-header" }, /* @__PURE__ */ import_react44.default.createElement("span", { className: "brokr-notif-dropdown-title" }, "Notifications"), unreadCount > 0 && /* @__PURE__ */ import_react44.default.createElement(
8816
+ /* @__PURE__ */ import_react46.default.createElement("svg", { "aria-hidden": "true", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react46.default.createElement("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }), /* @__PURE__ */ import_react46.default.createElement("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })),
8817
+ unreadCount > 0 && /* @__PURE__ */ import_react46.default.createElement("span", { className: "brokr-notif-badge" }, unreadCount > 99 ? "99+" : unreadCount)
8818
+ ), open && /* @__PURE__ */ import_react46.default.createElement("div", { className: "brokr-notif-dropdown", role: "menu" }, /* @__PURE__ */ import_react46.default.createElement("div", { className: "brokr-notif-dropdown-header" }, /* @__PURE__ */ import_react46.default.createElement("span", { className: "brokr-notif-dropdown-title" }, "Notifications"), unreadCount > 0 && /* @__PURE__ */ import_react46.default.createElement(
8736
8819
  "button",
8737
8820
  {
8738
8821
  type: "button",
@@ -8740,7 +8823,7 @@ function NotificationBell() {
8740
8823
  onClick: markAllRead
8741
8824
  },
8742
8825
  "Mark all read"
8743
- )), /* @__PURE__ */ import_react44.default.createElement("div", { className: "brokr-notif-dropdown-list" }, isLoading ? /* @__PURE__ */ import_react44.default.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ import_react44.default.createElement("span", { className: "brokr-notif-empty-text" }, "Loading\u2026")) : sorted.length === 0 ? /* @__PURE__ */ import_react44.default.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ import_react44.default.createElement("span", { className: "brokr-notif-empty-text" }, "No notifications yet")) : sorted.map((notif) => /* @__PURE__ */ import_react44.default.createElement(
8826
+ )), /* @__PURE__ */ import_react46.default.createElement("div", { className: "brokr-notif-dropdown-list" }, isLoading ? /* @__PURE__ */ import_react46.default.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ import_react46.default.createElement("span", { className: "brokr-notif-empty-text" }, "Loading\u2026")) : sorted.length === 0 ? /* @__PURE__ */ import_react46.default.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ import_react46.default.createElement("span", { className: "brokr-notif-empty-text" }, "No notifications yet")) : sorted.map((notif) => /* @__PURE__ */ import_react46.default.createElement(
8744
8827
  NotifDropdownItem,
8745
8828
  {
8746
8829
  key: notif.id,
@@ -8752,7 +8835,7 @@ function NotificationBell() {
8752
8835
  }
8753
8836
 
8754
8837
  // src/react/notifications/NotificationList.tsx
8755
- var import_react45 = __toESM(require("react"));
8838
+ var import_react47 = __toESM(require("react"));
8756
8839
  function formatTimestamp(iso) {
8757
8840
  const date = new Date(iso);
8758
8841
  return new Intl.DateTimeFormat("en-US", {
@@ -8763,38 +8846,38 @@ function formatTimestamp(iso) {
8763
8846
  }).format(date);
8764
8847
  }
8765
8848
  function NotificationListSkeleton() {
8766
- return /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-notif-list-items" }, [1, 2, 3].map((i) => /* @__PURE__ */ import_react45.default.createElement("div", { key: i, className: "brokr-notif-list-row brokr-notif-list-row--skeleton" }, /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-notif-item-dot brokr-notif-item-dot--skeleton" }), /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-notif-item-title brokr-skeleton-line", style: { width: "60%" } }), /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-notif-item-message brokr-skeleton-line", style: { width: "80%" } })), /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-notif-item-time brokr-skeleton-line", style: { width: 48 } }))));
8849
+ return /* @__PURE__ */ import_react47.default.createElement("div", { className: "brokr-notif-list-items" }, [1, 2, 3].map((i) => /* @__PURE__ */ import_react47.default.createElement("div", { key: i, className: "brokr-notif-list-row brokr-notif-list-row--skeleton" }, /* @__PURE__ */ import_react47.default.createElement("span", { className: "brokr-notif-item-dot brokr-notif-item-dot--skeleton" }), /* @__PURE__ */ import_react47.default.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ import_react47.default.createElement("span", { className: "brokr-notif-item-title brokr-skeleton-line", style: { width: "60%" } }), /* @__PURE__ */ import_react47.default.createElement("span", { className: "brokr-notif-item-message brokr-skeleton-line", style: { width: "80%" } })), /* @__PURE__ */ import_react47.default.createElement("span", { className: "brokr-notif-item-time brokr-skeleton-line", style: { width: 48 } }))));
8767
8850
  }
8768
8851
  function NotifListItem({
8769
8852
  notif,
8770
8853
  registry,
8771
8854
  onClick
8772
8855
  }) {
8773
- const handleClick = (0, import_react45.useCallback)(() => onClick(notif), [notif, onClick]);
8856
+ const handleClick = (0, import_react47.useCallback)(() => onClick(notif), [notif, onClick]);
8774
8857
  const notifData = notif.data ?? {};
8775
8858
  const notifType = notif.type ?? notifData.type ?? "default";
8776
8859
  const resolved = resolveNotificationType(registry, notifType, notifData);
8777
- return /* @__PURE__ */ import_react45.default.createElement(
8860
+ return /* @__PURE__ */ import_react47.default.createElement(
8778
8861
  "button",
8779
8862
  {
8780
8863
  type: "button",
8781
8864
  className: `brokr-notif-list-row${notif.read ? "" : " brokr-notif-list-row--unread"}`,
8782
8865
  onClick: handleClick
8783
8866
  },
8784
- resolved.image ? /* @__PURE__ */ import_react45.default.createElement("img", { src: resolved.image.url, alt: resolved.image.alt, className: "brokr-notif-item-logo" }) : /* @__PURE__ */ import_react45.default.createElement("span", { className: `brokr-notif-item-dot brokr-notif-item-dot--${notif.variant}` }),
8785
- /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-notif-item-title" }, notif.title), /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-notif-item-message" }, notif.message)),
8786
- /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-notif-item-time" }, formatTimestamp(notif.createdAt))
8867
+ resolved.image ? /* @__PURE__ */ import_react47.default.createElement("img", { src: resolved.image.url, alt: resolved.image.alt, className: "brokr-notif-item-logo" }) : /* @__PURE__ */ import_react47.default.createElement("span", { className: `brokr-notif-item-dot brokr-notif-item-dot--${notif.variant}` }),
8868
+ /* @__PURE__ */ import_react47.default.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ import_react47.default.createElement("span", { className: "brokr-notif-item-title" }, notif.title), /* @__PURE__ */ import_react47.default.createElement("span", { className: "brokr-notif-item-message" }, notif.message)),
8869
+ /* @__PURE__ */ import_react47.default.createElement("span", { className: "brokr-notif-item-time" }, formatTimestamp(notif.createdAt))
8787
8870
  );
8788
8871
  }
8789
8872
  function NotificationList() {
8790
8873
  const { notifications, unreadCount, markRead, markAllRead, isLoading, registry } = useNotifications();
8791
- const sorted = (0, import_react45.useMemo)(
8874
+ const sorted = (0, import_react47.useMemo)(
8792
8875
  () => [...notifications].sort(
8793
8876
  (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
8794
8877
  ),
8795
8878
  [notifications]
8796
8879
  );
8797
- const handleClick = (0, import_react45.useCallback)((notif) => {
8880
+ const handleClick = (0, import_react47.useCallback)((notif) => {
8798
8881
  if (!notif.read) markRead(notif.id);
8799
8882
  const notifData = notif.data ?? {};
8800
8883
  const notifType = notif.type ?? notifData.type ?? "default";
@@ -8804,7 +8887,7 @@ function NotificationList() {
8804
8887
  window.location.assign(href);
8805
8888
  }
8806
8889
  }, [markRead, registry]);
8807
- return /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-notif-list" }, /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-notif-list-header" }, /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-notif-list-title" }, "Notifications"), unreadCount > 0 && /* @__PURE__ */ import_react45.default.createElement(
8890
+ return /* @__PURE__ */ import_react47.default.createElement("div", { className: "brokr-notif-list" }, /* @__PURE__ */ import_react47.default.createElement("div", { className: "brokr-notif-list-header" }, /* @__PURE__ */ import_react47.default.createElement("span", { className: "brokr-notif-list-title" }, "Notifications"), unreadCount > 0 && /* @__PURE__ */ import_react47.default.createElement(
8808
8891
  "button",
8809
8892
  {
8810
8893
  type: "button",
@@ -8812,7 +8895,7 @@ function NotificationList() {
8812
8895
  onClick: markAllRead
8813
8896
  },
8814
8897
  "Mark all read"
8815
- )), isLoading ? /* @__PURE__ */ import_react45.default.createElement(NotificationListSkeleton, null) : sorted.length === 0 ? /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ import_react45.default.createElement("svg", { "aria-hidden": "true", width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", style: { opacity: 0.3 } }, /* @__PURE__ */ import_react45.default.createElement("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }), /* @__PURE__ */ import_react45.default.createElement("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })), /* @__PURE__ */ import_react45.default.createElement("span", { className: "brokr-notif-empty-text" }, "No notifications yet")) : /* @__PURE__ */ import_react45.default.createElement("div", { className: "brokr-notif-list-items" }, sorted.map((notif) => /* @__PURE__ */ import_react45.default.createElement(
8898
+ )), isLoading ? /* @__PURE__ */ import_react47.default.createElement(NotificationListSkeleton, null) : sorted.length === 0 ? /* @__PURE__ */ import_react47.default.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ import_react47.default.createElement("svg", { "aria-hidden": "true", width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", style: { opacity: 0.3 } }, /* @__PURE__ */ import_react47.default.createElement("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }), /* @__PURE__ */ import_react47.default.createElement("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })), /* @__PURE__ */ import_react47.default.createElement("span", { className: "brokr-notif-empty-text" }, "No notifications yet")) : /* @__PURE__ */ import_react47.default.createElement("div", { className: "brokr-notif-list-items" }, sorted.map((notif) => /* @__PURE__ */ import_react47.default.createElement(
8816
8899
  NotifListItem,
8817
8900
  {
8818
8901
  key: notif.id,
@@ -8853,6 +8936,7 @@ function defineAccount(config) {
8853
8936
  0 && (module.exports = {
8854
8937
  AIChat,
8855
8938
  AccountPanel,
8939
+ ActivityFeed,
8856
8940
  AuthPageShell,
8857
8941
  AuthWall,
8858
8942
  AutoReloadToggle,
@@ -8882,8 +8966,10 @@ function defineAccount(config) {
8882
8966
  UpdateBilling,
8883
8967
  UpgradePrompt,
8884
8968
  UsageGate,
8969
+ UsageGrid,
8885
8970
  UserButton,
8886
8971
  defineAccount,
8972
+ defineBrokrTheme,
8887
8973
  defineChat,
8888
8974
  useBrokr,
8889
8975
  useBrokrTheme,