
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
@healthie/chat
Advanced tools
This SDK is intended to be used in an existing projects that use Healthie's API. The user authentication flow is currently not included in this SDK and should be implemented separately in your project.
yarn add @healthie/chat
yarn add @rails/actioncable graphql-ruby-client
# or
npm i @healthie/chat
npm i @rails/actioncable graphql-ruby-client
This SDK works on top of the Apollo Client with the assumption that you already have the Apollo Client installed and set up.
Chat and other websocket capabilities are implemented using ActionCable.
The following is a basic configuration of the Apollo Client in order to let the SDK to work properly:
import {
ApolloProvider,
HttpLink,
ApolloClient,
InMemoryCache,
split,
} from '@apollo/client'
import { getMainDefinition } from '@apollo/client/utilities'
import * as ActionCable from '@rails/actioncable'
import ActionCableLink from 'graphql-ruby-client/subscriptions/ActionCableLink'
import { HealthieProvider } from '@healthie/chat'
const httpLink = new HttpLink({
uri: 'https://api.gethealthie.com/graphql',
headers: {
authorization: 'Basic <user_auth_token>',
authorizationsource: 'API',
},
})
const cable = ActionCable.createConsumer(
'wss://ws.gethealthie.com/subscriptions?token=<user_auth_token>'
)
const wsLink = new ActionCableLink({ cable })
const link = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query)
if (!('operation' in definition)) {
return false
}
const { kind, operation } = definition
return kind === 'OperationDefinition' && operation === 'subscription'
},
wsLink,
httpLink
)
const client = new ApolloClient({
link,
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
// custom configuration if needed
},
},
},
}),
})
export function App() {
return (
<ApolloProvider client={client}>
<HealthieProvider userId={'<user_id>'}>
{/* ... your app ... */}
</HealthieProvider>
</ApolloProvider>
)
}
Replace <user_auth_token> with the user's API key obtained during the authentication process and <user_id> with the ID of the currently authenticated user.
Read more about Healthie API authentication here.
Frameworks such as Next.js, Remix, Astro, and others heavily depend on server-side rendering (SSR). This means they attempt to render the code on the server where browser APIs are not available. The Healthie SDK utilizes WebSockets through the ActionCable library. If you try to use the provided code in Next.js or other SSR frameworks, you will likely encounter an error.
To address this issue, follow the steps below. This solution should work for most frameworks. If you prefer a framework-specific solution, such as next/dynamic, consult your framework's documentation.
First, create a useHydrated.ts React hook that will help us determine if the JS has been hydrated already.
import { useEffect, useState } from "react";
let isHydrating = true;
export function useHydrated() {
let [isHydrated, setIsHydrated] = useState(() => !isHydrating);
useEffect(function hydrate() {
isHydrating = false;
setIsHydrated(true);
}, []);
return isHydrated;
}
Next, define our ClientOnly.tsx component that renders its children only client-side.
import { ReactNode } from "react";
import { useHydrated } from "./useHydrated";
type Props = {
children(): ReactNode;
fallback?: ReactNode;
};
export function ClientOnly({ children, fallback = null }: Props) {
return useHydrated() ? <>{children()}</> : <>{fallback}</>;
}
Then make sure to lazy-load the ApolloProvider and its client definition, so we avoid running the WebSocket code on the server.
Create a file called ApolloForHealthie.tsx which wraps ApolloProvider.
type ProviderProps = {
children: React.ReactNode
}
// rest of the client initialization code (see the "Basic setup" guide)
// ...
// ...
// ...
const client = new ApolloClient({
link,
cache: new InMemoryCache(),
});
export default function ApolloForHealthie({ children }: ProviderProps) {
return (
<ApolloProvider client={client}>
{children}
</ApolloProvider>
)
}
Lastly, load the new provider lazily and wrap it with the ClientOnly component:
import { lazy } from 'react'
// it's important to use the React.lazy() instead of regular import
const ApolloForHealthie = lazy(() => import('./ApolloForHealthie'))
function Loading() {
return (
<div>
{/* Ideally this should be the same size as the original component to avoid layout shifts */}
</div>
)
}
export default function App() {
const healthieUserId = '__REPLACE_ME__'
return (
<ClientOnlyHydrated fallback={<Loading />}>
{() => (
<ApolloForHealthie>
<HealthieProvider userId={healthieUserId}>
{/* render Healthie components as usual */}
</HealthieProvider>
</ApolloForHealthie>
)}
</ClientOnlyHydrated>
)
}
The above code will render the ApolloClient and Healthie components client-side, while rendering the custom-defined Loading component on the server. This prevents the use of browser-specific APIs, such as ActionCable, on the server.
import { ConversationList, Chat } from '@healthie/chat'
import '@healthie/chat/dist/styles/index.css'
// This example assumes you defined the Apollo Client according to the
// instructions described in the "Basic setup" section of the Readme
// const client = ...
// HealthieProvider must be rendered before using any of these components
export function HealthieChatView() {
return (
<div>
<div className="conversation-list-container">
<ConversationList />
</div>
<div className="chat-container">
<Chat />
</div>
</div>
)
}
// in App.tsx
export default function App() {
const healthieUserId = '' // obtain during the auth flow
return (
<ApolloProvider client={client}>
<HealthieProvider userId={healthieUserId}>
{/* your app... */}
<HealthieChatView />
{/* your app... */}
</HealthieProvider>
</ApolloProvider>
)
}
Make sure to import the stylesheet, usually in the root component of your app:
import '@healthie/chat/dist/styles/index.css'
This component will fetch the list of active conversations for the currently authenticated user and display it on the screen.
If no onConversationClick or activeId props were provided, Healthie SDK will manage the state itself.
:bulb: The default and recommended way to render this component is to leave both props empty and let the HealthieContext manage it's state.
<ConversationList
onConversationClick={handleOnConversationClick}
activeId="<conversation_id>"
/>
| Prop name | Type | Description |
|---|---|---|
onConversationClick | Function | (optional) Callback to trigger when user clicks on the Conversation item. If not provided, will set the clicked conversaton as active. |
activeId | string / null | (optional) ID of the currently selected Conversation. If not provided, the component will set the first conversation on the list as active. |
import { useState } from 'react'
function Example() {
const [conversationId, setConversationId] = useState(null)
return (
<ConversationList
onConversationClick={(id) => {
setConversationId(id)
}}
activeId={conversationId}
/>
)
}
<Chat conversationId="<conversation_id>" />
Warning: If you rendered the
ConversationListcomponent without custom props, don't provide theconversationIdprop in order to leverage full capabilities of Healthie Context.
| Prop name | Type | Description |
|---|---|---|
conversationId | string | (optional) ID of the Conversation to open. Obtain this information via the GraphQL API or use the Conversation List component. If not provided, will render the active Conversation from HealthieContext |
The Chat component takes the full height of the parent container. This enables you to fully control this component's sizing and positioning.
Make sure to correctly specify the height of the container (fixed or fluid), otherwise chat messages may not be visible.
:bulb: Make sure to provide the currently authenticated Healthie User's ID to the
HealthieProvider. Otherwise the Chat component will not be able to distinguish incoming and outgoing messages.
FAQs
React SDK for Healthie Chat
We found that @healthie/chat demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.