stream-chat
Advanced tools
Comparing version 4.3.0 to 4.4.0-insights.0
@@ -9,2 +9,3 @@ /// <reference types="node" /> | ||
import { APIResponse, AppSettings, AppSettingsAPIResponse, BaseDeviceFields, BannedUsersFilters, BannedUsersPaginationOptions, BannedUsersResponse, BannedUsersSort, BanUserOptions, BlockList, BlockListResponse, ChannelAPIResponse, ChannelData, ChannelFilters, ChannelMute, ChannelOptions, ChannelSort, ChannelStateOptions, CheckPushResponse, CheckSQSResponse, Configs, ConnectAPIResponse, CreateChannelOptions, CreateChannelResponse, CreateCommandOptions, CreateCommandResponse, CustomPermissionOptions, DeleteCommandResponse, Device, EndpointName, Event, EventHandler, ExportChannelOptions, ExportChannelRequest, ExportChannelResponse, ExportChannelStatusResponse, MessageFlagsFilters, MessageFlagsPaginationOptions, MessageFlagsResponse, FlagMessageResponse, FlagUserResponse, GetChannelTypeResponse, GetCommandResponse, GetRateLimitsResponse, ListChannelResponse, ListCommandsResponse, LiteralStringForUnion, Logger, MarkChannelsReadOptions, MessageFilters, MessageResponse, Mute, MuteUserOptions, MuteUserResponse, OwnUserResponse, PartialMessageUpdate, PartialUserUpdate, PermissionAPIResponse, PermissionsAPIResponse, PushProvider, ReactionResponse, SearchOptions, SearchAPIResponse, SendFileAPIResponse, StreamChatOptions, TestPushDataInput, TestSQSDataInput, TokenOrProvider, UnBanUserOptions, UnknownType, UpdateChannelOptions, UpdateChannelResponse, UpdateCommandOptions, UpdateCommandResponse, UpdatedMessage, UpdateMessageAPIResponse, UserCustomEvent, UserFilters, UserOptions, UserResponse, UserSort, SegmentData, Segment, Campaign, CampaignData, OGAttachment, TaskStatus, DeleteUserOptions, TaskResponse } from './types'; | ||
import { InsightTypes, InsightMetrics } from './insights'; | ||
export declare class StreamChat<AttachmentType extends UnknownType = UnknownType, ChannelType extends UnknownType = UnknownType, CommandType extends string = LiteralStringForUnion, EventType extends UnknownType = UnknownType, MessageType extends UnknownType = UnknownType, ReactionType extends UnknownType = UnknownType, UserType extends UnknownType = UnknownType> { | ||
@@ -55,2 +56,3 @@ private static _instance?; | ||
consecutiveFailures: number; | ||
insightMetrics: InsightMetrics; | ||
/** | ||
@@ -1147,2 +1149,3 @@ * Initialize a client | ||
} & Partial<TaskResponse>>; | ||
postInsights: (insightType: InsightTypes, insights: Record<string, unknown>) => Promise<void>; | ||
/** | ||
@@ -1149,0 +1152,0 @@ * deleteUsers - Batch Delete Users |
@@ -5,2 +5,3 @@ /// <reference types="node" /> | ||
import { TokenManager } from './token_manager'; | ||
import { InsightMetrics, InsightTypes } from './insights'; | ||
import { BaseDeviceFields, ConnectAPIResponse, ConnectionChangeEvent, ConnectionOpen, LiteralStringForUnion, Logger, UnknownType, UserResponse } from './types'; | ||
@@ -12,2 +13,3 @@ declare type Constructor<ChannelType extends UnknownType = UnknownType, CommandType extends string = LiteralStringForUnion, UserType extends UnknownType = UnknownType> = { | ||
eventCallback: (event: ConnectionChangeEvent) => void; | ||
insightMetrics: InsightMetrics; | ||
logger: Logger | (() => void); | ||
@@ -22,2 +24,3 @@ messageCallback: (messageEvent: WebSocket.MessageEvent) => void; | ||
device?: BaseDeviceFields; | ||
postInsights?: (eventType: InsightTypes, event: Record<string, unknown>) => void; | ||
}; | ||
@@ -71,2 +74,4 @@ /** | ||
}) => void; | ||
requestID: string | undefined; | ||
connectionStartTimestamp: number | undefined; | ||
resolvePromise?: (value: WebSocket.MessageEvent) => void; | ||
@@ -76,3 +81,5 @@ totalFailures: number; | ||
wsID: number; | ||
constructor({ apiKey, authType, clientID, eventCallback, logger, messageCallback, recoverCallback, tokenManager, user, userAgent, userID, wsBaseURL, device, }: Constructor<ChannelType, CommandType, UserType>); | ||
postInsights?: Constructor<ChannelType, CommandType, UserType>['postInsights']; | ||
insightMetrics: InsightMetrics; | ||
constructor({ apiKey, authType, clientID, eventCallback, logger, messageCallback, recoverCallback, tokenManager, user, userAgent, userID, wsBaseURL, device, postInsights, insightMetrics, }: Constructor<ChannelType, CommandType, UserType>); | ||
/** | ||
@@ -90,4 +97,9 @@ * connect - Connect to the WS URL | ||
_waitForHealthy(timeout?: number): Promise<void | ConnectionOpen<ChannelType, CommandType, UserType>>; | ||
_buildUrl: () => string; | ||
/** | ||
* Builds and returns the url for websocket. | ||
* @param reqID Unique identifier generated on client side, to help tracking apis on backend. | ||
* @returns url string | ||
*/ | ||
_buildUrl: (reqID?: string | undefined) => string; | ||
/** | ||
* disconnect - Disconnect the connection and doesn't recover... | ||
@@ -94,0 +106,0 @@ * |
@@ -621,2 +621,3 @@ import { AxiosRequestConfig } from 'axios'; | ||
device?: BaseDeviceFields; | ||
enableInsights?: boolean; | ||
logger?: Logger; | ||
@@ -1015,3 +1016,3 @@ /** | ||
export declare type PushProvider = 'apn' | 'firebase' | 'huawei'; | ||
export declare type CommandVariants<CommandType extends string = LiteralStringForUnion> = 'all' | 'ban' | 'flag' | 'fun_set' | 'giphy' | 'imgur' | 'moderation_set' | 'mute' | 'unban' | 'unmute' | CommandType; | ||
export declare type CommandVariants<CommandType extends string = LiteralStringForUnion> = 'all' | 'ban' | 'fun_set' | 'giphy' | 'imgur' | 'moderation_set' | 'mute' | 'unban' | 'unmute' | CommandType; | ||
export declare type Configs<CommandType extends string = LiteralStringForUnion> = { | ||
@@ -1018,0 +1019,0 @@ [channel_type: string]: ChannelConfigWithInfo<CommandType> | undefined; |
@@ -33,2 +33,3 @@ /// <reference types="node" /> | ||
export declare function randomId(): string; | ||
export declare function generateUUIDv4(): string; | ||
//# sourceMappingURL=utils.d.ts.map |
{ | ||
"name": "stream-chat", | ||
"version": "4.3.0", | ||
"version": "4.4.0-insights.0", | ||
"description": "JS SDK for the Stream Chat API", | ||
@@ -129,3 +129,3 @@ "author": "GetStream", | ||
"version": "git add yarn.lock", | ||
"postversion": "git push && git push --tags && npm publish" | ||
"postversion": "git push && git push --tags" | ||
}, | ||
@@ -132,0 +132,0 @@ "husky": { |
import WebSocket from 'isomorphic-ws'; | ||
import { chatCodes, sleep, retryInterval } from './utils'; | ||
import { chatCodes, sleep, retryInterval, randomId } from './utils'; | ||
import { TokenManager } from './token_manager'; | ||
import { | ||
buildWsFatalInsight, | ||
buildWsSuccessAfterFailureInsight, | ||
InsightMetrics, | ||
InsightTypes, | ||
} from './insights'; | ||
import { | ||
BaseDeviceFields, | ||
@@ -33,2 +39,3 @@ ConnectAPIResponse, | ||
eventCallback: (event: ConnectionChangeEvent) => void; | ||
insightMetrics: InsightMetrics; | ||
logger: Logger | (() => void); | ||
@@ -45,2 +52,3 @@ messageCallback: (messageEvent: WebSocket.MessageEvent) => void; | ||
device?: BaseDeviceFields; | ||
postInsights?: (eventType: InsightTypes, event: Record<string, unknown>) => void; | ||
}; | ||
@@ -83,3 +91,2 @@ | ||
device: Constructor<ChannelType, CommandType, UserType>['device']; | ||
connectionID?: string; | ||
@@ -103,2 +110,4 @@ connectionOpen?: ConnectAPIResponse<ChannelType, CommandType, UserType>; | ||
) => void; | ||
requestID: string | undefined; | ||
connectionStartTimestamp: number | undefined; | ||
resolvePromise?: (value: WebSocket.MessageEvent) => void; | ||
@@ -108,3 +117,4 @@ totalFailures: number; | ||
wsID: number; | ||
postInsights?: Constructor<ChannelType, CommandType, UserType>['postInsights']; | ||
insightMetrics: InsightMetrics; | ||
constructor({ | ||
@@ -124,2 +134,4 @@ apiKey, | ||
device, | ||
postInsights, | ||
insightMetrics, | ||
}: Constructor<ChannelType, CommandType, UserType>) { | ||
@@ -158,2 +170,4 @@ this.wsBaseURL = wsBaseURL; | ||
this._listenForConnectionChanges(); | ||
this.postInsights = postInsights; | ||
this.insightMetrics = insightMetrics; | ||
} | ||
@@ -254,3 +268,8 @@ | ||
_buildUrl = () => { | ||
/** | ||
* Builds and returns the url for websocket. | ||
* @param reqID Unique identifier generated on client side, to help tracking apis on backend. | ||
* @returns url string | ||
*/ | ||
_buildUrl = (reqID?: string) => { | ||
const params = { | ||
@@ -262,2 +281,3 @@ user_id: this.user.id, | ||
device: this.device, | ||
request_id: reqID, | ||
}; | ||
@@ -364,7 +384,8 @@ const qs = encodeURIComponent(JSON.stringify(params)); | ||
this.isConnecting = true; | ||
this.requestID = randomId(); | ||
this.insightMetrics.connectionStartTimestamp = new Date().getTime(); | ||
try { | ||
await this.tokenManager.tokenReady(); | ||
this._setupConnectionPromise(); | ||
const wsURL = this._buildUrl(); | ||
const wsURL = this._buildUrl(this.requestID); | ||
this.ws = new WebSocket(wsURL); | ||
@@ -380,2 +401,9 @@ this.ws.onopen = this.onopen.bind(this, this.wsID); | ||
this.connectionID = response.connection_id; | ||
if (this.insightMetrics.wsConsecutiveFailures > 0) { | ||
this.postInsights?.( | ||
'ws_success_after_failure', | ||
buildWsSuccessAfterFailureInsight(this), | ||
); | ||
this.insightMetrics.wsConsecutiveFailures = 0; | ||
} | ||
return response; | ||
@@ -573,2 +601,8 @@ } | ||
onclose = (wsID: number, event: WebSocket.CloseEvent) => { | ||
if (event.code !== chatCodes.WS_CLOSED_SUCCESS) { | ||
this.insightMetrics.wsConsecutiveFailures++; | ||
this.insightMetrics.wsTotalFailures++; | ||
this.postInsights?.('ws_fatal', buildWsFatalInsight(this, event)); | ||
} | ||
this.logger('info', 'connection:onclose() - onclose callback - ' + event.code, { | ||
@@ -806,3 +840,2 @@ tags: ['connection'], | ||
client_id: this.clientID, | ||
user_id: this.userID, | ||
}, | ||
@@ -809,0 +842,0 @@ ]; |
@@ -998,2 +998,3 @@ import { AxiosRequestConfig } from 'axios'; | ||
device?: BaseDeviceFields; | ||
enableInsights?: boolean; | ||
logger?: Logger; | ||
@@ -1703,3 +1704,2 @@ /** | ||
| 'ban' | ||
| 'flag' | ||
| 'fun_set' | ||
@@ -1706,0 +1706,0 @@ | 'giphy' |
@@ -147,10 +147,55 @@ import FormData from 'form-data'; | ||
/** adopted from https://github.com/ai/nanoid/blob/master/non-secure/index.js */ | ||
const alphabet = 'ModuleSymbhasOwnPr0123456789ABCDEFGHNRVfgctiUvzKqYTJkLxpZXIjQW'; | ||
export function randomId() { | ||
let id = ''; | ||
for (let i = 0; i < 21; i++) { | ||
id += alphabet[(Math.random() * 64) | 0]; | ||
return generateUUIDv4(); | ||
} | ||
function hex(bytes: Uint8Array): string { | ||
let s = ''; | ||
for (let i = 0; i < bytes.length; i++) { | ||
s += bytes[i].toString(16).padStart(2, '0'); | ||
} | ||
return id; | ||
return s; | ||
} | ||
// https://tools.ietf.org/html/rfc4122 | ||
export function generateUUIDv4() { | ||
const bytes = getRandomBytes(16); | ||
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version | ||
bytes[8] = (bytes[8] & 0xbf) | 0x80; // variant | ||
return ( | ||
hex(bytes.subarray(0, 4)) + | ||
'-' + | ||
hex(bytes.subarray(4, 6)) + | ||
'-' + | ||
hex(bytes.subarray(6, 8)) + | ||
'-' + | ||
hex(bytes.subarray(8, 10)) + | ||
'-' + | ||
hex(bytes.subarray(10, 16)) | ||
); | ||
} | ||
function getRandomValuesWithMathRandom(bytes: Uint8Array): void { | ||
const max = Math.pow(2, (8 * bytes.byteLength) / bytes.length); | ||
for (let i = 0; i < bytes.length; i++) { | ||
bytes[i] = Math.random() * max; | ||
} | ||
} | ||
declare const msCrypto: Crypto; | ||
const getRandomValues = (() => { | ||
if (typeof crypto !== 'undefined') { | ||
return crypto.getRandomValues.bind(crypto); | ||
} else if (typeof msCrypto !== 'undefined') { | ||
return msCrypto.getRandomValues.bind(msCrypto); | ||
} else { | ||
return getRandomValuesWithMathRandom; | ||
} | ||
})(); | ||
function getRandomBytes(length: number): Uint8Array { | ||
const bytes = new Uint8Array(length); | ||
getRandomValues(bytes); | ||
return bytes; | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3973481
55
44872
1