@@ -76,6 +76,20 @@ export interface UseTock {
7676 sseInitializing : boolean ;
7777}
7878
79+ /**
80+ * Internal extensions for {@link UseTock}
81+ */
82+ interface UseTockInternal extends UseTock {
83+ /**
84+ * Hook that initializes the SSE connection
85+ *
86+ * If SSE is disabled by the settings, the hook simply resolves the sseInitPromise.
87+ *
88+ * This method is idempotent.
89+ */
90+ useSseInit : ( ) => void ;
91+ }
92+
7993function mapButton ( button : BotConnectorButton ) : Button {
8094 if ( button . type === 'postback' ) {
8195 return new PostBackButton ( button . title , button . payload , button . imageUrl ) ;
@@ -126,7 +140,7 @@ export const useTock0: (
126140 extraHeadersProvider ?: ( ) => Promise < Record < string , string > > ,
127141 disableSse ?: boolean ,
128142 localStorageHistory ?: TockLocalStorage ,
129- ) => UseTock = (
143+ ) => UseTockInternal = (
130144 tockEndPoint : string ,
131145 { locale, localStorage : localStorageSettings , network : networkSettings } ,
132146 extraHeadersProvider ?: ( ) => Promise < Record < string , string > > ,
@@ -594,24 +608,26 @@ export const useTock0: (
594608 [ ] ,
595609 ) ;
596610
597- useEffect ( ( ) => {
598- sseSource . current . onStateChange = onSseStateChange ;
599- sseSource . current . onResponse = handleSseBotResponse ;
600- } , [ handleSseBotResponse , onSseStateChange ] ) ;
611+ const useSseInit = ( ) => {
612+ useEffect ( ( ) => {
613+ sseSource . current . onStateChange = onSseStateChange ;
614+ sseSource . current . onResponse = handleSseBotResponse ;
615+ } , [ handleSseBotResponse , onSseStateChange ] ) ;
601616
602- useEffect ( ( ) => {
603- if ( disableSse || ! tockEndPoint . length ) {
604- afterInit . current ( ) ;
605- } else {
606- // Trigger afterInit regardless of whether the SSE call succeeded or failed
607- // (it is valid for the backend to refuse SSE connections, but we still attempt to connect by default)
608- sseSource . current
609- . open ( tockEndPoint , userId )
610- . catch ( ( e ) => console . error ( e ) )
611- . finally ( afterInit . current ) ;
612- }
613- return ( ) => sseSource . current . close ( ) ;
614- } , [ disableSse , tockEndPoint ] ) ;
617+ useEffect ( ( ) => {
618+ if ( disableSse || ! tockEndPoint . length ) {
619+ afterInit . current ( ) ;
620+ } else {
621+ // Trigger afterInit regardless of whether the SSE call succeeded or failed
622+ // (it is valid for the backend to refuse SSE connections, but we still attempt to connect by default)
623+ sseSource . current
624+ . open ( tockEndPoint , userId )
625+ . catch ( ( e ) => console . error ( e ) )
626+ . finally ( afterInit . current ) ;
627+ }
628+ return ( ) => sseSource . current . close ( ) ;
629+ } , [ disableSse , tockEndPoint ] ) ;
630+ } ;
615631
616632 const addHistory : (
617633 messageHistory : Array < Message > ,
@@ -698,36 +714,44 @@ export const useTock0: (
698714 loadHistory,
699715 sseInitPromise : afterInitPromise . current ,
700716 sseInitializing,
717+ useSseInit,
701718 } ;
702719} ;
703720
704- export const UseTockContext = createContext < UseTock | undefined > ( undefined ) ;
721+ export const UseTockContext = createContext < UseTockInternal | undefined > (
722+ undefined ,
723+ ) ;
705724
706725export default (
707726 tockEndPoint ?: string ,
708727 extraHeadersProvider ?: ( ) => Promise < Record < string , string > > ,
709728 disableSse ?: boolean ,
710729 localStorageHistory ?: TockLocalStorage ,
711- ) => {
730+ ) : UseTock => {
712731 const contextTock = useContext ( UseTockContext ) ;
713732 const settings = useTockSettings ( ) ;
714- if ( contextTock != null ) {
715- return contextTock ;
716- }
733+
717734 if ( settings . endpoint == null && tockEndPoint == null ) {
718735 throw new Error ( 'TOCK endpoint must be provided in TockContext' ) ;
719736 } else if ( settings . endpoint == null ) {
720737 console . warn (
721738 'Passing TOCK endpoint as argument to TockChat or useTock is deprecated; please set it in TockContext instead.' ,
722739 ) ;
723740 }
724- return contextTock
725- ? contextTock
726- : useTock0 (
727- ( tockEndPoint ?? settings . endpoint ) ! ,
728- settings ,
729- extraHeadersProvider ,
730- disableSse ,
731- localStorageHistory ,
732- ) ;
741+
742+ // the following conditional does not follow the rules of hooks,
743+ // but in practice the endpoint setting should not appear or disappear in a live app
744+ const ret =
745+ contextTock ??
746+ useTock0 (
747+ ( tockEndPoint ?? settings . endpoint ) ! ,
748+ settings ,
749+ extraHeadersProvider ,
750+ disableSse ,
751+ localStorageHistory ,
752+ ) ;
753+
754+ ret . useSseInit ( ) ;
755+
756+ return ret ;
733757} ;
0 commit comments