@graphcore/frontend
v0.3.3
Published
GraphCore React frontend — EntityRenderer, WebSocket plumbing, and view registry for building GraphCore-powered applications.
Readme
@graphcore/frontend
React 19 GraphCore frontend package with:
GraphCoreProviderfor auth + GraphCore bridge wiringEntityRendererfor rendering any GraphCore entity- self-hosted view widgets like
AgentChatView,AgentBuilder, andCanvasView - strategy request helpers for all writes
- entity graph hooks for new custom UI code
- a stable entity graph read API for package-owned frontend code
Install
npm install @graphcore/frontendImport the shared stylesheet once:
import '@graphcore/frontend/dist/style.css';Peer dependencies:
react >= 19react-dom >= 19
You do not need to install recoil.
How It Works
The package now uses a lightweight internal entity store.
- The backend remains the source of truth.
- Entity updates arrive over GraphCore WebSocket messages and are merged into the store.
- Custom components should treat the entity store as read-only.
- All mutations should go through strategy requests.
In practice, there are two recommended ways to build with the package:
- Render entities and views using the built-in rendering flow.
- Build custom UI on top of the exported entity graph hooks and strategy helpers.
Provider Setup
Wrap your app with GraphCoreProvider:
import { GraphCoreProvider } from '@graphcore/frontend';
import '@graphcore/frontend/dist/style.css';
export function AppRoot() {
return (
<GraphCoreProvider
apiUrl={process.env.GRAPHCORE_API_URL!}
wsUrl={process.env.GRAPHCORE_WS_URL!}
>
<App />
</GraphCoreProvider>
);
}GraphCoreProvider now sets up:
- GraphCore bridge / WebSocket lifecycle
- auth state
You should not add your own provider around package components to manage GraphCore transport state.
Props
| Prop | Type | Description |
|------|------|-------------|
| apiUrl | string | Full API base URL, for example https://api.example.com |
| wsUrl | string | WebSocket host:port, for example localhost:8000 |
| getToken | () => string \| null | Optional external token injector |
| userEntityId | string | Required when using getToken |
Auth Flow
The default flow is:
import { AuthPage, EntityRenderer, useAuth } from '@graphcore/frontend';
export function Shell() {
const { isAuthenticated, isLoading, userEntityId, logout } = useAuth();
if (isLoading) return <div>Loading...</div>;
if (!isAuthenticated) return <AuthPage />;
return (
<div className="h-screen">
<header>
<button onClick={logout}>Logout</button>
</header>
<main className="h-full">
<EntityRenderer entityId={userEntityId} className="h-full" />
</main>
</div>
);
}useAuth() is still the main consumer auth API:
login(username, password)logout()isAuthenticatedisLoadinguserEntityId
Token Injection
If your host application already owns auth, inject the token:
<GraphCoreProvider
apiUrl={apiUrl}
wsUrl={wsUrl}
getToken={() => externalAuth.getGraphCoreJwt()}
userEntityId={externalAuth.graphCoreUserEntityId}
>
<EntityRenderer entityId={externalAuth.graphCoreUserEntityId} />
</GraphCoreProvider>Flow 1: Render Entities
EntityRenderer is the highest-level rendering primitive.
import { EntityRenderer } from '@graphcore/frontend';
<EntityRenderer entityId={userEntityId} className="h-full" />;
<EntityRenderer entityId={agentId} />;
<EntityRenderer entityId={agentId} viewType="agentbuilder" />;
<EntityRenderer entityId={agentId} showBorder={false} />;Use this when you want the package to:
- fetch the entity graph on demand
- resolve the active view entity
- dispatch to the registered view component
- auto-wire strategy requests into package components
Flow 2: Drop In Self-Hosted Views
Many built-in views are exported as self-hosted widgets. These components can be mounted directly with a parentEntityId, and the package will ensure the matching view entity exists.
import { AgentChatView, AgentBuilder, CanvasView } from '@graphcore/frontend';
<AgentChatView parentEntityId={agentId} className="h-full" />
<AgentBuilder parentEntityId={agentId} className="h-full" />
<CanvasView parentEntityId={workspaceId} className="h-full" />Available pre-wrapped views:
| Export | View type key |
|--------|---------------|
| AgentChatView | agentchatview |
| AgentBuilder | agentbuilder |
| ConversationView | conversationview |
| KanbanBoardView | kanban_board_view |
| KanbanCardView | kanban_card_view |
| CanvasView | canvas |
| AdvancedDocumentEditor | advanced_document_editor |
| AgentWorkspaceView | agentworkspaceview |
Multiple slots under the same parent are supported:
<AgentChatView parentEntityId={agentId} selfHostedSlotKey="primary" />
<AgentChatView parentEntityId={agentId} selfHostedSlotKey="research" />Build Custom Views
Use withAutoViewEntity when you want the same self-hosted pattern for your own component:
import { withAutoViewEntity } from '@graphcore/frontend';
function MyView(props: { viewEntityId?: string }) {
return <div>My custom GraphCore view</div>;
}
export const MySelfHostedView = withAutoViewEntity(MyView, 'my_view_type');Then mount it with either:
parentEntityIdfor self-hosted modeviewEntityIdfor direct render mode
If you need GraphCore to use your component in normal entity rendering, also register it:
import { registerViewComponent } from '@graphcore/frontend';
import { MyView } from './MyView';
registerViewComponent('my_view_type', MyView);Writing New Custom Components
For new code, prefer the entity graph hooks exported by the package.
Read Entities
import { useEntity, useChildren, useEntities } from '@graphcore/frontend';
function AgentSummary({ entityId }: { entityId: string }) {
const entity = useEntity(entityId);
const children = useChildren(entityId, { types: ['entity_service.ViewEntity'] });
const loadedChildren = useEntities(entity?.children_ids || []);
return (
<div>
<div>Name: {entity?.name}</div>
<div>View count: {children.length}</div>
<div>Loaded child entities: {loadedChildren.filter(Boolean).length}</div>
</div>
);
}Available read APIs:
useEntity(id)useEntities(ids)useChildren(parentId, { type, types, enabled })useViewChildren(parentId)useRecursiveChildren(parentId, { types, excludeTypes, includeRoot })entityGraph.readEntity(id)entityGraph.readChildren(parentId, { types, excludeTypes })useBridgeStatus()useGraphCoreBridge()
Send Mutations
All writes should go through strategy requests.
Use the strategy hook:
import { StrategyRequests, useStrategyRequest } from '@graphcore/frontend';
function RenameButton({ entityId }: { entityId: string }) {
const sendStrategyRequest = useStrategyRequest();
return (
<button
onClick={() =>
sendStrategyRequest?.(
StrategyRequests.setAttributes(entityId, { name: 'Updated Name' }),
)
}
>
Rename
</button>
);
}Or use the compatibility wrapper:
import { useWebSocketConsumer } from '@graphcore/frontend';
const { sendStrategyRequest, isConnected } = useWebSocketConsumer();useWebSocketConsumer() remains supported, but new code should generally prefer useStrategyRequest() unless you specifically need the compatibility shape.
Await Strategy Results
const sendStrategyRequest = useStrategyRequest();
await sendStrategyRequest?.(
StrategyRequests.setAttributes(entityId, { name: 'Updated Name' }),
{ awaitResponse: true, timeout: 60000 },
);Strategy Helpers
StrategyRequests is a static factory object with builders for all common backend operations:
Attributes
setAttributes(entityId, attributes, addToHistory?)setFrameworkFields(entityId, frameworkFields, addToHistory?)hideEntity(entityId, hide?)
Entities
createEntity(parentEntityId, entityTypeId, initialAttributes?, entityUuid?)deleteEntity(entityId)ensureChildView(parentEntityId, viewComponentType, initialAttributes?, slotKey?)
Children
mutateChildren(entityId, operations, addToHistory?)addChildren(entityId, childIds, addToHistory?)removeChildren(entityId, childIds, addToHistory?)moveChildBefore(entityId, childId, beforeChildId, addToHistory?)moveChildAfter(entityId, childId, afterChildId, addToHistory?)
Queries
queryEntities(entityId, filters, resultAttributeName, addToHistory?)recurseEntities(targetEntityId, entityTypeIds?, rootEntityId?, addToHistory?)
List operations
listOperation(entityId, attributeName, operation, value?, index?, addToHistory?)
Pipeline
createNode(pipelineId, initialAttributes?, parentNodeId?)
Templates
serializeEntityGraph(targetEntityId, addToHistory?)publishTemplate(targetEntityId, rootEntityId?, addToHistory?, allowMissingPublishedStructure?)repairTemplateDraftFromLatestRelease(targetEntityId, addToHistory?)instantiateSnapshot(targetEntityId, snapshotJson, isManaged?, addToHistory?)applyTemplateUpgrade(targetEntityId, snapshotJson?, addToHistory?)detachTemplateManagement(targetEntityId, addToHistory?)
Other
executeChildren(entityId)updateStrategyRequest(entityId, updates, addToHistory?)builder()— returns a rawStrategyRequestBuilderfor custom requests
Example:
import { StrategyRequests } from '@graphcore/frontend';
const request = StrategyRequests.addChildren(parentId, childId);Public API Summary
Main exports:
GraphCoreProviderAuthPageuseAuthEntityRendererwithAutoViewEntityregisterViewComponentAgentChatViewAgentBuilderConversationViewKanbanBoardViewKanbanCardViewCanvasViewAdvancedDocumentEditorAgentWorkspaceViewuseEntityuseEntitiesuseChildrenuseViewChildrenuseRecursiveChildrenentityGraphuseStrategyRequestuseGraphCoreBridgeuseBridgeStatususeWebSocketConsumerStrategyRequests
Implementation Guidance
If you are integrating this library into a host app today:
- Mount a single
GraphCoreProvidernear the app root. - Use
AuthPage+useAuth, or inject your own token withgetToken. - Prefer
EntityRendereror the self-hosted view components for the fastest path. - For new custom UI, read data with
useEntity/useChildren/useEntities. - Send all writes through
useStrategyRequestoruseWebSocketConsumer. - Treat the entity store as read-only application state mirrored from the backend.
Notes
- This package targets React 19.
- Graph mutations are backend-authoritative.
- Entity store writes are owned by the GraphCore bridge, not by host app code.
