Skip to content

Commit abbd2d7

Browse files
committed
fixes theopenconversationkit#188: make SSE connection deferred to first useTock call
1 parent 15d19f6 commit abbd2d7

File tree

1 file changed

+49
-28
lines changed

1 file changed

+49
-28
lines changed

src/useTock.ts

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,20 @@ export interface UseTock {
7676
sseInitializing: boolean;
7777
}
7878

79+
/**
80+
* Internal extensions for {@link UseTock}
81+
*/
82+
interface UseTock0 extends UseTock {
83+
/**
84+
* Hook that initializes the SSE connection and returns {@link #sseInitPromise}
85+
*
86+
* If SSE is disabled by the settings, this method simply resolves the sseInitPromise.
87+
*
88+
* This method is idempotent.
89+
*/
90+
useSseInit: () => void;
91+
}
92+
7993
function 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+
) => UseTock0 = (
130144
tockEndPoint: string,
131145
{ locale, localStorage: localStorageSettings, network: networkSettings },
132146
extraHeadersProvider?: () => Promise<Record<string, string>>,
@@ -599,19 +613,20 @@ export const useTock0: (
599613
sseSource.current.onResponse = handleSseBotResponse;
600614
}, [handleSseBotResponse, onSseStateChange]);
601615

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]);
616+
const useSseInit = () =>
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]);
615630

616631
const addHistory: (
617632
messageHistory: Array<Message>,
@@ -698,36 +713,42 @@ export const useTock0: (
698713
loadHistory,
699714
sseInitPromise: afterInitPromise.current,
700715
sseInitializing,
716+
useSseInit,
701717
};
702718
};
703719

704-
export const UseTockContext = createContext<UseTock | undefined>(undefined);
720+
export const UseTockContext = createContext<UseTock0 | undefined>(undefined);
705721

706722
export default (
707723
tockEndPoint?: string,
708724
extraHeadersProvider?: () => Promise<Record<string, string>>,
709725
disableSse?: boolean,
710726
localStorageHistory?: TockLocalStorage,
711-
) => {
727+
): UseTock => {
712728
const contextTock = useContext(UseTockContext);
713729
const settings = useTockSettings();
714-
if (contextTock != null) {
715-
return contextTock;
716-
}
730+
717731
if (settings.endpoint == null && tockEndPoint == null) {
718732
throw new Error('TOCK endpoint must be provided in TockContext');
719733
} else if (settings.endpoint == null) {
720734
console.warn(
721735
'Passing TOCK endpoint as argument to TockChat or useTock is deprecated; please set it in TockContext instead.',
722736
);
723737
}
724-
return contextTock
725-
? contextTock
726-
: useTock0(
727-
(tockEndPoint ?? settings.endpoint)!,
728-
settings,
729-
extraHeadersProvider,
730-
disableSse,
731-
localStorageHistory,
732-
);
738+
739+
// the following conditional does not follow the rules of hooks,
740+
// but in practice the endpoint setting should not appear or disappear in a live app
741+
const ret =
742+
contextTock ??
743+
useTock0(
744+
(tockEndPoint ?? settings.endpoint)!,
745+
settings,
746+
extraHeadersProvider,
747+
disableSse,
748+
localStorageHistory,
749+
);
750+
751+
ret.useSseInit();
752+
753+
return ret;
733754
};

0 commit comments

Comments
 (0)