Core Client
@skystate/core exports createSkyStateClient(), the framework-agnostic client factory used by direct JavaScript integrations and wrapper SDKs.
Basic Example
ts
import { createSkyStateClient } from '@skystate/core';
const client = createSkyStateClient({
account: 'acc_example',
project: 'my-project',
environment: 'production',
});
await client.init();account, project, and environment are required. apiUrl defaults to https://api.skystate.io; fetch and storage can be supplied for tests, non-browser runtimes, or custom token persistence.
Common Workflows
Read public state
Public state is available without end-user auth. Use it for application config, feature flags, settings, and catalog or inventory values:
ts
const banner = client.publicState.get('banner', { enabled: false });Keys are top-level names such as banner, flags, or theme. They are not nested paths.
Attach hosted-auth tokens
The core client does not open login windows. Pass tokens from the hosted auth flow into the client:
ts
client.setAuthTokens({ idToken, refreshToken });Use client.clearAuthTokens() for local-only session cleanup. Use await client.logout() when the user signs out.
Read and write user state
User state is available after an end user signs in:
ts
const theme = client.userState.get('theme', 'dark');
client.userState.set('theme', 'light');Writes update local subscribers immediately and are persisted by the SDK. Temporary network, sign-in renewal, concurrent update, validation, and permission issues are reported through the client status and wrapper callbacks.
For signatures, parameters, return values, and draft handle members, see the @skystate/core user-state reference.
Stage edits with drafts
Drafts are useful for edit-then-save screens:
ts
const profile = client.userState.draft('profile', { displayName: '' });
profile.set((current) => ({ ...current, displayName: 'Ada' }));
profile.save();Use profile.discard() to drop local form edits before saving.
Failure handling
Every request (public-state loads, user-state reads and writes, and auth token refresh) runs under a hard ten-second deadline. A request that stalls past it is aborted and treated as a retryable network failure.
Failures fall into one status class per outcome: transient failures (network, 5xx, rate limits, quota) retry with capped backoff; content rejections (patch_* validation) are dropped from the queue; a data-plane authentication rejection resets the session, clearing the queue and optimistic state, unless the rejected token had already been superseded, in which case the write stays queued and retries on standard backoff; a version conflict (412) is auto-resolved via transparent refetch-and-replay; and a write the server committed but could not confirm is kept, never resent or rolled back, and surfaced once as a protocol error. See Error Handling for the full per-status contract. Auth failures surface on the auth snapshot, operational failures share one set of health codes (isHealthError(error) narrows to them), and write rejections surface on the user-state snapshot with the failing key in error.path.
Observe client status
Advanced integrations can subscribe to client status changes and read the latest snapshot:
ts
const unsubscribe = client.subscribe(() => {
const snapshot = client.getSnapshot();
console.log(snapshot.publicState.status, snapshot.auth.status, snapshot.userState.status);
});When snapshot.auth.status is 'authenticated', the snapshot also carries the signed-in user's name and email (each string | null).
SDK accessors return application values and subsystem status. Use the console, CLI, or REST API when you need inspection or audit metadata.