Skip to content

React Native SSE is always moving to 'error' but the API is working in web SSE and postman #69

Closed
@DeepikaSharma5

Description

@DeepikaSharma5

I am trying o implement react-native-sse in my react native application. I have converted the code from the web application which is already implemented using @microsoft/fetch-event-source. In there it is working without any issues.

But when I try to do the same implementation in react native app using react-native-sse it is always going to error. I wonder if I have missed anything or implemented anything wrong in the react-native code. I am passing all the values and necessary things as passed in the web application (values message and attachments are not empty and passing the value from props). I am new to sse and this is my first time implementing.

This is my coding for reference =>

`import 'react-native-get-random-values';
import {v4} from 'uuid';
import EventSource, {EventSourceListener} from 'react-native-sse';
import {BaseURL} from '../../utils/serviceURL';
import {getUserToken} from '../../asyncStorage/dataStore';
import {DeviceEventEmitter} from 'react-native';

const ABORT_STREAM_EVENT = 'abortStreamEvent'; // Define the abort event constant

export async function baseHeaders(): Promise<{Authorization: string | null}> {
  const basicAuth = await getUserToken();
  return {
    Authorization: basicAuth ? 'Bearer ${basicAuth}' : null,
  };
}

export const multiplexStream = async function ({
  workspaceSlug,
  threadSlug = null,
  prompt,
  chatHandler,
  attachments = [],
}: {
  workspaceSlug: string;
  threadSlug?: string | null;
  prompt: string;
  chatHandler: (chat: any) => void;
 attachments?: any[];
}) {
  if (threadSlug) {
    return streamChat({slug: threadSlug}, prompt, chatHandler, attachments);
  }
  return streamChat({slug: workspaceSlug}, prompt, chatHandler, attachments);
};

export const streamChat = async function (
  {slug}: {slug: string},
  message: string,
  handleChat: (chat: any) => void,
  attachments: any[] = [],
) {

  const ctrl = new AbortController();

  // Listen for the ABORT_STREAM_EVENT key to be emitted by the client
  const subscription = DeviceEventEmitter.addListener(
    ABORT_STREAM_EVENT,
    () => {
      ctrl.abort();
      handleChat({id: v4(), type: 'stopGeneration'});
    },
  );

  // Create the EventSource instance
  const eventSource = new EventSource(
    `${BaseURL}workspace/${slug}/stream-chat`,
    {
      method: 'POST',
      headers: await baseHeaders(),
     body: JSON.stringify({message, attachments}),
    },
  );

  const listener: EventSourceListener = (event: any) => {
    if (event.type === 'open') {
  console.log('Open SSE connection.');
  if (event.ok) {
    return; // everything's good
  } else if (
    event.xhrStatus >= 400 &&
    event.xhrStatus < 500 &&
    event.xhrStatus !== 429
  ) {
    handleChat({
      id: v4(),
      type: 'abort',
      textResponse: null,
      sources: [],
      close: true,
      error: `An error occurred while streaming response. Code ${
        event.xhrStatus
      }. Message - ${JSON.parse(event.message).error}`,
    });
    ctrl.abort();
    throw new Error('Invalid Status code response.');
  } else {
    handleChat({
      id: v4(),
      type: 'abort',
      textResponse: null,
      sources: [],
      close: true,
      error: `An error occurred while streaming response. Unknown Error.`,
    });
    ctrl.abort();
    throw new Error('Unknown error');
  }
} else if (event.type === 'message') {
  try {
    const chatResult = JSON.parse(event.data);
    handleChat(chatResult);
  } catch (error) {
    console.error('Failed to parse message:', error);
  }
} else if (event.type === 'error') {
  const data = JSON.parse(event.message);
  handleChat({
    id: data.id || v4(),
    type: data.type || 'abort',
    textResponse: data.textResponse || null,
    sources: data.source || [],
    close: data.close || true,
    error: `An error occurred while streaming response.  Code ${
      event.xhrStatus
    }. Message - ${JSON.parse(event.message).error}`,
  });
  ctrl.abort();
} else if (event.type === 'exception') {
  console.error('Error:', JSON.parse(event.message).error, event.xhrStatus);
}
   };

  eventSource.addEventListener('open', listener);
  eventSource.addEventListener('message', listener);
  eventSource.addEventListener('error', listener);

  return () => {
    eventSource.close();
    subscription.remove();
  };
};`

If anyone can help me identify if I have done something wrong or may be I may need to make any changes in the server side?

In the react application, this is how it is implemented =>

`multiplexStream: async function ({
    workspaceSlug,
    threadSlug = null,
    prompt,
    chatHandler,
    attachments = [],
  }) {
    if (!!threadSlug)
      return this.threads.streamChat(
        { workspaceSlug, threadSlug },
        prompt,
        chatHandler,
        attachments
      );
    return this.streamChat(
      { slug: workspaceSlug },
      prompt,
      chatHandler,
      attachments
    );
  },
  streamChat: async function ({ slug }, message, handleChat, attachments = []) {
    const ctrl = new AbortController();

// Listen for the ABORT_STREAM_EVENT key to be emitted by the client
// to early abort the streaming response. On abort we send a special `stopGeneration`
// event to be handled which resets the UI for us to be able to send another message.
// The backend response abort handling is done in each LLM's handleStreamResponse.
window.addEventListener(ABORT_STREAM_EVENT, () => {
  ctrl.abort();
  handleChat({ id: v4(), type: "stopGeneration" });
});

await fetchEventSource(`${API_BASE}/workspace/${slug}/stream-chat`, {
  method: "POST",
  body: JSON.stringify({ message, attachments }),
  headers: baseHeaders(),
  signal: ctrl.signal,
  openWhenHidden: true,
  async onopen(response) {
    if (response.ok) {
      return; // everything's good
    } else if (
      response.status >= 400 &&
      response.status < 500 &&
      response.status !== 429
    ) {
      handleChat({
        id: v4(),
        type: "abort",
        textResponse: null,
        sources: [],
        close: true,
        error: `An error occurred while streaming response. Code ${response.status}`,
      });
      ctrl.abort();
      throw new Error("Invalid Status code response.");
    } else {
      handleChat({
        id: v4(),
        type: "abort",
        textResponse: null,
        sources: [],
        close: true,
        error: `An error occurred while streaming response. Unknown Error.`,
      });
      ctrl.abort();
      throw new Error("Unknown error");
    }
  },
  async onmessage(msg) {
    try {
      const chatResult = JSON.parse(msg.data);
      handleChat(chatResult);
    } catch {}
  },
  onerror(err) {
    handleChat({
      id: v4(),
      type: "abort",
      textResponse: null,
      sources: [],
      close: true,
      error: `An error occurred while streaming response. ${err.message}`,
    });
    ctrl.abort();
    throw new Error();
  },
});

},`

Any help would be really helpful as I am trying this for more than a week to identify what the issue is. As the react application is working, backend developer are not supporting to debug or change the code.

It is working fine in the postman too =>
image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions