@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.cjs
CHANGED
|
@@ -5454,34 +5454,34 @@ function subcontent(events, eventIndex) {
|
|
|
5454
5454
|
let stream;
|
|
5455
5455
|
let previous3;
|
|
5456
5456
|
let index2 = -1;
|
|
5457
|
-
let
|
|
5457
|
+
let current3 = token;
|
|
5458
5458
|
let adjust = 0;
|
|
5459
5459
|
let start2 = 0;
|
|
5460
5460
|
const breaks = [start2];
|
|
5461
|
-
while (
|
|
5462
|
-
while (events.get(++startPosition)[1] !==
|
|
5461
|
+
while (current3) {
|
|
5462
|
+
while (events.get(++startPosition)[1] !== current3) {
|
|
5463
5463
|
}
|
|
5464
5464
|
startPositions.push(startPosition);
|
|
5465
|
-
if (!
|
|
5466
|
-
stream = context.sliceStream(
|
|
5467
|
-
if (!
|
|
5465
|
+
if (!current3._tokenizer) {
|
|
5466
|
+
stream = context.sliceStream(current3);
|
|
5467
|
+
if (!current3.next) {
|
|
5468
5468
|
stream.push(null);
|
|
5469
5469
|
}
|
|
5470
5470
|
if (previous3) {
|
|
5471
|
-
tokenizer.defineSkip(
|
|
5471
|
+
tokenizer.defineSkip(current3.start);
|
|
5472
5472
|
}
|
|
5473
|
-
if (
|
|
5473
|
+
if (current3._isInFirstContentOfListItem) {
|
|
5474
5474
|
tokenizer._gfmTasklistFirstContentOfListItem = true;
|
|
5475
5475
|
}
|
|
5476
5476
|
tokenizer.write(stream);
|
|
5477
|
-
if (
|
|
5477
|
+
if (current3._isInFirstContentOfListItem) {
|
|
5478
5478
|
tokenizer._gfmTasklistFirstContentOfListItem = void 0;
|
|
5479
5479
|
}
|
|
5480
5480
|
}
|
|
5481
|
-
previous3 =
|
|
5482
|
-
|
|
5481
|
+
previous3 = current3;
|
|
5482
|
+
current3 = current3.next;
|
|
5483
5483
|
}
|
|
5484
|
-
|
|
5484
|
+
current3 = token;
|
|
5485
5485
|
while (++index2 < childEvents.length) {
|
|
5486
5486
|
if (
|
|
5487
5487
|
// Find a void token that includes a break.
|
|
@@ -5489,15 +5489,15 @@ function subcontent(events, eventIndex) {
|
|
|
5489
5489
|
) {
|
|
5490
5490
|
start2 = index2 + 1;
|
|
5491
5491
|
breaks.push(start2);
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5492
|
+
current3._tokenizer = void 0;
|
|
5493
|
+
current3.previous = void 0;
|
|
5494
|
+
current3 = current3.next;
|
|
5495
5495
|
}
|
|
5496
5496
|
}
|
|
5497
5497
|
tokenizer.events = [];
|
|
5498
|
-
if (
|
|
5499
|
-
|
|
5500
|
-
|
|
5498
|
+
if (current3) {
|
|
5499
|
+
current3._tokenizer = void 0;
|
|
5500
|
+
current3.previous = void 0;
|
|
5501
5501
|
} else {
|
|
5502
5502
|
breaks.pop();
|
|
5503
5503
|
}
|
|
@@ -13512,9 +13512,9 @@ function isAsciiAlphaNumeric(code4) {
|
|
|
13512
13512
|
function isEntityInAttributeInvalidEnd(code4) {
|
|
13513
13513
|
return code4 === CharCodes.EQUALS || isAsciiAlphaNumeric(code4);
|
|
13514
13514
|
}
|
|
13515
|
-
function determineBranch(decodeTree,
|
|
13516
|
-
const branchCount = (
|
|
13517
|
-
const jumpOffset =
|
|
13515
|
+
function determineBranch(decodeTree, current3, nodeIndex, char) {
|
|
13516
|
+
const branchCount = (current3 & BinTrieFlags.BRANCH_LENGTH) >> 7;
|
|
13517
|
+
const jumpOffset = current3 & BinTrieFlags.JUMP_TABLE;
|
|
13518
13518
|
if (branchCount === 0) {
|
|
13519
13519
|
return jumpOffset !== 0 && char === jumpOffset ? nodeIndex : -1;
|
|
13520
13520
|
}
|
|
@@ -13753,19 +13753,19 @@ var init_decode = __esm({
|
|
|
13753
13753
|
*/
|
|
13754
13754
|
stateNamedEntity(input, offset) {
|
|
13755
13755
|
const { decodeTree } = this;
|
|
13756
|
-
let
|
|
13757
|
-
let valueLength = (
|
|
13756
|
+
let current3 = decodeTree[this.treeIndex];
|
|
13757
|
+
let valueLength = (current3 & BinTrieFlags.VALUE_LENGTH) >> 14;
|
|
13758
13758
|
for (; offset < input.length; offset++, this.excess++) {
|
|
13759
13759
|
const char = input.charCodeAt(offset);
|
|
13760
|
-
this.treeIndex = determineBranch(decodeTree,
|
|
13760
|
+
this.treeIndex = determineBranch(decodeTree, current3, this.treeIndex + Math.max(1, valueLength), char);
|
|
13761
13761
|
if (this.treeIndex < 0) {
|
|
13762
13762
|
return this.result === 0 || // If we are parsing an attribute
|
|
13763
13763
|
this.decodeMode === DecodingMode.Attribute && // We shouldn't have consumed any characters after the entity,
|
|
13764
13764
|
(valueLength === 0 || // And there should be no invalid characters.
|
|
13765
13765
|
isEntityInAttributeInvalidEnd(char)) ? 0 : this.emitNotTerminatedNamedEntity();
|
|
13766
13766
|
}
|
|
13767
|
-
|
|
13768
|
-
valueLength = (
|
|
13767
|
+
current3 = decodeTree[this.treeIndex];
|
|
13768
|
+
valueLength = (current3 & BinTrieFlags.VALUE_LENGTH) >> 14;
|
|
13769
13769
|
if (valueLength !== 0) {
|
|
13770
13770
|
if (char === CharCodes.SEMI) {
|
|
13771
13771
|
return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);
|
|
@@ -19821,8 +19821,8 @@ function startTagInForeignContent(p, token) {
|
|
|
19821
19821
|
popUntilHtmlOrIntegrationPoint(p);
|
|
19822
19822
|
p._startTagOutsideForeignContent(token);
|
|
19823
19823
|
} else {
|
|
19824
|
-
const
|
|
19825
|
-
const currentNs = p.treeAdapter.getNamespaceURI(
|
|
19824
|
+
const current3 = p._getAdjustedCurrentElement();
|
|
19825
|
+
const currentNs = p.treeAdapter.getNamespaceURI(current3);
|
|
19826
19826
|
if (currentNs === NS.MATHML) {
|
|
19827
19827
|
adjustTokenMathMLAttrs(token);
|
|
19828
19828
|
} else if (currentNs === NS.SVG) {
|
|
@@ -20010,21 +20010,21 @@ var init_parser = __esm({
|
|
|
20010
20010
|
}
|
|
20011
20011
|
(_b = (_a4 = this.treeAdapter).onItemPop) === null || _b === void 0 ? void 0 : _b.call(_a4, node2, this.openElements.current);
|
|
20012
20012
|
if (isTop) {
|
|
20013
|
-
let
|
|
20013
|
+
let current3;
|
|
20014
20014
|
let currentTagId;
|
|
20015
20015
|
if (this.openElements.stackTop === 0 && this.fragmentContext) {
|
|
20016
|
-
|
|
20016
|
+
current3 = this.fragmentContext;
|
|
20017
20017
|
currentTagId = this.fragmentContextID;
|
|
20018
20018
|
} else {
|
|
20019
|
-
({ current, currentTagId } = this.openElements);
|
|
20019
|
+
({ current: current3, currentTagId } = this.openElements);
|
|
20020
20020
|
}
|
|
20021
|
-
this._setContextModes(
|
|
20021
|
+
this._setContextModes(current3, currentTagId);
|
|
20022
20022
|
}
|
|
20023
20023
|
}
|
|
20024
|
-
_setContextModes(
|
|
20025
|
-
const isHTML =
|
|
20024
|
+
_setContextModes(current3, tid) {
|
|
20025
|
+
const isHTML = current3 === this.document || current3 && this.treeAdapter.getNamespaceURI(current3) === NS.HTML;
|
|
20026
20026
|
this.currentNotInHTML = !isHTML;
|
|
20027
|
-
this.tokenizer.inForeignNode = !isHTML &&
|
|
20027
|
+
this.tokenizer.inForeignNode = !isHTML && current3 !== void 0 && tid !== void 0 && !this._isIntegrationPoint(tid, current3);
|
|
20028
20028
|
}
|
|
20029
20029
|
/** @protected */
|
|
20030
20030
|
_switchToTextParsing(currentToken, nextTokenizerState) {
|
|
@@ -20222,22 +20222,22 @@ var init_parser = __esm({
|
|
|
20222
20222
|
shouldProcessStartTagTokenInForeignContent(token) {
|
|
20223
20223
|
if (!this.currentNotInHTML)
|
|
20224
20224
|
return false;
|
|
20225
|
-
let
|
|
20225
|
+
let current3;
|
|
20226
20226
|
let currentTagId;
|
|
20227
20227
|
if (this.openElements.stackTop === 0 && this.fragmentContext) {
|
|
20228
|
-
|
|
20228
|
+
current3 = this.fragmentContext;
|
|
20229
20229
|
currentTagId = this.fragmentContextID;
|
|
20230
20230
|
} else {
|
|
20231
|
-
({ current, currentTagId } = this.openElements);
|
|
20231
|
+
({ current: current3, currentTagId } = this.openElements);
|
|
20232
20232
|
}
|
|
20233
|
-
if (token.tagID === TAG_ID.SVG && this.treeAdapter.getTagName(
|
|
20233
|
+
if (token.tagID === TAG_ID.SVG && this.treeAdapter.getTagName(current3) === TAG_NAMES.ANNOTATION_XML && this.treeAdapter.getNamespaceURI(current3) === NS.MATHML) {
|
|
20234
20234
|
return false;
|
|
20235
20235
|
}
|
|
20236
20236
|
return (
|
|
20237
20237
|
// Check that `current` is not an integration point for HTML or MathML elements.
|
|
20238
20238
|
this.tokenizer.inForeignNode || // If it _is_ an integration point, then we might have to check that it is not an HTML
|
|
20239
20239
|
// integration point.
|
|
20240
|
-
(token.tagID === TAG_ID.MGLYPH || token.tagID === TAG_ID.MALIGNMARK) && currentTagId !== void 0 && !this._isIntegrationPoint(currentTagId,
|
|
20240
|
+
(token.tagID === TAG_ID.MGLYPH || token.tagID === TAG_ID.MALIGNMARK) && currentTagId !== void 0 && !this._isIntegrationPoint(currentTagId, current3, NS.HTML)
|
|
20241
20241
|
);
|
|
20242
20242
|
}
|
|
20243
20243
|
/** @protected */
|
|
@@ -21197,8 +21197,8 @@ function startTag(node2, state) {
|
|
|
21197
21197
|
const tagName = node2.tagName.toLowerCase();
|
|
21198
21198
|
if (state.parser.tokenizer.state === TokenizerMode.PLAINTEXT) return;
|
|
21199
21199
|
resetTokenizer(state, pointStart(node2));
|
|
21200
|
-
const
|
|
21201
|
-
let ns = "namespaceURI" in
|
|
21200
|
+
const current3 = state.parser.openElements.current;
|
|
21201
|
+
let ns = "namespaceURI" in current3 ? current3.namespaceURI : webNamespaces.html;
|
|
21202
21202
|
if (ns === webNamespaces.html && tagName === "svg") {
|
|
21203
21203
|
ns = webNamespaces.svg;
|
|
21204
21204
|
}
|
|
@@ -50467,11 +50467,13 @@ var init_Markdown = __esm({
|
|
|
50467
50467
|
// Suppress the default <pre> wrapper — code renderer owns the full block structure
|
|
50468
50468
|
pre: ({ node: _node, children }) => /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children }),
|
|
50469
50469
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50470
|
-
code: ({ node: _node,
|
|
50470
|
+
code: ({ node: _node, className, children, ...props }) => {
|
|
50471
50471
|
const langMatch = /language-(\w+)/.exec(className || "");
|
|
50472
50472
|
const language = langMatch ? langMatch[1] : "";
|
|
50473
|
-
|
|
50474
|
-
|
|
50473
|
+
const isBlock = Boolean(language) || String(children).includes("\n");
|
|
50474
|
+
const codeText2 = String(children).replace(/^\s*\n+/, "").replace(/\s+$/, "");
|
|
50475
|
+
if (isBlock) {
|
|
50476
|
+
return language ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sa-code-block not-prose my-4 rounded-lg overflow-hidden border border-base-300", children: [
|
|
50475
50477
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-neutral px-4 py-2 text-xs text-neutral-content font-mono", children: language }),
|
|
50476
50478
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
50477
50479
|
prism_default2,
|
|
@@ -50481,13 +50483,13 @@ var init_Markdown = __esm({
|
|
|
50481
50483
|
PreTag: "div",
|
|
50482
50484
|
className: "!my-0 !rounded-none text-sm",
|
|
50483
50485
|
customStyle: { margin: 0, borderRadius: 0, padding: "1rem" },
|
|
50484
|
-
codeTagProps: { style: { backgroundColor: "transparent", padding: 0, fontSize: "inherit"
|
|
50486
|
+
codeTagProps: { style: { backgroundColor: "transparent", padding: 0, fontSize: "inherit" } },
|
|
50485
50487
|
wrapLongLines: false,
|
|
50486
50488
|
...props,
|
|
50487
|
-
children:
|
|
50489
|
+
children: codeText2
|
|
50488
50490
|
}
|
|
50489
50491
|
) })
|
|
50490
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "not-prose my-4 rounded-lg overflow-hidden border border-base-300", children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("code", { ...props, children }) }) });
|
|
50492
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sa-code-block not-prose my-4 rounded-lg overflow-hidden border border-base-300", children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("code", { ...props, children: codeText2 }) }) });
|
|
50491
50493
|
}
|
|
50492
50494
|
return /* @__PURE__ */ jsxRuntime.jsx("code", { className: "bg-base-200 text-teal-700 px-1.5 py-0.5 rounded text-sm font-mono break-words", ...props, children });
|
|
50493
50495
|
},
|
|
@@ -66197,6 +66199,7 @@ __export(services_exports, {
|
|
|
66197
66199
|
deleteArtifact: () => deleteArtifact,
|
|
66198
66200
|
deleteBookmark: () => deleteBookmark,
|
|
66199
66201
|
deleteThread: () => deleteThread,
|
|
66202
|
+
deleteUserConversation: () => deleteUserConversation,
|
|
66200
66203
|
getActions: () => getActions,
|
|
66201
66204
|
getAllArtifacts: () => getAllArtifacts,
|
|
66202
66205
|
getAllBookmarks: () => getAllBookmarks,
|
|
@@ -66336,6 +66339,34 @@ function injectBundleStyles() {
|
|
|
66336
66339
|
daisyThemes.type = "text/css";
|
|
66337
66340
|
daisyThemes.href = "https://cdn.jsdelivr.net/npm/daisyui@5/themes.css";
|
|
66338
66341
|
document.head.appendChild(daisyThemes);
|
|
66342
|
+
const codeStyles = document.createElement("style");
|
|
66343
|
+
codeStyles.setAttribute("data-sa-code-styles", "true");
|
|
66344
|
+
codeStyles.textContent = `
|
|
66345
|
+
.sa-code-block, .sa-code-block * {
|
|
66346
|
+
text-decoration: none !important;
|
|
66347
|
+
text-shadow: none !important;
|
|
66348
|
+
border: 0;
|
|
66349
|
+
list-style: none;
|
|
66350
|
+
}
|
|
66351
|
+
.sa-code-block pre, .sa-code-block code, .sa-code-block span {
|
|
66352
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace !important;
|
|
66353
|
+
line-height: 1.5 !important;
|
|
66354
|
+
letter-spacing: normal !important;
|
|
66355
|
+
}
|
|
66356
|
+
.sa-code-block code { background: transparent !important; }
|
|
66357
|
+
|
|
66358
|
+
/* Tailwind v4 dropped the browser default of cursor:pointer on buttons, so
|
|
66359
|
+
anything clickable in our components would otherwise show an arrow. */
|
|
66360
|
+
.sa-ui button:not(:disabled),
|
|
66361
|
+
.sa-ui [role="button"]:not([aria-disabled="true"]),
|
|
66362
|
+
.sa-ui summary,
|
|
66363
|
+
.sa-ui label[for],
|
|
66364
|
+
.sa-ui select {
|
|
66365
|
+
cursor: pointer;
|
|
66366
|
+
}
|
|
66367
|
+
.sa-ui button:disabled { cursor: not-allowed; }
|
|
66368
|
+
`;
|
|
66369
|
+
document.head.appendChild(codeStyles);
|
|
66339
66370
|
}
|
|
66340
66371
|
async function requestBundle(client, options) {
|
|
66341
66372
|
injectBundleStyles();
|
|
@@ -67152,6 +67183,29 @@ async function deleteThread(client, userId, threadId, clearCache = true, timeout
|
|
|
67152
67183
|
};
|
|
67153
67184
|
}
|
|
67154
67185
|
}
|
|
67186
|
+
async function deleteUserConversation(client, userPrompt, userId, clearCache = true, timeout = 3e4) {
|
|
67187
|
+
try {
|
|
67188
|
+
const response = await client.requestData({
|
|
67189
|
+
collection: "user-conversations",
|
|
67190
|
+
operation: "deleteByUserPrompt",
|
|
67191
|
+
params: { userPrompt, userId, clearCache },
|
|
67192
|
+
timeout
|
|
67193
|
+
});
|
|
67194
|
+
if (response.error) {
|
|
67195
|
+
return { success: false, error: response.error };
|
|
67196
|
+
}
|
|
67197
|
+
const data = response.data;
|
|
67198
|
+
if (data?.success === false) {
|
|
67199
|
+
return { success: false, error: data.message || "Failed to delete the message" };
|
|
67200
|
+
}
|
|
67201
|
+
return { success: true, message: data?.message, queriesDeleted: data?.queriesDeleted };
|
|
67202
|
+
} catch (error51) {
|
|
67203
|
+
return {
|
|
67204
|
+
success: false,
|
|
67205
|
+
error: error51 instanceof Error ? error51.message : "Failed to delete the message"
|
|
67206
|
+
};
|
|
67207
|
+
}
|
|
67208
|
+
}
|
|
67155
67209
|
async function updateThreadTitle(client, userId, threadId, title, timeout = 15e3) {
|
|
67156
67210
|
try {
|
|
67157
67211
|
const response = await client.requestData({
|
|
@@ -67212,6 +67266,10 @@ var SuperatomClient = class {
|
|
|
67212
67266
|
this.errorHandlers = /* @__PURE__ */ new Set();
|
|
67213
67267
|
this.connectPromise = null;
|
|
67214
67268
|
this.connectResolve = null;
|
|
67269
|
+
// Supplies a valid session token before each (re)connect — see ClientConfig.getAccessToken.
|
|
67270
|
+
this.getAccessToken = null;
|
|
67271
|
+
// Waiting for getAccessToken; the socket does not exist yet.
|
|
67272
|
+
this.fetchingToken = false;
|
|
67215
67273
|
// Heartbeat — detects zombie sockets that readyState=OPEN can't catch.
|
|
67216
67274
|
this.heartbeatInterval = null;
|
|
67217
67275
|
this.pongDeadline = null;
|
|
@@ -67230,6 +67288,7 @@ var SuperatomClient = class {
|
|
|
67230
67288
|
this.boundHandlePageShow = null;
|
|
67231
67289
|
const parsed = ClientConfigSchema.parse(config2);
|
|
67232
67290
|
this.config = parsed;
|
|
67291
|
+
this.getAccessToken = config2.getAccessToken ?? null;
|
|
67233
67292
|
this.registerGlobals();
|
|
67234
67293
|
}
|
|
67235
67294
|
registerGlobals() {
|
|
@@ -67381,21 +67440,7 @@ var SuperatomClient = class {
|
|
|
67381
67440
|
* callbacks so the eventual real close doesn't double-fire everything.
|
|
67382
67441
|
*/
|
|
67383
67442
|
markAsDead(reasonMessage) {
|
|
67384
|
-
|
|
67385
|
-
const dying = this.socket;
|
|
67386
|
-
this.socket = null;
|
|
67387
|
-
try {
|
|
67388
|
-
dying.onopen = null;
|
|
67389
|
-
dying.onmessage = null;
|
|
67390
|
-
dying.onerror = null;
|
|
67391
|
-
dying.onclose = null;
|
|
67392
|
-
if (dying.readyState === WebSocket.OPEN || dying.readyState === WebSocket.CONNECTING) {
|
|
67393
|
-
dying.close();
|
|
67394
|
-
}
|
|
67395
|
-
} catch (err) {
|
|
67396
|
-
this.log("error", "Failed to detach dying socket:", err);
|
|
67397
|
-
}
|
|
67398
|
-
}
|
|
67443
|
+
this.discardSocket();
|
|
67399
67444
|
this.stopHeartbeat();
|
|
67400
67445
|
this.failPendingRequests(new Error(reasonMessage));
|
|
67401
67446
|
this.disconnectionHandlers.forEach((handler) => handler());
|
|
@@ -67412,21 +67457,39 @@ var SuperatomClient = class {
|
|
|
67412
67457
|
this.cancelReconnectTimer();
|
|
67413
67458
|
this.reconnectAttempts = 0;
|
|
67414
67459
|
this.shouldReconnect = true;
|
|
67415
|
-
|
|
67416
|
-
try {
|
|
67417
|
-
const old = this.socket;
|
|
67418
|
-
this.socket = null;
|
|
67419
|
-
if (old.readyState === WebSocket.OPEN || old.readyState === WebSocket.CONNECTING) {
|
|
67420
|
-
old.close();
|
|
67421
|
-
}
|
|
67422
|
-
} catch (err) {
|
|
67423
|
-
this.log("error", "Failed to close old socket during forceReconnect:", err);
|
|
67424
|
-
}
|
|
67425
|
-
}
|
|
67460
|
+
const wasOpen = this.discardSocket();
|
|
67426
67461
|
this.stopHeartbeat();
|
|
67427
67462
|
this.failPendingRequests(new Error("Connection reset"));
|
|
67463
|
+
if (wasOpen) this.disconnectionHandlers.forEach((handler) => handler());
|
|
67428
67464
|
return this.connect();
|
|
67429
67465
|
}
|
|
67466
|
+
/**
|
|
67467
|
+
* Drop the current socket without triggering its handlers: they are detached
|
|
67468
|
+
* first, so its eventual real close is a no-op (on Linux/Chrome that close
|
|
67469
|
+
* can arrive 30-60s later). Returns whether it was open.
|
|
67470
|
+
*/
|
|
67471
|
+
discardSocket() {
|
|
67472
|
+
const old = this.socket;
|
|
67473
|
+
if (!old) return false;
|
|
67474
|
+
this.socket = null;
|
|
67475
|
+
const wasOpen = old.readyState === WebSocket.OPEN;
|
|
67476
|
+
try {
|
|
67477
|
+
old.onopen = null;
|
|
67478
|
+
old.onmessage = null;
|
|
67479
|
+
old.onerror = null;
|
|
67480
|
+
old.onclose = null;
|
|
67481
|
+
if (wasOpen || old.readyState === WebSocket.CONNECTING) {
|
|
67482
|
+
old.close();
|
|
67483
|
+
}
|
|
67484
|
+
} catch (err) {
|
|
67485
|
+
this.log("error", "Failed to detach old socket:", err);
|
|
67486
|
+
}
|
|
67487
|
+
return wasOpen;
|
|
67488
|
+
}
|
|
67489
|
+
/** A connection attempt is under way — fetching the session token, or the socket handshake. */
|
|
67490
|
+
isConnecting() {
|
|
67491
|
+
return this.fetchingToken || this.socket?.readyState === WebSocket.CONNECTING;
|
|
67492
|
+
}
|
|
67430
67493
|
/**
|
|
67431
67494
|
* Attach window-level listeners that catch network changes faster than
|
|
67432
67495
|
* the socket's own onclose. The browser's onclose for a half-open TCP can
|
|
@@ -67448,15 +67511,18 @@ var SuperatomClient = class {
|
|
|
67448
67511
|
this.boundHandleVisibilityChange = () => {
|
|
67449
67512
|
if (typeof document === "undefined") return;
|
|
67450
67513
|
if (document.visibilityState !== "visible") return;
|
|
67451
|
-
if (
|
|
67514
|
+
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
67515
|
+
this.sendHeartbeatProbe();
|
|
67516
|
+
} else if (this.isConnecting()) {
|
|
67517
|
+
return;
|
|
67518
|
+
} else if (this.shouldReconnect) {
|
|
67452
67519
|
this.forceReconnect().catch((err) => {
|
|
67453
67520
|
this.log("error", "forceReconnect from visibility failed:", err);
|
|
67454
67521
|
});
|
|
67455
|
-
} else {
|
|
67456
|
-
this.sendHeartbeatProbe();
|
|
67457
67522
|
}
|
|
67458
67523
|
};
|
|
67459
|
-
this.boundHandlePageShow = (() => {
|
|
67524
|
+
this.boundHandlePageShow = ((event) => {
|
|
67525
|
+
if (!event.persisted) return;
|
|
67460
67526
|
this.forceReconnect().catch((err) => {
|
|
67461
67527
|
this.log("error", "forceReconnect from pageshow failed:", err);
|
|
67462
67528
|
});
|
|
@@ -67571,13 +67637,50 @@ var SuperatomClient = class {
|
|
|
67571
67637
|
this.log("warn", "Already connected");
|
|
67572
67638
|
return Promise.resolve();
|
|
67573
67639
|
}
|
|
67574
|
-
if (this.socket?.readyState === WebSocket.CONNECTING && this.connectPromise) {
|
|
67640
|
+
if ((this.socket?.readyState === WebSocket.CONNECTING || this.fetchingToken) && this.connectPromise) {
|
|
67575
67641
|
this.log("warn", "Connection already in progress");
|
|
67576
67642
|
return this.connectPromise;
|
|
67577
67643
|
}
|
|
67578
67644
|
this.connectPromise = new Promise((resolve) => {
|
|
67579
67645
|
this.connectResolve = resolve;
|
|
67580
67646
|
});
|
|
67647
|
+
if (this.getAccessToken) {
|
|
67648
|
+
void this.openWithFreshToken();
|
|
67649
|
+
} else {
|
|
67650
|
+
this.openSocket();
|
|
67651
|
+
}
|
|
67652
|
+
return this.connectPromise;
|
|
67653
|
+
}
|
|
67654
|
+
/**
|
|
67655
|
+
* Get a valid session token, then open the socket. The relay checks the token
|
|
67656
|
+
* only at handshake, so every (re)connect must present one that is still valid.
|
|
67657
|
+
*
|
|
67658
|
+
* A fatal auth failure (see SuperAtomAuthError.fatal) stops reconnecting — the
|
|
67659
|
+
* session reports it to the host, and retrying would only repeat it. Anything
|
|
67660
|
+
* else goes through the normal back-off.
|
|
67661
|
+
*/
|
|
67662
|
+
async openWithFreshToken() {
|
|
67663
|
+
this.fetchingToken = true;
|
|
67664
|
+
try {
|
|
67665
|
+
this.config.token = await this.getAccessToken();
|
|
67666
|
+
} catch (error51) {
|
|
67667
|
+
this.fetchingToken = false;
|
|
67668
|
+
const err = error51 instanceof Error ? error51 : new Error("Could not get a session token");
|
|
67669
|
+
this.errorHandlers.forEach((handler) => handler(err));
|
|
67670
|
+
if (error51?.fatal) {
|
|
67671
|
+
this.log("error", "Sign-in failed; not reconnecting:", err.message);
|
|
67672
|
+
this.shouldReconnect = false;
|
|
67673
|
+
this.cancelReconnectTimer();
|
|
67674
|
+
} else {
|
|
67675
|
+
this.scheduleReconnect();
|
|
67676
|
+
}
|
|
67677
|
+
return;
|
|
67678
|
+
}
|
|
67679
|
+
this.fetchingToken = false;
|
|
67680
|
+
if (!this.shouldReconnect) return;
|
|
67681
|
+
this.openSocket();
|
|
67682
|
+
}
|
|
67683
|
+
openSocket() {
|
|
67581
67684
|
try {
|
|
67582
67685
|
this.socket = new WebSocket(this.getWebSocketUrl());
|
|
67583
67686
|
this.setupSocketHandlers();
|
|
@@ -67588,7 +67691,6 @@ var SuperatomClient = class {
|
|
|
67588
67691
|
this.errorHandlers.forEach((handler) => handler(err));
|
|
67589
67692
|
this.scheduleReconnect();
|
|
67590
67693
|
}
|
|
67591
|
-
return this.connectPromise;
|
|
67592
67694
|
}
|
|
67593
67695
|
/**
|
|
67594
67696
|
* Disconnect from WebSocket server
|
|
@@ -67612,6 +67714,7 @@ var SuperatomClient = class {
|
|
|
67612
67714
|
const merged = { ...this.config, ...config2 };
|
|
67613
67715
|
const parsed = ClientConfigSchema.parse(merged);
|
|
67614
67716
|
this.config = parsed;
|
|
67717
|
+
if ("getAccessToken" in config2) this.getAccessToken = config2.getAccessToken ?? null;
|
|
67615
67718
|
}
|
|
67616
67719
|
/**
|
|
67617
67720
|
* Reconnect with new configuration
|
|
@@ -68038,6 +68141,190 @@ var SuperatomClient = class {
|
|
|
68038
68141
|
}
|
|
68039
68142
|
};
|
|
68040
68143
|
|
|
68144
|
+
// src/auth.ts
|
|
68145
|
+
var DEFAULT_API_URL = "https://sa-api.superatom.ai";
|
|
68146
|
+
var SuperAtomAuthError = class extends Error {
|
|
68147
|
+
constructor(code4, message, options) {
|
|
68148
|
+
super(message);
|
|
68149
|
+
this.name = "SuperAtomAuthError";
|
|
68150
|
+
this.code = code4;
|
|
68151
|
+
this.status = options.status;
|
|
68152
|
+
this.fatal = options.fatal;
|
|
68153
|
+
if (options.cause !== void 0) this.cause = options.cause;
|
|
68154
|
+
}
|
|
68155
|
+
};
|
|
68156
|
+
var MIN_REMAINING_MS = 6e4;
|
|
68157
|
+
var RENEW_AHEAD_MS = 12e4;
|
|
68158
|
+
var RENEW_RETRY_MS = 3e4;
|
|
68159
|
+
var RETRIES_BEFORE_REPORTING = 2;
|
|
68160
|
+
var EXCHANGE_TIMEOUT_MS = 15e3;
|
|
68161
|
+
function expiryOf(token) {
|
|
68162
|
+
try {
|
|
68163
|
+
const payload = token.split(".")[1];
|
|
68164
|
+
if (!payload) return null;
|
|
68165
|
+
const json3 = JSON.parse(atob(payload.replace(/-/g, "+").replace(/_/g, "/")));
|
|
68166
|
+
return typeof json3.exp === "number" ? json3.exp * 1e3 : null;
|
|
68167
|
+
} catch {
|
|
68168
|
+
return null;
|
|
68169
|
+
}
|
|
68170
|
+
}
|
|
68171
|
+
var SdkSession = class {
|
|
68172
|
+
constructor(opts) {
|
|
68173
|
+
this.token = null;
|
|
68174
|
+
this.expiresAt = 0;
|
|
68175
|
+
this.currentUser = null;
|
|
68176
|
+
/** The one renewal in flight — every caller shares it. */
|
|
68177
|
+
this.inFlight = null;
|
|
68178
|
+
this.fatalError = null;
|
|
68179
|
+
/** Retryable failures in a row; reset by a successful exchange. */
|
|
68180
|
+
this.retries = 0;
|
|
68181
|
+
this.renewTimer = null;
|
|
68182
|
+
this.stopped = false;
|
|
68183
|
+
this.opts = opts;
|
|
68184
|
+
this.apiUrl = (opts.apiUrl || DEFAULT_API_URL).replace(/\/+$/, "");
|
|
68185
|
+
}
|
|
68186
|
+
get user() {
|
|
68187
|
+
return this.currentUser;
|
|
68188
|
+
}
|
|
68189
|
+
/** The fatal error that stopped the session, if any. */
|
|
68190
|
+
get error() {
|
|
68191
|
+
return this.fatalError;
|
|
68192
|
+
}
|
|
68193
|
+
/**
|
|
68194
|
+
* A token with at least a minute left — the cached one, or a fresh exchange.
|
|
68195
|
+
* Rejects with SuperAtomAuthError.
|
|
68196
|
+
*/
|
|
68197
|
+
getAccessToken() {
|
|
68198
|
+
if (this.fatalError) return Promise.reject(this.fatalError);
|
|
68199
|
+
if (this.token && this.expiresAt - Date.now() > MIN_REMAINING_MS) {
|
|
68200
|
+
return Promise.resolve(this.token);
|
|
68201
|
+
}
|
|
68202
|
+
return this.renew();
|
|
68203
|
+
}
|
|
68204
|
+
/** Clear a fatal error so the next getAccessToken() tries again (e.g. after the user signs in again). */
|
|
68205
|
+
reset() {
|
|
68206
|
+
this.fatalError = null;
|
|
68207
|
+
this.stopped = false;
|
|
68208
|
+
}
|
|
68209
|
+
/** Stop renewing — the host unmounted or disconnected. */
|
|
68210
|
+
stop() {
|
|
68211
|
+
this.stopped = true;
|
|
68212
|
+
this.clearRenewTimer();
|
|
68213
|
+
}
|
|
68214
|
+
renew() {
|
|
68215
|
+
if (!this.inFlight) {
|
|
68216
|
+
this.inFlight = this.exchange().finally(() => {
|
|
68217
|
+
this.inFlight = null;
|
|
68218
|
+
});
|
|
68219
|
+
}
|
|
68220
|
+
return this.inFlight;
|
|
68221
|
+
}
|
|
68222
|
+
async exchange() {
|
|
68223
|
+
let customerToken;
|
|
68224
|
+
try {
|
|
68225
|
+
customerToken = await this.opts.getToken();
|
|
68226
|
+
} catch (err) {
|
|
68227
|
+
throw this.fail(new SuperAtomAuthError("get_token_failed", "getToken() failed", { fatal: true, cause: err }));
|
|
68228
|
+
}
|
|
68229
|
+
if (typeof customerToken !== "string" || !customerToken.trim()) {
|
|
68230
|
+
throw this.fail(new SuperAtomAuthError("get_token_failed", "getToken() returned no token", { fatal: true }));
|
|
68231
|
+
}
|
|
68232
|
+
const controller = new AbortController();
|
|
68233
|
+
const timeout = setTimeout(() => controller.abort(), EXCHANGE_TIMEOUT_MS);
|
|
68234
|
+
let res;
|
|
68235
|
+
try {
|
|
68236
|
+
res = await fetch(`${this.apiUrl}/auth/sdk/exchange`, {
|
|
68237
|
+
method: "POST",
|
|
68238
|
+
headers: { "Content-Type": "application/json" },
|
|
68239
|
+
body: JSON.stringify({ projectId: this.opts.projectId, token: customerToken.trim() }),
|
|
68240
|
+
signal: controller.signal
|
|
68241
|
+
});
|
|
68242
|
+
} catch (err) {
|
|
68243
|
+
throw this.fail(new SuperAtomAuthError("network", "Could not reach Superatom to sign in", { fatal: false, cause: err }));
|
|
68244
|
+
} finally {
|
|
68245
|
+
clearTimeout(timeout);
|
|
68246
|
+
}
|
|
68247
|
+
const body = await res.json().catch(() => ({}));
|
|
68248
|
+
if (!res.ok) {
|
|
68249
|
+
const message = typeof body?.error === "string" ? body.error : `Sign-in failed (${res.status})`;
|
|
68250
|
+
const fatal = res.status >= 400 && res.status < 500 && res.status !== 429;
|
|
68251
|
+
throw this.fail(
|
|
68252
|
+
new SuperAtomAuthError(fatal ? "exchange_rejected" : "exchange_unavailable", message, { status: res.status, fatal })
|
|
68253
|
+
);
|
|
68254
|
+
}
|
|
68255
|
+
if (typeof body?.token !== "string" || !body.user?.id) {
|
|
68256
|
+
throw this.fail(
|
|
68257
|
+
new SuperAtomAuthError("exchange_unavailable", "Unexpected sign-in response", { status: res.status, fatal: false })
|
|
68258
|
+
);
|
|
68259
|
+
}
|
|
68260
|
+
if (Array.isArray(body.warnings)) {
|
|
68261
|
+
for (const w of body.warnings) console.warn("[SuperAtom] Sign-in warning:", w);
|
|
68262
|
+
}
|
|
68263
|
+
this.token = body.token;
|
|
68264
|
+
this.expiresAt = expiryOf(body.token) ?? Date.now() + 15 * 6e4;
|
|
68265
|
+
this.currentUser = {
|
|
68266
|
+
id: body.user.id,
|
|
68267
|
+
email: body.user.email,
|
|
68268
|
+
name: body.user.name,
|
|
68269
|
+
role: body.user.role,
|
|
68270
|
+
externalRoles: Array.isArray(body.user.externalRoles) ? body.user.externalRoles : []
|
|
68271
|
+
};
|
|
68272
|
+
this.log(`Signed in as ${this.currentUser.email}; token valid until ${new Date(this.expiresAt).toISOString()}`);
|
|
68273
|
+
if (this.retries) {
|
|
68274
|
+
this.retries = 0;
|
|
68275
|
+
this.opts.onRetrying?.(null);
|
|
68276
|
+
}
|
|
68277
|
+
this.opts.onSession?.(this.currentUser);
|
|
68278
|
+
this.scheduleRenew(this.expiresAt - RENEW_AHEAD_MS - Date.now());
|
|
68279
|
+
return body.token;
|
|
68280
|
+
}
|
|
68281
|
+
/** Record a failure: a fatal one stops the session and is reported once. */
|
|
68282
|
+
fail(error51) {
|
|
68283
|
+
if (error51.fatal) {
|
|
68284
|
+
this.fatalError = error51;
|
|
68285
|
+
this.clearRenewTimer();
|
|
68286
|
+
console.error(`[SuperAtom] Sign-in failed: ${error51.message}`, error51);
|
|
68287
|
+
try {
|
|
68288
|
+
this.opts.onAuthError?.(error51);
|
|
68289
|
+
} catch (err) {
|
|
68290
|
+
console.error("[SuperAtom] onAuthError threw:", err);
|
|
68291
|
+
}
|
|
68292
|
+
} else {
|
|
68293
|
+
this.retries++;
|
|
68294
|
+
if (this.retries === RETRIES_BEFORE_REPORTING) {
|
|
68295
|
+
console.warn(`[SuperAtom] ${error51.message} (${this.apiUrl}) \u2014 retrying`);
|
|
68296
|
+
}
|
|
68297
|
+
if (this.retries >= RETRIES_BEFORE_REPORTING) this.opts.onRetrying?.(error51);
|
|
68298
|
+
this.log(`Sign-in attempt failed, will retry: ${error51.message}`);
|
|
68299
|
+
this.scheduleRenew(RENEW_RETRY_MS);
|
|
68300
|
+
}
|
|
68301
|
+
return error51;
|
|
68302
|
+
}
|
|
68303
|
+
/**
|
|
68304
|
+
* Renew in the background ahead of expiry. Timers are paused while the machine
|
|
68305
|
+
* sleeps and fire on wake; a reconnect after wake also renews first if needed.
|
|
68306
|
+
*/
|
|
68307
|
+
scheduleRenew(inMs) {
|
|
68308
|
+
this.clearRenewTimer();
|
|
68309
|
+
if (this.stopped || this.fatalError) return;
|
|
68310
|
+
this.renewTimer = setTimeout(() => {
|
|
68311
|
+
this.renewTimer = null;
|
|
68312
|
+
if (this.stopped || this.fatalError) return;
|
|
68313
|
+
this.renew().catch(() => {
|
|
68314
|
+
});
|
|
68315
|
+
}, Math.max(inMs, 5e3));
|
|
68316
|
+
}
|
|
68317
|
+
clearRenewTimer() {
|
|
68318
|
+
if (this.renewTimer) {
|
|
68319
|
+
clearTimeout(this.renewTimer);
|
|
68320
|
+
this.renewTimer = null;
|
|
68321
|
+
}
|
|
68322
|
+
}
|
|
68323
|
+
log(message) {
|
|
68324
|
+
if (this.opts.debug) console.log(`[SuperAtom] ${message}`);
|
|
68325
|
+
}
|
|
68326
|
+
};
|
|
68327
|
+
|
|
68041
68328
|
// src/setup.ts
|
|
68042
68329
|
function setup(components) {
|
|
68043
68330
|
if (typeof window === "undefined") {
|
|
@@ -68674,13 +68961,13 @@ var ExpressionEvaluator = class {
|
|
|
68674
68961
|
resolveDataPath(path2, data) {
|
|
68675
68962
|
if (!path2 || !data) return void 0;
|
|
68676
68963
|
try {
|
|
68677
|
-
return path2.split(".").reduce((
|
|
68678
|
-
if (
|
|
68964
|
+
return path2.split(".").reduce((current3, key) => {
|
|
68965
|
+
if (current3 === null || current3 === void 0) return void 0;
|
|
68679
68966
|
if (!isNaN(Number(key))) {
|
|
68680
68967
|
const index2 = parseInt(key, 10);
|
|
68681
|
-
return Array.isArray(
|
|
68968
|
+
return Array.isArray(current3) ? current3[index2] : current3;
|
|
68682
68969
|
}
|
|
68683
|
-
return
|
|
68970
|
+
return current3[key];
|
|
68684
68971
|
}, data);
|
|
68685
68972
|
} catch (error51) {
|
|
68686
68973
|
console.warn("Error resolving data path:", path2, error51);
|
|
@@ -69159,6 +69446,71 @@ function resetRegistration() {
|
|
|
69159
69446
|
registeredKeys.forEach((key) => delete COMP_REGISTRY[key]);
|
|
69160
69447
|
registeredKeys.clear();
|
|
69161
69448
|
}
|
|
69449
|
+
var current = null;
|
|
69450
|
+
var retrying = null;
|
|
69451
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
69452
|
+
function setAuthStatus(error51) {
|
|
69453
|
+
if (current === error51) return;
|
|
69454
|
+
current = error51;
|
|
69455
|
+
if (error51) retrying = null;
|
|
69456
|
+
listeners.forEach((l) => l());
|
|
69457
|
+
}
|
|
69458
|
+
function setRetryingStatus(error51) {
|
|
69459
|
+
if (retrying === error51) return;
|
|
69460
|
+
retrying = error51;
|
|
69461
|
+
listeners.forEach((l) => l());
|
|
69462
|
+
}
|
|
69463
|
+
function useRetryingStatus() {
|
|
69464
|
+
return React6.useSyncExternalStore(
|
|
69465
|
+
(l) => {
|
|
69466
|
+
listeners.add(l);
|
|
69467
|
+
return () => listeners.delete(l);
|
|
69468
|
+
},
|
|
69469
|
+
() => retrying,
|
|
69470
|
+
() => null
|
|
69471
|
+
);
|
|
69472
|
+
}
|
|
69473
|
+
function useAuthStatus() {
|
|
69474
|
+
return React6.useSyncExternalStore(
|
|
69475
|
+
(l) => {
|
|
69476
|
+
listeners.add(l);
|
|
69477
|
+
return () => listeners.delete(l);
|
|
69478
|
+
},
|
|
69479
|
+
() => current,
|
|
69480
|
+
() => null
|
|
69481
|
+
);
|
|
69482
|
+
}
|
|
69483
|
+
function authStatusMessage(error51) {
|
|
69484
|
+
switch (error51.code) {
|
|
69485
|
+
case "get_token_failed":
|
|
69486
|
+
return "Your session has ended. Please sign in again to continue.";
|
|
69487
|
+
case "exchange_rejected":
|
|
69488
|
+
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.";
|
|
69489
|
+
default:
|
|
69490
|
+
return "Could not connect to Superatom. Please try again in a moment.";
|
|
69491
|
+
}
|
|
69492
|
+
}
|
|
69493
|
+
function retryingStatusMessage(error51) {
|
|
69494
|
+
return error51.code === "network" ? "Cannot reach Superatom \u2014 retrying\u2026" : "Superatom is not responding \u2014 retrying\u2026";
|
|
69495
|
+
}
|
|
69496
|
+
var current2 = {};
|
|
69497
|
+
var listeners2 = /* @__PURE__ */ new Set();
|
|
69498
|
+
function setMessageActions(actions) {
|
|
69499
|
+
current2 = actions;
|
|
69500
|
+
listeners2.forEach((l) => l());
|
|
69501
|
+
}
|
|
69502
|
+
function useMessageActions() {
|
|
69503
|
+
return React6.useSyncExternalStore(
|
|
69504
|
+
(l) => {
|
|
69505
|
+
listeners2.add(l);
|
|
69506
|
+
return () => listeners2.delete(l);
|
|
69507
|
+
},
|
|
69508
|
+
() => current2,
|
|
69509
|
+
() => current2
|
|
69510
|
+
);
|
|
69511
|
+
}
|
|
69512
|
+
|
|
69513
|
+
// src/ui/hooks/useSuperAtom.ts
|
|
69162
69514
|
function newThreadId() {
|
|
69163
69515
|
return `thread_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
69164
69516
|
}
|
|
@@ -69318,17 +69670,40 @@ function buildResponseIssueSchema(response, messageId) {
|
|
|
69318
69670
|
var MAX_ABORTED_TRACKED = 100;
|
|
69319
69671
|
var THREADS_LIMIT = 50;
|
|
69320
69672
|
var THREAD_MESSAGES_LIMIT = 50;
|
|
69321
|
-
function useSuperAtom({
|
|
69322
|
-
|
|
69673
|
+
function useSuperAtom({
|
|
69674
|
+
token,
|
|
69675
|
+
userId,
|
|
69676
|
+
projectId,
|
|
69677
|
+
getToken,
|
|
69678
|
+
onAuthError,
|
|
69679
|
+
apiUrl,
|
|
69680
|
+
wsUrl,
|
|
69681
|
+
debug = false,
|
|
69682
|
+
streaming = false
|
|
69683
|
+
}) {
|
|
69684
|
+
const sdkSignIn = !!getToken;
|
|
69685
|
+
if (sdkSignIn && token) throw new Error("[SuperAtom] Pass either token or getToken, not both");
|
|
69686
|
+
const [user, setUser] = React6.useState(null);
|
|
69687
|
+
const [authError, setAuthError] = React6.useState(null);
|
|
69688
|
+
const [signInAttempt, setSignInAttempt] = React6.useState(0);
|
|
69689
|
+
const directUserId = (() => {
|
|
69690
|
+
if (sdkSignIn) return void 0;
|
|
69323
69691
|
if (token) {
|
|
69324
69692
|
const payload = decodeJWT(token);
|
|
69325
69693
|
const id = payload.sub ?? payload.userId;
|
|
69326
69694
|
if (!id) throw new Error("[SuperAtom] JWT decoded but no userId or sub field found in payload");
|
|
69327
69695
|
return id;
|
|
69328
69696
|
}
|
|
69329
|
-
if (!userId) throw new Error("[SuperAtom] Either token or userId must be provided");
|
|
69697
|
+
if (!userId) throw new Error("[SuperAtom] Either token, getToken or userId must be provided");
|
|
69330
69698
|
return userId;
|
|
69331
69699
|
})();
|
|
69700
|
+
const resolvedUserId = directUserId ?? user?.id ?? "";
|
|
69701
|
+
const getTokenRef = React6.useRef(getToken);
|
|
69702
|
+
getTokenRef.current = getToken;
|
|
69703
|
+
const onAuthErrorRef = React6.useRef(onAuthError);
|
|
69704
|
+
onAuthErrorRef.current = onAuthError;
|
|
69705
|
+
const sessionRef = React6.useRef(null);
|
|
69706
|
+
const setupDoneRef = React6.useRef(false);
|
|
69332
69707
|
const clientRef = React6.useRef(null);
|
|
69333
69708
|
const tokenRef = React6.useRef(token);
|
|
69334
69709
|
tokenRef.current = token;
|
|
@@ -69355,7 +69730,54 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
|
|
|
69355
69730
|
injectBundleStyles();
|
|
69356
69731
|
const timeoutId = setTimeout(async () => {
|
|
69357
69732
|
if (cancelled) return;
|
|
69358
|
-
|
|
69733
|
+
let clientUserId = directUserId;
|
|
69734
|
+
let session = null;
|
|
69735
|
+
if (sdkSignIn) {
|
|
69736
|
+
session = new SdkSession({
|
|
69737
|
+
projectId,
|
|
69738
|
+
apiUrl,
|
|
69739
|
+
debug,
|
|
69740
|
+
getToken: () => getTokenRef.current(),
|
|
69741
|
+
onAuthError: (err) => {
|
|
69742
|
+
setAuthError(err);
|
|
69743
|
+
setAuthStatus(err);
|
|
69744
|
+
onAuthErrorRef.current?.(err);
|
|
69745
|
+
},
|
|
69746
|
+
onSession: (u) => {
|
|
69747
|
+
setAuthError(null);
|
|
69748
|
+
setAuthStatus(null);
|
|
69749
|
+
setUser(u);
|
|
69750
|
+
},
|
|
69751
|
+
// Superatom unreachable or down, after a couple of tries: say so in the
|
|
69752
|
+
// chat instead of sitting on "Connecting…".
|
|
69753
|
+
onRetrying: (err) => setRetryingStatus(err)
|
|
69754
|
+
});
|
|
69755
|
+
sessionRef.current = session;
|
|
69756
|
+
for (let delay = 1e3; ; delay = Math.min(delay * 2, 3e4)) {
|
|
69757
|
+
try {
|
|
69758
|
+
await session.getAccessToken();
|
|
69759
|
+
break;
|
|
69760
|
+
} catch (err) {
|
|
69761
|
+
if (cancelled || err?.fatal) return;
|
|
69762
|
+
await new Promise((r2) => setTimeout(r2, delay));
|
|
69763
|
+
if (cancelled) return;
|
|
69764
|
+
}
|
|
69765
|
+
}
|
|
69766
|
+
if (cancelled) {
|
|
69767
|
+
session.stop();
|
|
69768
|
+
return;
|
|
69769
|
+
}
|
|
69770
|
+
clientUserId = session.user.id;
|
|
69771
|
+
}
|
|
69772
|
+
const activeSession = session;
|
|
69773
|
+
const client = new SuperatomClient({
|
|
69774
|
+
userId: clientUserId,
|
|
69775
|
+
projectId,
|
|
69776
|
+
type: "runtime",
|
|
69777
|
+
debug,
|
|
69778
|
+
...wsUrl ? { baseUrl: wsUrl } : {},
|
|
69779
|
+
...activeSession ? { getAccessToken: () => activeSession.getAccessToken() } : { token: tokenRef.current }
|
|
69780
|
+
});
|
|
69359
69781
|
clientRef.current = client;
|
|
69360
69782
|
client.onError((err) => console.error("[SuperAtom] Error:", err));
|
|
69361
69783
|
try {
|
|
@@ -69372,11 +69794,11 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
|
|
|
69372
69794
|
};
|
|
69373
69795
|
const unsub = client.onConnect(done);
|
|
69374
69796
|
const cancelPoll = setInterval(() => {
|
|
69375
|
-
if (cancelled) done();
|
|
69797
|
+
if (cancelled || activeSession?.error) done();
|
|
69376
69798
|
}, 50);
|
|
69377
69799
|
});
|
|
69378
|
-
if (cancelled) {
|
|
69379
|
-
client.disconnect();
|
|
69800
|
+
if (cancelled || activeSession?.error) {
|
|
69801
|
+
if (cancelled) client.disconnect();
|
|
69380
69802
|
return;
|
|
69381
69803
|
}
|
|
69382
69804
|
window.dispatchEvent(new CustomEvent("sa:client-connected"));
|
|
@@ -69452,7 +69874,10 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
|
|
|
69452
69874
|
]);
|
|
69453
69875
|
};
|
|
69454
69876
|
}
|
|
69455
|
-
if (!cancelled)
|
|
69877
|
+
if (!cancelled) {
|
|
69878
|
+
setupDoneRef.current = true;
|
|
69879
|
+
setBundleReady(true);
|
|
69880
|
+
}
|
|
69456
69881
|
} catch (err) {
|
|
69457
69882
|
console.error("[SuperAtom] Setup failed:", err);
|
|
69458
69883
|
}
|
|
@@ -69466,9 +69891,25 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
|
|
|
69466
69891
|
}
|
|
69467
69892
|
clientRef.current?.disconnect();
|
|
69468
69893
|
clientRef.current = null;
|
|
69894
|
+
sessionRef.current?.stop();
|
|
69895
|
+
sessionRef.current = null;
|
|
69896
|
+
setAuthStatus(null);
|
|
69897
|
+
setupDoneRef.current = false;
|
|
69469
69898
|
setBundleReady(false);
|
|
69470
69899
|
};
|
|
69471
|
-
}, [
|
|
69900
|
+
}, [directUserId, sdkSignIn, projectId, apiUrl, wsUrl, debug, signInAttempt]);
|
|
69901
|
+
const reconnect = React6.useCallback(() => {
|
|
69902
|
+
const session = sessionRef.current;
|
|
69903
|
+
const client = clientRef.current;
|
|
69904
|
+
session?.reset();
|
|
69905
|
+
setAuthError(null);
|
|
69906
|
+
setAuthStatus(null);
|
|
69907
|
+
if (client && setupDoneRef.current) {
|
|
69908
|
+
client.forceReconnect().catch((err) => console.error("[SuperAtom] Reconnect failed:", err));
|
|
69909
|
+
} else {
|
|
69910
|
+
setSignInAttempt((n) => n + 1);
|
|
69911
|
+
}
|
|
69912
|
+
}, []);
|
|
69472
69913
|
const sendMessage = React6.useCallback(async () => {
|
|
69473
69914
|
const text9 = input.trim();
|
|
69474
69915
|
const client = clientRef.current;
|
|
@@ -69860,6 +70301,39 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
|
|
|
69860
70301
|
if (threadId.current === id) newChat();
|
|
69861
70302
|
return { success: true };
|
|
69862
70303
|
}, [resolvedUserId, newChat]);
|
|
70304
|
+
const deleteMessage = React6.useCallback(async (messageId) => {
|
|
70305
|
+
const client = clientRef.current;
|
|
70306
|
+
if (!client) return { success: false, error: "Not connected" };
|
|
70307
|
+
const list4 = messagesRef.current;
|
|
70308
|
+
const index2 = list4.findIndex((m) => m.id === messageId);
|
|
70309
|
+
if (index2 === -1) return { success: false, error: "Message not found" };
|
|
70310
|
+
let questionIndex = list4[index2]?.role === "user" ? index2 : -1;
|
|
70311
|
+
if (questionIndex === -1) {
|
|
70312
|
+
for (let i = index2 - 1; i >= 0; i--) {
|
|
70313
|
+
if (list4[i]?.role === "user") {
|
|
70314
|
+
questionIndex = i;
|
|
70315
|
+
break;
|
|
70316
|
+
}
|
|
70317
|
+
}
|
|
70318
|
+
}
|
|
70319
|
+
const question = questionIndex >= 0 ? list4[questionIndex]?.text ?? "" : "";
|
|
70320
|
+
if (!question.trim()) return { success: false, error: "Could not find the question for this answer" };
|
|
70321
|
+
const res = await deleteUserConversation(client, question, resolvedUserId);
|
|
70322
|
+
if (!res.success) return res;
|
|
70323
|
+
const removed = /* @__PURE__ */ new Set();
|
|
70324
|
+
for (let i = questionIndex; i < list4.length; i++) {
|
|
70325
|
+
const msg = list4[i];
|
|
70326
|
+
if (!msg) continue;
|
|
70327
|
+
if (i > questionIndex && msg.role === "user") break;
|
|
70328
|
+
removed.add(msg.id);
|
|
70329
|
+
}
|
|
70330
|
+
setMessages((prev) => prev.filter((m) => !removed.has(m.id)));
|
|
70331
|
+
return { success: true };
|
|
70332
|
+
}, [resolvedUserId]);
|
|
70333
|
+
React6.useEffect(() => {
|
|
70334
|
+
setMessageActions({ deleteMessage });
|
|
70335
|
+
return () => setMessageActions({});
|
|
70336
|
+
}, [deleteMessage]);
|
|
69863
70337
|
const renameThread = React6.useCallback(async (id, title) => {
|
|
69864
70338
|
const client = clientRef.current;
|
|
69865
70339
|
if (!client) return { success: false, error: "Not connected" };
|
|
@@ -69883,7 +70357,11 @@ function useSuperAtom({ token, userId, projectId, debug = false, streaming = fal
|
|
|
69883
70357
|
isLoadingThread,
|
|
69884
70358
|
refreshThreads,
|
|
69885
70359
|
deleteThread: deleteThread2,
|
|
69886
|
-
renameThread
|
|
70360
|
+
renameThread,
|
|
70361
|
+
isNewChat: bundleReady && !isLoadingThread && messages2.length === 0,
|
|
70362
|
+
user,
|
|
70363
|
+
authError,
|
|
70364
|
+
reconnect
|
|
69887
70365
|
};
|
|
69888
70366
|
}
|
|
69889
70367
|
|
|
@@ -69979,6 +70457,8 @@ function ChatInput({
|
|
|
69979
70457
|
isResponding = false,
|
|
69980
70458
|
onStop
|
|
69981
70459
|
}) {
|
|
70460
|
+
const authError = useAuthStatus();
|
|
70461
|
+
const isLocked = disabled || !!authError;
|
|
69982
70462
|
const textareaRef = React6.useRef(null);
|
|
69983
70463
|
const historyRef = React6.useRef(null);
|
|
69984
70464
|
const [isMultiline, setIsMultiline] = React6.useState(false);
|
|
@@ -70032,14 +70512,15 @@ function ChatInput({
|
|
|
70032
70512
|
}, 0);
|
|
70033
70513
|
};
|
|
70034
70514
|
const handleSend = React6.useCallback(() => {
|
|
70035
|
-
if (!input.trim() ||
|
|
70515
|
+
if (!input.trim() || isLocked) return;
|
|
70036
70516
|
const history = getOrCreateHistory();
|
|
70037
70517
|
history?.addCommand(input.trim());
|
|
70038
70518
|
history?.resetNavigation();
|
|
70039
70519
|
onSend();
|
|
70040
|
-
}, [input,
|
|
70520
|
+
}, [input, isLocked, onSend, getOrCreateHistory]);
|
|
70041
70521
|
const themeColor = getThemeColor();
|
|
70042
|
-
|
|
70522
|
+
const effectivePlaceholder = authError ? authStatusMessage(authError) : placeholder;
|
|
70523
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `sa-ui shrink-0 bg-base-100 border-t border-base-300 px-4 py-2 ${className}`, children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(
|
|
70043
70524
|
"div",
|
|
70044
70525
|
{
|
|
70045
70526
|
className: `flex flex-col ${isMultiline ? "rounded-3xl" : "rounded-full"} border-2 shadow-sm transition-all duration-200 hover:shadow-md`,
|
|
@@ -70059,7 +70540,7 @@ function ChatInput({
|
|
|
70059
70540
|
autoCapitalize: "off",
|
|
70060
70541
|
ref: textareaRef,
|
|
70061
70542
|
value: input,
|
|
70062
|
-
placeholder,
|
|
70543
|
+
placeholder: effectivePlaceholder,
|
|
70063
70544
|
onChange: (e) => setInput(e.currentTarget.value),
|
|
70064
70545
|
onBlur: () => setIsFocused(false),
|
|
70065
70546
|
onFocus: () => setIsFocused(true),
|
|
@@ -70090,7 +70571,7 @@ function ChatInput({
|
|
|
70090
70571
|
},
|
|
70091
70572
|
rows: 1,
|
|
70092
70573
|
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]",
|
|
70093
|
-
disabled,
|
|
70574
|
+
disabled: isLocked,
|
|
70094
70575
|
style: { maxHeight: "200px" }
|
|
70095
70576
|
}
|
|
70096
70577
|
),
|
|
@@ -70112,11 +70593,11 @@ function ChatInput({
|
|
|
70112
70593
|
"button",
|
|
70113
70594
|
{
|
|
70114
70595
|
onClick: handleSend,
|
|
70115
|
-
disabled: !input.trim() ||
|
|
70596
|
+
disabled: !input.trim() || isLocked,
|
|
70116
70597
|
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`,
|
|
70117
70598
|
style: {
|
|
70118
|
-
backgroundColor: input.trim() && !
|
|
70119
|
-
color: input.trim() && !
|
|
70599
|
+
backgroundColor: input.trim() && !isLocked ? themeColor : "transparent",
|
|
70600
|
+
color: input.trim() && !isLocked ? "white" : themeColor
|
|
70120
70601
|
},
|
|
70121
70602
|
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: "ph:paper-plane-right-fill", width: 20, height: 20, className: "sm:w-6 sm:h-6" })
|
|
70122
70603
|
}
|
|
@@ -70132,6 +70613,86 @@ init_iconify();
|
|
|
70132
70613
|
// src/ui/components/MessageBubble.tsx
|
|
70133
70614
|
init_iconify();
|
|
70134
70615
|
init_Markdown();
|
|
70616
|
+
|
|
70617
|
+
// src/ui/components/ConfirmDeleteModal.tsx
|
|
70618
|
+
init_iconify();
|
|
70619
|
+
function ConfirmDeleteModal({
|
|
70620
|
+
isOpen,
|
|
70621
|
+
onClose,
|
|
70622
|
+
onConfirm,
|
|
70623
|
+
isDeleting,
|
|
70624
|
+
title = "Delete",
|
|
70625
|
+
message = "Are you sure you want to delete this?"
|
|
70626
|
+
}) {
|
|
70627
|
+
React6.useEffect(() => {
|
|
70628
|
+
if (!isOpen) return;
|
|
70629
|
+
const handleEscape = (e) => {
|
|
70630
|
+
if (e.key === "Escape" && !isDeleting) {
|
|
70631
|
+
onClose();
|
|
70632
|
+
}
|
|
70633
|
+
};
|
|
70634
|
+
document.addEventListener("keydown", handleEscape);
|
|
70635
|
+
document.body.style.overflow = "hidden";
|
|
70636
|
+
return () => {
|
|
70637
|
+
document.removeEventListener("keydown", handleEscape);
|
|
70638
|
+
document.body.style.overflow = "unset";
|
|
70639
|
+
};
|
|
70640
|
+
}, [isOpen, onClose, isDeleting]);
|
|
70641
|
+
const handleBackdropClick = (e) => {
|
|
70642
|
+
if (e.target === e.currentTarget && !isDeleting) {
|
|
70643
|
+
onClose();
|
|
70644
|
+
}
|
|
70645
|
+
};
|
|
70646
|
+
if (!isOpen) return null;
|
|
70647
|
+
return reactDom.createPortal(
|
|
70648
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
70649
|
+
"div",
|
|
70650
|
+
{
|
|
70651
|
+
className: "sa-ui fixed inset-0 flex items-center justify-center bg-black/50 backdrop-blur-sm",
|
|
70652
|
+
style: { zIndex: 9999 },
|
|
70653
|
+
onClick: handleBackdropClick,
|
|
70654
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-base-100 rounded-xl shadow-2xl w-full max-w-sm mx-4 overflow-hidden", children: [
|
|
70655
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-4 border-b border-base-300", children: [
|
|
70656
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-base-content", children: title }),
|
|
70657
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
70658
|
+
"button",
|
|
70659
|
+
{
|
|
70660
|
+
type: "button",
|
|
70661
|
+
disabled: isDeleting,
|
|
70662
|
+
onClick: onClose,
|
|
70663
|
+
className: "p-1 rounded-lg hover:bg-base-200 transition-colors",
|
|
70664
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: "ph:x-bold", width: 20, height: 20, className: "text-base-content/60" })
|
|
70665
|
+
}
|
|
70666
|
+
)
|
|
70667
|
+
] }),
|
|
70668
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base-content/80", children: message }) }),
|
|
70669
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2 p-4 border-t border-base-300", children: [
|
|
70670
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
70671
|
+
"button",
|
|
70672
|
+
{
|
|
70673
|
+
type: "button",
|
|
70674
|
+
onClick: onClose,
|
|
70675
|
+
disabled: isDeleting,
|
|
70676
|
+
className: "px-4 py-2 rounded-lg text-base-content hover:bg-base-200 transition-colors",
|
|
70677
|
+
children: "Cancel"
|
|
70678
|
+
}
|
|
70679
|
+
),
|
|
70680
|
+
isDeleting ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-20 px-4 py-2 rounded-lg bg-red-600 text-white flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: "eos-icons:loading", width: 20, height: 20, className: "animate-spin" }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
70681
|
+
"button",
|
|
70682
|
+
{
|
|
70683
|
+
type: "button",
|
|
70684
|
+
onClick: onConfirm,
|
|
70685
|
+
className: "min-w-20 px-4 py-2 rounded-lg bg-red-600 text-white hover:bg-red-700 transition-colors",
|
|
70686
|
+
children: "Delete"
|
|
70687
|
+
}
|
|
70688
|
+
)
|
|
70689
|
+
] })
|
|
70690
|
+
] })
|
|
70691
|
+
}
|
|
70692
|
+
),
|
|
70693
|
+
document.body
|
|
70694
|
+
);
|
|
70695
|
+
}
|
|
70135
70696
|
function StopButton({ onStop }) {
|
|
70136
70697
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
70137
70698
|
"button",
|
|
@@ -70157,17 +70718,40 @@ function MessageBubble({ message, onStop }) {
|
|
|
70157
70718
|
const isTextOnly = message.isTextOnlyResponse === true;
|
|
70158
70719
|
const isAborted = message.aborted === true;
|
|
70159
70720
|
const responseComplete = hasComponent || isTextOnly || !isStreaming && hasText;
|
|
70721
|
+
const [watchedGeneration] = React6.useState(() => !responseComplete);
|
|
70160
70722
|
React6.useEffect(() => {
|
|
70161
|
-
if (message.role !== "assistant") return;
|
|
70162
|
-
startTime.current = Date.now();
|
|
70723
|
+
if (message.role !== "assistant" || !watchedGeneration) return;
|
|
70163
70724
|
if (responseComplete) {
|
|
70164
70725
|
setElapsedMs(Date.now() - startTime.current);
|
|
70165
70726
|
return;
|
|
70166
70727
|
}
|
|
70728
|
+
setElapsedMs(Date.now() - startTime.current);
|
|
70167
70729
|
const interval = setInterval(() => setElapsedMs(Date.now() - startTime.current), 100);
|
|
70168
70730
|
return () => clearInterval(interval);
|
|
70169
|
-
}, [message.role, responseComplete]);
|
|
70731
|
+
}, [message.role, responseComplete, watchedGeneration]);
|
|
70170
70732
|
const formatMs = (ms) => ms < 1e3 ? `${ms}ms` : `${(ms / 1e3).toFixed(1)}s`;
|
|
70733
|
+
const { deleteMessage } = useMessageActions();
|
|
70734
|
+
const [confirmOpen, setConfirmOpen] = React6.useState(false);
|
|
70735
|
+
const [isDeleting, setIsDeleting] = React6.useState(false);
|
|
70736
|
+
const handleDelete2 = async () => {
|
|
70737
|
+
if (!deleteMessage) return;
|
|
70738
|
+
setIsDeleting(true);
|
|
70739
|
+
const res = await deleteMessage(message.id);
|
|
70740
|
+
setIsDeleting(false);
|
|
70741
|
+
setConfirmOpen(false);
|
|
70742
|
+
if (!res.success) console.error("[SuperAtom] Could not delete the message:", res.error);
|
|
70743
|
+
};
|
|
70744
|
+
const deleteButton = deleteMessage && responseComplete && !isAborted ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
70745
|
+
"button",
|
|
70746
|
+
{
|
|
70747
|
+
onClick: () => setConfirmOpen(true),
|
|
70748
|
+
disabled: isDeleting,
|
|
70749
|
+
title: "Delete this answer",
|
|
70750
|
+
"aria-label": "Delete this answer",
|
|
70751
|
+
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",
|
|
70752
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsxRuntime.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" }) })
|
|
70753
|
+
}
|
|
70754
|
+
) }) : null;
|
|
70171
70755
|
const accordionHeader = React6.useMemo(() => {
|
|
70172
70756
|
if (isAborted) return hasText ? "Stopped" : "Stopped (no response yet)";
|
|
70173
70757
|
if (!hasText) return "Thinking...";
|
|
@@ -70203,7 +70787,7 @@ function MessageBubble({ message, onStop }) {
|
|
|
70203
70787
|
children: [
|
|
70204
70788
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-base-content truncate text-left flex-1", children: accordionHeader }),
|
|
70205
70789
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 shrink-0", children: [
|
|
70206
|
-
!message.fromHistory && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-teal-50 border border-teal-200", children: [
|
|
70790
|
+
!message.fromHistory && watchedGeneration && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-teal-50 border border-teal-200", children: [
|
|
70207
70791
|
responseComplete ? /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "text-teal-600", width: 12, height: 12, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" }) }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "loading loading-spinner loading-xs text-teal-600" }),
|
|
70208
70792
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-teal-700 font-medium font-mono", children: formatMs(elapsedMs) })
|
|
70209
70793
|
] }),
|
|
@@ -70253,8 +70837,25 @@ function MessageBubble({ message, onStop }) {
|
|
|
70253
70837
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-base-content/70", children: "Generating component..." })
|
|
70254
70838
|
] })
|
|
70255
70839
|
] }) }),
|
|
70256
|
-
hasComponent && /* @__PURE__ */ jsxRuntime.
|
|
70257
|
-
|
|
70840
|
+
hasComponent && /* @__PURE__ */ jsxRuntime.jsxs("div", { id: `box-${message.id}`, className: "w-full px-4 lg:px-16 xl:px-24 2xl:px-32", children: [
|
|
70841
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(DSLRenderer, { dsl: message.schema.ui, data: message.schema.data ?? {} }) }),
|
|
70842
|
+
deleteButton
|
|
70843
|
+
] }),
|
|
70844
|
+
!isStreaming && !hasComponent && hasText && isTextOnly && !isAborted && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center w-full px-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full md:w-[60vw]", children: [
|
|
70845
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl shadow-sm bg-base-100 border-2 border-base-300 p-4 text-base-content", children: /* @__PURE__ */ jsxRuntime.jsx(Markdown_default, { content: fullText, isStreaming: false }) }),
|
|
70846
|
+
deleteButton
|
|
70847
|
+
] }) }),
|
|
70848
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
70849
|
+
ConfirmDeleteModal,
|
|
70850
|
+
{
|
|
70851
|
+
isOpen: confirmOpen,
|
|
70852
|
+
onClose: () => setConfirmOpen(false),
|
|
70853
|
+
onConfirm: handleDelete2,
|
|
70854
|
+
isDeleting,
|
|
70855
|
+
title: "Delete this answer?",
|
|
70856
|
+
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."
|
|
70857
|
+
}
|
|
70858
|
+
)
|
|
70258
70859
|
] });
|
|
70259
70860
|
}
|
|
70260
70861
|
function DynamicSpacer({ messages: messages2 }) {
|
|
@@ -70268,6 +70869,7 @@ function MessageList({
|
|
|
70268
70869
|
bundleReady,
|
|
70269
70870
|
connectingText = "Connecting to SuperAtom...",
|
|
70270
70871
|
emptyText = "Start a conversation",
|
|
70872
|
+
emptyState,
|
|
70271
70873
|
className = "",
|
|
70272
70874
|
isResponding = false,
|
|
70273
70875
|
onStop,
|
|
@@ -70351,11 +70953,16 @@ function MessageList({
|
|
|
70351
70953
|
}
|
|
70352
70954
|
}, 300);
|
|
70353
70955
|
}, [messages2]);
|
|
70354
|
-
|
|
70355
|
-
|
|
70956
|
+
const authError = useAuthStatus();
|
|
70957
|
+
const retrying2 = useRetryingStatus();
|
|
70958
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `sa-ui flex-1 relative overflow-hidden ${className}`, children: [
|
|
70959
|
+
/* @__PURE__ */ jsxRuntime.jsx("main", { ref: containerRef, className: "h-full overflow-y-auto py-6", children: authError ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col items-center justify-center gap-3 px-6 text-center", children: [
|
|
70960
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: "mdi:lock-alert-outline", width: 28, height: 28, className: "text-base-content/40" }),
|
|
70961
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-base-content/70 max-w-sm", children: authStatusMessage(authError) })
|
|
70962
|
+
] }) : !bundleReady || isLoadingThread && messages2.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col items-center justify-center gap-3 text-base-content/50", children: [
|
|
70356
70963
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "loading loading-spinner loading-md" }),
|
|
70357
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: !bundleReady ? connectingText : loadingThreadText })
|
|
70358
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
70964
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: !bundleReady ? retrying2 ? retryingStatusMessage(retrying2) : connectingText : loadingThreadText })
|
|
70965
|
+
] }) : messages2.length === 0 && emptyState ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full flex flex-col", children: emptyState }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
70359
70966
|
messages2.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center mt-24", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base-content/40 text-sm", children: emptyText }) }),
|
|
70360
70967
|
messages2.map((msg) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
70361
70968
|
MessageBubble,
|
|
@@ -70737,87 +71344,8 @@ var MenuV1RendererCollapsed = ({ items, onItemClick }) => {
|
|
|
70737
71344
|
groupIndex < groupedItems.length - 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 border-t border-base-300 my-2" })
|
|
70738
71345
|
] }, groupIndex)) });
|
|
70739
71346
|
};
|
|
70740
|
-
|
|
70741
|
-
// src/ui/components/ConfirmDeleteModal.tsx
|
|
70742
|
-
init_iconify();
|
|
70743
|
-
function ConfirmDeleteModal({
|
|
70744
|
-
isOpen,
|
|
70745
|
-
onClose,
|
|
70746
|
-
onConfirm,
|
|
70747
|
-
isDeleting,
|
|
70748
|
-
title = "Delete",
|
|
70749
|
-
message = "Are you sure you want to delete this?"
|
|
70750
|
-
}) {
|
|
70751
|
-
React6.useEffect(() => {
|
|
70752
|
-
if (!isOpen) return;
|
|
70753
|
-
const handleEscape = (e) => {
|
|
70754
|
-
if (e.key === "Escape" && !isDeleting) {
|
|
70755
|
-
onClose();
|
|
70756
|
-
}
|
|
70757
|
-
};
|
|
70758
|
-
document.addEventListener("keydown", handleEscape);
|
|
70759
|
-
document.body.style.overflow = "hidden";
|
|
70760
|
-
return () => {
|
|
70761
|
-
document.removeEventListener("keydown", handleEscape);
|
|
70762
|
-
document.body.style.overflow = "unset";
|
|
70763
|
-
};
|
|
70764
|
-
}, [isOpen, onClose, isDeleting]);
|
|
70765
|
-
const handleBackdropClick = (e) => {
|
|
70766
|
-
if (e.target === e.currentTarget && !isDeleting) {
|
|
70767
|
-
onClose();
|
|
70768
|
-
}
|
|
70769
|
-
};
|
|
70770
|
-
if (!isOpen) return null;
|
|
70771
|
-
return reactDom.createPortal(
|
|
70772
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
70773
|
-
"div",
|
|
70774
|
-
{
|
|
70775
|
-
className: "fixed inset-0 flex items-center justify-center bg-black/50 backdrop-blur-sm",
|
|
70776
|
-
style: { zIndex: 9999 },
|
|
70777
|
-
onClick: handleBackdropClick,
|
|
70778
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-base-100 rounded-xl shadow-2xl w-full max-w-sm mx-4 overflow-hidden", children: [
|
|
70779
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-4 border-b border-base-300", children: [
|
|
70780
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-base-content", children: title }),
|
|
70781
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
70782
|
-
"button",
|
|
70783
|
-
{
|
|
70784
|
-
type: "button",
|
|
70785
|
-
disabled: isDeleting,
|
|
70786
|
-
onClick: onClose,
|
|
70787
|
-
className: "p-1 rounded-lg hover:bg-base-200 transition-colors",
|
|
70788
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: "ph:x-bold", width: 20, height: 20, className: "text-base-content/60" })
|
|
70789
|
-
}
|
|
70790
|
-
)
|
|
70791
|
-
] }),
|
|
70792
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base-content/80", children: message }) }),
|
|
70793
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2 p-4 border-t border-base-300", children: [
|
|
70794
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
70795
|
-
"button",
|
|
70796
|
-
{
|
|
70797
|
-
type: "button",
|
|
70798
|
-
onClick: onClose,
|
|
70799
|
-
disabled: isDeleting,
|
|
70800
|
-
className: "px-4 py-2 rounded-lg text-base-content hover:bg-base-200 transition-colors",
|
|
70801
|
-
children: "Cancel"
|
|
70802
|
-
}
|
|
70803
|
-
),
|
|
70804
|
-
isDeleting ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-20 px-4 py-2 rounded-lg bg-red-600 text-white flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: "eos-icons:loading", width: 20, height: 20, className: "animate-spin" }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
70805
|
-
"button",
|
|
70806
|
-
{
|
|
70807
|
-
type: "button",
|
|
70808
|
-
onClick: onConfirm,
|
|
70809
|
-
className: "min-w-20 px-4 py-2 rounded-lg bg-red-600 text-white hover:bg-red-700 transition-colors",
|
|
70810
|
-
children: "Delete"
|
|
70811
|
-
}
|
|
70812
|
-
)
|
|
70813
|
-
] })
|
|
70814
|
-
] })
|
|
70815
|
-
}
|
|
70816
|
-
),
|
|
70817
|
-
document.body
|
|
70818
|
-
);
|
|
70819
|
-
}
|
|
70820
71347
|
var CHATS_OPEN_KEY = "chats-section-open";
|
|
71348
|
+
var SIDEBAR_COLLAPSED_KEY = "sa-sidebar-collapsed";
|
|
70821
71349
|
function Sidebar({
|
|
70822
71350
|
children,
|
|
70823
71351
|
className = "",
|
|
@@ -70879,8 +71407,20 @@ function Sidebar({
|
|
|
70879
71407
|
setThreadToDelete(null);
|
|
70880
71408
|
}
|
|
70881
71409
|
};
|
|
70882
|
-
const [collapsed, setCollapsed] = React6.useState(
|
|
70883
|
-
|
|
71410
|
+
const [collapsed, setCollapsed] = React6.useState(() => {
|
|
71411
|
+
try {
|
|
71412
|
+
return localStorage.getItem(SIDEBAR_COLLAPSED_KEY) === "true";
|
|
71413
|
+
} catch {
|
|
71414
|
+
return false;
|
|
71415
|
+
}
|
|
71416
|
+
});
|
|
71417
|
+
const [showContent, setShowContent] = React6.useState(() => {
|
|
71418
|
+
try {
|
|
71419
|
+
return localStorage.getItem(SIDEBAR_COLLAPSED_KEY) !== "true";
|
|
71420
|
+
} catch {
|
|
71421
|
+
return true;
|
|
71422
|
+
}
|
|
71423
|
+
});
|
|
70884
71424
|
const [menuV1Data, setMenuV1Data] = React6.useState(null);
|
|
70885
71425
|
const [isChatsOpen, setIsChatsOpen] = React6.useState(() => {
|
|
70886
71426
|
try {
|
|
@@ -70924,6 +71464,10 @@ function Sidebar({
|
|
|
70924
71464
|
function toggle() {
|
|
70925
71465
|
const next2 = !collapsed;
|
|
70926
71466
|
setCollapsed(next2);
|
|
71467
|
+
try {
|
|
71468
|
+
localStorage.setItem(SIDEBAR_COLLAPSED_KEY, String(next2));
|
|
71469
|
+
} catch {
|
|
71470
|
+
}
|
|
70927
71471
|
if (!next2) {
|
|
70928
71472
|
setTimeout(() => setShowContent(true), 150);
|
|
70929
71473
|
} else {
|
|
@@ -70950,7 +71494,7 @@ function Sidebar({
|
|
|
70950
71494
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
70951
71495
|
"aside",
|
|
70952
71496
|
{
|
|
70953
|
-
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}`,
|
|
71497
|
+
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}`,
|
|
70954
71498
|
children: [
|
|
70955
71499
|
!collapsed && showContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full w-60", children: [
|
|
70956
71500
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-3 py-3 border-b border-base-300 flex-shrink-0", children: [
|
|
@@ -71120,7 +71664,7 @@ function NewChatHero({
|
|
|
71120
71664
|
subtitle = "Ask a question to start a new chat",
|
|
71121
71665
|
className = ""
|
|
71122
71666
|
}) {
|
|
71123
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex-1 min-h-0 flex flex-col items-center justify-center gap-6 px-4 ${className}`, children: [
|
|
71667
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `sa-ui flex-1 min-h-0 flex flex-col items-center justify-center gap-6 px-4 ${className}`, children: [
|
|
71124
71668
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2 text-center", children: [
|
|
71125
71669
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl md:text-3xl font-semibold text-base-content", children: title }),
|
|
71126
71670
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-base-content/50", children: subtitle })
|
|
@@ -71130,7 +71674,7 @@ function NewChatHero({
|
|
|
71130
71674
|
}
|
|
71131
71675
|
|
|
71132
71676
|
// src/index.ts
|
|
71133
|
-
var SDK_VERSION = "0.0.
|
|
71677
|
+
var SDK_VERSION = "0.0.3";
|
|
71134
71678
|
|
|
71135
71679
|
exports.ActionsRequestMessageSchema = ActionsRequestMessageSchema;
|
|
71136
71680
|
exports.ActionsRequestPayloadSchema = ActionsRequestPayloadSchema;
|
|
@@ -71150,6 +71694,7 @@ exports.ComponentSchema = ComponentSchema;
|
|
|
71150
71694
|
exports.ComponentsSendMessageSchema = ComponentsSendMessageSchema;
|
|
71151
71695
|
exports.ComponentsSendPayloadSchema = ComponentsSendPayloadSchema;
|
|
71152
71696
|
exports.ConfirmDeleteModal = ConfirmDeleteModal;
|
|
71697
|
+
exports.DEFAULT_API_URL = DEFAULT_API_URL;
|
|
71153
71698
|
exports.DSLErrorBoundary = DSLErrorBoundary;
|
|
71154
71699
|
exports.DSLRenderer = DSLRenderer;
|
|
71155
71700
|
exports.DSLRendererPropsSchema = DSLRendererPropsSchema3;
|
|
@@ -71175,7 +71720,9 @@ exports.MessageSchema = MessageSchema;
|
|
|
71175
71720
|
exports.NewChatHero = NewChatHero;
|
|
71176
71721
|
exports.QuerySpecSchema = QuerySpecSchema3;
|
|
71177
71722
|
exports.SDK_VERSION = SDK_VERSION;
|
|
71723
|
+
exports.SdkSession = SdkSession;
|
|
71178
71724
|
exports.Sidebar = Sidebar;
|
|
71725
|
+
exports.SuperAtomAuthError = SuperAtomAuthError;
|
|
71179
71726
|
exports.SuperatomClient = SuperatomClient;
|
|
71180
71727
|
exports.UIComponentSchema = UIComponentSchema3;
|
|
71181
71728
|
exports.UIElementSchema = UIElementSchema3;
|