@getnexorai/sdk 0.1.4 → 0.1.7
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/chat.cjs +124 -20
- package/dist/chat.cjs.map +1 -1
- package/dist/chat.d.cts +2 -2
- package/dist/chat.d.ts +2 -2
- package/dist/chat.js +1 -1
- package/dist/{chunk-WUUXZIQN.js → chunk-DSKP6MXM.js} +126 -22
- package/dist/chunk-DSKP6MXM.js.map +1 -0
- package/dist/{config-C39P5Aax.d.cts → config-DBEY3q4Q.d.cts} +13 -1
- package/dist/{config-C39P5Aax.d.ts → config-DBEY3q4Q.d.ts} +13 -1
- package/dist/index.cjs +124 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/nexor.iife.js +71 -20
- package/dist/nexor.iife.js.map +1 -1
- package/package.json +4 -2
- package/dist/chunk-WUUXZIQN.js.map +0 -1
|
@@ -277,6 +277,16 @@ interface IsPausedResponse {
|
|
|
277
277
|
success: true;
|
|
278
278
|
paused: boolean;
|
|
279
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* A file the AI attached to a chat reply (File Library media). The API resolves
|
|
282
|
+
* the agent's handle(s) server-side and returns only the renderable contract —
|
|
283
|
+
* `image` renders inline, `document` (e.g. PDF) as a download link.
|
|
284
|
+
*/
|
|
285
|
+
interface ChatMedia {
|
|
286
|
+
type: "image" | "document";
|
|
287
|
+
url: string;
|
|
288
|
+
filename?: string;
|
|
289
|
+
}
|
|
280
290
|
|
|
281
291
|
/**
|
|
282
292
|
* Low-level Nexor API client.
|
|
@@ -390,6 +400,8 @@ declare class NexorClient {
|
|
|
390
400
|
workflow_run_id?: UUID;
|
|
391
401
|
/** True when the API recognised an existing lead (returning visitor). */
|
|
392
402
|
matched_existing?: boolean;
|
|
403
|
+
/** File(s) the AI attached to this reply (inline media channels). */
|
|
404
|
+
media?: ChatMedia[];
|
|
393
405
|
}>;
|
|
394
406
|
/**
|
|
395
407
|
* Create (or upsert) a lead from the web chat widget and force its FIRST
|
|
@@ -640,4 +652,4 @@ interface ChatHandle {
|
|
|
640
652
|
getSessionId(): string;
|
|
641
653
|
}
|
|
642
654
|
|
|
643
|
-
export { type AutomationInput as A, type BulkResultEntry as B, type Campaign as C, type ForceFirstMessage as F, type GetLeadHistoryParams as G, type ISODateString as I, type Lead as L, type MeetingNotesInput as M, NexorClient as N, type RequestOptions as R, type SendMessageInput as S, type UUID as U, type WhatsAppTemplate as W, type ChatChannelKey as a, type ChatChannels as b, type ChatHandle as c, type ChatInitOptions as d, type ChatLeadCapture as e, type
|
|
655
|
+
export { type AutomationInput as A, type BulkResultEntry as B, type Campaign as C, type ForceFirstMessage as F, type GetLeadHistoryParams as G, type ISODateString as I, type Lead as L, type MeetingNotesInput as M, NexorClient as N, type RequestOptions as R, type SendMessageInput as S, type UUID as U, type WhatsAppTemplate as W, type ChatChannelKey as a, type ChatChannels as b, type ChatHandle as c, type ChatInitOptions as d, type ChatLeadCapture as e, type ChatMedia as f, type ClientOptions as g, type CreateLeadBulkResponse as h, type CreateLeadInput as i, type CreateLeadResponse as j, type CreateMeetingInput as k, type GetLeadHistoryResponse as l, type GetLeadResponse as m, type IsPausedResponse as n, type LeadHistoryItem as o, type ListTemplatesParams as p, type ResumeAutomationInput as q, type SyncTagsInput as r, type SyncTagsResponse as s, type Workflow as t, type WorkflowRunStub as u };
|
package/dist/index.cjs
CHANGED
|
@@ -676,10 +676,21 @@ function randomHex(bytes) {
|
|
|
676
676
|
}
|
|
677
677
|
|
|
678
678
|
// src/chat/validate.ts
|
|
679
|
+
var EMAIL_RE = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
|
|
679
680
|
function isValidEmail(value) {
|
|
680
681
|
const s = (value || "").trim();
|
|
681
682
|
if (s.length < 6 || s.length > 254) return false;
|
|
682
|
-
|
|
683
|
+
const at = s.lastIndexOf("@");
|
|
684
|
+
if (at < 1) return false;
|
|
685
|
+
const local = s.slice(0, at);
|
|
686
|
+
const domain = s.slice(at + 1);
|
|
687
|
+
if (local.length > 64) return false;
|
|
688
|
+
if (local.startsWith(".") || local.endsWith(".") || local.includes("..")) {
|
|
689
|
+
return false;
|
|
690
|
+
}
|
|
691
|
+
if (domain.includes("..")) return false;
|
|
692
|
+
if (!/\.[a-zA-Z]{2,}$/.test(domain)) return false;
|
|
693
|
+
return EMAIL_RE.test(s);
|
|
683
694
|
}
|
|
684
695
|
|
|
685
696
|
// src/chat/template.ts
|
|
@@ -1140,6 +1151,40 @@ var widgetCss = (accent, accentText) => `
|
|
|
1140
1151
|
}
|
|
1141
1152
|
.nexor-chat__msg--bot .nexor-chat__msg-time { text-align: left; }
|
|
1142
1153
|
|
|
1154
|
+
/* File Library attachment: the image itself is the bubble (no padding/bg). */
|
|
1155
|
+
.nexor-chat__msg--media {
|
|
1156
|
+
padding: 0;
|
|
1157
|
+
background: transparent;
|
|
1158
|
+
border: none;
|
|
1159
|
+
box-shadow: none;
|
|
1160
|
+
overflow: hidden;
|
|
1161
|
+
}
|
|
1162
|
+
.nexor-chat__media-img {
|
|
1163
|
+
display: block;
|
|
1164
|
+
max-width: 100%;
|
|
1165
|
+
max-height: 260px;
|
|
1166
|
+
width: auto;
|
|
1167
|
+
height: auto;
|
|
1168
|
+
border-radius: 14px;
|
|
1169
|
+
border-bottom-left-radius: 4px;
|
|
1170
|
+
object-fit: cover;
|
|
1171
|
+
}
|
|
1172
|
+
.nexor-chat__media-doc {
|
|
1173
|
+
display: inline-flex;
|
|
1174
|
+
align-items: center;
|
|
1175
|
+
gap: 6px;
|
|
1176
|
+
padding: 8px 12px;
|
|
1177
|
+
border-radius: 14px;
|
|
1178
|
+
border-bottom-left-radius: 4px;
|
|
1179
|
+
background: #fff;
|
|
1180
|
+
border: 1px solid rgba(0,0,0,0.06);
|
|
1181
|
+
color: ${accent};
|
|
1182
|
+
text-decoration: none;
|
|
1183
|
+
font-size: 13px;
|
|
1184
|
+
font-weight: 500;
|
|
1185
|
+
}
|
|
1186
|
+
.nexor-chat__media-doc::before { content: "\\1F4CE"; }
|
|
1187
|
+
|
|
1143
1188
|
@keyframes nexor-msg-in {
|
|
1144
1189
|
from { transform: translateY(8px) scale(0.96); opacity: 0; }
|
|
1145
1190
|
to { transform: translateY(0) scale(1); opacity: 1; }
|
|
@@ -1279,7 +1324,8 @@ var widgetCss = (accent, accentText) => `
|
|
|
1279
1324
|
transition: border-color 140ms ease, box-shadow 140ms ease;
|
|
1280
1325
|
}
|
|
1281
1326
|
/* Composer textarea: auto-grows (height managed in JS) up to ~4 lines, then
|
|
1282
|
-
scrolls. resize:none disables the manual drag handle.
|
|
1327
|
+
scrolls. resize:none disables the manual drag handle. Filled style: neutral
|
|
1328
|
+
pill at rest that "lights up" white on focus \u2014 calmer than a glowing ring. */
|
|
1283
1329
|
textarea.nexor-chat__input {
|
|
1284
1330
|
display: block;
|
|
1285
1331
|
resize: none;
|
|
@@ -1288,11 +1334,22 @@ textarea.nexor-chat__input {
|
|
|
1288
1334
|
max-height: 98px; /* 4 lines (20\xD74) + 16 padding + 2 border */
|
|
1289
1335
|
white-space: pre-wrap;
|
|
1290
1336
|
word-break: break-word;
|
|
1337
|
+
background: #f3f4f6;
|
|
1338
|
+
border-color: transparent;
|
|
1339
|
+
border-radius: 19px;
|
|
1340
|
+
padding: 8px 14px;
|
|
1341
|
+
transition: background 140ms ease, border-color 140ms ease, box-shadow 140ms ease;
|
|
1291
1342
|
}
|
|
1343
|
+
textarea.nexor-chat__input::placeholder { color: #9ca3af; }
|
|
1292
1344
|
.nexor-chat__input:focus,
|
|
1293
1345
|
.nexor-chat__capture input:focus {
|
|
1294
1346
|
border-color: ${accent};
|
|
1295
|
-
box-shadow: 0 0 0
|
|
1347
|
+
box-shadow: 0 0 0 2px ${accent}1f;
|
|
1348
|
+
}
|
|
1349
|
+
textarea.nexor-chat__input:focus {
|
|
1350
|
+
background: #fff;
|
|
1351
|
+
border-color: ${accent}99;
|
|
1352
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
|
|
1296
1353
|
}
|
|
1297
1354
|
.nexor-chat__input--error,
|
|
1298
1355
|
.nexor-chat__capture input.nexor-chat__input--error {
|
|
@@ -1433,21 +1490,26 @@ textarea.nexor-chat__input {
|
|
|
1433
1490
|
background: ${accent};
|
|
1434
1491
|
color: ${accentText};
|
|
1435
1492
|
border: none;
|
|
1436
|
-
border-radius:
|
|
1437
|
-
padding: 0
|
|
1493
|
+
border-radius: 9999px; /* circle, matches the pill composer */
|
|
1494
|
+
padding: 0;
|
|
1438
1495
|
font: inherit;
|
|
1439
1496
|
font-weight: 600;
|
|
1440
1497
|
cursor: pointer;
|
|
1441
|
-
|
|
1498
|
+
width: 38px;
|
|
1442
1499
|
height: 38px; /* matches the one-line textarea height */
|
|
1443
1500
|
flex: none;
|
|
1444
1501
|
display: flex;
|
|
1445
1502
|
align-items: center;
|
|
1446
1503
|
justify-content: center;
|
|
1447
|
-
|
|
1504
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.12);
|
|
1505
|
+
transition: transform 140ms ease, filter 140ms ease, box-shadow 140ms ease;
|
|
1506
|
+
}
|
|
1507
|
+
.nexor-chat__send:hover {
|
|
1508
|
+
filter: brightness(1.08);
|
|
1509
|
+
box-shadow: 0 2px 6px rgba(0,0,0,0.18);
|
|
1510
|
+
transform: translateY(-1px);
|
|
1448
1511
|
}
|
|
1449
|
-
.nexor-chat__send:
|
|
1450
|
-
.nexor-chat__send:active { transform: scale(0.95); }
|
|
1512
|
+
.nexor-chat__send:active { transform: scale(0.93); }
|
|
1451
1513
|
.nexor-chat__send[disabled] {
|
|
1452
1514
|
opacity: 0.6;
|
|
1453
1515
|
cursor: not-allowed;
|
|
@@ -1458,7 +1520,7 @@ textarea.nexor-chat__input {
|
|
|
1458
1520
|
height: 18px;
|
|
1459
1521
|
transition: transform 200ms ease;
|
|
1460
1522
|
}
|
|
1461
|
-
.nexor-chat__send:not([disabled]):hover svg { transform:
|
|
1523
|
+
.nexor-chat__send:not([disabled]):hover svg { transform: translateY(-1.5px); }
|
|
1462
1524
|
|
|
1463
1525
|
/* Small spinner inside the send button while a turn is in flight */
|
|
1464
1526
|
.nexor-chat__send--loading svg { display: none; }
|
|
@@ -1611,11 +1673,13 @@ textarea.nexor-chat__input {
|
|
|
1611
1673
|
// src/chat/dom.ts
|
|
1612
1674
|
var STYLE_ATTR = "data-nexor-chat-styles";
|
|
1613
1675
|
function injectStyles(accent, accentText) {
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1676
|
+
let style = document.querySelector(`style[${STYLE_ATTR}]`);
|
|
1677
|
+
if (!style) {
|
|
1678
|
+
style = document.createElement("style");
|
|
1679
|
+
style.setAttribute(STYLE_ATTR, "1");
|
|
1680
|
+
document.head.appendChild(style);
|
|
1681
|
+
}
|
|
1617
1682
|
style.textContent = widgetCss(accent, accentText);
|
|
1618
|
-
document.head.appendChild(style);
|
|
1619
1683
|
}
|
|
1620
1684
|
var CHAT_ICON = `
|
|
1621
1685
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
|
@@ -1978,8 +2042,8 @@ function buildComposer(cfg) {
|
|
|
1978
2042
|
send.setAttribute("aria-label", "Send message");
|
|
1979
2043
|
send.innerHTML = `
|
|
1980
2044
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
|
1981
|
-
<path d="
|
|
1982
|
-
stroke="currentColor" stroke-width="
|
|
2045
|
+
<path d="M12 19V5.8M5.8 12 12 5.8 18.2 12"
|
|
2046
|
+
stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1983
2047
|
</svg>
|
|
1984
2048
|
`;
|
|
1985
2049
|
form.appendChild(input);
|
|
@@ -2021,6 +2085,28 @@ function buildMessage(role, text, ts, locale) {
|
|
|
2021
2085
|
}
|
|
2022
2086
|
return el;
|
|
2023
2087
|
}
|
|
2088
|
+
function buildMediaMessage(item) {
|
|
2089
|
+
const el = document.createElement("div");
|
|
2090
|
+
el.className = "nexor-chat__msg nexor-chat__msg--bot nexor-chat__msg--media";
|
|
2091
|
+
if (item.type === "image") {
|
|
2092
|
+
const img = document.createElement("img");
|
|
2093
|
+
img.className = "nexor-chat__media-img";
|
|
2094
|
+
img.src = item.url;
|
|
2095
|
+
img.alt = item.filename || "";
|
|
2096
|
+
img.loading = "lazy";
|
|
2097
|
+
img.addEventListener("error", () => el.remove());
|
|
2098
|
+
el.appendChild(img);
|
|
2099
|
+
} else {
|
|
2100
|
+
const a = document.createElement("a");
|
|
2101
|
+
a.className = "nexor-chat__media-doc";
|
|
2102
|
+
a.href = item.url;
|
|
2103
|
+
a.target = "_blank";
|
|
2104
|
+
a.rel = "noopener noreferrer";
|
|
2105
|
+
a.textContent = item.filename || "Descargar archivo";
|
|
2106
|
+
el.appendChild(a);
|
|
2107
|
+
}
|
|
2108
|
+
return el;
|
|
2109
|
+
}
|
|
2024
2110
|
function formatRelativeTime(ts, locale, now = Date.now()) {
|
|
2025
2111
|
try {
|
|
2026
2112
|
const diff = Math.max(0, now - ts);
|
|
@@ -2198,7 +2284,8 @@ function initChat(client, options) {
|
|
|
2198
2284
|
setView("chat");
|
|
2199
2285
|
renderResumeBanner();
|
|
2200
2286
|
for (const m of persisted.history) {
|
|
2201
|
-
|
|
2287
|
+
if (m.media) appendNode(buildMediaMessage(m.media));
|
|
2288
|
+
else appendBubble(m.role === "user" ? "user" : "bot", m.text, m.ts);
|
|
2202
2289
|
}
|
|
2203
2290
|
scrollToBottom();
|
|
2204
2291
|
}
|
|
@@ -2731,9 +2818,12 @@ function initChat(client, options) {
|
|
|
2731
2818
|
renderResumeBanner(true);
|
|
2732
2819
|
}
|
|
2733
2820
|
const reply = (res.reply ?? "").trim();
|
|
2821
|
+
const hasMedia = Array.isArray(res.media) && res.media.length > 0;
|
|
2734
2822
|
hideTyping();
|
|
2735
2823
|
if (reply) {
|
|
2736
|
-
appendBotReply(reply);
|
|
2824
|
+
appendBotReply(reply, hasMedia ? () => appendBotMedia(res.media) : void 0);
|
|
2825
|
+
} else if (hasMedia) {
|
|
2826
|
+
appendBotMedia(res.media);
|
|
2737
2827
|
} else {
|
|
2738
2828
|
appendSystem(cfg.errorText);
|
|
2739
2829
|
cfg.onError?.(new Error("Nexor SDK: empty reply from server"));
|
|
@@ -2768,10 +2858,21 @@ function initChat(client, options) {
|
|
|
2768
2858
|
if (!state.isOpen) bumpUnread();
|
|
2769
2859
|
cfg.onMessage?.({ role: "bot", text });
|
|
2770
2860
|
}
|
|
2771
|
-
function
|
|
2861
|
+
function appendBotMedia(items) {
|
|
2862
|
+
if (!Array.isArray(items) || items.length === 0) return;
|
|
2863
|
+
for (const item of items) {
|
|
2864
|
+
if (!item || typeof item.url !== "string" || !item.url) continue;
|
|
2865
|
+
appendNode(buildMediaMessage(item));
|
|
2866
|
+
state.history.push({ role: "bot", text: "", ts: Date.now(), media: item });
|
|
2867
|
+
}
|
|
2868
|
+
saveHistory();
|
|
2869
|
+
if (!state.isOpen) bumpUnread();
|
|
2870
|
+
}
|
|
2871
|
+
function appendBotReply(text, after) {
|
|
2772
2872
|
const parts = cfg.splitReplies ? splitReply(text) : [text];
|
|
2773
2873
|
if (parts.length <= 1) {
|
|
2774
2874
|
appendBot(text);
|
|
2875
|
+
after?.();
|
|
2775
2876
|
return;
|
|
2776
2877
|
}
|
|
2777
2878
|
const [first, ...rest] = parts;
|
|
@@ -2779,7 +2880,10 @@ function initChat(client, options) {
|
|
|
2779
2880
|
let i = 0;
|
|
2780
2881
|
const sendNext = () => {
|
|
2781
2882
|
const part = rest[i];
|
|
2782
|
-
if (part === void 0)
|
|
2883
|
+
if (part === void 0) {
|
|
2884
|
+
after?.();
|
|
2885
|
+
return;
|
|
2886
|
+
}
|
|
2783
2887
|
const isLast = i === rest.length - 1;
|
|
2784
2888
|
i++;
|
|
2785
2889
|
showTyping();
|