@antzsoft/chat-core 1.2.5 → 1.2.6
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/README.md +320 -0
- package/dist/{chunk-ZNA6B2R5.js → chunk-XTQYF5HU.js} +99 -4
- package/dist/chunk-XTQYF5HU.js.map +1 -0
- package/dist/index.cjs +132 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -1
- package/dist/index.d.ts +43 -1
- package/dist/index.js +39 -13
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +6 -1
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.js +1 -1
- package/docs/integration-guide.html +835 -130
- package/package.json +1 -1
- package/dist/chunk-ZNA6B2R5.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -99,7 +99,13 @@ var init_chat_store = __esm({
|
|
|
99
99
|
// src/index.ts
|
|
100
100
|
var src_exports = {};
|
|
101
101
|
__export(src_exports, {
|
|
102
|
+
AntzChatAuthError: () => AntzChatAuthError,
|
|
102
103
|
AntzChatClient: () => AntzChatClient,
|
|
104
|
+
AntzChatError: () => AntzChatError,
|
|
105
|
+
AntzChatNetworkError: () => AntzChatNetworkError,
|
|
106
|
+
AntzChatPermissionError: () => AntzChatPermissionError,
|
|
107
|
+
AntzChatServerError: () => AntzChatServerError,
|
|
108
|
+
AntzChatValidationError: () => AntzChatValidationError,
|
|
103
109
|
appConfigApi: () => appConfigApi,
|
|
104
110
|
authApi: () => authApi,
|
|
105
111
|
connectSocket: () => connectSocket,
|
|
@@ -123,6 +129,7 @@ __export(src_exports, {
|
|
|
123
129
|
initAuthStore: () => initAuthStore,
|
|
124
130
|
isTransitEnvelope: () => isTransitEnvelope,
|
|
125
131
|
messagesApi: () => messagesApi,
|
|
132
|
+
normalizeAxiosError: () => normalizeAxiosError,
|
|
126
133
|
normalizeConversation: () => normalizeConversation,
|
|
127
134
|
onSocketStatus: () => onSocketStatus,
|
|
128
135
|
performHandshake: () => performHandshake,
|
|
@@ -265,7 +272,7 @@ async function compressFile(file, platformCompressFn, config) {
|
|
|
265
272
|
}
|
|
266
273
|
|
|
267
274
|
// src/api/client.ts
|
|
268
|
-
var
|
|
275
|
+
var import_axios2 = __toESM(require("axios"), 1);
|
|
269
276
|
|
|
270
277
|
// src/crypto/transit.ts
|
|
271
278
|
function hasWebCrypto() {
|
|
@@ -561,6 +568,94 @@ function base64ToUint82(b64) {
|
|
|
561
568
|
return buf;
|
|
562
569
|
}
|
|
563
570
|
|
|
571
|
+
// src/errors.ts
|
|
572
|
+
var import_axios = require("axios");
|
|
573
|
+
var AntzChatError = class extends Error {
|
|
574
|
+
constructor(code, message, retryable = false, context) {
|
|
575
|
+
super(message);
|
|
576
|
+
this.name = "AntzChatError";
|
|
577
|
+
this.code = code;
|
|
578
|
+
this.retryable = retryable;
|
|
579
|
+
this.context = context;
|
|
580
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
var AntzChatAuthError = class extends AntzChatError {
|
|
584
|
+
constructor(message, code = "AUTH_FAILED", context) {
|
|
585
|
+
super(code, message, false, context);
|
|
586
|
+
this.name = "AntzChatAuthError";
|
|
587
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
var AntzChatValidationError = class extends AntzChatError {
|
|
591
|
+
constructor(message, context) {
|
|
592
|
+
const msg = Array.isArray(message) ? message.join("; ") : message;
|
|
593
|
+
super("VALIDATION_ERROR", msg, false, context);
|
|
594
|
+
this.name = "AntzChatValidationError";
|
|
595
|
+
this.fields = Array.isArray(message) ? message : void 0;
|
|
596
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
var AntzChatNetworkError = class extends AntzChatError {
|
|
600
|
+
constructor(message, code = "NETWORK_ERROR", context) {
|
|
601
|
+
super(code, message, true, context);
|
|
602
|
+
this.name = "AntzChatNetworkError";
|
|
603
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
var AntzChatPermissionError = class extends AntzChatError {
|
|
607
|
+
constructor(message, context) {
|
|
608
|
+
super("PERMISSION_DENIED", message, false, context);
|
|
609
|
+
this.name = "AntzChatPermissionError";
|
|
610
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
var AntzChatServerError = class extends AntzChatError {
|
|
614
|
+
constructor(message, httpStatus, context) {
|
|
615
|
+
super("SERVER_ERROR", message, true, context);
|
|
616
|
+
this.name = "AntzChatServerError";
|
|
617
|
+
this.httpStatus = httpStatus;
|
|
618
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
function normalizeAxiosError(error) {
|
|
622
|
+
if (error instanceof AntzChatError) return error;
|
|
623
|
+
if ((0, import_axios.isAxiosError)(error)) {
|
|
624
|
+
const status = error.response?.status;
|
|
625
|
+
const body = error.response?.data;
|
|
626
|
+
const decryptionFailed = body != null && isTransitEnvelope(body);
|
|
627
|
+
const rawMessage = decryptionFailed ? void 0 : body?.message ?? void 0;
|
|
628
|
+
const message = (Array.isArray(rawMessage) ? rawMessage.join("; ") : rawMessage) || error.message || "Request failed";
|
|
629
|
+
const ctx = {
|
|
630
|
+
...status != null && { httpStatus: status },
|
|
631
|
+
...body?.path != null && { path: body.path },
|
|
632
|
+
...body?.error != null && { serverError: body.error },
|
|
633
|
+
...error.code != null && { axiosCode: error.code },
|
|
634
|
+
...decryptionFailed && { decryptionFailed: true, note: "Transit decryption failed \u2014 server error body is an encrypted envelope" }
|
|
635
|
+
};
|
|
636
|
+
if (!error.response) {
|
|
637
|
+
return new AntzChatNetworkError(message || "Network error", "NETWORK_ERROR", ctx);
|
|
638
|
+
}
|
|
639
|
+
if (status === 401) {
|
|
640
|
+
const code = error.config?._retry ? "AUTH_FAILED" : "SESSION_EXPIRED";
|
|
641
|
+
return new AntzChatAuthError(message, code, ctx);
|
|
642
|
+
}
|
|
643
|
+
if (status === 403) return new AntzChatPermissionError(message, ctx);
|
|
644
|
+
if (status === 400 || status === 422) {
|
|
645
|
+
return new AntzChatValidationError(
|
|
646
|
+
Array.isArray(rawMessage) ? rawMessage : message,
|
|
647
|
+
ctx
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
if (status === 404) return new AntzChatServerError(message, 404, ctx);
|
|
651
|
+
if (status === 429) return new AntzChatNetworkError(message, "RATE_LIMITED", ctx);
|
|
652
|
+
if (status != null && status >= 500) return new AntzChatServerError(message, status, ctx);
|
|
653
|
+
return new AntzChatServerError(message, status, ctx);
|
|
654
|
+
}
|
|
655
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
656
|
+
return new AntzChatError("UNKNOWN_ERROR", msg, false);
|
|
657
|
+
}
|
|
658
|
+
|
|
564
659
|
// src/api/client.ts
|
|
565
660
|
var _tokenStore = null;
|
|
566
661
|
var _config = null;
|
|
@@ -573,7 +668,7 @@ function initApiClient(config, tokenStore) {
|
|
|
573
668
|
_config = config;
|
|
574
669
|
_tokenStore = tokenStore;
|
|
575
670
|
_avatarSent = false;
|
|
576
|
-
const client =
|
|
671
|
+
const client = import_axios2.default.create({
|
|
577
672
|
baseURL: config.apiUrl,
|
|
578
673
|
headers: { "Content-Type": "application/json" }
|
|
579
674
|
});
|
|
@@ -658,7 +753,7 @@ function initApiClient(config, tokenStore) {
|
|
|
658
753
|
const refreshToken = _tokenStore?.getRefreshToken();
|
|
659
754
|
if (!refreshToken) {
|
|
660
755
|
_tokenStore?.clearTokens();
|
|
661
|
-
return Promise.reject(error);
|
|
756
|
+
return Promise.reject(normalizeAxiosError(error));
|
|
662
757
|
}
|
|
663
758
|
if (isRefreshing) {
|
|
664
759
|
return new Promise((resolve) => {
|
|
@@ -671,7 +766,7 @@ function initApiClient(config, tokenStore) {
|
|
|
671
766
|
original._retry = true;
|
|
672
767
|
isRefreshing = true;
|
|
673
768
|
try {
|
|
674
|
-
const { data } = await
|
|
769
|
+
const { data } = await import_axios2.default.post(
|
|
675
770
|
`${_config.apiUrl}/auth/refresh`,
|
|
676
771
|
{ refreshToken }
|
|
677
772
|
);
|
|
@@ -683,12 +778,12 @@ function initApiClient(config, tokenStore) {
|
|
|
683
778
|
return client(original);
|
|
684
779
|
} catch {
|
|
685
780
|
_tokenStore?.clearTokens();
|
|
686
|
-
return Promise.reject(error);
|
|
781
|
+
return Promise.reject(normalizeAxiosError(error));
|
|
687
782
|
} finally {
|
|
688
783
|
isRefreshing = false;
|
|
689
784
|
}
|
|
690
785
|
}
|
|
691
|
-
return Promise.reject(error);
|
|
786
|
+
return Promise.reject(normalizeAxiosError(error));
|
|
692
787
|
}
|
|
693
788
|
);
|
|
694
789
|
return client;
|
|
@@ -1116,6 +1211,9 @@ var conversationsApi = {
|
|
|
1116
1211
|
async removeIcon(conversationId) {
|
|
1117
1212
|
const { data } = await getApiClient().post(`/conversations/${conversationId}/icon/remove`);
|
|
1118
1213
|
return normalizeConversation(data);
|
|
1214
|
+
},
|
|
1215
|
+
async clearChat(conversationId) {
|
|
1216
|
+
await getApiClient().post(`/conversations/${conversationId}/clear-for-me`);
|
|
1119
1217
|
}
|
|
1120
1218
|
};
|
|
1121
1219
|
|
|
@@ -1483,8 +1581,11 @@ async function _doConnect(config, getToken) {
|
|
|
1483
1581
|
try {
|
|
1484
1582
|
const serverKeys = await fetchServerKeys(config.apiUrl);
|
|
1485
1583
|
if (!serverKeys.enabled) {
|
|
1486
|
-
throw new
|
|
1487
|
-
"
|
|
1584
|
+
throw new AntzChatError(
|
|
1585
|
+
"TRANSIT_MISMATCH",
|
|
1586
|
+
"[AntzChat] Transit encryption mismatch: SDK has transitEncryption=true but server has TRANSIT_ENCRYPTION_ENABLED=false. Align the config on both sides.",
|
|
1587
|
+
false,
|
|
1588
|
+
{ sdkEnabled: true, serverEnabled: false }
|
|
1488
1589
|
);
|
|
1489
1590
|
}
|
|
1490
1591
|
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
@@ -1497,12 +1598,15 @@ async function _doConnect(config, getToken) {
|
|
|
1497
1598
|
try {
|
|
1498
1599
|
const serverKeys = await fetchServerKeys(config.apiUrl);
|
|
1499
1600
|
if (serverKeys.enabled) {
|
|
1500
|
-
throw new
|
|
1501
|
-
"
|
|
1601
|
+
throw new AntzChatError(
|
|
1602
|
+
"TRANSIT_MISMATCH",
|
|
1603
|
+
"[AntzChat] Transit encryption mismatch: SDK has transitEncryption=false but server has TRANSIT_ENCRYPTION_ENABLED=true. Align the config on both sides.",
|
|
1604
|
+
false,
|
|
1605
|
+
{ sdkEnabled: false, serverEnabled: true }
|
|
1502
1606
|
);
|
|
1503
1607
|
}
|
|
1504
1608
|
} catch (err) {
|
|
1505
|
-
if (err
|
|
1609
|
+
if (err?.code === "TRANSIT_MISMATCH") throw err;
|
|
1506
1610
|
}
|
|
1507
1611
|
}
|
|
1508
1612
|
_socket = (0, import_socket.io)(`${config.socketOrigin}/chat`, {
|
|
@@ -1646,7 +1750,7 @@ async function drainSendQueue(conversationId) {
|
|
|
1646
1750
|
while (queue.length > 0) {
|
|
1647
1751
|
const entry = queue.shift();
|
|
1648
1752
|
if (Date.now() - entry.enqueuedAt > QUEUE_ENTRY_TTL) {
|
|
1649
|
-
entry.reject(new
|
|
1753
|
+
entry.reject(new AntzChatNetworkError("Message dropped: queued too long", "MESSAGE_DROPPED"));
|
|
1650
1754
|
continue;
|
|
1651
1755
|
}
|
|
1652
1756
|
entry.run().then(entry.resolve).catch(entry.reject);
|
|
@@ -1659,7 +1763,7 @@ function queueSendMessage(payload) {
|
|
|
1659
1763
|
if (!sendQueues.has(conversationId)) sendQueues.set(conversationId, []);
|
|
1660
1764
|
const queue = sendQueues.get(conversationId);
|
|
1661
1765
|
if (queue.length >= QUEUE_MAX_SIZE) {
|
|
1662
|
-
return Promise.reject(new
|
|
1766
|
+
return Promise.reject(new AntzChatNetworkError("Send queue full: too many messages in flight", "SEND_QUEUE_FULL", { conversationId }));
|
|
1663
1767
|
}
|
|
1664
1768
|
return new Promise((resolve, reject) => {
|
|
1665
1769
|
queue.push({ run: () => withAck("send_message", payload), resolve, reject, enqueuedAt: Date.now() });
|
|
@@ -1670,7 +1774,7 @@ function waitForReconnect() {
|
|
|
1670
1774
|
return new Promise((resolve, reject) => {
|
|
1671
1775
|
const timer = setTimeout(() => {
|
|
1672
1776
|
unsubscribe();
|
|
1673
|
-
reject(new
|
|
1777
|
+
reject(new AntzChatNetworkError("Socket reconnect timeout", "SOCKET_TIMEOUT"));
|
|
1674
1778
|
}, RECONNECT_WAIT_TIMEOUT);
|
|
1675
1779
|
const unsubscribe = onSocketStatus((status) => {
|
|
1676
1780
|
if (status === "connected") {
|
|
@@ -1680,7 +1784,7 @@ function waitForReconnect() {
|
|
|
1680
1784
|
} else if (status === "error") {
|
|
1681
1785
|
clearTimeout(timer);
|
|
1682
1786
|
unsubscribe();
|
|
1683
|
-
reject(new
|
|
1787
|
+
reject(new AntzChatNetworkError("Socket reconnect failed", "SOCKET_NOT_CONNECTED"));
|
|
1684
1788
|
}
|
|
1685
1789
|
});
|
|
1686
1790
|
});
|
|
@@ -1691,14 +1795,14 @@ async function withAck(event, payload) {
|
|
|
1691
1795
|
await waitForReconnect();
|
|
1692
1796
|
socket = tryGetSocket();
|
|
1693
1797
|
}
|
|
1694
|
-
if (!socket) return Promise.reject(new
|
|
1798
|
+
if (!socket) return Promise.reject(new AntzChatNetworkError(`Socket not connected (event: ${event})`, "SOCKET_NOT_CONNECTED", { event }));
|
|
1695
1799
|
return new Promise((resolve, reject) => {
|
|
1696
1800
|
let timer;
|
|
1697
1801
|
secureEmit(socket, event, payload, (response) => {
|
|
1698
1802
|
clearTimeout(timer);
|
|
1699
1803
|
resolve(response);
|
|
1700
1804
|
}).then(() => {
|
|
1701
|
-
timer = setTimeout(() => reject(new
|
|
1805
|
+
timer = setTimeout(() => reject(new AntzChatNetworkError(`Socket ack timeout: ${event}`, "SOCKET_TIMEOUT", { event })), ACK_TIMEOUT);
|
|
1702
1806
|
}).catch(reject);
|
|
1703
1807
|
});
|
|
1704
1808
|
}
|
|
@@ -1726,6 +1830,9 @@ var socketEmit = {
|
|
|
1726
1830
|
deleteMessageForMe(messageId) {
|
|
1727
1831
|
return withAck("delete_message_for_me", { messageId });
|
|
1728
1832
|
},
|
|
1833
|
+
clearChat(conversationId) {
|
|
1834
|
+
return withAck("clear_chat_for_me", { conversationId });
|
|
1835
|
+
},
|
|
1729
1836
|
addReaction(messageId, emoji) {
|
|
1730
1837
|
return withAck("add_reaction", { messageId, emoji });
|
|
1731
1838
|
},
|
|
@@ -1761,7 +1868,7 @@ var socketEmit = {
|
|
|
1761
1868
|
resolve([]);
|
|
1762
1869
|
}
|
|
1763
1870
|
}).then(() => {
|
|
1764
|
-
timer = setTimeout(() => reject(new
|
|
1871
|
+
timer = setTimeout(() => reject(new AntzChatNetworkError("Socket ack timeout: get_online_users", "SOCKET_TIMEOUT", { event: "get_online_users" })), ACK_TIMEOUT);
|
|
1765
1872
|
}).catch(reject);
|
|
1766
1873
|
});
|
|
1767
1874
|
},
|
|
@@ -1824,7 +1931,13 @@ var AntzChatClient = class {
|
|
|
1824
1931
|
};
|
|
1825
1932
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1826
1933
|
0 && (module.exports = {
|
|
1934
|
+
AntzChatAuthError,
|
|
1827
1935
|
AntzChatClient,
|
|
1936
|
+
AntzChatError,
|
|
1937
|
+
AntzChatNetworkError,
|
|
1938
|
+
AntzChatPermissionError,
|
|
1939
|
+
AntzChatServerError,
|
|
1940
|
+
AntzChatValidationError,
|
|
1828
1941
|
appConfigApi,
|
|
1829
1942
|
authApi,
|
|
1830
1943
|
connectSocket,
|
|
@@ -1848,6 +1961,7 @@ var AntzChatClient = class {
|
|
|
1848
1961
|
initAuthStore,
|
|
1849
1962
|
isTransitEnvelope,
|
|
1850
1963
|
messagesApi,
|
|
1964
|
+
normalizeAxiosError,
|
|
1851
1965
|
normalizeConversation,
|
|
1852
1966
|
onSocketStatus,
|
|
1853
1967
|
performHandshake,
|