Skip to content

Framework Wrapper Guide

Build framework integrations on top of createSkyStateClient() from @skystate/core.

Core Shape

Create one client per (apiUrl, account, project, environment) scope and expose it through your framework's provider/context mechanism.

ts
import { createSkyStateClient } from '@skystate/core';

const client = createSkyStateClient({
  apiUrl,
  account,
  project,
  environment,
});

await client.init();

Do not recreate the client on every render. If connection parameters change, unmount and create a new client.

State Updates

Wrappers should create one framework-facing store from the core client and update that store when SkyState status or values change. The snapshot contains:

  • publicState for anonymous public-state loading status and data.
  • auth for unauthenticated, authenticating, and authenticated states.
  • userState for authenticated user state.
  • misuse for the permanent async-misuse pin (AsyncMisuseError | null).

Expose two orthogonal facets rather than per-subsystem status: an auth facet built from snapshot.auth, and one unified operational-health signal derived from the state facets. isHealthError(error) decides what belongs on health; auth errors belong on the auth facet instead, and a non-null snapshot.misuse should pin health to error for the client's lifetime.

For keyed user reads and writes, expose clear(key) and syncStatus(key) alongside get/set: clear is the only removal path (set rejects undefined at the type level), and syncStatus reports whether the key's stored value is 'unset', 'syncing', or 'synced'.

SkyStateError is a discriminated union. Narrow on error.code before reading variant fields such as httpStatus, path (the failing user-state key on keyed writes), or retryAfter. Keep the wrapper focused on values and status; leave inspection and history workflows to the console, CLI, or REST API.

Auth Actions

Browser wrappers own the hosted login redirect. After the hosted flow exchanges a code for tokens, call:

ts
client.setAuthTokens({ idToken, refreshToken });

Expose two separate actions:

  • logout() should call await client.logout() so the refresh-token family is revoked server-side.
  • clearAuthTokens() should be local-only and should call client.clearAuthTokens().