@servicetitan/titan-chat-ui-common 7.1.2 → 9.0.0
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/CHANGELOG.md +25 -0
- package/dist/hooks/use-customization-chat.js +2 -1
- package/dist/hooks/use-customization-chat.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/models/__mocks__/support-chat.mock.js +13 -12
- package/dist/models/__mocks__/support-chat.mock.js.map +1 -1
- package/dist/models/chat-customizations.js +2 -1
- package/dist/models/chat-customizations.js.map +1 -1
- package/dist/models/file-descriptor.js +2 -1
- package/dist/models/file-descriptor.js.map +1 -1
- package/dist/models/index.d.ts +2 -2
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +1 -2
- package/dist/models/index.js.map +1 -1
- package/dist/models/support-chat.js +37 -41
- package/dist/models/support-chat.js.map +1 -1
- package/dist/stores/__tests__/chat-ui.store.test.js +117 -106
- package/dist/stores/__tests__/chat-ui.store.test.js.map +1 -1
- package/dist/stores/chat-ui-backend-echo.store.js +86 -87
- package/dist/stores/chat-ui-backend-echo.store.js.map +1 -1
- package/dist/stores/chat-ui-backend.store.js +1 -0
- package/dist/stores/chat-ui-backend.store.js.map +1 -1
- package/dist/stores/chat-ui.store.d.ts +2 -2
- package/dist/stores/chat-ui.store.d.ts.map +1 -1
- package/dist/stores/chat-ui.store.js +307 -329
- package/dist/stores/chat-ui.store.js.map +1 -1
- package/dist/stores/index.d.ts +4 -2
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js +2 -1
- package/dist/stores/index.js.map +1 -1
- package/dist/streaming/__tests__/chat-sse-client-lifecycle.test.d.ts +2 -0
- package/dist/streaming/__tests__/chat-sse-client-lifecycle.test.d.ts.map +1 -0
- package/dist/streaming/__tests__/chat-sse-client-lifecycle.test.js +86 -0
- package/dist/streaming/__tests__/chat-sse-client-lifecycle.test.js.map +1 -0
- package/dist/streaming/__tests__/chat-sse-client-resilience.test.d.ts +2 -0
- package/dist/streaming/__tests__/chat-sse-client-resilience.test.d.ts.map +1 -0
- package/dist/streaming/__tests__/chat-sse-client-resilience.test.js +140 -0
- package/dist/streaming/__tests__/chat-sse-client-resilience.test.js.map +1 -0
- package/dist/streaming/__tests__/chat-sse-client.test.d.ts +2 -0
- package/dist/streaming/__tests__/chat-sse-client.test.d.ts.map +1 -0
- package/dist/streaming/__tests__/chat-sse-client.test.js +209 -0
- package/dist/streaming/__tests__/chat-sse-client.test.js.map +1 -0
- package/dist/streaming/__tests__/mock-wiring.test.d.ts +2 -0
- package/dist/streaming/__tests__/mock-wiring.test.d.ts.map +1 -0
- package/dist/streaming/__tests__/mock-wiring.test.js +20 -0
- package/dist/streaming/__tests__/mock-wiring.test.js.map +1 -0
- package/dist/streaming/__tests__/streaming-progress.model.test.d.ts +2 -0
- package/dist/streaming/__tests__/streaming-progress.model.test.d.ts.map +1 -0
- package/dist/streaming/__tests__/streaming-progress.model.test.js +89 -0
- package/dist/streaming/__tests__/streaming-progress.model.test.js.map +1 -0
- package/dist/streaming/chat-sse-client.d.ts +75 -0
- package/dist/streaming/chat-sse-client.d.ts.map +1 -0
- package/dist/streaming/chat-sse-client.js +189 -0
- package/dist/streaming/chat-sse-client.js.map +1 -0
- package/dist/streaming/index.d.ts +3 -0
- package/dist/streaming/index.d.ts.map +1 -0
- package/dist/streaming/index.js +4 -0
- package/dist/streaming/index.js.map +1 -0
- package/dist/streaming/streaming-progress.model.d.ts +39 -0
- package/dist/streaming/streaming-progress.model.d.ts.map +1 -0
- package/dist/streaming/streaming-progress.model.js +69 -0
- package/dist/streaming/streaming-progress.model.js.map +1 -0
- package/dist/utils/__tests__/text-utils.test.js +33 -14
- package/dist/utils/__tests__/text-utils.test.js.map +1 -1
- package/dist/utils/test-utils.js +5 -5
- package/dist/utils/test-utils.js.map +1 -1
- package/dist/utils/text-utils.js +12 -12
- package/dist/utils/text-utils.js.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +1 -0
- package/src/models/index.ts +2 -2
- package/src/stores/chat-ui.store.ts +1 -3
- package/src/stores/index.ts +3 -3
- package/src/streaming/__tests__/chat-sse-client-lifecycle.test.ts +67 -0
- package/src/streaming/__tests__/chat-sse-client-resilience.test.ts +141 -0
- package/src/streaming/__tests__/chat-sse-client.test.ts +152 -0
- package/src/streaming/__tests__/mock-wiring.test.ts +25 -0
- package/src/streaming/__tests__/streaming-progress.model.test.ts +72 -0
- package/src/streaming/chat-sse-client.ts +236 -0
- package/src/streaming/index.ts +2 -0
- package/src/streaming/streaming-progress.model.ts +80 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-ui.store.js","sourceRoot":"","sources":["../../src/stores/chat-ui.store.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/stores/chat-ui.store.ts"],"sourcesContent":["import { EventEmitter } from 'events';\nimport { injectable, symbolToken } from '@servicetitan/react-ioc';\nimport { action, computed, makeObservable, observable, runInAction } from 'mobx';\nimport { nanoid } from 'nanoid';\nimport {\n ChatConfiguration,\n ChatCustomizations,\n ChatEndReason,\n ChatError,\n ChatErrorOptions,\n ChatMessageModelBase,\n ChatMessageModelFile,\n ChatMessageModelText,\n ChatMessageModelTimeout,\n ChatMessageModelWelcome,\n ChatMessageState,\n ChatParticipantIcon,\n ChatParticipantModel,\n ChatRunState,\n ChatTimer,\n} from '../models';\nimport { FileDescriptor } from '../models/file-descriptor';\n\nexport const symbolAgent = Symbol('SupportChatAgent');\nexport const symbolUser = Symbol('SupportChatUser');\n\nexport enum ChatUiEvent {\n eventRun = 'eventRun',\n eventDestroy = 'eventDestroy',\n eventRestart = 'eventRestart',\n eventCancel = 'eventCancel',\n eventEndChat = 'eventEndChat',\n eventRecover = 'eventRecover',\n eventChasitorTyping = 'eventChasitorTyping',\n eventTimerRestart = 'eventTimerRestart',\n eventMessageSend = 'eventMessageSend',\n eventMessageSendRetry = 'eventMessageSendRetry',\n eventMessageSendFile = 'eventMessageSendFile',\n eventMessageSendFileRetry = 'eventMessageSendFileRetry',\n}\n\nexport type ChatUiEventListener<T = void> = (\n resolve: (value: T | PromiseLike<T>) => void,\n reject: (reason?: any) => void,\n ...args: unknown[]\n) => void;\n\nexport interface IChatUiStore<T extends ChatCustomizations = ChatCustomizations> {\n scrollCounter: number;\n\n status: ChatRunState;\n get isStarting(): boolean;\n get isStarted(): boolean;\n get isError(): boolean;\n get isEnded(): boolean;\n get customizations(): T;\n timer?: ChatTimer;\n endReason?: ChatEndReason;\n\n participants: { [key: symbol]: ChatParticipantModel };\n messages: ChatMessageModelBase[];\n isAgentTyping: boolean;\n isFilePickerEnabled: boolean;\n file?: FileDescriptor;\n error?: ChatError;\n\n get agent(): ChatParticipantModel;\n get user(): ChatParticipantModel;\n\n on<T>(event: string, listener: ChatUiEventListener<T>): void;\n off<T>(event: string, listener: ChatUiEventListener<T>): void;\n\n setCustomizationContext(customizationContext?: T): void;\n setIncomingSound(soundUrl: string): void;\n setTimer(timer?: ChatTimer): void;\n setFile(file: FileDescriptor | undefined): void;\n setFilePickerEnabled(isEnabled: boolean): void;\n setAgentTyping(typing: boolean): void;\n setMessageState(message: ChatMessageModelBase, state: ChatMessageState, data?: any): void;\n setMessages(messages: ChatMessageModelBase[]): void;\n setAgentName(name: string): void;\n setAgentIcon(icon: ChatParticipantIcon): void;\n setChatError(chatError: ChatError): void;\n setError<T = any>(message: string, options?: ChatErrorOptions<T>): void;\n setStatus(status: ChatRunState): void;\n resetError(runState: ChatRunState): void;\n reset(resetStatus?: boolean): void;\n resetFile(): void;\n\n triggerScroll(): void;\n configure(configuration?: ChatConfiguration): void;\n run(configuration?: ChatConfiguration, data?: unknown): Promise<void>;\n recover(): Promise<void>;\n destroy(): Promise<void>;\n chasitorTyping(isTyping: boolean): Promise<void>;\n restartTimers(): Promise<void>;\n restart(): Promise<void>;\n cancelChat(): Promise<void>;\n endChat(endReason?: ChatEndReason): Promise<void>;\n sendMessageText<O extends {}>(messageText: string, options?: O): Promise<void>;\n sendMessageRetry(message: ChatMessageModelBase): Promise<void>;\n addMessage(isAgent: boolean, message: string, data?: any): void;\n addMessageWelcome(message: string): void;\n}\nexport const CHAT_UI_STORE_TOKEN = symbolToken<IChatUiStore>('CHAT_UI_STORE_TOKEN');\n\n@injectable()\nexport class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T> {\n @observable isAgentTyping = false;\n\n @observable status = ChatRunState.Offline;\n\n @observable isFilePickerEnabled = false;\n\n @observable file?: FileDescriptor;\n\n @observable.ref error?: ChatError;\n\n @observable endReason?: ChatEndReason;\n\n @observable messages: ChatMessageModelBase[] = [];\n\n @observable currentFileMessage?: ChatMessageModelFile;\n\n @observable scrollCounter = 1;\n\n @observable timer?: ChatTimer;\n\n @observable participants: { [key: symbol]: ChatParticipantModel } = {\n [symbolAgent]: {\n isAgent: true,\n name: 'Agent',\n icon: ChatParticipantIcon.Initials,\n },\n [symbolUser]: {\n isAgent: false,\n name: 'User',\n icon: ChatParticipantIcon.Initials,\n },\n };\n\n @computed\n get agent() {\n return this.participants[symbolAgent];\n }\n\n @computed\n get user() {\n return this.participants[symbolUser];\n }\n\n @computed\n get isStarted() {\n return this.status === ChatRunState.Started;\n }\n\n @computed\n get isError() {\n return this.status === ChatRunState.Error;\n }\n\n @computed\n get isEnded() {\n return this.status === ChatRunState.Ended;\n }\n\n @computed\n get isStarting() {\n return this.status === ChatRunState.Initializing;\n }\n\n @computed\n get customizations() {\n return this.customizationContext;\n }\n\n @observable\n protected customizationContext: T = {} as T;\n private eventEmitter = new EventEmitter();\n private incomingMessageSound?: HTMLAudioElement;\n private incomingMessageSoundPromise?: Promise<void>;\n\n constructor() {\n makeObservable(this);\n }\n\n on = <T>(event: string, listener: ChatUiEventListener<T>) => {\n this.eventEmitter.on(event, listener);\n };\n\n off = <T>(event: string, listener: ChatUiEventListener<T>) => {\n this.eventEmitter.off(event, listener);\n };\n\n @action\n setCustomizationContext(customizationContext?: T) {\n this.customizationContext = customizationContext ?? ({} as T);\n this.triggerScroll();\n }\n\n setIncomingSound(soundUrl: string) {\n if (this.incomingMessageSound) {\n return;\n }\n this.incomingMessageSound = new Audio(soundUrl);\n }\n\n @action\n setFile(file?: FileDescriptor) {\n this.file = file;\n }\n\n @action\n setFilePickerEnabled(isEnabled: boolean) {\n this.isFilePickerEnabled = isEnabled;\n this.setFile();\n this.triggerScroll();\n }\n\n @action\n setTimer(timer?: ChatTimer) {\n this.timer = timer;\n }\n\n @action\n resetError(runState: ChatRunState) {\n this.error = undefined;\n this.setStatus(runState);\n this.triggerScroll();\n }\n\n @action\n setChatError(chatError: ChatError) {\n this.error = chatError;\n this.setStatus(ChatRunState.Error);\n this.triggerScroll();\n }\n\n @action\n setError<T = any>(message: string, options?: ChatErrorOptions<T>) {\n this.setChatError(new ChatError(message, options));\n }\n\n @action\n setStatus(status: ChatRunState) {\n this.status = status;\n }\n\n @action\n setMessages(messages: ChatMessageModelBase[]) {\n this.messages = messages;\n this.triggerScroll();\n }\n\n @action\n setAgentName(name: string) {\n this.agent.name = name;\n }\n\n @action\n setAgentIcon(icon: ChatParticipantIcon) {\n this.agent.icon = icon;\n }\n\n @action\n setAgentTyping(isAgentTyping: boolean) {\n this.isAgentTyping = isAgentTyping;\n this.triggerScroll();\n }\n\n @action\n setEndReason(reason?: ChatEndReason) {\n this.endReason = reason;\n this.triggerScroll();\n }\n\n @action\n setEndedChatState(endReason: ChatEndReason) {\n this.setEndReason(endReason);\n this.setStatus(ChatRunState.Ended);\n this.setAgentTyping(false);\n this.resetFile();\n this.triggerScroll();\n }\n\n @action\n configure(configuration?: ChatConfiguration) {\n if (!configuration) {\n return;\n }\n if (configuration.agentName) {\n this.setAgentName(configuration.agentName);\n }\n if (configuration.agentIcon) {\n this.setAgentIcon(configuration.agentIcon);\n }\n }\n\n async run(configuration?: ChatConfiguration, data?: unknown) {\n this.configure(configuration);\n if (!this.eventEmitter.listeners(ChatUiEvent.eventRun).length) {\n throw new Error(\"No listeners for ChatUiEvent.eventRun ('eventRun')\");\n }\n await this.emitAsync(ChatUiEvent.eventRun, data);\n }\n\n async recover() {\n await this.emitAsync(ChatUiEvent.eventRecover, this.error);\n }\n\n async destroy() {\n this.reset();\n await this.emitAsync(ChatUiEvent.eventDestroy);\n }\n\n async restart() {\n this.reset();\n await this.emitAsync(ChatUiEvent.eventRestart);\n }\n\n async cancelChat() {\n await this.emitAsync(ChatUiEvent.eventCancel);\n }\n\n async endChat(endReason?: ChatEndReason) {\n await this.emitAsync(ChatUiEvent.eventEndChat, endReason);\n }\n\n async chasitorTyping(isTyping: boolean) {\n await this.emitAsync(ChatUiEvent.eventChasitorTyping, isTyping);\n }\n\n @action\n async sendMessageText(message: string) {\n if (this.isFilePickerEnabled && this.file) {\n // Send text message with file\n runInAction(() => {\n this.isFilePickerEnabled = false;\n this.currentFileMessage = this.addMessageFile(this.file!);\n });\n let messageModel: ChatMessageModelText | undefined;\n if (message.trim() !== '') {\n messageModel = this.addMessage(false, message);\n }\n await this.emitAsync(\n ChatUiEvent.eventMessageSendFile,\n this.currentFileMessage,\n this.file,\n messageModel\n );\n this.setFilePickerEnabled(false);\n this.setFile(undefined);\n } else {\n // Send plain text message\n await this.sendMessageTextInternal(message);\n }\n }\n\n @action\n async sendMessageRetry(messageModel: ChatMessageModelBase) {\n this.resetError(ChatRunState.Started);\n this.setMessageState(messageModel, ChatMessageState.Delivering);\n await this.emitAsync(ChatUiEvent.eventMessageSendRetry, messageModel);\n await this.restartTimers();\n }\n\n @action\n async sendMessageFileRetry(messageModel: ChatMessageModelFile) {\n this.resetError(ChatRunState.Started);\n this.setMessageState(messageModel, ChatMessageState.Delivering);\n await this.emitAsync(ChatUiEvent.eventMessageSendFileRetry, messageModel);\n }\n\n getParticipant(participantKey: symbol): ChatParticipantModel {\n const participant = this.participants[participantKey];\n return { ...participant };\n }\n\n @action\n addMessage(isAgent: boolean, message: string, data?: any) {\n return this.addMessageInternal<ChatMessageModelText>({\n type: 'message',\n state: ChatMessageState.Delivering,\n participant: this.getParticipant(isAgent ? symbolAgent : symbolUser),\n data,\n message,\n });\n }\n\n @action\n addMessageTimeout() {\n const isNewChat =\n this.messages.length === 0 || this.messages.every(m => m.type === 'welcome');\n if (isNewChat) {\n return;\n }\n return this.addMessageInternal<ChatMessageModelTimeout>({\n type: 'timeout',\n participant: this.agent,\n state: ChatMessageState.Delivered,\n });\n }\n\n @action\n addMessageWelcome(message: string) {\n return this.addMessageInternal<ChatMessageModelWelcome>({\n type: 'welcome',\n state: ChatMessageState.Delivered,\n participant: this.getParticipant(symbolAgent),\n message,\n });\n }\n\n @action\n addMessageFile(file: FileDescriptor) {\n return this.addMessageInternal<ChatMessageModelFile>({\n fileName: file.displayName ?? 'attachment',\n type: 'file',\n state: ChatMessageState.Delivering,\n participant: this.user,\n });\n }\n\n @action\n async restartTimers() {\n this.removeMessageByType('timeout');\n await this.emitAsync(ChatUiEvent.eventTimerRestart);\n }\n\n @action\n setMessageState(message: ChatMessageModelBase, state: ChatMessageState, data?: any) {\n const foundMessage = this.messages.find(m => m.id === message.id);\n if (foundMessage) {\n foundMessage.state = state;\n if (data) {\n foundMessage.data = data;\n }\n }\n }\n\n @action\n resetFile() {\n this.currentFileMessage = undefined;\n this.file = undefined;\n this.isFilePickerEnabled = false;\n this.triggerScroll();\n }\n\n @action\n reset(resetStatus = true) {\n this.setMessages([]);\n if (resetStatus) {\n this.status = ChatRunState.Offline;\n }\n this.error = undefined;\n this.isAgentTyping = false;\n this.endReason = undefined;\n this.resetFile();\n }\n\n getLastFailedMessages() {\n const result: ChatMessageModelText[] = [];\n for (let i = this.messages.length - 1; i >= 0; i--) {\n const message = this.messages[i];\n if (message.type === 'message' && !message.participant.isAgent) {\n if (message.state !== ChatMessageState.Failed) {\n break;\n }\n result.push(message as ChatMessageModelText);\n }\n }\n return result;\n }\n\n triggerScroll() {\n setTimeout(() => {\n runInAction(() => {\n this.scrollCounter++;\n });\n }, 0);\n }\n\n protected async emitAsync<T>(event: string, ...args: unknown[]) {\n if (!this.eventEmitter.listenerCount(event)) {\n return Promise.resolve(undefined);\n }\n return new Promise<T>((resolve, reject) => {\n this.eventEmitter.emit(event, resolve, reject, ...args);\n });\n }\n\n protected addMessageInternal<T extends ChatMessageModelBase>(\n message: Omit<T, 'id' | 'timestamp'>\n ): T {\n if (message.type === 'timeout') {\n this.removeMessageByType('timeout'); // Remove previous timeout messages\n } else {\n this.restartTimers().then(() => {});\n }\n this.setMessages([...this.messages, this.createMessage<T>(message)]);\n if (message.participant.isAgent) {\n this.beepIncoming().catch(() => {});\n }\n return this.messages.at(-1) as T;\n }\n\n protected removeMessageByType(type: string) {\n if (this.messages.some(m => m.type === type)) {\n this.setMessages(this.messages.filter(m => m.type !== type));\n }\n }\n\n private async sendMessageTextInternal(message: string) {\n if (message.trim() === '') {\n return;\n }\n const messageModel = this.addMessage(false, message);\n await this.emitAsync(ChatUiEvent.eventMessageSend, messageModel);\n }\n\n private createMessage<T extends ChatMessageModelBase>(rest: Omit<T, 'id' | 'timestamp'>) {\n return {\n id: nanoid(),\n timestamp: new Date(),\n ...rest,\n } as T;\n }\n\n private async beepIncoming() {\n if (!this.incomingMessageSound) {\n return;\n }\n try {\n this.incomingMessageSoundPromise ??= this.incomingMessageSound.play();\n await this.incomingMessageSoundPromise;\n } finally {\n this.incomingMessageSoundPromise = undefined;\n }\n }\n}\n"],"names":["EventEmitter","injectable","symbolToken","action","computed","makeObservable","observable","runInAction","nanoid","ChatConfiguration","ChatEndReason","ChatError","ChatErrorOptions","ChatMessageModelBase","ChatMessageModelFile","ChatMessageState","ChatParticipantIcon","ChatRunState","ChatTimer","FileDescriptor","symbolAgent","Symbol","symbolUser","ChatUiEvent","CHAT_UI_STORE_TOKEN","ChatUiStore","agent","participants","user","isStarted","status","Started","isError","Error","isEnded","Ended","isStarting","Initializing","customizations","customizationContext","setCustomizationContext","triggerScroll","setIncomingSound","soundUrl","incomingMessageSound","Audio","setFile","file","setFilePickerEnabled","isEnabled","isFilePickerEnabled","setTimer","timer","resetError","runState","error","undefined","setStatus","setChatError","chatError","setError","message","options","setMessages","messages","setAgentName","name","setAgentIcon","icon","setAgentTyping","isAgentTyping","setEndReason","reason","endReason","setEndedChatState","resetFile","configure","configuration","agentName","agentIcon","run","data","eventEmitter","listeners","length","emitAsync","recover","destroy","reset","restart","cancelChat","endChat","chasitorTyping","isTyping","sendMessageText","currentFileMessage","addMessageFile","messageModel","trim","addMessage","sendMessageTextInternal","sendMessageRetry","setMessageState","Delivering","restartTimers","sendMessageFileRetry","getParticipant","participantKey","participant","isAgent","addMessageInternal","type","state","addMessageTimeout","isNewChat","every","m","Delivered","addMessageWelcome","fileName","displayName","removeMessageByType","foundMessage","find","id","resetStatus","Offline","getLastFailedMessages","result","i","Failed","push","setTimeout","scrollCounter","event","args","listenerCount","Promise","resolve","reject","emit","then","createMessage","beepIncoming","catch","at","some","filter","rest","timestamp","Date","incomingMessageSoundPromise","play","Initials","on","listener","off","ref"],"mappings":"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"}
|
package/dist/stores/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export type { IChatUiStore, ChatUiEventListener } from './chat-ui.store';
|
|
2
|
+
export { CHAT_UI_STORE_TOKEN, ChatUiStore, ChatUiEvent, symbolUser, symbolAgent, } from './chat-ui.store';
|
|
2
3
|
export { ChatUiBackendEchoStore } from './chat-ui-backend-echo.store';
|
|
3
|
-
export {
|
|
4
|
+
export type { IChatUiBackendStore } from './chat-ui-backend.store';
|
|
5
|
+
export { CHAT_UI_BACKEND_STORE_TOKEN } from './chat-ui-backend.store';
|
|
4
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stores/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,mBAAmB,EACnB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stores/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EACH,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,UAAU,EACV,WAAW,GACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/stores/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { CHAT_UI_STORE_TOKEN, ChatUiStore, ChatUiEvent, symbolUser, symbolAgent
|
|
1
|
+
export { CHAT_UI_STORE_TOKEN, ChatUiStore, ChatUiEvent, symbolUser, symbolAgent } from './chat-ui.store';
|
|
2
2
|
export { ChatUiBackendEchoStore } from './chat-ui-backend-echo.store';
|
|
3
3
|
export { CHAT_UI_BACKEND_STORE_TOKEN } from './chat-ui-backend.store';
|
|
4
|
+
|
|
4
5
|
//# sourceMappingURL=index.js.map
|
package/dist/stores/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../../src/stores/index.ts"],"sourcesContent":["export type { IChatUiStore, ChatUiEventListener } from './chat-ui.store';\nexport {\n CHAT_UI_STORE_TOKEN,\n ChatUiStore,\n ChatUiEvent,\n symbolUser,\n symbolAgent,\n} from './chat-ui.store';\nexport { ChatUiBackendEchoStore } from './chat-ui-backend-echo.store';\nexport type { IChatUiBackendStore } from './chat-ui-backend.store';\nexport { CHAT_UI_BACKEND_STORE_TOKEN } from './chat-ui-backend.store';\n"],"names":["CHAT_UI_STORE_TOKEN","ChatUiStore","ChatUiEvent","symbolUser","symbolAgent","ChatUiBackendEchoStore","CHAT_UI_BACKEND_STORE_TOKEN"],"mappings":"AACA,SACIA,mBAAmB,EACnBC,WAAW,EACXC,WAAW,EACXC,UAAU,EACVC,WAAW,QACR,kBAAkB;AACzB,SAASC,sBAAsB,QAAQ,+BAA+B;AAEtE,SAASC,2BAA2B,QAAQ,0BAA0B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-sse-client-lifecycle.test.d.ts","sourceRoot":"","sources":["../../../src/streaming/__tests__/chat-sse-client-lifecycle.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
|
|
2
|
+
import { fetchEventSource } from '@microsoft/fetch-event-source';
|
|
3
|
+
import { ChatSseClient } from '../chat-sse-client';
|
|
4
|
+
jest.mock('@microsoft/fetch-event-source');
|
|
5
|
+
const fetchEventSourceMock = fetchEventSource;
|
|
6
|
+
const msg = (event, data)=>({
|
|
7
|
+
id: '',
|
|
8
|
+
event,
|
|
9
|
+
data
|
|
10
|
+
});
|
|
11
|
+
const okResponse = ()=>({
|
|
12
|
+
ok: true,
|
|
13
|
+
status: 200,
|
|
14
|
+
headers: {
|
|
15
|
+
get: ()=>'text/event-stream'
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const badResponse = ()=>({
|
|
19
|
+
ok: false,
|
|
20
|
+
status: 502,
|
|
21
|
+
headers: {
|
|
22
|
+
get: ()=>'text/html'
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
describe('ChatSseClient — lifecycle wiring', ()=>{
|
|
26
|
+
beforeEach(()=>{
|
|
27
|
+
fetchEventSourceMock.mockReset();
|
|
28
|
+
});
|
|
29
|
+
test('valid onopen reports connected', async ()=>{
|
|
30
|
+
const onConnected = jest.fn();
|
|
31
|
+
fetchEventSourceMock.mockImplementation(async (_url, init)=>{
|
|
32
|
+
var _init_onopen;
|
|
33
|
+
await ((_init_onopen = init.onopen) === null || _init_onopen === void 0 ? void 0 : _init_onopen.call(init, okResponse()));
|
|
34
|
+
});
|
|
35
|
+
await new ChatSseClient({
|
|
36
|
+
url: 'u',
|
|
37
|
+
onConnected
|
|
38
|
+
}).start();
|
|
39
|
+
expect(onConnected).toHaveBeenCalledTimes(1);
|
|
40
|
+
});
|
|
41
|
+
test('non-OK onopen is a connect-time failure: start rejects and onError fires', async ()=>{
|
|
42
|
+
const onError = jest.fn();
|
|
43
|
+
fetchEventSourceMock.mockImplementation(async (_url, init)=>{
|
|
44
|
+
// Faithful to the lib: an onopen throw is routed to onerror, which (rethrowing) rejects.
|
|
45
|
+
try {
|
|
46
|
+
var _init_onopen;
|
|
47
|
+
await ((_init_onopen = init.onopen) === null || _init_onopen === void 0 ? void 0 : _init_onopen.call(init, badResponse()));
|
|
48
|
+
} catch (err) {
|
|
49
|
+
var _init_onerror;
|
|
50
|
+
const result = (_init_onerror = init.onerror) === null || _init_onerror === void 0 ? void 0 : _init_onerror.call(init, err);
|
|
51
|
+
if (result === undefined || result === null) {
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
const client = new ChatSseClient({
|
|
57
|
+
url: 'u',
|
|
58
|
+
onError
|
|
59
|
+
});
|
|
60
|
+
await expect(client.start()).rejects.toBeDefined();
|
|
61
|
+
expect(onError).toHaveBeenCalledTimes(1);
|
|
62
|
+
});
|
|
63
|
+
test('malformed JSON data is skipped without tearing down or erroring', async ()=>{
|
|
64
|
+
const onError = jest.fn();
|
|
65
|
+
const onEvent = jest.fn();
|
|
66
|
+
let captured;
|
|
67
|
+
fetchEventSourceMock.mockImplementation(async (_url, init)=>{
|
|
68
|
+
var _init_onopen;
|
|
69
|
+
captured = init;
|
|
70
|
+
await ((_init_onopen = init.onopen) === null || _init_onopen === void 0 ? void 0 : _init_onopen.call(init, okResponse()));
|
|
71
|
+
});
|
|
72
|
+
await new ChatSseClient({
|
|
73
|
+
url: 'u',
|
|
74
|
+
onError,
|
|
75
|
+
onEvent
|
|
76
|
+
}).start();
|
|
77
|
+
expect(()=>{
|
|
78
|
+
var _captured_onmessage;
|
|
79
|
+
return (_captured_onmessage = captured.onmessage) === null || _captured_onmessage === void 0 ? void 0 : _captured_onmessage.call(captured, msg('status.changed', 'not-json{'));
|
|
80
|
+
}).not.toThrow();
|
|
81
|
+
expect(onError).not.toHaveBeenCalled();
|
|
82
|
+
expect(onEvent).not.toHaveBeenCalled();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=chat-sse-client-lifecycle.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/streaming/__tests__/chat-sse-client-lifecycle.test.ts"],"sourcesContent":["import { beforeEach, describe, expect, jest, test } from '@jest/globals';\nimport { type EventSourceMessage, fetchEventSource } from '@microsoft/fetch-event-source';\nimport { ChatSseClient } from '../chat-sse-client';\n\njest.mock('@microsoft/fetch-event-source');\n\nconst fetchEventSourceMock = fetchEventSource as jest.MockedFunction<typeof fetchEventSource>;\n\nconst msg = (event: string, data: string): EventSourceMessage => ({ id: '', event, data });\n\nconst okResponse = () =>\n ({ ok: true, status: 200, headers: { get: () => 'text/event-stream' } }) as unknown as Response;\nconst badResponse = () =>\n ({ ok: false, status: 502, headers: { get: () => 'text/html' } }) as unknown as Response;\n\ndescribe('ChatSseClient — lifecycle wiring', () => {\n beforeEach(() => {\n fetchEventSourceMock.mockReset();\n });\n\n test('valid onopen reports connected', async () => {\n const onConnected = jest.fn();\n fetchEventSourceMock.mockImplementation(async (_url, init) => {\n await init.onopen?.(okResponse());\n });\n\n await new ChatSseClient({ url: 'u', onConnected }).start();\n\n expect(onConnected).toHaveBeenCalledTimes(1);\n });\n\n test('non-OK onopen is a connect-time failure: start rejects and onError fires', async () => {\n const onError = jest.fn();\n fetchEventSourceMock.mockImplementation(async (_url, init) => {\n // Faithful to the lib: an onopen throw is routed to onerror, which (rethrowing) rejects.\n try {\n await init.onopen?.(badResponse());\n } catch (err) {\n const result = init.onerror?.(err);\n if (result === undefined || result === null) {\n throw err;\n }\n }\n });\n\n const client = new ChatSseClient({ url: 'u', onError });\n\n await expect(client.start()).rejects.toBeDefined();\n expect(onError).toHaveBeenCalledTimes(1);\n });\n\n test('malformed JSON data is skipped without tearing down or erroring', async () => {\n const onError = jest.fn();\n const onEvent = jest.fn();\n let captured: any;\n fetchEventSourceMock.mockImplementation(async (_url, init) => {\n captured = init;\n await init.onopen?.(okResponse());\n });\n\n await new ChatSseClient({ url: 'u', onError, onEvent }).start();\n\n expect(() => captured.onmessage?.(msg('status.changed', 'not-json{'))).not.toThrow();\n expect(onError).not.toHaveBeenCalled();\n expect(onEvent).not.toHaveBeenCalled();\n });\n});\n"],"names":["beforeEach","describe","expect","jest","test","fetchEventSource","ChatSseClient","mock","fetchEventSourceMock","msg","event","data","id","okResponse","ok","status","headers","get","badResponse","mockReset","onConnected","fn","mockImplementation","_url","init","onopen","url","start","toHaveBeenCalledTimes","onError","err","result","onerror","undefined","client","rejects","toBeDefined","onEvent","captured","onmessage","not","toThrow","toHaveBeenCalled"],"mappings":"AAAA,SAASA,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,IAAI,EAAEC,IAAI,QAAQ,gBAAgB;AACzE,SAAkCC,gBAAgB,QAAQ,gCAAgC;AAC1F,SAASC,aAAa,QAAQ,qBAAqB;AAEnDH,KAAKI,IAAI,CAAC;AAEV,MAAMC,uBAAuBH;AAE7B,MAAMI,MAAM,CAACC,OAAeC,OAAsC,CAAA;QAAEC,IAAI;QAAIF;QAAOC;IAAK,CAAA;AAExF,MAAME,aAAa,IACd,CAAA;QAAEC,IAAI;QAAMC,QAAQ;QAAKC,SAAS;YAAEC,KAAK,IAAM;QAAoB;IAAE,CAAA;AAC1E,MAAMC,cAAc,IACf,CAAA;QAAEJ,IAAI;QAAOC,QAAQ;QAAKC,SAAS;YAAEC,KAAK,IAAM;QAAY;IAAE,CAAA;AAEnEhB,SAAS,oCAAoC;IACzCD,WAAW;QACPQ,qBAAqBW,SAAS;IAClC;IAEAf,KAAK,kCAAkC;QACnC,MAAMgB,cAAcjB,KAAKkB,EAAE;QAC3Bb,qBAAqBc,kBAAkB,CAAC,OAAOC,MAAMC;gBAC3CA;YAAN,QAAMA,eAAAA,KAAKC,MAAM,cAAXD,mCAAAA,kBAAAA,MAAcX;QACxB;QAEA,MAAM,IAAIP,cAAc;YAAEoB,KAAK;YAAKN;QAAY,GAAGO,KAAK;QAExDzB,OAAOkB,aAAaQ,qBAAqB,CAAC;IAC9C;IAEAxB,KAAK,4EAA4E;QAC7E,MAAMyB,UAAU1B,KAAKkB,EAAE;QACvBb,qBAAqBc,kBAAkB,CAAC,OAAOC,MAAMC;YACjD,yFAAyF;YACzF,IAAI;oBACMA;gBAAN,QAAMA,eAAAA,KAAKC,MAAM,cAAXD,mCAAAA,kBAAAA,MAAcN;YACxB,EAAE,OAAOY,KAAK;oBACKN;gBAAf,MAAMO,UAASP,gBAAAA,KAAKQ,OAAO,cAAZR,oCAAAA,mBAAAA,MAAeM;gBAC9B,IAAIC,WAAWE,aAAaF,WAAW,MAAM;oBACzC,MAAMD;gBACV;YACJ;QACJ;QAEA,MAAMI,SAAS,IAAI5B,cAAc;YAAEoB,KAAK;YAAKG;QAAQ;QAErD,MAAM3B,OAAOgC,OAAOP,KAAK,IAAIQ,OAAO,CAACC,WAAW;QAChDlC,OAAO2B,SAASD,qBAAqB,CAAC;IAC1C;IAEAxB,KAAK,mEAAmE;QACpE,MAAMyB,UAAU1B,KAAKkB,EAAE;QACvB,MAAMgB,UAAUlC,KAAKkB,EAAE;QACvB,IAAIiB;QACJ9B,qBAAqBc,kBAAkB,CAAC,OAAOC,MAAMC;gBAE3CA;YADNc,WAAWd;YACX,QAAMA,eAAAA,KAAKC,MAAM,cAAXD,mCAAAA,kBAAAA,MAAcX;QACxB;QAEA,MAAM,IAAIP,cAAc;YAAEoB,KAAK;YAAKG;YAASQ;QAAQ,GAAGV,KAAK;QAE7DzB,OAAO;gBAAMoC;oBAAAA,sBAAAA,SAASC,SAAS,cAAlBD,0CAAAA,yBAAAA,UAAqB7B,IAAI,kBAAkB;WAAe+B,GAAG,CAACC,OAAO;QAClFvC,OAAO2B,SAASW,GAAG,CAACE,gBAAgB;QACpCxC,OAAOmC,SAASG,GAAG,CAACE,gBAAgB;IACxC;AACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-sse-client-resilience.test.d.ts","sourceRoot":"","sources":["../../../src/streaming/__tests__/chat-sse-client-resilience.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, jest, test } from '@jest/globals';
|
|
2
|
+
import { fetchEventSource } from '@microsoft/fetch-event-source';
|
|
3
|
+
import { ChatSseClient } from '../chat-sse-client';
|
|
4
|
+
jest.mock('@microsoft/fetch-event-source');
|
|
5
|
+
const fetchEventSourceMock = fetchEventSource;
|
|
6
|
+
const msg = (event, data)=>({
|
|
7
|
+
id: '',
|
|
8
|
+
event,
|
|
9
|
+
data: typeof data === 'string' ? data : JSON.stringify(data)
|
|
10
|
+
});
|
|
11
|
+
const okResponse = ()=>({
|
|
12
|
+
ok: true,
|
|
13
|
+
status: 200,
|
|
14
|
+
headers: {
|
|
15
|
+
get: ()=>'text/event-stream'
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Capture init, run a successful onopen, then stay open (pending) until the client aborts —
|
|
20
|
+
* mirroring real `fetchEventSource`, which resolves only when the stream actually closes.
|
|
21
|
+
*/ function captureOpen() {
|
|
22
|
+
const capture = {
|
|
23
|
+
opened: undefined
|
|
24
|
+
};
|
|
25
|
+
capture.opened = new Promise((markOpened)=>{
|
|
26
|
+
fetchEventSourceMock.mockImplementation(async (_url, init)=>{
|
|
27
|
+
var _init_onopen;
|
|
28
|
+
capture.init = init;
|
|
29
|
+
await ((_init_onopen = init.onopen) === null || _init_onopen === void 0 ? void 0 : _init_onopen.call(init, okResponse()));
|
|
30
|
+
markOpened();
|
|
31
|
+
await new Promise((resolve)=>{
|
|
32
|
+
const signal = init.signal;
|
|
33
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
34
|
+
resolve();
|
|
35
|
+
} else {
|
|
36
|
+
signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', ()=>resolve(), {
|
|
37
|
+
once: true
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
return capture;
|
|
44
|
+
}
|
|
45
|
+
describe('ChatSseClient — inactivity, reconnect, completion', ()=>{
|
|
46
|
+
beforeEach(()=>{
|
|
47
|
+
fetchEventSourceMock.mockReset();
|
|
48
|
+
jest.useFakeTimers();
|
|
49
|
+
});
|
|
50
|
+
afterEach(()=>{
|
|
51
|
+
jest.useRealTimers();
|
|
52
|
+
});
|
|
53
|
+
test('inactivity callback + onTimeout fire after the threshold, keeping the connection open', async ()=>{
|
|
54
|
+
var _capture_init_signal;
|
|
55
|
+
const onInactivity = jest.fn();
|
|
56
|
+
const onTimeout = jest.fn();
|
|
57
|
+
const capture = captureOpen();
|
|
58
|
+
new ChatSseClient({
|
|
59
|
+
url: 'u',
|
|
60
|
+
inactivityTimeoutMs: 16000,
|
|
61
|
+
onInactivity,
|
|
62
|
+
onTimeout
|
|
63
|
+
}).start();
|
|
64
|
+
await capture.opened;
|
|
65
|
+
jest.advanceTimersByTime(15999);
|
|
66
|
+
expect(onInactivity).not.toHaveBeenCalled();
|
|
67
|
+
jest.advanceTimersByTime(1);
|
|
68
|
+
expect(onInactivity).toHaveBeenCalledTimes(1);
|
|
69
|
+
expect(onTimeout).toHaveBeenCalledTimes(1);
|
|
70
|
+
// Connection is not aborted by inactivity.
|
|
71
|
+
expect((_capture_init_signal = capture.init.signal) === null || _capture_init_signal === void 0 ? void 0 : _capture_init_signal.aborted).toBeFalsy();
|
|
72
|
+
});
|
|
73
|
+
test('a received event resets the inactivity timer', async ()=>{
|
|
74
|
+
const onInactivity = jest.fn();
|
|
75
|
+
const capture = captureOpen();
|
|
76
|
+
new ChatSseClient({
|
|
77
|
+
url: 'u',
|
|
78
|
+
inactivityTimeoutMs: 16000,
|
|
79
|
+
onInactivity
|
|
80
|
+
}).start();
|
|
81
|
+
await capture.opened;
|
|
82
|
+
jest.advanceTimersByTime(10000);
|
|
83
|
+
capture.init.onmessage(msg('status.changed', {
|
|
84
|
+
seq: 1
|
|
85
|
+
})); // reset
|
|
86
|
+
jest.advanceTimersByTime(10000); // 10s since reset < 16s
|
|
87
|
+
expect(onInactivity).not.toHaveBeenCalled();
|
|
88
|
+
jest.advanceTimersByTime(6000); // now 16s since reset
|
|
89
|
+
expect(onInactivity).toHaveBeenCalledTimes(1);
|
|
90
|
+
});
|
|
91
|
+
test('transient drops reconnect up to the limit, then report a fatal error', async ()=>{
|
|
92
|
+
const onDisconnected = jest.fn();
|
|
93
|
+
const onError = jest.fn();
|
|
94
|
+
const capture = captureOpen();
|
|
95
|
+
new ChatSseClient({
|
|
96
|
+
url: 'u',
|
|
97
|
+
maxReconnectAttempts: 2,
|
|
98
|
+
onDisconnected,
|
|
99
|
+
onError
|
|
100
|
+
}).start();
|
|
101
|
+
await capture.opened;
|
|
102
|
+
const r1 = capture.init.onerror(new Error('drop1'));
|
|
103
|
+
const r2 = capture.init.onerror(new Error('drop2'));
|
|
104
|
+
expect(typeof r1).toBe('number');
|
|
105
|
+
expect(typeof r2).toBe('number');
|
|
106
|
+
expect(onDisconnected).toHaveBeenCalledTimes(2);
|
|
107
|
+
expect(onError).not.toHaveBeenCalled();
|
|
108
|
+
expect(()=>capture.init.onerror(new Error('drop3'))).toThrow();
|
|
109
|
+
expect(onError).toHaveBeenCalledTimes(1);
|
|
110
|
+
});
|
|
111
|
+
test('a terminal event completes the run, fires onCompleted, and stops the timer', async ()=>{
|
|
112
|
+
const onCompleted = jest.fn();
|
|
113
|
+
const onInactivity = jest.fn();
|
|
114
|
+
const onFinished = jest.fn();
|
|
115
|
+
const capture = captureOpen();
|
|
116
|
+
new ChatSseClient({
|
|
117
|
+
url: 'u',
|
|
118
|
+
inactivityTimeoutMs: 16000,
|
|
119
|
+
isTerminalEvent: (e)=>e.event === 'run.finished',
|
|
120
|
+
handlers: {
|
|
121
|
+
'run.finished': onFinished
|
|
122
|
+
},
|
|
123
|
+
onCompleted,
|
|
124
|
+
onInactivity
|
|
125
|
+
}).start();
|
|
126
|
+
await capture.opened;
|
|
127
|
+
capture.init.onmessage(msg('run.finished', {
|
|
128
|
+
seq: 1,
|
|
129
|
+
answer: 'done'
|
|
130
|
+
}));
|
|
131
|
+
expect(onFinished).toHaveBeenCalledTimes(1);
|
|
132
|
+
expect(onCompleted).toHaveBeenCalledTimes(1);
|
|
133
|
+
// After completion: timer stopped and post-terminal errors are not fatal.
|
|
134
|
+
jest.advanceTimersByTime(60000);
|
|
135
|
+
expect(onInactivity).not.toHaveBeenCalled();
|
|
136
|
+
expect(()=>capture.init.onerror(new Error('late'))).not.toThrow();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
//# sourceMappingURL=chat-sse-client-resilience.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/streaming/__tests__/chat-sse-client-resilience.test.ts"],"sourcesContent":["import { afterEach, beforeEach, describe, expect, jest, test } from '@jest/globals';\nimport { type EventSourceMessage, fetchEventSource } from '@microsoft/fetch-event-source';\nimport { ChatSseClient } from '../chat-sse-client';\n\njest.mock('@microsoft/fetch-event-source');\n\nconst fetchEventSourceMock = fetchEventSource as jest.MockedFunction<typeof fetchEventSource>;\n\nconst msg = (event: string, data: unknown): EventSourceMessage => ({\n id: '',\n event,\n data: typeof data === 'string' ? data : JSON.stringify(data),\n});\nconst okResponse = () =>\n ({ ok: true, status: 200, headers: { get: () => 'text/event-stream' } }) as unknown as Response;\n\n/**\n * Capture init, run a successful onopen, then stay open (pending) until the client aborts —\n * mirroring real `fetchEventSource`, which resolves only when the stream actually closes.\n */\nfunction captureOpen() {\n const capture: { init?: any; opened: Promise<void> } = {\n opened: undefined as any,\n };\n capture.opened = new Promise<void>(markOpened => {\n fetchEventSourceMock.mockImplementation(async (_url, init) => {\n capture.init = init;\n await init.onopen?.(okResponse());\n markOpened();\n await new Promise<void>(resolve => {\n const signal: AbortSignal | null | undefined = init.signal;\n if (signal?.aborted) {\n resolve();\n } else {\n signal?.addEventListener('abort', () => resolve(), { once: true });\n }\n });\n });\n });\n return capture;\n}\n\ndescribe('ChatSseClient — inactivity, reconnect, completion', () => {\n beforeEach(() => {\n fetchEventSourceMock.mockReset();\n jest.useFakeTimers();\n });\n afterEach(() => {\n jest.useRealTimers();\n });\n\n test('inactivity callback + onTimeout fire after the threshold, keeping the connection open', async () => {\n const onInactivity = jest.fn();\n const onTimeout = jest.fn();\n const capture = captureOpen();\n\n new ChatSseClient({\n url: 'u',\n inactivityTimeoutMs: 16_000,\n onInactivity,\n onTimeout,\n }).start();\n await capture.opened;\n\n jest.advanceTimersByTime(15_999);\n expect(onInactivity).not.toHaveBeenCalled();\n\n jest.advanceTimersByTime(1);\n expect(onInactivity).toHaveBeenCalledTimes(1);\n expect(onTimeout).toHaveBeenCalledTimes(1);\n // Connection is not aborted by inactivity.\n expect(capture.init.signal?.aborted).toBeFalsy();\n });\n\n test('a received event resets the inactivity timer', async () => {\n const onInactivity = jest.fn();\n const capture = captureOpen();\n\n new ChatSseClient({ url: 'u', inactivityTimeoutMs: 16_000, onInactivity }).start();\n await capture.opened;\n\n jest.advanceTimersByTime(10_000);\n capture.init.onmessage(msg('status.changed', { seq: 1 })); // reset\n jest.advanceTimersByTime(10_000); // 10s since reset < 16s\n expect(onInactivity).not.toHaveBeenCalled();\n\n jest.advanceTimersByTime(6_000); // now 16s since reset\n expect(onInactivity).toHaveBeenCalledTimes(1);\n });\n\n test('transient drops reconnect up to the limit, then report a fatal error', async () => {\n const onDisconnected = jest.fn();\n const onError = jest.fn();\n const capture = captureOpen();\n\n new ChatSseClient({\n url: 'u',\n maxReconnectAttempts: 2,\n onDisconnected,\n onError,\n }).start();\n await capture.opened;\n\n const r1 = capture.init.onerror(new Error('drop1'));\n const r2 = capture.init.onerror(new Error('drop2'));\n expect(typeof r1).toBe('number');\n expect(typeof r2).toBe('number');\n expect(onDisconnected).toHaveBeenCalledTimes(2);\n expect(onError).not.toHaveBeenCalled();\n\n expect(() => capture.init.onerror(new Error('drop3'))).toThrow();\n expect(onError).toHaveBeenCalledTimes(1);\n });\n\n test('a terminal event completes the run, fires onCompleted, and stops the timer', async () => {\n const onCompleted = jest.fn();\n const onInactivity = jest.fn();\n const onFinished = jest.fn();\n const capture = captureOpen();\n\n new ChatSseClient({\n url: 'u',\n inactivityTimeoutMs: 16_000,\n isTerminalEvent: e => e.event === 'run.finished',\n handlers: { 'run.finished': onFinished },\n onCompleted,\n onInactivity,\n }).start();\n await capture.opened;\n\n capture.init.onmessage(msg('run.finished', { seq: 1, answer: 'done' }));\n\n expect(onFinished).toHaveBeenCalledTimes(1);\n expect(onCompleted).toHaveBeenCalledTimes(1);\n\n // After completion: timer stopped and post-terminal errors are not fatal.\n jest.advanceTimersByTime(60_000);\n expect(onInactivity).not.toHaveBeenCalled();\n expect(() => capture.init.onerror(new Error('late'))).not.toThrow();\n });\n});\n"],"names":["afterEach","beforeEach","describe","expect","jest","test","fetchEventSource","ChatSseClient","mock","fetchEventSourceMock","msg","event","data","id","JSON","stringify","okResponse","ok","status","headers","get","captureOpen","capture","opened","undefined","Promise","markOpened","mockImplementation","_url","init","onopen","resolve","signal","aborted","addEventListener","once","mockReset","useFakeTimers","useRealTimers","onInactivity","fn","onTimeout","url","inactivityTimeoutMs","start","advanceTimersByTime","not","toHaveBeenCalled","toHaveBeenCalledTimes","toBeFalsy","onmessage","seq","onDisconnected","onError","maxReconnectAttempts","r1","onerror","Error","r2","toBe","toThrow","onCompleted","onFinished","isTerminalEvent","e","handlers","answer"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-sse-client.test.d.ts","sourceRoot":"","sources":["../../../src/streaming/__tests__/chat-sse-client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
|
|
2
|
+
import { fetchEventSource } from '@microsoft/fetch-event-source';
|
|
3
|
+
import { ChatSseClient } from '../chat-sse-client';
|
|
4
|
+
jest.mock('@microsoft/fetch-event-source');
|
|
5
|
+
const fetchEventSourceMock = fetchEventSource;
|
|
6
|
+
/** Capture the init passed to fetchEventSource so tests can drive its callbacks. */ function captureInit() {
|
|
7
|
+
const capture = {};
|
|
8
|
+
fetchEventSourceMock.mockImplementation((url, init)=>{
|
|
9
|
+
capture.url = url;
|
|
10
|
+
capture.init = init;
|
|
11
|
+
return Promise.resolve();
|
|
12
|
+
});
|
|
13
|
+
return capture;
|
|
14
|
+
}
|
|
15
|
+
const msg = (event, data)=>({
|
|
16
|
+
id: '',
|
|
17
|
+
event,
|
|
18
|
+
data: typeof data === 'string' ? data : JSON.stringify(data)
|
|
19
|
+
});
|
|
20
|
+
describe('ChatSseClient — open / decode / dispatch / seq / registry', ()=>{
|
|
21
|
+
beforeEach(()=>{
|
|
22
|
+
fetchEventSourceMock.mockReset();
|
|
23
|
+
});
|
|
24
|
+
test('opens a POST stream with body, headers and event-stream Accept', async ()=>{
|
|
25
|
+
var _capture_init, _capture_init1, _capture_init2;
|
|
26
|
+
const capture = captureInit();
|
|
27
|
+
await new ChatSseClient({
|
|
28
|
+
url: 'https://api.test/api/v2/message/stream',
|
|
29
|
+
body: {
|
|
30
|
+
question: 'hi',
|
|
31
|
+
sessionId: 7
|
|
32
|
+
},
|
|
33
|
+
headers: {
|
|
34
|
+
'Authorization': 'Bearer t',
|
|
35
|
+
'X-Client-ID': 'help-center'
|
|
36
|
+
}
|
|
37
|
+
}).start();
|
|
38
|
+
expect(capture.url).toBe('https://api.test/api/v2/message/stream');
|
|
39
|
+
expect((_capture_init = capture.init) === null || _capture_init === void 0 ? void 0 : _capture_init.method).toBe('POST');
|
|
40
|
+
expect((_capture_init1 = capture.init) === null || _capture_init1 === void 0 ? void 0 : _capture_init1.body).toBe(JSON.stringify({
|
|
41
|
+
question: 'hi',
|
|
42
|
+
sessionId: 7
|
|
43
|
+
}));
|
|
44
|
+
expect((_capture_init2 = capture.init) === null || _capture_init2 === void 0 ? void 0 : _capture_init2.headers).toMatchObject({
|
|
45
|
+
'Accept': 'text/event-stream',
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
'Authorization': 'Bearer t',
|
|
48
|
+
'X-Client-ID': 'help-center'
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
test('JSON-decodes data and dispatches to the registered handler with seq', async ()=>{
|
|
52
|
+
var _capture_init_onmessage, _capture_init;
|
|
53
|
+
const capture = captureInit();
|
|
54
|
+
const onStatus = jest.fn();
|
|
55
|
+
const client = new ChatSseClient({
|
|
56
|
+
url: 'u',
|
|
57
|
+
handlers: {
|
|
58
|
+
'status.changed': onStatus
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
await client.start();
|
|
62
|
+
(_capture_init = capture.init) === null || _capture_init === void 0 ? void 0 : (_capture_init_onmessage = _capture_init.onmessage) === null || _capture_init_onmessage === void 0 ? void 0 : _capture_init_onmessage.call(_capture_init, msg('status.changed', {
|
|
63
|
+
text: 'Thinking…',
|
|
64
|
+
seq: 2
|
|
65
|
+
}));
|
|
66
|
+
expect(onStatus).toHaveBeenCalledTimes(1);
|
|
67
|
+
const [data, event] = onStatus.mock.calls[0];
|
|
68
|
+
expect(data).toEqual({
|
|
69
|
+
text: 'Thinking…',
|
|
70
|
+
seq: 2
|
|
71
|
+
});
|
|
72
|
+
expect(event).toEqual({
|
|
73
|
+
event: 'status.changed',
|
|
74
|
+
data: {
|
|
75
|
+
text: 'Thinking…',
|
|
76
|
+
seq: 2
|
|
77
|
+
},
|
|
78
|
+
seq: 2
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
test('handlers registered via on() receive matching events; consumer can extend new types', async ()=>{
|
|
82
|
+
var _capture_init_onmessage, _capture_init;
|
|
83
|
+
const capture = captureInit();
|
|
84
|
+
const onCustom = jest.fn();
|
|
85
|
+
const client = new ChatSseClient({
|
|
86
|
+
url: 'u'
|
|
87
|
+
});
|
|
88
|
+
client.on('custom.future-event', onCustom);
|
|
89
|
+
await client.start();
|
|
90
|
+
(_capture_init = capture.init) === null || _capture_init === void 0 ? void 0 : (_capture_init_onmessage = _capture_init.onmessage) === null || _capture_init_onmessage === void 0 ? void 0 : _capture_init_onmessage.call(_capture_init, msg('custom.future-event', {
|
|
91
|
+
foo: 1,
|
|
92
|
+
seq: 1
|
|
93
|
+
}));
|
|
94
|
+
expect(onCustom).toHaveBeenCalledTimes(1);
|
|
95
|
+
expect(onCustom.mock.calls[0][0]).toEqual({
|
|
96
|
+
foo: 1,
|
|
97
|
+
seq: 1
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
test('unknown event with no handler is ignored without closing; onEvent still fires', async ()=>{
|
|
101
|
+
const capture = captureInit();
|
|
102
|
+
const onEvent = jest.fn();
|
|
103
|
+
const onError = jest.fn();
|
|
104
|
+
const client = new ChatSseClient({
|
|
105
|
+
url: 'u',
|
|
106
|
+
onEvent,
|
|
107
|
+
onError
|
|
108
|
+
});
|
|
109
|
+
await client.start();
|
|
110
|
+
expect(()=>{
|
|
111
|
+
var _capture_init_onmessage, _capture_init;
|
|
112
|
+
return (_capture_init = capture.init) === null || _capture_init === void 0 ? void 0 : (_capture_init_onmessage = _capture_init.onmessage) === null || _capture_init_onmessage === void 0 ? void 0 : _capture_init_onmessage.call(_capture_init, msg('totally.unknown', {
|
|
113
|
+
seq: 1
|
|
114
|
+
}));
|
|
115
|
+
}).not.toThrow();
|
|
116
|
+
expect(onError).not.toHaveBeenCalled();
|
|
117
|
+
expect(onEvent).toHaveBeenCalledTimes(1);
|
|
118
|
+
expect(onEvent.mock.calls[0][0]).toMatchObject({
|
|
119
|
+
event: 'totally.unknown',
|
|
120
|
+
seq: 1
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
test('ignores null / non-object JSON payloads without throwing or dispatching', async ()=>{
|
|
124
|
+
var // A valid event after the bad ones is still processed (the stream is not wedged).
|
|
125
|
+
_capture_init_onmessage, _capture_init;
|
|
126
|
+
const capture = captureInit();
|
|
127
|
+
const onText = jest.fn();
|
|
128
|
+
const onEvent = jest.fn();
|
|
129
|
+
const onError = jest.fn();
|
|
130
|
+
const client = new ChatSseClient({
|
|
131
|
+
url: 'u',
|
|
132
|
+
handlers: {
|
|
133
|
+
'text.appended': onText
|
|
134
|
+
},
|
|
135
|
+
onEvent,
|
|
136
|
+
onError
|
|
137
|
+
});
|
|
138
|
+
await client.start();
|
|
139
|
+
// `JSON.parse` yields a value that has no `seq`; accessing `.seq` on `null` would throw.
|
|
140
|
+
expect(()=>{
|
|
141
|
+
var _capture_init_onmessage, _capture_init;
|
|
142
|
+
return (_capture_init = capture.init) === null || _capture_init === void 0 ? void 0 : (_capture_init_onmessage = _capture_init.onmessage) === null || _capture_init_onmessage === void 0 ? void 0 : _capture_init_onmessage.call(_capture_init, msg('text.appended', null));
|
|
143
|
+
}).not.toThrow();
|
|
144
|
+
expect(()=>{
|
|
145
|
+
var _capture_init_onmessage, _capture_init;
|
|
146
|
+
return (_capture_init = capture.init) === null || _capture_init === void 0 ? void 0 : (_capture_init_onmessage = _capture_init.onmessage) === null || _capture_init_onmessage === void 0 ? void 0 : _capture_init_onmessage.call(_capture_init, msg('text.appended', '42'));
|
|
147
|
+
}).not.toThrow();
|
|
148
|
+
expect(()=>{
|
|
149
|
+
var _capture_init_onmessage, _capture_init;
|
|
150
|
+
return (_capture_init = capture.init) === null || _capture_init === void 0 ? void 0 : (_capture_init_onmessage = _capture_init.onmessage) === null || _capture_init_onmessage === void 0 ? void 0 : _capture_init_onmessage.call(_capture_init, msg('text.appended', '"hi"'));
|
|
151
|
+
}).not.toThrow();
|
|
152
|
+
// Unparseable data is likewise skipped.
|
|
153
|
+
expect(()=>{
|
|
154
|
+
var _capture_init_onmessage, _capture_init;
|
|
155
|
+
return (_capture_init = capture.init) === null || _capture_init === void 0 ? void 0 : (_capture_init_onmessage = _capture_init.onmessage) === null || _capture_init_onmessage === void 0 ? void 0 : _capture_init_onmessage.call(_capture_init, msg('text.appended', 'not json'));
|
|
156
|
+
}).not.toThrow();
|
|
157
|
+
expect(onText).not.toHaveBeenCalled();
|
|
158
|
+
expect(onEvent).not.toHaveBeenCalled();
|
|
159
|
+
expect(onError).not.toHaveBeenCalled();
|
|
160
|
+
(_capture_init = capture.init) === null || _capture_init === void 0 ? void 0 : (_capture_init_onmessage = _capture_init.onmessage) === null || _capture_init_onmessage === void 0 ? void 0 : _capture_init_onmessage.call(_capture_init, msg('text.appended', {
|
|
161
|
+
text: 'a',
|
|
162
|
+
seq: 1
|
|
163
|
+
}));
|
|
164
|
+
expect(onText).toHaveBeenCalledTimes(1);
|
|
165
|
+
expect(onText.mock.calls[0][0]).toEqual({
|
|
166
|
+
text: 'a',
|
|
167
|
+
seq: 1
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
test('discards events whose seq is not greater than the last processed seq', async ()=>{
|
|
171
|
+
var _capture_init_onmessage, _capture_init, _capture_init_onmessage1, _capture_init1, _capture_init_onmessage2, _capture_init2, _capture_init_onmessage3, _capture_init3;
|
|
172
|
+
const capture = captureInit();
|
|
173
|
+
const onText = jest.fn();
|
|
174
|
+
const client = new ChatSseClient({
|
|
175
|
+
url: 'u',
|
|
176
|
+
handlers: {
|
|
177
|
+
'text.appended': onText
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
await client.start();
|
|
181
|
+
(_capture_init = capture.init) === null || _capture_init === void 0 ? void 0 : (_capture_init_onmessage = _capture_init.onmessage) === null || _capture_init_onmessage === void 0 ? void 0 : _capture_init_onmessage.call(_capture_init, msg('text.appended', {
|
|
182
|
+
text: 'a',
|
|
183
|
+
seq: 5
|
|
184
|
+
}));
|
|
185
|
+
(_capture_init1 = capture.init) === null || _capture_init1 === void 0 ? void 0 : (_capture_init_onmessage1 = _capture_init1.onmessage) === null || _capture_init_onmessage1 === void 0 ? void 0 : _capture_init_onmessage1.call(_capture_init1, msg('text.appended', {
|
|
186
|
+
text: 'dup',
|
|
187
|
+
seq: 5
|
|
188
|
+
})); // duplicate
|
|
189
|
+
(_capture_init2 = capture.init) === null || _capture_init2 === void 0 ? void 0 : (_capture_init_onmessage2 = _capture_init2.onmessage) === null || _capture_init_onmessage2 === void 0 ? void 0 : _capture_init_onmessage2.call(_capture_init2, msg('text.appended', {
|
|
190
|
+
text: 'old',
|
|
191
|
+
seq: 3
|
|
192
|
+
})); // out of order
|
|
193
|
+
(_capture_init3 = capture.init) === null || _capture_init3 === void 0 ? void 0 : (_capture_init_onmessage3 = _capture_init3.onmessage) === null || _capture_init_onmessage3 === void 0 ? void 0 : _capture_init_onmessage3.call(_capture_init3, msg('text.appended', {
|
|
194
|
+
text: 'b',
|
|
195
|
+
seq: 6
|
|
196
|
+
})); // newer
|
|
197
|
+
expect(onText).toHaveBeenCalledTimes(2);
|
|
198
|
+
expect(onText.mock.calls[0][0]).toEqual({
|
|
199
|
+
text: 'a',
|
|
200
|
+
seq: 5
|
|
201
|
+
});
|
|
202
|
+
expect(onText.mock.calls[1][0]).toEqual({
|
|
203
|
+
text: 'b',
|
|
204
|
+
seq: 6
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
//# sourceMappingURL=chat-sse-client.test.js.map
|