Skip to main content

Webapp Composition

A Labkit-style webapp keeps product code in app folders and isolates Labkit wiring in small adapter files.

Adapter Files

A practical browser layout:

src/shared/auth/session.ts
src/shared/auth/auth-api.ts
src/shared/graphql/endpoints.ts
src/shared/realtime/realtime-connection.ts
src/shared/relay/environment.ts
src/shared/theme/theme-store.ts

Those files expose stable app names such as getAccessToken, refreshStoredAuthSession, createRelayEnvironment, and useAuthState. Routes and components import the app adapters, not raw package factories.

Auth Session

import { useSyncExternalStore } from "react";
import {
cookieRefreshTokenTransport,
createAuthSessionHintStorage,
createWebappAuthSession,
} from "@omgjs/labkit-webapp-auth";

const authSession = createWebappAuthSession({
refreshTokenTransport: cookieRefreshTokenTransport,
sessionHintStorage: createAuthSessionHintStorage({
storageKey: "webapp:auth-session-hint",
}),
});

export const getAccessToken = authSession.getAccessToken;
export const getAuthSession = authSession.getAuthSession;
export const subscribeAuthState = authSession.subscribeAuthState;

export function useAuthState() {
return useSyncExternalStore(
authSession.subscribeAuthState,
authSession.getAuthState,
authSession.getAuthState,
);
}

Relay Environment

import { DefaultWebappRelayRuntime } from "@omgjs/labkit-webapp-graphql-relay";

export const relayRuntime = new DefaultWebappRelayRuntime({
httpEndpoint: HTTP_ENDPOINT,
wsEndpoint: WS_ENDPOINT,
auth,
});

export function createRelayEnvironment() {
return relayRuntime.getEnvironment();
}

The auth adapter provides access-token reads, auth-state subscription, auth-session reads, refresh, credentials, and auth-required error checks. The runtime provides the Relay environment, the realtime instance, and observable connection state.

App Providers

At the top of the React tree, create one Relay environment, bootstrap auth once, and apply theme classes from your app-owned theme adapter.

export function AppProviders() {
const environment = useMemo(() => createRelayEnvironment(), []);

useEffect(() => {
void bootstrapAuthSession();
}, []);

return (
<RelayEnvironmentProvider environment={environment}>
<RouterProvider router={router} />
</RelayEnvironmentProvider>
);
}

Labkit owns the mechanics. The app owns routes, generated operations, hooks, UI, and visual design.