@superatomai/application-react 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import React6, { Component, useState, useEffect, forwardRef, memo, useMemo, useRef, useCallback, createElement, lazy as lazy$1, Suspense } from 'react';
1
+ import React6, { Component, useState, useEffect, forwardRef, memo, useMemo, useRef, useCallback, createElement, lazy as lazy$1, Suspense, useSyncExternalStore } from 'react';
2
2
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
3
3
  import { createPortal } from 'react-dom';
4
4
 
@@ -5448,34 +5448,34 @@ function subcontent(events, eventIndex) {
5448
5448
  let stream;
5449
5449
  let previous3;
5450
5450
  let index2 = -1;
5451
- let current = token;
5451
+ let current3 = token;
5452
5452
  let adjust = 0;
5453
5453
  let start2 = 0;
5454
5454
  const breaks = [start2];
5455
- while (current) {
5456
- while (events.get(++startPosition)[1] !== current) {
5455
+ while (current3) {
5456
+ while (events.get(++startPosition)[1] !== current3) {
5457
5457
  }
5458
5458
  startPositions.push(startPosition);
5459
- if (!current._tokenizer) {
5460
- stream = context.sliceStream(current);
5461
- if (!current.next) {
5459
+ if (!current3._tokenizer) {
5460
+ stream = context.sliceStream(current3);
5461
+ if (!current3.next) {
5462
5462
  stream.push(null);
5463
5463
  }
5464
5464
  if (previous3) {
5465
- tokenizer.defineSkip(current.start);
5465
+ tokenizer.defineSkip(current3.start);
5466
5466
  }
5467
- if (current._isInFirstContentOfListItem) {
5467
+ if (current3._isInFirstContentOfListItem) {
5468
5468
  tokenizer._gfmTasklistFirstContentOfListItem = true;
5469
5469
  }
5470
5470
  tokenizer.write(stream);
5471
- if (current._isInFirstContentOfListItem) {
5471
+ if (current3._isInFirstContentOfListItem) {
5472
5472
  tokenizer._gfmTasklistFirstContentOfListItem = void 0;
5473
5473
  }
5474
5474
  }
5475
- previous3 = current;
5476
- current = current.next;
5475
+ previous3 = current3;
5476
+ current3 = current3.next;
5477
5477
  }
5478
- current = token;
5478
+ current3 = token;
5479
5479
  while (++index2 < childEvents.length) {
5480
5480
  if (
5481
5481
  // Find a void token that includes a break.
@@ -5483,15 +5483,15 @@ function subcontent(events, eventIndex) {
5483
5483
  ) {
5484
5484
  start2 = index2 + 1;
5485
5485
  breaks.push(start2);
5486
- current._tokenizer = void 0;
5487
- current.previous = void 0;
5488
- current = current.next;
5486
+ current3._tokenizer = void 0;
5487
+ current3.previous = void 0;
5488
+ current3 = current3.next;
5489
5489
  }
5490
5490
  }
5491
5491
  tokenizer.events = [];
5492
- if (current) {
5493
- current._tokenizer = void 0;
5494
- current.previous = void 0;
5492
+ if (current3) {
5493
+ current3._tokenizer = void 0;
5494
+ current3.previous = void 0;
5495
5495
  } else {
5496
5496
  breaks.pop();
5497
5497
  }
@@ -13506,9 +13506,9 @@ function isAsciiAlphaNumeric(code4) {
13506
13506
  function isEntityInAttributeInvalidEnd(code4) {
13507
13507
  return code4 === CharCodes.EQUALS || isAsciiAlphaNumeric(code4);
13508
13508
  }
13509
- function determineBranch(decodeTree, current, nodeIndex, char) {
13510
- const branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7;
13511
- const jumpOffset = current & BinTrieFlags.JUMP_TABLE;
13509
+ function determineBranch(decodeTree, current3, nodeIndex, char) {
13510
+ const branchCount = (current3 & BinTrieFlags.BRANCH_LENGTH) >> 7;
13511
+ const jumpOffset = current3 & BinTrieFlags.JUMP_TABLE;
13512
13512
  if (branchCount === 0) {
13513
13513
  return jumpOffset !== 0 && char === jumpOffset ? nodeIndex : -1;
13514
13514
  }
@@ -13747,19 +13747,19 @@ var init_decode = __esm({
13747
13747
  */
13748
13748
  stateNamedEntity(input, offset) {
13749
13749
  const { decodeTree } = this;
13750
- let current = decodeTree[this.treeIndex];
13751
- let valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
13750
+ let current3 = decodeTree[this.treeIndex];
13751
+ let valueLength = (current3 & BinTrieFlags.VALUE_LENGTH) >> 14;
13752
13752
  for (; offset < input.length; offset++, this.excess++) {
13753
13753
  const char = input.charCodeAt(offset);
13754
- this.treeIndex = determineBranch(decodeTree, current, this.treeIndex + Math.max(1, valueLength), char);
13754
+ this.treeIndex = determineBranch(decodeTree, current3, this.treeIndex + Math.max(1, valueLength), char);
13755
13755
  if (this.treeIndex < 0) {
13756
13756
  return this.result === 0 || // If we are parsing an attribute
13757
13757
  this.decodeMode === DecodingMode.Attribute && // We shouldn't have consumed any characters after the entity,
13758
13758
  (valueLength === 0 || // And there should be no invalid characters.
13759
13759
  isEntityInAttributeInvalidEnd(char)) ? 0 : this.emitNotTerminatedNamedEntity();
13760
13760
  }
13761
- current = decodeTree[this.treeIndex];
13762
- valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
13761
+ current3 = decodeTree[this.treeIndex];
13762
+ valueLength = (current3 & BinTrieFlags.VALUE_LENGTH) >> 14;
13763
13763
  if (valueLength !== 0) {
13764
13764
  if (char === CharCodes.SEMI) {
13765
13765
  return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);
@@ -19815,8 +19815,8 @@ function startTagInForeignContent(p, token) {
19815
19815
  popUntilHtmlOrIntegrationPoint(p);
19816
19816
  p._startTagOutsideForeignContent(token);
19817
19817
  } else {
19818
- const current = p._getAdjustedCurrentElement();
19819
- const currentNs = p.treeAdapter.getNamespaceURI(current);
19818
+ const current3 = p._getAdjustedCurrentElement();
19819
+ const currentNs = p.treeAdapter.getNamespaceURI(current3);
19820
19820
  if (currentNs === NS.MATHML) {
19821
19821
  adjustTokenMathMLAttrs(token);
19822
19822
  } else if (currentNs === NS.SVG) {
@@ -20004,21 +20004,21 @@ var init_parser = __esm({
20004
20004
  }
20005
20005
  (_b = (_a4 = this.treeAdapter).onItemPop) === null || _b === void 0 ? void 0 : _b.call(_a4, node2, this.openElements.current);
20006
20006
  if (isTop) {
20007
- let current;
20007
+ let current3;
20008
20008
  let currentTagId;
20009
20009
  if (this.openElements.stackTop === 0 && this.fragmentContext) {
20010
- current = this.fragmentContext;
20010
+ current3 = this.fragmentContext;
20011
20011
  currentTagId = this.fragmentContextID;
20012
20012
  } else {
20013
- ({ current, currentTagId } = this.openElements);
20013
+ ({ current: current3, currentTagId } = this.openElements);
20014
20014
  }
20015
- this._setContextModes(current, currentTagId);
20015
+ this._setContextModes(current3, currentTagId);
20016
20016
  }
20017
20017
  }
20018
- _setContextModes(current, tid) {
20019
- const isHTML = current === this.document || current && this.treeAdapter.getNamespaceURI(current) === NS.HTML;
20018
+ _setContextModes(current3, tid) {
20019
+ const isHTML = current3 === this.document || current3 && this.treeAdapter.getNamespaceURI(current3) === NS.HTML;
20020
20020
  this.currentNotInHTML = !isHTML;
20021
- this.tokenizer.inForeignNode = !isHTML && current !== void 0 && tid !== void 0 && !this._isIntegrationPoint(tid, current);
20021
+ this.tokenizer.inForeignNode = !isHTML && current3 !== void 0 && tid !== void 0 && !this._isIntegrationPoint(tid, current3);
20022
20022
  }
20023
20023
  /** @protected */
20024
20024
  _switchToTextParsing(currentToken, nextTokenizerState) {
@@ -20216,22 +20216,22 @@ var init_parser = __esm({
20216
20216
  shouldProcessStartTagTokenInForeignContent(token) {
20217
20217
  if (!this.currentNotInHTML)
20218
20218
  return false;
20219
- let current;
20219
+ let current3;
20220
20220
  let currentTagId;
20221
20221
  if (this.openElements.stackTop === 0 && this.fragmentContext) {
20222
- current = this.fragmentContext;
20222
+ current3 = this.fragmentContext;
20223
20223
  currentTagId = this.fragmentContextID;
20224
20224
  } else {
20225
- ({ current, currentTagId } = this.openElements);
20225
+ ({ current: current3, currentTagId } = this.openElements);
20226
20226
  }
20227
- if (token.tagID === TAG_ID.SVG && this.treeAdapter.getTagName(current) === TAG_NAMES.ANNOTATION_XML && this.treeAdapter.getNamespaceURI(current) === NS.MATHML) {
20227
+ if (token.tagID === TAG_ID.SVG && this.treeAdapter.getTagName(current3) === TAG_NAMES.ANNOTATION_XML && this.treeAdapter.getNamespaceURI(current3) === NS.MATHML) {
20228
20228
  return false;
20229
20229
  }
20230
20230
  return (
20231
20231
  // Check that `current` is not an integration point for HTML or MathML elements.
20232
20232
  this.tokenizer.inForeignNode || // If it _is_ an integration point, then we might have to check that it is not an HTML
20233
20233
  // integration point.
20234
- (token.tagID === TAG_ID.MGLYPH || token.tagID === TAG_ID.MALIGNMARK) && currentTagId !== void 0 && !this._isIntegrationPoint(currentTagId, current, NS.HTML)
20234
+ (token.tagID === TAG_ID.MGLYPH || token.tagID === TAG_ID.MALIGNMARK) && currentTagId !== void 0 && !this._isIntegrationPoint(currentTagId, current3, NS.HTML)
20235
20235
  );
20236
20236
  }
20237
20237
  /** @protected */
@@ -21191,8 +21191,8 @@ function startTag(node2, state) {
21191
21191
  const tagName = node2.tagName.toLowerCase();
21192
21192
  if (state.parser.tokenizer.state === TokenizerMode.PLAINTEXT) return;
21193
21193
  resetTokenizer(state, pointStart(node2));
21194
- const current = state.parser.openElements.current;
21195
- let ns = "namespaceURI" in current ? current.namespaceURI : webNamespaces.html;
21194
+ const current3 = state.parser.openElements.current;
21195
+ let ns = "namespaceURI" in current3 ? current3.namespaceURI : webNamespaces.html;
21196
21196
  if (ns === webNamespaces.html && tagName === "svg") {
21197
21197
  ns = webNamespaces.svg;
21198
21198
  }
@@ -50461,11 +50461,13 @@ var init_Markdown = __esm({
50461
50461
  // Suppress the default <pre> wrapper — code renderer owns the full block structure
50462
50462
  pre: ({ node: _node, children }) => /* @__PURE__ */ jsx(Fragment, { children }),
50463
50463
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
50464
- code: ({ node: _node, inline, className, children, ...props }) => {
50464
+ code: ({ node: _node, className, children, ...props }) => {
50465
50465
  const langMatch = /language-(\w+)/.exec(className || "");
50466
50466
  const language = langMatch ? langMatch[1] : "";
50467
- if (!inline) {
50468
- return language ? /* @__PURE__ */ jsxs("div", { className: "not-prose my-4 rounded-lg overflow-hidden border border-base-300", children: [
50467
+ const isBlock = Boolean(language) || String(children).includes("\n");
50468
+ const codeText2 = String(children).replace(/^\s*\n+/, "").replace(/\s+$/, "");
50469
+ if (isBlock) {
50470
+ return language ? /* @__PURE__ */ jsxs("div", { className: "sa-code-block not-prose my-4 rounded-lg overflow-hidden border border-base-300", children: [
50469
50471
  /* @__PURE__ */ jsx("div", { className: "bg-neutral px-4 py-2 text-xs text-neutral-content font-mono", children: language }),
50470
50472
  /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsx(
50471
50473
  prism_default2,
@@ -50475,13 +50477,13 @@ var init_Markdown = __esm({
50475
50477
  PreTag: "div",
50476
50478
  className: "!my-0 !rounded-none text-sm",
50477
50479
  customStyle: { margin: 0, borderRadius: 0, padding: "1rem" },
50478
- codeTagProps: { style: { backgroundColor: "transparent", padding: 0, fontSize: "inherit", textDecoration: "none" } },
50480
+ codeTagProps: { style: { backgroundColor: "transparent", padding: 0, fontSize: "inherit" } },
50479
50481
  wrapLongLines: false,
50480
50482
  ...props,
50481
- children: String(children).replace(/\n$/, "")
50483
+ children: codeText2
50482
50484
  }
50483
50485
  ) })
50484
- ] }) : /* @__PURE__ */ jsx("div", { className: "not-prose my-4 rounded-lg overflow-hidden border border-base-300", children: /* @__PURE__ */ jsx("pre", { className: "bg-base-200 text-base-content p-4 overflow-x-auto text-sm font-mono whitespace-pre-wrap break-words", children: /* @__PURE__ */ jsx("code", { ...props, children }) }) });
50486
+ ] }) : /* @__PURE__ */ jsx("div", { className: "sa-code-block not-prose my-4 rounded-lg overflow-hidden border border-base-300", children: /* @__PURE__ */ jsx("pre", { className: "bg-base-200 text-base-content p-4 overflow-x-auto text-sm font-mono whitespace-pre-wrap break-words", children: /* @__PURE__ */ jsx("code", { ...props, children: codeText2 }) }) });
50485
50487
  }
50486
50488
  return /* @__PURE__ */ jsx("code", { className: "bg-base-200 text-teal-700 px-1.5 py-0.5 rounded text-sm font-mono break-words", ...props, children });
50487
50489
  },
@@ -66191,6 +66193,7 @@ __export(services_exports, {
66191
66193
  deleteArtifact: () => deleteArtifact,
66192
66194
  deleteBookmark: () => deleteBookmark,
66193
66195
  deleteThread: () => deleteThread,
66196
+ deleteUserConversation: () => deleteUserConversation,
66194
66197
  getActions: () => getActions,
66195
66198
  getAllArtifacts: () => getAllArtifacts,
66196
66199
  getAllBookmarks: () => getAllBookmarks,
@@ -66330,6 +66333,34 @@ function injectBundleStyles() {
66330
66333
  daisyThemes.type = "text/css";
66331
66334
  daisyThemes.href = "https://cdn.jsdelivr.net/npm/daisyui@5/themes.css";
66332
66335
  document.head.appendChild(daisyThemes);
66336
+ const codeStyles = document.createElement("style");
66337
+ codeStyles.setAttribute("data-sa-code-styles", "true");
66338
+ codeStyles.textContent = `
66339
+ .sa-code-block, .sa-code-block * {
66340
+ text-decoration: none !important;
66341
+ text-shadow: none !important;
66342
+ border: 0;
66343
+ list-style: none;
66344
+ }
66345
+ .sa-code-block pre, .sa-code-block code, .sa-code-block span {
66346
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace !important;
66347
+ line-height: 1.5 !important;
66348
+ letter-spacing: normal !important;
66349
+ }
66350
+ .sa-code-block code { background: transparent !important; }
66351
+
66352
+ /* Tailwind v4 dropped the browser default of cursor:pointer on buttons, so
66353
+ anything clickable in our components would otherwise show an arrow. */
66354
+ .sa-ui button:not(:disabled),
66355
+ .sa-ui [role="button"]:not([aria-disabled="true"]),
66356
+ .sa-ui summary,
66357
+ .sa-ui label[for],
66358
+ .sa-ui select {
66359
+ cursor: pointer;
66360
+ }
66361
+ .sa-ui button:disabled { cursor: not-allowed; }
66362
+ `;
66363
+ document.head.appendChild(codeStyles);
66333
66364
  }
66334
66365
  async function requestBundle(client, options) {
66335
66366
  injectBundleStyles();
@@ -67146,6 +67177,29 @@ async function deleteThread(client, userId, threadId, clearCache = true, timeout
67146
67177
  };
67147
67178
  }
67148
67179
  }
67180
+ async function deleteUserConversation(client, userPrompt, userId, clearCache = true, timeout = 3e4) {
67181
+ try {
67182
+ const response = await client.requestData({
67183
+ collection: "user-conversations",
67184
+ operation: "deleteByUserPrompt",
67185
+ params: { userPrompt, userId, clearCache },
67186
+ timeout
67187
+ });
67188
+ if (response.error) {
67189
+ return { success: false, error: response.error };
67190
+ }
67191
+ const data = response.data;
67192
+ if (data?.success === false) {
67193
+ return { success: false, error: data.message || "Failed to delete the message" };
67194
+ }
67195
+ return { success: true, message: data?.message, queriesDeleted: data?.queriesDeleted };
67196
+ } catch (error51) {
67197
+ return {
67198
+ success: false,
67199
+ error: error51 instanceof Error ? error51.message : "Failed to delete the message"
67200
+ };
67201
+ }
67202
+ }
67149
67203
  async function updateThreadTitle(client, userId, threadId, title, timeout = 15e3) {
67150
67204
  try {
67151
67205
  const response = await client.requestData({
@@ -67206,6 +67260,10 @@ var SuperatomClient = class {
67206
67260
  this.errorHandlers = /* @__PURE__ */ new Set();
67207
67261
  this.connectPromise = null;
67208
67262
  this.connectResolve = null;
67263
+ // Supplies a valid session token before each (re)connect — see ClientConfig.getAccessToken.
67264
+ this.getAccessToken = null;
67265
+ // Waiting for getAccessToken; the socket does not exist yet.
67266
+ this.fetchingToken = false;
67209
67267
  // Heartbeat — detects zombie sockets that readyState=OPEN can't catch.
67210
67268
  this.heartbeatInterval = null;
67211
67269
  this.pongDeadline = null;
@@ -67224,6 +67282,7 @@ var SuperatomClient = class {
67224
67282
  this.boundHandlePageShow = null;
67225
67283
  const parsed = ClientConfigSchema.parse(config2);
67226
67284
  this.config = parsed;
67285
+ this.getAccessToken = config2.getAccessToken ?? null;
67227
67286
  this.registerGlobals();
67228
67287
  }
67229
67288
  registerGlobals() {
@@ -67375,21 +67434,7 @@ var SuperatomClient = class {
67375
67434
  * callbacks so the eventual real close doesn't double-fire everything.
67376
67435
  */
67377
67436
  markAsDead(reasonMessage) {
67378
- if (this.socket) {
67379
- const dying = this.socket;
67380
- this.socket = null;
67381
- try {
67382
- dying.onopen = null;
67383
- dying.onmessage = null;
67384
- dying.onerror = null;
67385
- dying.onclose = null;
67386
- if (dying.readyState === WebSocket.OPEN || dying.readyState === WebSocket.CONNECTING) {
67387
- dying.close();
67388
- }
67389
- } catch (err) {
67390
- this.log("error", "Failed to detach dying socket:", err);
67391
- }
67392
- }
67437
+ this.discardSocket();
67393
67438
  this.stopHeartbeat();
67394
67439
  this.failPendingRequests(new Error(reasonMessage));
67395
67440
  this.disconnectionHandlers.forEach((handler) => handler());
@@ -67406,21 +67451,39 @@ var SuperatomClient = class {
67406
67451
  this.cancelReconnectTimer();
67407
67452
  this.reconnectAttempts = 0;
67408
67453
  this.shouldReconnect = true;
67409
- if (this.socket) {
67410
- try {
67411
- const old = this.socket;
67412
- this.socket = null;
67413
- if (old.readyState === WebSocket.OPEN || old.readyState === WebSocket.CONNECTING) {
67414
- old.close();
67415
- }
67416
- } catch (err) {
67417
- this.log("error", "Failed to close old socket during forceReconnect:", err);
67418
- }
67419
- }
67454
+ const wasOpen = this.discardSocket();
67420
67455
  this.stopHeartbeat();
67421
67456
  this.failPendingRequests(new Error("Connection reset"));
67457
+ if (wasOpen) this.disconnectionHandlers.forEach((handler) => handler());
67422
67458
  return this.connect();
67423
67459
  }
67460
+ /**
67461
+ * Drop the current socket without triggering its handlers: they are detached
67462
+ * first, so its eventual real close is a no-op (on Linux/Chrome that close
67463
+ * can arrive 30-60s later). Returns whether it was open.
67464
+ */
67465
+ discardSocket() {
67466
+ const old = this.socket;
67467
+ if (!old) return false;
67468
+ this.socket = null;
67469
+ const wasOpen = old.readyState === WebSocket.OPEN;
67470
+ try {
67471
+ old.onopen = null;
67472
+ old.onmessage = null;
67473
+ old.onerror = null;
67474
+ old.onclose = null;
67475
+ if (wasOpen || old.readyState === WebSocket.CONNECTING) {
67476
+ old.close();
67477
+ }
67478
+ } catch (err) {
67479
+ this.log("error", "Failed to detach old socket:", err);
67480
+ }
67481
+ return wasOpen;
67482
+ }
67483
+ /** A connection attempt is under way — fetching the session token, or the socket handshake. */
67484
+ isConnecting() {
67485
+ return this.fetchingToken || this.socket?.readyState === WebSocket.CONNECTING;
67486
+ }
67424
67487
  /**
67425
67488
  * Attach window-level listeners that catch network changes faster than
67426
67489
  * the socket's own onclose. The browser's onclose for a half-open TCP can
@@ -67442,15 +67505,18 @@ var SuperatomClient = class {
67442
67505
  this.boundHandleVisibilityChange = () => {
67443
67506
  if (typeof document === "undefined") return;
67444
67507
  if (document.visibilityState !== "visible") return;
67445
- if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
67508
+ if (this.socket?.readyState === WebSocket.OPEN) {
67509
+ this.sendHeartbeatProbe();
67510
+ } else if (this.isConnecting()) {
67511
+ return;
67512
+ } else if (this.shouldReconnect) {
67446
67513
  this.forceReconnect().catch((err) => {
67447
67514
  this.log("error", "forceReconnect from visibility failed:", err);
67448
67515
  });
67449
- } else {
67450
- this.sendHeartbeatProbe();
67451
67516
  }
67452
67517
  };
67453
- this.boundHandlePageShow = (() => {
67518
+ this.boundHandlePageShow = ((event) => {
67519
+ if (!event.persisted) return;
67454
67520
  this.forceReconnect().catch((err) => {
67455
67521
  this.log("error", "forceReconnect from pageshow failed:", err);
67456
67522
  });
@@ -67565,13 +67631,50 @@ var SuperatomClient = class {
67565
67631
  this.log("warn", "Already connected");
67566
67632
  return Promise.resolve();
67567
67633
  }
67568
- if (this.socket?.readyState === WebSocket.CONNECTING && this.connectPromise) {
67634
+ if ((this.socket?.readyState === WebSocket.CONNECTING || this.fetchingToken) && this.connectPromise) {
67569
67635
  this.log("warn", "Connection already in progress");
67570
67636
  return this.connectPromise;
67571
67637
  }
67572
67638
  this.connectPromise = new Promise((resolve) => {
67573
67639
  this.connectResolve = resolve;
67574
67640
  });
67641
+ if (this.getAccessToken) {
67642
+ void this.openWithFreshToken();
67643
+ } else {
67644
+ this.openSocket();
67645
+ }
67646
+ return this.connectPromise;
67647
+ }
67648
+ /**
67649
+ * Get a valid session token, then open the socket. The relay checks the token
67650
+ * only at handshake, so every (re)connect must present one that is still valid.
67651
+ *
67652
+ * A fatal auth failure (see SuperAtomAuthError.fatal) stops reconnecting — the
67653
+ * session reports it to the host, and retrying would only repeat it. Anything
67654
+ * else goes through the normal back-off.
67655
+ */
67656
+ async openWithFreshToken() {
67657
+ this.fetchingToken = true;
67658
+ try {
67659
+ this.config.token = await this.getAccessToken();
67660
+ } catch (error51) {
67661
+ this.fetchingToken = false;
67662
+ const err = error51 instanceof Error ? error51 : new Error("Could not get a session token");
67663
+ this.errorHandlers.forEach((handler) => handler(err));
67664
+ if (error51?.fatal) {
67665
+ this.log("error", "Sign-in failed; not reconnecting:", err.message);
67666
+ this.shouldReconnect = false;
67667
+ this.cancelReconnectTimer();
67668
+ } else {
67669
+ this.scheduleReconnect();
67670
+ }
67671
+ return;
67672
+ }
67673
+ this.fetchingToken = false;
67674
+ if (!this.shouldReconnect) return;
67675
+ this.openSocket();
67676
+ }
67677
+ openSocket() {
67575
67678
  try {
67576
67679
  this.socket = new WebSocket(this.getWebSocketUrl());
67577
67680
  this.setupSocketHandlers();
@@ -67582,7 +67685,6 @@ var SuperatomClient = class {
67582
67685
  this.errorHandlers.forEach((handler) => handler(err));
67583
67686
  this.scheduleReconnect();
67584
67687
  }
67585
- return this.connectPromise;
67586
67688
  }
67587
67689
  /**
67588
67690
  * Disconnect from WebSocket server
@@ -67606,6 +67708,7 @@ var SuperatomClient = class {
67606
67708
  const merged = { ...this.config, ...config2 };
67607
67709
  const parsed = ClientConfigSchema.parse(merged);
67608
67710
  this.config = parsed;
67711
+ if ("getAccessToken" in config2) this.getAccessToken = config2.getAccessToken ?? null;
67609
67712
  }
67610
67713
  /**
67611
67714
  * Reconnect with new configuration
@@ -68032,6 +68135,190 @@ var SuperatomClient = class {
68032
68135
  }
68033
68136
  };
68034
68137
 
68138
+ // src/auth.ts
68139
+ var DEFAULT_API_URL = "https://sa-api.superatom.ai";
68140
+ var SuperAtomAuthError = class extends Error {
68141
+ constructor(code4, message, options) {
68142
+ super(message);
68143
+ this.name = "SuperAtomAuthError";
68144
+ this.code = code4;
68145
+ this.status = options.status;
68146
+ this.fatal = options.fatal;
68147
+ if (options.cause !== void 0) this.cause = options.cause;
68148
+ }
68149
+ };
68150
+ var MIN_REMAINING_MS = 6e4;
68151
+ var RENEW_AHEAD_MS = 12e4;
68152
+ var RENEW_RETRY_MS = 3e4;
68153
+ var RETRIES_BEFORE_REPORTING = 2;
68154
+ var EXCHANGE_TIMEOUT_MS = 15e3;
68155
+ function expiryOf(token) {
68156
+ try {
68157
+ const payload = token.split(".")[1];
68158
+ if (!payload) return null;
68159
+ const json3 = JSON.parse(atob(payload.replace(/-/g, "+").replace(/_/g, "/")));
68160
+ return typeof json3.exp === "number" ? json3.exp * 1e3 : null;
68161
+ } catch {
68162
+ return null;
68163
+ }
68164
+ }
68165
+ var SdkSession = class {
68166
+ constructor(opts) {
68167
+ this.token = null;
68168
+ this.expiresAt = 0;
68169
+ this.currentUser = null;
68170
+ /** The one renewal in flight — every caller shares it. */
68171
+ this.inFlight = null;
68172
+ this.fatalError = null;
68173
+ /** Retryable failures in a row; reset by a successful exchange. */
68174
+ this.retries = 0;
68175
+ this.renewTimer = null;
68176
+ this.stopped = false;
68177
+ this.opts = opts;
68178
+ this.apiUrl = (opts.apiUrl || DEFAULT_API_URL).replace(/\/+$/, "");
68179
+ }
68180
+ get user() {
68181
+ return this.currentUser;
68182
+ }
68183
+ /** The fatal error that stopped the session, if any. */
68184
+ get error() {
68185
+ return this.fatalError;
68186
+ }
68187
+ /**
68188
+ * A token with at least a minute left — the cached one, or a fresh exchange.
68189
+ * Rejects with SuperAtomAuthError.
68190
+ */
68191
+ getAccessToken() {
68192
+ if (this.fatalError) return Promise.reject(this.fatalError);
68193
+ if (this.token && this.expiresAt - Date.now() > MIN_REMAINING_MS) {
68194
+ return Promise.resolve(this.token);
68195
+ }
68196
+ return this.renew();
68197
+ }
68198
+ /** Clear a fatal error so the next getAccessToken() tries again (e.g. after the user signs in again). */
68199
+ reset() {
68200
+ this.fatalError = null;
68201
+ this.stopped = false;
68202
+ }
68203
+ /** Stop renewing — the host unmounted or disconnected. */
68204
+ stop() {
68205
+ this.stopped = true;
68206
+ this.clearRenewTimer();
68207
+ }
68208
+ renew() {
68209
+ if (!this.inFlight) {
68210
+ this.inFlight = this.exchange().finally(() => {
68211
+ this.inFlight = null;
68212
+ });
68213
+ }
68214
+ return this.inFlight;
68215
+ }
68216
+ async exchange() {
68217
+ let customerToken;
68218
+ try {
68219
+ customerToken = await this.opts.getToken();
68220
+ } catch (err) {
68221
+ throw this.fail(new SuperAtomAuthError("get_token_failed", "getToken() failed", { fatal: true, cause: err }));
68222
+ }
68223
+ if (typeof customerToken !== "string" || !customerToken.trim()) {
68224
+ throw this.fail(new SuperAtomAuthError("get_token_failed", "getToken() returned no token", { fatal: true }));
68225
+ }
68226
+ const controller = new AbortController();
68227
+ const timeout = setTimeout(() => controller.abort(), EXCHANGE_TIMEOUT_MS);
68228
+ let res;
68229
+ try {
68230
+ res = await fetch(`${this.apiUrl}/auth/sdk/exchange`, {
68231
+ method: "POST",
68232
+ headers: { "Content-Type": "application/json" },
68233
+ body: JSON.stringify({ projectId: this.opts.projectId, token: customerToken.trim() }),
68234
+ signal: controller.signal
68235
+ });
68236
+ } catch (err) {
68237
+ throw this.fail(new SuperAtomAuthError("network", "Could not reach Superatom to sign in", { fatal: false, cause: err }));
68238
+ } finally {
68239
+ clearTimeout(timeout);
68240
+ }
68241
+ const body = await res.json().catch(() => ({}));
68242
+ if (!res.ok) {
68243
+ const message = typeof body?.error === "string" ? body.error : `Sign-in failed (${res.status})`;
68244
+ const fatal = res.status >= 400 && res.status < 500 && res.status !== 429;
68245
+ throw this.fail(
68246
+ new SuperAtomAuthError(fatal ? "exchange_rejected" : "exchange_unavailable", message, { status: res.status, fatal })
68247
+ );
68248
+ }
68249
+ if (typeof body?.token !== "string" || !body.user?.id) {
68250
+ throw this.fail(
68251
+ new SuperAtomAuthError("exchange_unavailable", "Unexpected sign-in response", { status: res.status, fatal: false })
68252
+ );
68253
+ }
68254
+ if (Array.isArray(body.warnings)) {
68255
+ for (const w of body.warnings) console.warn("[SuperAtom] Sign-in warning:", w);
68256
+ }
68257
+ this.token = body.token;
68258
+ this.expiresAt = expiryOf(body.token) ?? Date.now() + 15 * 6e4;
68259
+ this.currentUser = {
68260
+ id: body.user.id,
68261
+ email: body.user.email,
68262
+ name: body.user.name,
68263
+ role: body.user.role,
68264
+ externalRoles: Array.isArray(body.user.externalRoles) ? body.user.externalRoles : []
68265
+ };
68266
+ this.log(`Signed in as ${this.currentUser.email}; token valid until ${new Date(this.expiresAt).toISOString()}`);
68267
+ if (this.retries) {
68268
+ this.retries = 0;
68269
+ this.opts.onRetrying?.(null);
68270
+ }
68271
+ this.opts.onSession?.(this.currentUser);
68272
+ this.scheduleRenew(this.expiresAt - RENEW_AHEAD_MS - Date.now());
68273
+ return body.token;
68274
+ }
68275
+ /** Record a failure: a fatal one stops the session and is reported once. */
68276
+ fail(error51) {
68277
+ if (error51.fatal) {
68278
+ this.fatalError = error51;
68279
+ this.clearRenewTimer();
68280
+ console.error(`[SuperAtom] Sign-in failed: ${error51.message}`, error51);
68281
+ try {
68282
+ this.opts.onAuthError?.(error51);
68283
+ } catch (err) {
68284
+ console.error("[SuperAtom] onAuthError threw:", err);
68285
+ }
68286
+ } else {
68287
+ this.retries++;
68288
+ if (this.retries === RETRIES_BEFORE_REPORTING) {
68289
+ console.warn(`[SuperAtom] ${error51.message} (${this.apiUrl}) \u2014 retrying`);
68290
+ }
68291
+ if (this.retries >= RETRIES_BEFORE_REPORTING) this.opts.onRetrying?.(error51);
68292
+ this.log(`Sign-in attempt failed, will retry: ${error51.message}`);
68293
+ this.scheduleRenew(RENEW_RETRY_MS);
68294
+ }
68295
+ return error51;
68296
+ }
68297
+ /**
68298
+ * Renew in the background ahead of expiry. Timers are paused while the machine
68299
+ * sleeps and fire on wake; a reconnect after wake also renews first if needed.
68300
+ */
68301
+ scheduleRenew(inMs) {
68302
+ this.clearRenewTimer();
68303
+ if (this.stopped || this.fatalError) return;
68304
+ this.renewTimer = setTimeout(() => {
68305
+ this.renewTimer = null;
68306
+ if (this.stopped || this.fatalError) return;
68307
+ this.renew().catch(() => {
68308
+ });
68309
+ }, Math.max(inMs, 5e3));
68310
+ }
68311
+ clearRenewTimer() {
68312
+ if (this.renewTimer) {
68313
+ clearTimeout(this.renewTimer);
68314
+ this.renewTimer = null;
68315
+ }
68316
+ }
68317
+ log(message) {
68318
+ if (this.opts.debug) console.log(`[SuperAtom] ${message}`);
68319
+ }
68320
+ };
68321
+
68035
68322
  // src/setup.ts
68036
68323
  function setup(components) {
68037
68324
  if (typeof window === "undefined") {
@@ -68668,13 +68955,13 @@ var ExpressionEvaluator = class {
68668
68955
  resolveDataPath(path2, data) {
68669
68956
  if (!path2 || !data) return void 0;
68670
68957
  try {
68671
- return path2.split(".").reduce((current, key) => {
68672
- if (current === null || current === void 0) return void 0;
68958
+ return path2.split(".").reduce((current3, key) => {
68959
+ if (current3 === null || current3 === void 0) return void 0;
68673
68960
  if (!isNaN(Number(key))) {
68674
68961
  const index2 = parseInt(key, 10);
68675
- return Array.isArray(current) ? current[index2] : current;
68962
+ return Array.isArray(current3) ? current3[index2] : current3;
68676
68963
  }
68677
- return current[key];
68964
+ return current3[key];
68678
68965
  }, data);
68679
68966
  } catch (error51) {
68680
68967
  console.warn("Error resolving data path:", path2, error51);
@@ -69153,6 +69440,71 @@ function resetRegistration() {
69153
69440
  registeredKeys.forEach((key) => delete COMP_REGISTRY[key]);
69154
69441
  registeredKeys.clear();
69155
69442
  }
69443
+ var current = null;
69444
+ var retrying = null;
69445
+ var listeners = /* @__PURE__ */ new Set();
69446
+ function setAuthStatus(error51) {
69447
+ if (current === error51) return;
69448
+ current = error51;
69449
+ if (error51) retrying = null;
69450
+ listeners.forEach((l) => l());
69451
+ }
69452
+ function setRetryingStatus(error51) {
69453
+ if (retrying === error51) return;
69454
+ retrying = error51;
69455
+ listeners.forEach((l) => l());
69456
+ }
69457
+ function useRetryingStatus() {
69458
+ return useSyncExternalStore(
69459
+ (l) => {
69460
+ listeners.add(l);
69461
+ return () => listeners.delete(l);
69462
+ },
69463
+ () => retrying,
69464
+ () => null
69465
+ );
69466
+ }
69467
+ function useAuthStatus() {
69468
+ return useSyncExternalStore(
69469
+ (l) => {
69470
+ listeners.add(l);
69471
+ return () => listeners.delete(l);
69472
+ },
69473
+ () => current,
69474
+ () => null
69475
+ );
69476
+ }
69477
+ function authStatusMessage(error51) {
69478
+ switch (error51.code) {
69479
+ case "get_token_failed":
69480
+ return "Your session has ended. Please sign in again to continue.";
69481
+ case "exchange_rejected":
69482
+ return error51.status === 403 ? "This account cannot use the chat. Please contact your administrator." : "Your session is no longer valid. Please sign in again to continue.";
69483
+ default:
69484
+ return "Could not connect to Superatom. Please try again in a moment.";
69485
+ }
69486
+ }
69487
+ function retryingStatusMessage(error51) {
69488
+ return error51.code === "network" ? "Cannot reach Superatom \u2014 retrying\u2026" : "Superatom is not responding \u2014 retrying\u2026";
69489
+ }
69490
+ var current2 = {};
69491
+ var listeners2 = /* @__PURE__ */ new Set();
69492
+ function setMessageActions(actions) {
69493
+ current2 = actions;
69494
+ listeners2.forEach((l) => l());
69495
+ }
69496
+ function useMessageActions() {
69497
+ return useSyncExternalStore(
69498
+ (l) => {
69499
+ listeners2.add(l);
69500
+ return () => listeners2.delete(l);
69501
+ },
69502
+ () => current2,
69503
+ () => current2
69504
+ );
69505
+ }
69506
+
69507
+ // src/ui/hooks/useSuperAtom.ts
69156
69508
  function newThreadId() {
69157
69509
  return `thread_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
69158
69510
  }
@@ -69312,17 +69664,40 @@ function buildResponseIssueSchema(response, messageId) {
69312
69664
  var MAX_ABORTED_TRACKED = 100;
69313
69665
  var THREADS_LIMIT = 50;
69314
69666
  var THREAD_MESSAGES_LIMIT = 50;
69315
- function useSuperAtom({ token, userId, projectId, debug = false, streaming = false }) {
69316
- const resolvedUserId = (() => {
69667
+ function useSuperAtom({
69668
+ token,
69669
+ userId,
69670
+ projectId,
69671
+ getToken,
69672
+ onAuthError,
69673
+ apiUrl,
69674
+ wsUrl,
69675
+ debug = false,
69676
+ streaming = false
69677
+ }) {
69678
+ const sdkSignIn = !!getToken;
69679
+ if (sdkSignIn && token) throw new Error("[SuperAtom] Pass either token or getToken, not both");
69680
+ const [user, setUser] = useState(null);
69681
+ const [authError, setAuthError] = useState(null);
69682
+ const [signInAttempt, setSignInAttempt] = useState(0);
69683
+ const directUserId = (() => {
69684
+ if (sdkSignIn) return void 0;
69317
69685
  if (token) {
69318
69686
  const payload = decodeJWT(token);
69319
69687
  const id = payload.sub ?? payload.userId;
69320
69688
  if (!id) throw new Error("[SuperAtom] JWT decoded but no userId or sub field found in payload");
69321
69689
  return id;
69322
69690
  }
69323
- if (!userId) throw new Error("[SuperAtom] Either token or userId must be provided");
69691
+ if (!userId) throw new Error("[SuperAtom] Either token, getToken or userId must be provided");
69324
69692
  return userId;
69325
69693
  })();
69694
+ const resolvedUserId = directUserId ?? user?.id ?? "";
69695
+ const getTokenRef = useRef(getToken);
69696
+ getTokenRef.current = getToken;
69697
+ const onAuthErrorRef = useRef(onAuthError);
69698
+ onAuthErrorRef.current = onAuthError;
69699
+ const sessionRef = useRef(null);
69700
+ const setupDoneRef = useRef(false);
69326
69701
  const clientRef = useRef(null);
69327
69702
  const tokenRef = useRef(token);
69328
69703
  tokenRef.current = token;
@@ -69349,7 +69724,54 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
69349
69724
  injectBundleStyles();
69350
69725
  const timeoutId = setTimeout(async () => {
69351
69726
  if (cancelled) return;
69352
- const client = new SuperatomClient({ userId: resolvedUserId, projectId, type: "runtime", debug, token: tokenRef.current });
69727
+ let clientUserId = directUserId;
69728
+ let session = null;
69729
+ if (sdkSignIn) {
69730
+ session = new SdkSession({
69731
+ projectId,
69732
+ apiUrl,
69733
+ debug,
69734
+ getToken: () => getTokenRef.current(),
69735
+ onAuthError: (err) => {
69736
+ setAuthError(err);
69737
+ setAuthStatus(err);
69738
+ onAuthErrorRef.current?.(err);
69739
+ },
69740
+ onSession: (u) => {
69741
+ setAuthError(null);
69742
+ setAuthStatus(null);
69743
+ setUser(u);
69744
+ },
69745
+ // Superatom unreachable or down, after a couple of tries: say so in the
69746
+ // chat instead of sitting on "Connecting…".
69747
+ onRetrying: (err) => setRetryingStatus(err)
69748
+ });
69749
+ sessionRef.current = session;
69750
+ for (let delay = 1e3; ; delay = Math.min(delay * 2, 3e4)) {
69751
+ try {
69752
+ await session.getAccessToken();
69753
+ break;
69754
+ } catch (err) {
69755
+ if (cancelled || err?.fatal) return;
69756
+ await new Promise((r2) => setTimeout(r2, delay));
69757
+ if (cancelled) return;
69758
+ }
69759
+ }
69760
+ if (cancelled) {
69761
+ session.stop();
69762
+ return;
69763
+ }
69764
+ clientUserId = session.user.id;
69765
+ }
69766
+ const activeSession = session;
69767
+ const client = new SuperatomClient({
69768
+ userId: clientUserId,
69769
+ projectId,
69770
+ type: "runtime",
69771
+ debug,
69772
+ ...wsUrl ? { baseUrl: wsUrl } : {},
69773
+ ...activeSession ? { getAccessToken: () => activeSession.getAccessToken() } : { token: tokenRef.current }
69774
+ });
69353
69775
  clientRef.current = client;
69354
69776
  client.onError((err) => console.error("[SuperAtom] Error:", err));
69355
69777
  try {
@@ -69366,11 +69788,11 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
69366
69788
  };
69367
69789
  const unsub = client.onConnect(done);
69368
69790
  const cancelPoll = setInterval(() => {
69369
- if (cancelled) done();
69791
+ if (cancelled || activeSession?.error) done();
69370
69792
  }, 50);
69371
69793
  });
69372
- if (cancelled) {
69373
- client.disconnect();
69794
+ if (cancelled || activeSession?.error) {
69795
+ if (cancelled) client.disconnect();
69374
69796
  return;
69375
69797
  }
69376
69798
  window.dispatchEvent(new CustomEvent("sa:client-connected"));
@@ -69446,7 +69868,10 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
69446
69868
  ]);
69447
69869
  };
69448
69870
  }
69449
- if (!cancelled) setBundleReady(true);
69871
+ if (!cancelled) {
69872
+ setupDoneRef.current = true;
69873
+ setBundleReady(true);
69874
+ }
69450
69875
  } catch (err) {
69451
69876
  console.error("[SuperAtom] Setup failed:", err);
69452
69877
  }
@@ -69460,9 +69885,25 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
69460
69885
  }
69461
69886
  clientRef.current?.disconnect();
69462
69887
  clientRef.current = null;
69888
+ sessionRef.current?.stop();
69889
+ sessionRef.current = null;
69890
+ setAuthStatus(null);
69891
+ setupDoneRef.current = false;
69463
69892
  setBundleReady(false);
69464
69893
  };
69465
- }, [resolvedUserId, projectId, debug]);
69894
+ }, [directUserId, sdkSignIn, projectId, apiUrl, wsUrl, debug, signInAttempt]);
69895
+ const reconnect = useCallback(() => {
69896
+ const session = sessionRef.current;
69897
+ const client = clientRef.current;
69898
+ session?.reset();
69899
+ setAuthError(null);
69900
+ setAuthStatus(null);
69901
+ if (client && setupDoneRef.current) {
69902
+ client.forceReconnect().catch((err) => console.error("[SuperAtom] Reconnect failed:", err));
69903
+ } else {
69904
+ setSignInAttempt((n) => n + 1);
69905
+ }
69906
+ }, []);
69466
69907
  const sendMessage = useCallback(async () => {
69467
69908
  const text9 = input.trim();
69468
69909
  const client = clientRef.current;
@@ -69854,6 +70295,39 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
69854
70295
  if (threadId.current === id) newChat();
69855
70296
  return { success: true };
69856
70297
  }, [resolvedUserId, newChat]);
70298
+ const deleteMessage = useCallback(async (messageId) => {
70299
+ const client = clientRef.current;
70300
+ if (!client) return { success: false, error: "Not connected" };
70301
+ const list4 = messagesRef.current;
70302
+ const index2 = list4.findIndex((m) => m.id === messageId);
70303
+ if (index2 === -1) return { success: false, error: "Message not found" };
70304
+ let questionIndex = list4[index2]?.role === "user" ? index2 : -1;
70305
+ if (questionIndex === -1) {
70306
+ for (let i = index2 - 1; i >= 0; i--) {
70307
+ if (list4[i]?.role === "user") {
70308
+ questionIndex = i;
70309
+ break;
70310
+ }
70311
+ }
70312
+ }
70313
+ const question = questionIndex >= 0 ? list4[questionIndex]?.text ?? "" : "";
70314
+ if (!question.trim()) return { success: false, error: "Could not find the question for this answer" };
70315
+ const res = await deleteUserConversation(client, question, resolvedUserId);
70316
+ if (!res.success) return res;
70317
+ const removed = /* @__PURE__ */ new Set();
70318
+ for (let i = questionIndex; i < list4.length; i++) {
70319
+ const msg = list4[i];
70320
+ if (!msg) continue;
70321
+ if (i > questionIndex && msg.role === "user") break;
70322
+ removed.add(msg.id);
70323
+ }
70324
+ setMessages((prev) => prev.filter((m) => !removed.has(m.id)));
70325
+ return { success: true };
70326
+ }, [resolvedUserId]);
70327
+ useEffect(() => {
70328
+ setMessageActions({ deleteMessage });
70329
+ return () => setMessageActions({});
70330
+ }, [deleteMessage]);
69857
70331
  const renameThread = useCallback(async (id, title) => {
69858
70332
  const client = clientRef.current;
69859
70333
  if (!client) return { success: false, error: "Not connected" };
@@ -69877,7 +70351,11 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
69877
70351
  isLoadingThread,
69878
70352
  refreshThreads,
69879
70353
  deleteThread: deleteThread2,
69880
- renameThread
70354
+ renameThread,
70355
+ isNewChat: bundleReady && !isLoadingThread && messages2.length === 0,
70356
+ user,
70357
+ authError,
70358
+ reconnect
69881
70359
  };
69882
70360
  }
69883
70361
 
@@ -69973,6 +70451,8 @@ function ChatInput({
69973
70451
  isResponding = false,
69974
70452
  onStop
69975
70453
  }) {
70454
+ const authError = useAuthStatus();
70455
+ const isLocked = disabled || !!authError;
69976
70456
  const textareaRef = useRef(null);
69977
70457
  const historyRef = useRef(null);
69978
70458
  const [isMultiline, setIsMultiline] = useState(false);
@@ -70026,14 +70506,15 @@ function ChatInput({
70026
70506
  }, 0);
70027
70507
  };
70028
70508
  const handleSend = useCallback(() => {
70029
- if (!input.trim() || disabled) return;
70509
+ if (!input.trim() || isLocked) return;
70030
70510
  const history = getOrCreateHistory();
70031
70511
  history?.addCommand(input.trim());
70032
70512
  history?.resetNavigation();
70033
70513
  onSend();
70034
- }, [input, disabled, onSend, getOrCreateHistory]);
70514
+ }, [input, isLocked, onSend, getOrCreateHistory]);
70035
70515
  const themeColor = getThemeColor();
70036
- return /* @__PURE__ */ jsx("div", { className: `shrink-0 bg-base-100 border-t border-base-300 px-4 py-2 ${className}`, children: /* @__PURE__ */ jsx("div", { className: `group ${isMultiline ? "rounded-3xl" : "rounded-full"} bg-base-200 transition-all duration-200 w-full max-w-2xl mx-auto`, children: /* @__PURE__ */ jsx(
70516
+ const effectivePlaceholder = authError ? authStatusMessage(authError) : placeholder;
70517
+ return /* @__PURE__ */ jsx("div", { className: `sa-ui shrink-0 bg-base-100 border-t border-base-300 px-4 py-2 ${className}`, children: /* @__PURE__ */ jsx("div", { className: `group ${isMultiline ? "rounded-3xl" : "rounded-full"} bg-base-200 transition-all duration-200 w-full max-w-2xl mx-auto`, children: /* @__PURE__ */ jsx(
70037
70518
  "div",
70038
70519
  {
70039
70520
  className: `flex flex-col ${isMultiline ? "rounded-3xl" : "rounded-full"} border-2 shadow-sm transition-all duration-200 hover:shadow-md`,
@@ -70053,7 +70534,7 @@ function ChatInput({
70053
70534
  autoCapitalize: "off",
70054
70535
  ref: textareaRef,
70055
70536
  value: input,
70056
- placeholder,
70537
+ placeholder: effectivePlaceholder,
70057
70538
  onChange: (e) => setInput(e.currentTarget.value),
70058
70539
  onBlur: () => setIsFocused(false),
70059
70540
  onFocus: () => setIsFocused(true),
@@ -70084,7 +70565,7 @@ function ChatInput({
70084
70565
  },
70085
70566
  rows: 1,
70086
70567
  className: "textarea textarea-ghost w-full focus:outline-none focus:bg-transparent min-h-[40px] resize-none overflow-y-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]",
70087
- disabled,
70568
+ disabled: isLocked,
70088
70569
  style: { maxHeight: "200px" }
70089
70570
  }
70090
70571
  ),
@@ -70106,11 +70587,11 @@ function ChatInput({
70106
70587
  "button",
70107
70588
  {
70108
70589
  onClick: handleSend,
70109
- disabled: !input.trim() || disabled,
70590
+ disabled: !input.trim() || isLocked,
70110
70591
  className: `transition-colors duration-150 rounded-full p-2 flex-shrink-0 ${isMultiline ? "mb-1" : ""} disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-transparent disabled:text-base-content/40`,
70111
70592
  style: {
70112
- backgroundColor: input.trim() && !disabled ? themeColor : "transparent",
70113
- color: input.trim() && !disabled ? "white" : themeColor
70593
+ backgroundColor: input.trim() && !isLocked ? themeColor : "transparent",
70594
+ color: input.trim() && !isLocked ? "white" : themeColor
70114
70595
  },
70115
70596
  children: /* @__PURE__ */ jsx(Icon, { icon: "ph:paper-plane-right-fill", width: 20, height: 20, className: "sm:w-6 sm:h-6" })
70116
70597
  }
@@ -70126,6 +70607,86 @@ init_iconify();
70126
70607
  // src/ui/components/MessageBubble.tsx
70127
70608
  init_iconify();
70128
70609
  init_Markdown();
70610
+
70611
+ // src/ui/components/ConfirmDeleteModal.tsx
70612
+ init_iconify();
70613
+ function ConfirmDeleteModal({
70614
+ isOpen,
70615
+ onClose,
70616
+ onConfirm,
70617
+ isDeleting,
70618
+ title = "Delete",
70619
+ message = "Are you sure you want to delete this?"
70620
+ }) {
70621
+ useEffect(() => {
70622
+ if (!isOpen) return;
70623
+ const handleEscape = (e) => {
70624
+ if (e.key === "Escape" && !isDeleting) {
70625
+ onClose();
70626
+ }
70627
+ };
70628
+ document.addEventListener("keydown", handleEscape);
70629
+ document.body.style.overflow = "hidden";
70630
+ return () => {
70631
+ document.removeEventListener("keydown", handleEscape);
70632
+ document.body.style.overflow = "unset";
70633
+ };
70634
+ }, [isOpen, onClose, isDeleting]);
70635
+ const handleBackdropClick = (e) => {
70636
+ if (e.target === e.currentTarget && !isDeleting) {
70637
+ onClose();
70638
+ }
70639
+ };
70640
+ if (!isOpen) return null;
70641
+ return createPortal(
70642
+ /* @__PURE__ */ jsx(
70643
+ "div",
70644
+ {
70645
+ className: "sa-ui fixed inset-0 flex items-center justify-center bg-black/50 backdrop-blur-sm",
70646
+ style: { zIndex: 9999 },
70647
+ onClick: handleBackdropClick,
70648
+ children: /* @__PURE__ */ jsxs("div", { className: "bg-base-100 rounded-xl shadow-2xl w-full max-w-sm mx-4 overflow-hidden", children: [
70649
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border-b border-base-300", children: [
70650
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-base-content", children: title }),
70651
+ /* @__PURE__ */ jsx(
70652
+ "button",
70653
+ {
70654
+ type: "button",
70655
+ disabled: isDeleting,
70656
+ onClick: onClose,
70657
+ className: "p-1 rounded-lg hover:bg-base-200 transition-colors",
70658
+ children: /* @__PURE__ */ jsx(Icon, { icon: "ph:x-bold", width: 20, height: 20, className: "text-base-content/60" })
70659
+ }
70660
+ )
70661
+ ] }),
70662
+ /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx("p", { className: "text-base-content/80", children: message }) }),
70663
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 p-4 border-t border-base-300", children: [
70664
+ /* @__PURE__ */ jsx(
70665
+ "button",
70666
+ {
70667
+ type: "button",
70668
+ onClick: onClose,
70669
+ disabled: isDeleting,
70670
+ className: "px-4 py-2 rounded-lg text-base-content hover:bg-base-200 transition-colors",
70671
+ children: "Cancel"
70672
+ }
70673
+ ),
70674
+ isDeleting ? /* @__PURE__ */ jsx("div", { className: "min-w-20 px-4 py-2 rounded-lg bg-red-600 text-white flex items-center justify-center", children: /* @__PURE__ */ jsx(Icon, { icon: "eos-icons:loading", width: 20, height: 20, className: "animate-spin" }) }) : /* @__PURE__ */ jsx(
70675
+ "button",
70676
+ {
70677
+ type: "button",
70678
+ onClick: onConfirm,
70679
+ className: "min-w-20 px-4 py-2 rounded-lg bg-red-600 text-white hover:bg-red-700 transition-colors",
70680
+ children: "Delete"
70681
+ }
70682
+ )
70683
+ ] })
70684
+ ] })
70685
+ }
70686
+ ),
70687
+ document.body
70688
+ );
70689
+ }
70129
70690
  function StopButton({ onStop }) {
70130
70691
  return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(
70131
70692
  "button",
@@ -70151,17 +70712,40 @@ function MessageBubble({ message, onStop }) {
70151
70712
  const isTextOnly = message.isTextOnlyResponse === true;
70152
70713
  const isAborted = message.aborted === true;
70153
70714
  const responseComplete = hasComponent || isTextOnly || !isStreaming && hasText;
70715
+ const [watchedGeneration] = useState(() => !responseComplete);
70154
70716
  useEffect(() => {
70155
- if (message.role !== "assistant") return;
70156
- startTime.current = Date.now();
70717
+ if (message.role !== "assistant" || !watchedGeneration) return;
70157
70718
  if (responseComplete) {
70158
70719
  setElapsedMs(Date.now() - startTime.current);
70159
70720
  return;
70160
70721
  }
70722
+ setElapsedMs(Date.now() - startTime.current);
70161
70723
  const interval = setInterval(() => setElapsedMs(Date.now() - startTime.current), 100);
70162
70724
  return () => clearInterval(interval);
70163
- }, [message.role, responseComplete]);
70725
+ }, [message.role, responseComplete, watchedGeneration]);
70164
70726
  const formatMs = (ms) => ms < 1e3 ? `${ms}ms` : `${(ms / 1e3).toFixed(1)}s`;
70727
+ const { deleteMessage } = useMessageActions();
70728
+ const [confirmOpen, setConfirmOpen] = useState(false);
70729
+ const [isDeleting, setIsDeleting] = useState(false);
70730
+ const handleDelete2 = async () => {
70731
+ if (!deleteMessage) return;
70732
+ setIsDeleting(true);
70733
+ const res = await deleteMessage(message.id);
70734
+ setIsDeleting(false);
70735
+ setConfirmOpen(false);
70736
+ if (!res.success) console.error("[SuperAtom] Could not delete the message:", res.error);
70737
+ };
70738
+ const deleteButton = deleteMessage && responseComplete && !isAborted ? /* @__PURE__ */ jsx("div", { className: "flex justify-end mt-2", children: /* @__PURE__ */ jsx(
70739
+ "button",
70740
+ {
70741
+ onClick: () => setConfirmOpen(true),
70742
+ disabled: isDeleting,
70743
+ title: "Delete this answer",
70744
+ "aria-label": "Delete this answer",
70745
+ className: "cursor-pointer p-2 rounded-lg shadow-md bg-base-100 text-base-content/40 hover:text-red-500 hover:shadow-lg transition-colors duration-150 disabled:opacity-50 disabled:cursor-wait",
70746
+ children: /* @__PURE__ */ jsx("svg", { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) })
70747
+ }
70748
+ ) }) : null;
70165
70749
  const accordionHeader = useMemo(() => {
70166
70750
  if (isAborted) return hasText ? "Stopped" : "Stopped (no response yet)";
70167
70751
  if (!hasText) return "Thinking...";
@@ -70197,7 +70781,7 @@ function MessageBubble({ message, onStop }) {
70197
70781
  children: [
70198
70782
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-base-content truncate text-left flex-1", children: accordionHeader }),
70199
70783
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 shrink-0", children: [
70200
- !message.fromHistory && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-teal-50 border border-teal-200", children: [
70784
+ !message.fromHistory && watchedGeneration && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-teal-50 border border-teal-200", children: [
70201
70785
  responseComplete ? /* @__PURE__ */ jsx("svg", { className: "text-teal-600", width: 12, height: 12, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" }) }) : /* @__PURE__ */ jsx("span", { className: "loading loading-spinner loading-xs text-teal-600" }),
70202
70786
  /* @__PURE__ */ jsx("span", { className: "text-xs text-teal-700 font-medium font-mono", children: formatMs(elapsedMs) })
70203
70787
  ] }),
@@ -70247,8 +70831,25 @@ function MessageBubble({ message, onStop }) {
70247
70831
  /* @__PURE__ */ jsx("span", { className: "text-sm text-base-content/70", children: "Generating component..." })
70248
70832
  ] })
70249
70833
  ] }) }),
70250
- hasComponent && /* @__PURE__ */ jsx("div", { id: `box-${message.id}`, className: "w-full px-4 lg:px-16 xl:px-24 2xl:px-32", children: /* @__PURE__ */ jsx("div", { className: "rounded-xl shadow-sm bg-base-100 border-2 border-base-300 min-h-[85vh] overflow-auto flex items-center justify-center p-5", children: /* @__PURE__ */ jsx(DSLRenderer, { dsl: message.schema.ui, data: message.schema.data ?? {} }) }) }),
70251
- !isStreaming && !hasComponent && hasText && isTextOnly && !isAborted && /* @__PURE__ */ jsx("div", { className: "flex justify-center w-full px-4", children: /* @__PURE__ */ jsx("div", { className: "w-full md:w-[60vw]", children: /* @__PURE__ */ jsx("div", { className: "rounded-xl shadow-sm bg-base-100 border-2 border-base-300 p-4 text-base-content", children: /* @__PURE__ */ jsx(Markdown_default, { content: fullText, isStreaming: false }) }) }) })
70834
+ hasComponent && /* @__PURE__ */ jsxs("div", { id: `box-${message.id}`, className: "w-full px-4 lg:px-16 xl:px-24 2xl:px-32", children: [
70835
+ /* @__PURE__ */ jsx("div", { className: "rounded-xl shadow-sm bg-base-100 border-2 border-base-300 min-h-[85vh] overflow-auto flex items-center justify-center p-5", children: /* @__PURE__ */ jsx(DSLRenderer, { dsl: message.schema.ui, data: message.schema.data ?? {} }) }),
70836
+ deleteButton
70837
+ ] }),
70838
+ !isStreaming && !hasComponent && hasText && isTextOnly && !isAborted && /* @__PURE__ */ jsx("div", { className: "flex justify-center w-full px-4", children: /* @__PURE__ */ jsxs("div", { className: "w-full md:w-[60vw]", children: [
70839
+ /* @__PURE__ */ jsx("div", { className: "rounded-xl shadow-sm bg-base-100 border-2 border-base-300 p-4 text-base-content", children: /* @__PURE__ */ jsx(Markdown_default, { content: fullText, isStreaming: false }) }),
70840
+ deleteButton
70841
+ ] }) }),
70842
+ /* @__PURE__ */ jsx(
70843
+ ConfirmDeleteModal,
70844
+ {
70845
+ isOpen: confirmOpen,
70846
+ onClose: () => setConfirmOpen(false),
70847
+ onConfirm: handleDelete2,
70848
+ isDeleting,
70849
+ title: "Delete this answer?",
70850
+ message: "The question and its answer are removed from this chat and from your history. Anything cached for it is cleared too, so asking again re-runs it."
70851
+ }
70852
+ )
70252
70853
  ] });
70253
70854
  }
70254
70855
  function DynamicSpacer({ messages: messages2 }) {
@@ -70262,6 +70863,7 @@ function MessageList({
70262
70863
  bundleReady,
70263
70864
  connectingText = "Connecting to SuperAtom...",
70264
70865
  emptyText = "Start a conversation",
70866
+ emptyState,
70265
70867
  className = "",
70266
70868
  isResponding = false,
70267
70869
  onStop,
@@ -70345,11 +70947,16 @@ function MessageList({
70345
70947
  }
70346
70948
  }, 300);
70347
70949
  }, [messages2]);
70348
- return /* @__PURE__ */ jsxs("div", { className: `flex-1 relative overflow-hidden ${className}`, children: [
70349
- /* @__PURE__ */ jsx("main", { ref: containerRef, className: "h-full overflow-y-auto py-6", children: !bundleReady || isLoadingThread && messages2.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col items-center justify-center gap-3 text-base-content/50", children: [
70950
+ const authError = useAuthStatus();
70951
+ const retrying2 = useRetryingStatus();
70952
+ return /* @__PURE__ */ jsxs("div", { className: `sa-ui flex-1 relative overflow-hidden ${className}`, children: [
70953
+ /* @__PURE__ */ jsx("main", { ref: containerRef, className: "h-full overflow-y-auto py-6", children: authError ? /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col items-center justify-center gap-3 px-6 text-center", children: [
70954
+ /* @__PURE__ */ jsx(Icon, { icon: "mdi:lock-alert-outline", width: 28, height: 28, className: "text-base-content/40" }),
70955
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-base-content/70 max-w-sm", children: authStatusMessage(authError) })
70956
+ ] }) : !bundleReady || isLoadingThread && messages2.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col items-center justify-center gap-3 text-base-content/50", children: [
70350
70957
  /* @__PURE__ */ jsx("span", { className: "loading loading-spinner loading-md" }),
70351
- /* @__PURE__ */ jsx("span", { className: "text-sm", children: !bundleReady ? connectingText : loadingThreadText })
70352
- ] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
70958
+ /* @__PURE__ */ jsx("span", { className: "text-sm", children: !bundleReady ? retrying2 ? retryingStatusMessage(retrying2) : connectingText : loadingThreadText })
70959
+ ] }) : messages2.length === 0 && emptyState ? /* @__PURE__ */ jsx("div", { className: "h-full flex flex-col", children: emptyState }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
70353
70960
  messages2.length === 0 && /* @__PURE__ */ jsx("div", { className: "text-center mt-24", children: /* @__PURE__ */ jsx("p", { className: "text-base-content/40 text-sm", children: emptyText }) }),
70354
70961
  messages2.map((msg) => /* @__PURE__ */ jsx(
70355
70962
  MessageBubble,
@@ -70731,87 +71338,8 @@ var MenuV1RendererCollapsed = ({ items, onItemClick }) => {
70731
71338
  groupIndex < groupedItems.length - 1 && /* @__PURE__ */ jsx("div", { className: "w-8 border-t border-base-300 my-2" })
70732
71339
  ] }, groupIndex)) });
70733
71340
  };
70734
-
70735
- // src/ui/components/ConfirmDeleteModal.tsx
70736
- init_iconify();
70737
- function ConfirmDeleteModal({
70738
- isOpen,
70739
- onClose,
70740
- onConfirm,
70741
- isDeleting,
70742
- title = "Delete",
70743
- message = "Are you sure you want to delete this?"
70744
- }) {
70745
- useEffect(() => {
70746
- if (!isOpen) return;
70747
- const handleEscape = (e) => {
70748
- if (e.key === "Escape" && !isDeleting) {
70749
- onClose();
70750
- }
70751
- };
70752
- document.addEventListener("keydown", handleEscape);
70753
- document.body.style.overflow = "hidden";
70754
- return () => {
70755
- document.removeEventListener("keydown", handleEscape);
70756
- document.body.style.overflow = "unset";
70757
- };
70758
- }, [isOpen, onClose, isDeleting]);
70759
- const handleBackdropClick = (e) => {
70760
- if (e.target === e.currentTarget && !isDeleting) {
70761
- onClose();
70762
- }
70763
- };
70764
- if (!isOpen) return null;
70765
- return createPortal(
70766
- /* @__PURE__ */ jsx(
70767
- "div",
70768
- {
70769
- className: "fixed inset-0 flex items-center justify-center bg-black/50 backdrop-blur-sm",
70770
- style: { zIndex: 9999 },
70771
- onClick: handleBackdropClick,
70772
- children: /* @__PURE__ */ jsxs("div", { className: "bg-base-100 rounded-xl shadow-2xl w-full max-w-sm mx-4 overflow-hidden", children: [
70773
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border-b border-base-300", children: [
70774
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-base-content", children: title }),
70775
- /* @__PURE__ */ jsx(
70776
- "button",
70777
- {
70778
- type: "button",
70779
- disabled: isDeleting,
70780
- onClick: onClose,
70781
- className: "p-1 rounded-lg hover:bg-base-200 transition-colors",
70782
- children: /* @__PURE__ */ jsx(Icon, { icon: "ph:x-bold", width: 20, height: 20, className: "text-base-content/60" })
70783
- }
70784
- )
70785
- ] }),
70786
- /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx("p", { className: "text-base-content/80", children: message }) }),
70787
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 p-4 border-t border-base-300", children: [
70788
- /* @__PURE__ */ jsx(
70789
- "button",
70790
- {
70791
- type: "button",
70792
- onClick: onClose,
70793
- disabled: isDeleting,
70794
- className: "px-4 py-2 rounded-lg text-base-content hover:bg-base-200 transition-colors",
70795
- children: "Cancel"
70796
- }
70797
- ),
70798
- isDeleting ? /* @__PURE__ */ jsx("div", { className: "min-w-20 px-4 py-2 rounded-lg bg-red-600 text-white flex items-center justify-center", children: /* @__PURE__ */ jsx(Icon, { icon: "eos-icons:loading", width: 20, height: 20, className: "animate-spin" }) }) : /* @__PURE__ */ jsx(
70799
- "button",
70800
- {
70801
- type: "button",
70802
- onClick: onConfirm,
70803
- className: "min-w-20 px-4 py-2 rounded-lg bg-red-600 text-white hover:bg-red-700 transition-colors",
70804
- children: "Delete"
70805
- }
70806
- )
70807
- ] })
70808
- ] })
70809
- }
70810
- ),
70811
- document.body
70812
- );
70813
- }
70814
71341
  var CHATS_OPEN_KEY = "chats-section-open";
71342
+ var SIDEBAR_COLLAPSED_KEY = "sa-sidebar-collapsed";
70815
71343
  function Sidebar({
70816
71344
  children,
70817
71345
  className = "",
@@ -70873,8 +71401,20 @@ function Sidebar({
70873
71401
  setThreadToDelete(null);
70874
71402
  }
70875
71403
  };
70876
- const [collapsed, setCollapsed] = useState(true);
70877
- const [showContent, setShowContent] = useState(false);
71404
+ const [collapsed, setCollapsed] = useState(() => {
71405
+ try {
71406
+ return localStorage.getItem(SIDEBAR_COLLAPSED_KEY) === "true";
71407
+ } catch {
71408
+ return false;
71409
+ }
71410
+ });
71411
+ const [showContent, setShowContent] = useState(() => {
71412
+ try {
71413
+ return localStorage.getItem(SIDEBAR_COLLAPSED_KEY) !== "true";
71414
+ } catch {
71415
+ return true;
71416
+ }
71417
+ });
70878
71418
  const [menuV1Data, setMenuV1Data] = useState(null);
70879
71419
  const [isChatsOpen, setIsChatsOpen] = useState(() => {
70880
71420
  try {
@@ -70918,6 +71458,10 @@ function Sidebar({
70918
71458
  function toggle() {
70919
71459
  const next2 = !collapsed;
70920
71460
  setCollapsed(next2);
71461
+ try {
71462
+ localStorage.setItem(SIDEBAR_COLLAPSED_KEY, String(next2));
71463
+ } catch {
71464
+ }
70921
71465
  if (!next2) {
70922
71466
  setTimeout(() => setShowContent(true), 150);
70923
71467
  } else {
@@ -70944,7 +71488,7 @@ function Sidebar({
70944
71488
  return /* @__PURE__ */ jsxs(
70945
71489
  "aside",
70946
71490
  {
70947
- className: `flex flex-col shrink-0 border-r border-base-300 transition-all duration-300 ease-in-out overflow-hidden bg-base-200 ${collapsed ? "w-16" : "w-60"} ${className}`,
71491
+ className: `sa-ui flex flex-col shrink-0 border-r border-base-300 transition-all duration-300 ease-in-out overflow-hidden bg-base-200 ${collapsed ? "w-16" : "w-60"} ${className}`,
70948
71492
  children: [
70949
71493
  !collapsed && showContent && /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full w-60", children: [
70950
71494
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-3 border-b border-base-300 flex-shrink-0", children: [
@@ -71114,7 +71658,7 @@ function NewChatHero({
71114
71658
  subtitle = "Ask a question to start a new chat",
71115
71659
  className = ""
71116
71660
  }) {
71117
- return /* @__PURE__ */ jsxs("div", { className: `flex-1 min-h-0 flex flex-col items-center justify-center gap-6 px-4 ${className}`, children: [
71661
+ return /* @__PURE__ */ jsxs("div", { className: `sa-ui flex-1 min-h-0 flex flex-col items-center justify-center gap-6 px-4 ${className}`, children: [
71118
71662
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 text-center", children: [
71119
71663
  /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl font-semibold text-base-content", children: title }),
71120
71664
  /* @__PURE__ */ jsx("p", { className: "text-sm text-base-content/50", children: subtitle })
@@ -71124,8 +71668,8 @@ function NewChatHero({
71124
71668
  }
71125
71669
 
71126
71670
  // src/index.ts
71127
- var SDK_VERSION = "0.0.2";
71671
+ var SDK_VERSION = "0.0.3";
71128
71672
 
71129
- export { ActionsRequestMessageSchema, ActionsRequestPayloadSchema, ActionsResponseMessageSchema, ActionsResponsePayloadSchema, BindingSchema3 as BindingSchema, BundleChunkMessageSchema, BundleChunkPayloadSchema, BundleErrorMessageSchema, BundleErrorPayloadSchema, BundleRequestMessageSchema, BundleRequestPayloadSchema, COMP_REGISTRY, ChatInput, ClientConfigSchema, ComponentSchema, ComponentsSendMessageSchema, ComponentsSendPayloadSchema, ConfirmDeleteModal, DSLErrorBoundary, DSLRenderer, DSLRendererPropsSchema3 as DSLRendererPropsSchema, DataRequestMessageSchema, DataRequestPayloadSchema, DataResponseMessageSchema, DataResponsePayloadSchema, DynamicComponent, ExpressionSchema3 as ExpressionSchema, ForDirectiveSchema3 as ForDirectiveSchema, MenuDataSchema, MenuQueryFiltersSchema, MenuV1Renderer, MenuV1RendererCollapsed, MenusRequestMessageSchema, MenusRequestPayloadSchema, MenusResponseMessageSchema, MenusResponsePayloadSchema, MessageBubble, MessageList, MessageParticipantSchema, MessageSchema, NewChatHero, QuerySpecSchema3 as QuerySpecSchema, SDK_VERSION, Sidebar, SuperatomClient, UIComponentSchema3 as UIComponentSchema, UIElementSchema3 as UIElementSchema, UILogEntrySchema, UILogsMessageSchema, UILogsPayloadSchema, UserPromptAbortRequestMessageSchema, UserPromptAbortRequestPayloadSchema, UserPromptRequestMessageSchema, UserPromptRequestPayloadSchema, UserPromptResponseMessageSchema, UserPromptResponsePayloadSchema, UserPromptSuggestionsRequestMessageSchema, UserPromptSuggestionsRequestPayloadSchema, UserPromptSuggestionsResponseMessageSchema, UserPromptSuggestionsResponsePayloadSchema, getComponent, getComponentStates, getComponents, hasComponents, registerBundleComponents, resetAllFailedComponents, resetFailedComponent, resetRegistration, sanitizeDSL, services_exports as services, setup, useDynamicComponent, useSuperAtom, validateDSL, validateUIComponent, validateUIElement, withConditionalErrorBoundary };
71673
+ export { ActionsRequestMessageSchema, ActionsRequestPayloadSchema, ActionsResponseMessageSchema, ActionsResponsePayloadSchema, BindingSchema3 as BindingSchema, BundleChunkMessageSchema, BundleChunkPayloadSchema, BundleErrorMessageSchema, BundleErrorPayloadSchema, BundleRequestMessageSchema, BundleRequestPayloadSchema, COMP_REGISTRY, ChatInput, ClientConfigSchema, ComponentSchema, ComponentsSendMessageSchema, ComponentsSendPayloadSchema, ConfirmDeleteModal, DEFAULT_API_URL, DSLErrorBoundary, DSLRenderer, DSLRendererPropsSchema3 as DSLRendererPropsSchema, DataRequestMessageSchema, DataRequestPayloadSchema, DataResponseMessageSchema, DataResponsePayloadSchema, DynamicComponent, ExpressionSchema3 as ExpressionSchema, ForDirectiveSchema3 as ForDirectiveSchema, MenuDataSchema, MenuQueryFiltersSchema, MenuV1Renderer, MenuV1RendererCollapsed, MenusRequestMessageSchema, MenusRequestPayloadSchema, MenusResponseMessageSchema, MenusResponsePayloadSchema, MessageBubble, MessageList, MessageParticipantSchema, MessageSchema, NewChatHero, QuerySpecSchema3 as QuerySpecSchema, SDK_VERSION, SdkSession, Sidebar, SuperAtomAuthError, SuperatomClient, UIComponentSchema3 as UIComponentSchema, UIElementSchema3 as UIElementSchema, UILogEntrySchema, UILogsMessageSchema, UILogsPayloadSchema, UserPromptAbortRequestMessageSchema, UserPromptAbortRequestPayloadSchema, UserPromptRequestMessageSchema, UserPromptRequestPayloadSchema, UserPromptResponseMessageSchema, UserPromptResponsePayloadSchema, UserPromptSuggestionsRequestMessageSchema, UserPromptSuggestionsRequestPayloadSchema, UserPromptSuggestionsResponseMessageSchema, UserPromptSuggestionsResponsePayloadSchema, getComponent, getComponentStates, getComponents, hasComponents, registerBundleComponents, resetAllFailedComponents, resetFailedComponent, resetRegistration, sanitizeDSL, services_exports as services, setup, useDynamicComponent, useSuperAtom, validateDSL, validateUIComponent, validateUIElement, withConditionalErrorBoundary };
71130
71674
  //# sourceMappingURL=index.js.map
71131
71675
  //# sourceMappingURL=index.js.map