@antzsoft/chat-core 1.4.5 → 1.4.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 +64 -1
- package/dist/{chunk-WUNH3UTE.js → chunk-U637W5MD.js} +62 -13
- package/dist/chunk-U637W5MD.js.map +1 -0
- package/dist/index.cjs +66 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -3
- package/dist/index.d.ts +52 -3
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.js +1 -1
- package/docs/integration-guide.html +151 -4
- package/package.json +1 -1
- package/dist/chunk-WUNH3UTE.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -395,17 +395,66 @@ declare function encryptPayload(data: unknown, sessionKey: AnySessionKey): Promi
|
|
|
395
395
|
declare function decryptPayload(envelope: TransitEnvelope, sessionKey: AnySessionKey): Promise<unknown>;
|
|
396
396
|
declare function isTransitEnvelope(v: unknown): v is TransitEnvelope;
|
|
397
397
|
|
|
398
|
+
/**
|
|
399
|
+
* Caller identity attached to the pre-auth transit handshake requests.
|
|
400
|
+
*
|
|
401
|
+
* GET /crypto/pubkey and POST /crypto/session run BEFORE a transit session (and
|
|
402
|
+
* therefore before the authenticated axios client) exists, so they bypass the
|
|
403
|
+
* request interceptor that normally adds these headers. Without them the server
|
|
404
|
+
* can only rate-limit these two routes by client IP — which means every user
|
|
405
|
+
* behind one NAT, office proxy or ALB shares a single bucket, and one client's
|
|
406
|
+
* reload loop 429s everyone else.
|
|
407
|
+
*
|
|
408
|
+
* These values are NOT used for authentication: the endpoints are unauthenticated
|
|
409
|
+
* by design and the server treats the headers as a fairness hint only, with a
|
|
410
|
+
* per-IP ceiling underneath as the real abuse limit. Sending them is therefore
|
|
411
|
+
* safe, optional, and backward compatible — an older SDK that omits them simply
|
|
412
|
+
* falls back to the shared per-IP bucket.
|
|
413
|
+
*/
|
|
414
|
+
interface TransitIdentity {
|
|
415
|
+
/** External user id — same value sent as x-user-id on authenticated requests. */
|
|
416
|
+
userId?: string;
|
|
417
|
+
/** Tenant id — same value sent as X-Tenant-ID on authenticated requests. */
|
|
418
|
+
tenantId?: string;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* How long the server asked us to wait, in ms, from a 429's Retry-After.
|
|
422
|
+
*
|
|
423
|
+
* The chat server runs TWO named rate-limit layers, and @nestjs/throttler
|
|
424
|
+
* suffixes its headers with the throttler name unless that name is literally
|
|
425
|
+
* "default". So a 429 carries `Retry-After-identity` or `Retry-After-ip`, not a
|
|
426
|
+
* bare `Retry-After`. Older servers and intermediary proxies may still send the
|
|
427
|
+
* bare name, so all three are read; when more than one is present the LONGER
|
|
428
|
+
* wait wins, since retrying before the slower bucket drains just earns another
|
|
429
|
+
* 429.
|
|
430
|
+
*
|
|
431
|
+
* Returns undefined when no variant is readable — in a browser that also
|
|
432
|
+
* happens when the server omits these from Access-Control-Expose-Headers, in
|
|
433
|
+
* which case callers must fall back to their own backoff.
|
|
434
|
+
*/
|
|
435
|
+
declare function readRetryAfterMs(headers: Headers): number | undefined;
|
|
436
|
+
/**
|
|
437
|
+
* Thrown when the transit handshake is rate-limited (HTTP 429).
|
|
438
|
+
*
|
|
439
|
+
* Distinct from a generic failure because the correct response differs: a 429
|
|
440
|
+
* means "wait", not "this is broken", so callers must not burn their retry
|
|
441
|
+
* budget on it and should honour `retryAfterMs` when the server supplied it.
|
|
442
|
+
*/
|
|
443
|
+
declare class TransitRateLimitedError extends Error {
|
|
444
|
+
readonly retryAfterMs?: number;
|
|
445
|
+
constructor(retryAfterMs?: number);
|
|
446
|
+
}
|
|
398
447
|
interface ServerPublicKeys {
|
|
399
448
|
x25519: string;
|
|
400
449
|
p256: string;
|
|
401
450
|
enabled: boolean;
|
|
402
451
|
}
|
|
403
|
-
declare function fetchServerKeys(apiUrl: string): Promise<ServerPublicKeys>;
|
|
452
|
+
declare function fetchServerKeys(apiUrl: string, identity?: TransitIdentity): Promise<ServerPublicKeys>;
|
|
404
453
|
declare function generateEphemeralKey(algo: TransitAlgo, serverKeys: ServerPublicKeys): Promise<{
|
|
405
454
|
ephemeralPubB64: string;
|
|
406
455
|
deriveSessionKey: (sessionId: string) => Promise<unknown>;
|
|
407
456
|
}>;
|
|
408
|
-
declare function createRestTransitSession(apiUrl: string): Promise<{
|
|
457
|
+
declare function createRestTransitSession(apiUrl: string, identity?: TransitIdentity): Promise<{
|
|
409
458
|
sessionId: string;
|
|
410
459
|
sessionKey: CryptoKey | Uint8Array;
|
|
411
460
|
} | null>;
|
|
@@ -799,4 +848,4 @@ declare class AntzChatClient {
|
|
|
799
848
|
uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
|
|
800
849
|
}
|
|
801
850
|
|
|
802
|
-
export { AntzChatAuthError, AntzChatClient, AntzChatConfig, AntzChatError, AntzChatNetworkError, AntzChatPermissionError, AntzChatServerError, AntzChatValidationError, AppConfig, AuthResponse, AuthTokens, BatchUploadResult, CompletedPart, Conversation, ConversationListParams, ConversationSyncResponse, ConversationUnreadCount, type CreateDirectData, type CreateGroupData, CrossConversationSyncResponse, CursorPaginatedResponse, FileResponse, FileType, ForwardAckPayload, ForwardMessagePayload, type ForwardResult, HIGHLY_FORWARDED_DEPTH_THRESHOLD, type LastReadEntry, type ListMessagesParams, LoginCredentials, MAX_FORWARD_TARGETS, type MentionPart, type MentionSegment, Message, MessageReactionsResponse, MessageReceiptsResponse, type MobileDeviceToken, PaginatedResponse, type ParsedMention, Participant, PersistStorage, PresignedUrlRequest, PresignedUrlResponse, RegisterData, type RegisterDeviceTokenPayload, ResolvedCompressionConfig, ResolvedConfig, type SearchParams, type SendData, SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, UnreadSummary, type UpdateConversationData, type UpdateProfilePayload, UploadableFile, User, UserPreferences, type WebPushDeviceToken, appConfigApi, authApi, buildMentionText, connectSocket, conversationsApi, createAuthStore, createRestTransitSession, decryptPayload, devicesApi, disconnectSocket, encryptPayload, extractMentionIds, fetchServerKeys, generateEphemeralKey, getApiClient, getAuthStore, getCompressionStrategy, getSessionId, getSessionKey, getSocket, getSocketStatus, initApiClient, initAuthStore, isApiClientConfigured, isMentionAll, isTransitEnvelope, messagesApi, normalizeAxiosError, normalizeConversation, onSocketStatus, parseMentions, performHandshake, reconnectSocket, refreshSocketAuth, renderMentionParts, resetAuthStore, resetTrackedRooms, resolveSystemMessageText, setApiClientInstance, setAuthReadyPromise, setTransitSession, socketEmit, syncApi, tryGetSocket, useChatStore, usersApi };
|
|
851
|
+
export { AntzChatAuthError, AntzChatClient, AntzChatConfig, AntzChatError, AntzChatNetworkError, AntzChatPermissionError, AntzChatServerError, AntzChatValidationError, AppConfig, AuthResponse, AuthTokens, BatchUploadResult, CompletedPart, Conversation, ConversationListParams, ConversationSyncResponse, ConversationUnreadCount, type CreateDirectData, type CreateGroupData, CrossConversationSyncResponse, CursorPaginatedResponse, FileResponse, FileType, ForwardAckPayload, ForwardMessagePayload, type ForwardResult, HIGHLY_FORWARDED_DEPTH_THRESHOLD, type LastReadEntry, type ListMessagesParams, LoginCredentials, MAX_FORWARD_TARGETS, type MentionPart, type MentionSegment, Message, MessageReactionsResponse, MessageReceiptsResponse, type MobileDeviceToken, PaginatedResponse, type ParsedMention, Participant, PersistStorage, PresignedUrlRequest, PresignedUrlResponse, RegisterData, type RegisterDeviceTokenPayload, ResolvedCompressionConfig, ResolvedConfig, type SearchParams, type SendData, SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, type TransitIdentity, TransitRateLimitedError, UnreadSummary, type UpdateConversationData, type UpdateProfilePayload, UploadableFile, User, UserPreferences, type WebPushDeviceToken, appConfigApi, authApi, buildMentionText, connectSocket, conversationsApi, createAuthStore, createRestTransitSession, decryptPayload, devicesApi, disconnectSocket, encryptPayload, extractMentionIds, fetchServerKeys, generateEphemeralKey, getApiClient, getAuthStore, getCompressionStrategy, getSessionId, getSessionKey, getSocket, getSocketStatus, initApiClient, initAuthStore, isApiClientConfigured, isMentionAll, isTransitEnvelope, messagesApi, normalizeAxiosError, normalizeConversation, onSocketStatus, parseMentions, performHandshake, readRetryAfterMs, reconnectSocket, refreshSocketAuth, renderMentionParts, resetAuthStore, resetTrackedRooms, resolveSystemMessageText, setApiClientInstance, setAuthReadyPromise, setTransitSession, socketEmit, syncApi, tryGetSocket, useChatStore, usersApi };
|
package/dist/index.d.ts
CHANGED
|
@@ -395,17 +395,66 @@ declare function encryptPayload(data: unknown, sessionKey: AnySessionKey): Promi
|
|
|
395
395
|
declare function decryptPayload(envelope: TransitEnvelope, sessionKey: AnySessionKey): Promise<unknown>;
|
|
396
396
|
declare function isTransitEnvelope(v: unknown): v is TransitEnvelope;
|
|
397
397
|
|
|
398
|
+
/**
|
|
399
|
+
* Caller identity attached to the pre-auth transit handshake requests.
|
|
400
|
+
*
|
|
401
|
+
* GET /crypto/pubkey and POST /crypto/session run BEFORE a transit session (and
|
|
402
|
+
* therefore before the authenticated axios client) exists, so they bypass the
|
|
403
|
+
* request interceptor that normally adds these headers. Without them the server
|
|
404
|
+
* can only rate-limit these two routes by client IP — which means every user
|
|
405
|
+
* behind one NAT, office proxy or ALB shares a single bucket, and one client's
|
|
406
|
+
* reload loop 429s everyone else.
|
|
407
|
+
*
|
|
408
|
+
* These values are NOT used for authentication: the endpoints are unauthenticated
|
|
409
|
+
* by design and the server treats the headers as a fairness hint only, with a
|
|
410
|
+
* per-IP ceiling underneath as the real abuse limit. Sending them is therefore
|
|
411
|
+
* safe, optional, and backward compatible — an older SDK that omits them simply
|
|
412
|
+
* falls back to the shared per-IP bucket.
|
|
413
|
+
*/
|
|
414
|
+
interface TransitIdentity {
|
|
415
|
+
/** External user id — same value sent as x-user-id on authenticated requests. */
|
|
416
|
+
userId?: string;
|
|
417
|
+
/** Tenant id — same value sent as X-Tenant-ID on authenticated requests. */
|
|
418
|
+
tenantId?: string;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* How long the server asked us to wait, in ms, from a 429's Retry-After.
|
|
422
|
+
*
|
|
423
|
+
* The chat server runs TWO named rate-limit layers, and @nestjs/throttler
|
|
424
|
+
* suffixes its headers with the throttler name unless that name is literally
|
|
425
|
+
* "default". So a 429 carries `Retry-After-identity` or `Retry-After-ip`, not a
|
|
426
|
+
* bare `Retry-After`. Older servers and intermediary proxies may still send the
|
|
427
|
+
* bare name, so all three are read; when more than one is present the LONGER
|
|
428
|
+
* wait wins, since retrying before the slower bucket drains just earns another
|
|
429
|
+
* 429.
|
|
430
|
+
*
|
|
431
|
+
* Returns undefined when no variant is readable — in a browser that also
|
|
432
|
+
* happens when the server omits these from Access-Control-Expose-Headers, in
|
|
433
|
+
* which case callers must fall back to their own backoff.
|
|
434
|
+
*/
|
|
435
|
+
declare function readRetryAfterMs(headers: Headers): number | undefined;
|
|
436
|
+
/**
|
|
437
|
+
* Thrown when the transit handshake is rate-limited (HTTP 429).
|
|
438
|
+
*
|
|
439
|
+
* Distinct from a generic failure because the correct response differs: a 429
|
|
440
|
+
* means "wait", not "this is broken", so callers must not burn their retry
|
|
441
|
+
* budget on it and should honour `retryAfterMs` when the server supplied it.
|
|
442
|
+
*/
|
|
443
|
+
declare class TransitRateLimitedError extends Error {
|
|
444
|
+
readonly retryAfterMs?: number;
|
|
445
|
+
constructor(retryAfterMs?: number);
|
|
446
|
+
}
|
|
398
447
|
interface ServerPublicKeys {
|
|
399
448
|
x25519: string;
|
|
400
449
|
p256: string;
|
|
401
450
|
enabled: boolean;
|
|
402
451
|
}
|
|
403
|
-
declare function fetchServerKeys(apiUrl: string): Promise<ServerPublicKeys>;
|
|
452
|
+
declare function fetchServerKeys(apiUrl: string, identity?: TransitIdentity): Promise<ServerPublicKeys>;
|
|
404
453
|
declare function generateEphemeralKey(algo: TransitAlgo, serverKeys: ServerPublicKeys): Promise<{
|
|
405
454
|
ephemeralPubB64: string;
|
|
406
455
|
deriveSessionKey: (sessionId: string) => Promise<unknown>;
|
|
407
456
|
}>;
|
|
408
|
-
declare function createRestTransitSession(apiUrl: string): Promise<{
|
|
457
|
+
declare function createRestTransitSession(apiUrl: string, identity?: TransitIdentity): Promise<{
|
|
409
458
|
sessionId: string;
|
|
410
459
|
sessionKey: CryptoKey | Uint8Array;
|
|
411
460
|
} | null>;
|
|
@@ -799,4 +848,4 @@ declare class AntzChatClient {
|
|
|
799
848
|
uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
|
|
800
849
|
}
|
|
801
850
|
|
|
802
|
-
export { AntzChatAuthError, AntzChatClient, AntzChatConfig, AntzChatError, AntzChatNetworkError, AntzChatPermissionError, AntzChatServerError, AntzChatValidationError, AppConfig, AuthResponse, AuthTokens, BatchUploadResult, CompletedPart, Conversation, ConversationListParams, ConversationSyncResponse, ConversationUnreadCount, type CreateDirectData, type CreateGroupData, CrossConversationSyncResponse, CursorPaginatedResponse, FileResponse, FileType, ForwardAckPayload, ForwardMessagePayload, type ForwardResult, HIGHLY_FORWARDED_DEPTH_THRESHOLD, type LastReadEntry, type ListMessagesParams, LoginCredentials, MAX_FORWARD_TARGETS, type MentionPart, type MentionSegment, Message, MessageReactionsResponse, MessageReceiptsResponse, type MobileDeviceToken, PaginatedResponse, type ParsedMention, Participant, PersistStorage, PresignedUrlRequest, PresignedUrlResponse, RegisterData, type RegisterDeviceTokenPayload, ResolvedCompressionConfig, ResolvedConfig, type SearchParams, type SendData, SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, UnreadSummary, type UpdateConversationData, type UpdateProfilePayload, UploadableFile, User, UserPreferences, type WebPushDeviceToken, appConfigApi, authApi, buildMentionText, connectSocket, conversationsApi, createAuthStore, createRestTransitSession, decryptPayload, devicesApi, disconnectSocket, encryptPayload, extractMentionIds, fetchServerKeys, generateEphemeralKey, getApiClient, getAuthStore, getCompressionStrategy, getSessionId, getSessionKey, getSocket, getSocketStatus, initApiClient, initAuthStore, isApiClientConfigured, isMentionAll, isTransitEnvelope, messagesApi, normalizeAxiosError, normalizeConversation, onSocketStatus, parseMentions, performHandshake, reconnectSocket, refreshSocketAuth, renderMentionParts, resetAuthStore, resetTrackedRooms, resolveSystemMessageText, setApiClientInstance, setAuthReadyPromise, setTransitSession, socketEmit, syncApi, tryGetSocket, useChatStore, usersApi };
|
|
851
|
+
export { AntzChatAuthError, AntzChatClient, AntzChatConfig, AntzChatError, AntzChatNetworkError, AntzChatPermissionError, AntzChatServerError, AntzChatValidationError, AppConfig, AuthResponse, AuthTokens, BatchUploadResult, CompletedPart, Conversation, ConversationListParams, ConversationSyncResponse, ConversationUnreadCount, type CreateDirectData, type CreateGroupData, CrossConversationSyncResponse, CursorPaginatedResponse, FileResponse, FileType, ForwardAckPayload, ForwardMessagePayload, type ForwardResult, HIGHLY_FORWARDED_DEPTH_THRESHOLD, type LastReadEntry, type ListMessagesParams, LoginCredentials, MAX_FORWARD_TARGETS, type MentionPart, type MentionSegment, Message, MessageReactionsResponse, MessageReceiptsResponse, type MobileDeviceToken, PaginatedResponse, type ParsedMention, Participant, PersistStorage, PresignedUrlRequest, PresignedUrlResponse, RegisterData, type RegisterDeviceTokenPayload, ResolvedCompressionConfig, ResolvedConfig, type SearchParams, type SendData, SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, type TransitIdentity, TransitRateLimitedError, UnreadSummary, type UpdateConversationData, type UpdateProfilePayload, UploadableFile, User, UserPreferences, type WebPushDeviceToken, appConfigApi, authApi, buildMentionText, connectSocket, conversationsApi, createAuthStore, createRestTransitSession, decryptPayload, devicesApi, disconnectSocket, encryptPayload, extractMentionIds, fetchServerKeys, generateEphemeralKey, getApiClient, getAuthStore, getCompressionStrategy, getSessionId, getSessionKey, getSocket, getSocketStatus, initApiClient, initAuthStore, isApiClientConfigured, isMentionAll, isTransitEnvelope, messagesApi, normalizeAxiosError, normalizeConversation, onSocketStatus, parseMentions, performHandshake, readRetryAfterMs, reconnectSocket, refreshSocketAuth, renderMentionParts, resetAuthStore, resetTrackedRooms, resolveSystemMessageText, setApiClientInstance, setAuthReadyPromise, setTransitSession, socketEmit, syncApi, tryGetSocket, useChatStore, usersApi };
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
AntzChatPermissionError,
|
|
6
6
|
AntzChatServerError,
|
|
7
7
|
AntzChatValidationError,
|
|
8
|
+
TransitRateLimitedError,
|
|
8
9
|
awaitTransitReadyOr,
|
|
9
10
|
clearTransitSession,
|
|
10
11
|
configureTransitIfUnset,
|
|
@@ -30,13 +31,14 @@ import {
|
|
|
30
31
|
normalizeAxiosError,
|
|
31
32
|
onTransitReady,
|
|
32
33
|
performHandshake,
|
|
34
|
+
readRetryAfterMs,
|
|
33
35
|
resetAlgoCache,
|
|
34
36
|
setApiClientInstance,
|
|
35
37
|
setAuthReadyPromise,
|
|
36
38
|
setTransitSession,
|
|
37
39
|
storageApi,
|
|
38
40
|
uploadBatch
|
|
39
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-U637W5MD.js";
|
|
40
42
|
import {
|
|
41
43
|
useChatStore
|
|
42
44
|
} from "./chunk-UIYJAOGL.js";
|
|
@@ -456,7 +458,7 @@ async function _doConnect(config, getToken) {
|
|
|
456
458
|
if (existingSession?.enabled && existingSession.sessionId) {
|
|
457
459
|
httpsSession = { sessionId: existingSession.sessionId, sessionKey: existingSession.sessionKey };
|
|
458
460
|
} else {
|
|
459
|
-
httpsSession = await createRestTransitSession(config.apiUrl);
|
|
461
|
+
httpsSession = await createRestTransitSession(config.apiUrl, { userId: config.userId, tenantId: config.tenantId });
|
|
460
462
|
if (httpsSession) {
|
|
461
463
|
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
462
464
|
setTransitSession({ sessionKey: httpsSession.sessionKey, algo, sessionId: httpsSession.sessionId, enabled: true });
|
|
@@ -467,7 +469,7 @@ async function _doConnect(config, getToken) {
|
|
|
467
469
|
boundDeriveSessionKey = null;
|
|
468
470
|
} else {
|
|
469
471
|
try {
|
|
470
|
-
const serverKeys = await fetchServerKeys(config.apiUrl);
|
|
472
|
+
const serverKeys = await fetchServerKeys(config.apiUrl, { userId: config.userId, tenantId: config.tenantId });
|
|
471
473
|
if (!serverKeys.enabled) {
|
|
472
474
|
throw new AntzChatError(
|
|
473
475
|
"TRANSIT_MISMATCH",
|
|
@@ -484,7 +486,7 @@ async function _doConnect(config, getToken) {
|
|
|
484
486
|
}
|
|
485
487
|
} else {
|
|
486
488
|
try {
|
|
487
|
-
const serverKeys = await fetchServerKeys(config.apiUrl);
|
|
489
|
+
const serverKeys = await fetchServerKeys(config.apiUrl, { userId: config.userId, tenantId: config.tenantId });
|
|
488
490
|
if (serverKeys.enabled) {
|
|
489
491
|
throw new AntzChatError(
|
|
490
492
|
"TRANSIT_MISMATCH",
|
|
@@ -1331,6 +1333,7 @@ export {
|
|
|
1331
1333
|
HIGHLY_FORWARDED_DEPTH_THRESHOLD,
|
|
1332
1334
|
MAX_FORWARD_TARGETS,
|
|
1333
1335
|
MENTION_ALL_ID,
|
|
1336
|
+
TransitRateLimitedError,
|
|
1334
1337
|
appConfigApi,
|
|
1335
1338
|
authApi,
|
|
1336
1339
|
buildMentionText,
|
|
@@ -1363,6 +1366,7 @@ export {
|
|
|
1363
1366
|
onSocketStatus,
|
|
1364
1367
|
parseMentions,
|
|
1365
1368
|
performHandshake,
|
|
1369
|
+
readRetryAfterMs,
|
|
1366
1370
|
reconnectSocket,
|
|
1367
1371
|
refreshSocketAuth,
|
|
1368
1372
|
renderMentionParts,
|