@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.cjs +744 -197
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +194 -6
- package/dist/index.d.ts +194 -6
- package/dist/index.js +743 -199
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
5451
|
+
let current3 = token;
|
|
5452
5452
|
let adjust = 0;
|
|
5453
5453
|
let start2 = 0;
|
|
5454
5454
|
const breaks = [start2];
|
|
5455
|
-
while (
|
|
5456
|
-
while (events.get(++startPosition)[1] !==
|
|
5455
|
+
while (current3) {
|
|
5456
|
+
while (events.get(++startPosition)[1] !== current3) {
|
|
5457
5457
|
}
|
|
5458
5458
|
startPositions.push(startPosition);
|
|
5459
|
-
if (!
|
|
5460
|
-
stream = context.sliceStream(
|
|
5461
|
-
if (!
|
|
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(
|
|
5465
|
+
tokenizer.defineSkip(current3.start);
|
|
5466
5466
|
}
|
|
5467
|
-
if (
|
|
5467
|
+
if (current3._isInFirstContentOfListItem) {
|
|
5468
5468
|
tokenizer._gfmTasklistFirstContentOfListItem = true;
|
|
5469
5469
|
}
|
|
5470
5470
|
tokenizer.write(stream);
|
|
5471
|
-
if (
|
|
5471
|
+
if (current3._isInFirstContentOfListItem) {
|
|
5472
5472
|
tokenizer._gfmTasklistFirstContentOfListItem = void 0;
|
|
5473
5473
|
}
|
|
5474
5474
|
}
|
|
5475
|
-
previous3 =
|
|
5476
|
-
|
|
5475
|
+
previous3 = current3;
|
|
5476
|
+
current3 = current3.next;
|
|
5477
5477
|
}
|
|
5478
|
-
|
|
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
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5486
|
+
current3._tokenizer = void 0;
|
|
5487
|
+
current3.previous = void 0;
|
|
5488
|
+
current3 = current3.next;
|
|
5489
5489
|
}
|
|
5490
5490
|
}
|
|
5491
5491
|
tokenizer.events = [];
|
|
5492
|
-
if (
|
|
5493
|
-
|
|
5494
|
-
|
|
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,
|
|
13510
|
-
const branchCount = (
|
|
13511
|
-
const jumpOffset =
|
|
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
|
|
13751
|
-
let valueLength = (
|
|
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,
|
|
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
|
-
|
|
13762
|
-
valueLength = (
|
|
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
|
|
19819
|
-
const currentNs = p.treeAdapter.getNamespaceURI(
|
|
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
|
|
20007
|
+
let current3;
|
|
20008
20008
|
let currentTagId;
|
|
20009
20009
|
if (this.openElements.stackTop === 0 && this.fragmentContext) {
|
|
20010
|
-
|
|
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(
|
|
20015
|
+
this._setContextModes(current3, currentTagId);
|
|
20016
20016
|
}
|
|
20017
20017
|
}
|
|
20018
|
-
_setContextModes(
|
|
20019
|
-
const isHTML =
|
|
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 &&
|
|
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
|
|
20219
|
+
let current3;
|
|
20220
20220
|
let currentTagId;
|
|
20221
20221
|
if (this.openElements.stackTop === 0 && this.fragmentContext) {
|
|
20222
|
-
|
|
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(
|
|
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,
|
|
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
|
|
21195
|
-
let ns = "namespaceURI" in
|
|
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,
|
|
50464
|
+
code: ({ node: _node, className, children, ...props }) => {
|
|
50465
50465
|
const langMatch = /language-(\w+)/.exec(className || "");
|
|
50466
50466
|
const language = langMatch ? langMatch[1] : "";
|
|
50467
|
-
|
|
50468
|
-
|
|
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"
|
|
50480
|
+
codeTagProps: { style: { backgroundColor: "transparent", padding: 0, fontSize: "inherit" } },
|
|
50479
50481
|
wrapLongLines: false,
|
|
50480
50482
|
...props,
|
|
50481
|
-
children:
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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((
|
|
68672
|
-
if (
|
|
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(
|
|
68962
|
+
return Array.isArray(current3) ? current3[index2] : current3;
|
|
68676
68963
|
}
|
|
68677
|
-
return
|
|
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({
|
|
69316
|
-
|
|
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
|
-
|
|
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)
|
|
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
|
-
}, [
|
|
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() ||
|
|
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,
|
|
70514
|
+
}, [input, isLocked, onSend, getOrCreateHistory]);
|
|
70035
70515
|
const themeColor = getThemeColor();
|
|
70036
|
-
|
|
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() ||
|
|
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() && !
|
|
70113
|
-
color: input.trim() && !
|
|
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__ */
|
|
70251
|
-
|
|
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
|
-
|
|
70349
|
-
|
|
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(
|
|
70877
|
-
|
|
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.
|
|
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
|