Skip to content

Core API ​

createStore(config) ​

Creates a store instance with state, actions, computed, selectors, effects, and hooks.

Signature ​

ts
function createStore<S extends object>(
  config: S & StatoStoreConfig<S>,
  __internal?: { skipInit?: boolean }
): StatoStoreInstance<S>

Config ​

The config object contains your state properties at the root level, plus optional reserved keys:

ts
const store = createStore({
  // ── State (any key not listed below) ──
  count:    0,
  users:    [] as User[],
  loading:  false,

  // ── Actions ──
  actions?: {
    [name: string]: (state: S, ...args: any[]) => void | Promise<void>
  },

  // ── Computed (recalculated on every access) ──
  computed?: {
    [name: string]: (state: S) => any
  },

  // ── Selectors (memoized — recalculated only when deps change) ──
  selectors?: {
    [name: string]: (state: S) => any
  },

  // ── Effects (dependency-tracked side effects) ──
  effects?: [
    [(state: S) => any, (depsValue, ctx) => void | (() => void)]
  ],

  // ── Hooks (lifecycle callbacks) ──
  hooks?: StatoHooks<S>
})

Return value ​

The returned store exposes:

PropertyTypeDescription
store.xreadonlyState values (read-only getters)
store.myAction(args)(...args) => Promise<void>Actions (without state param)
store.myComputedreadonlyComputed values
store.mySelectorreadonlyMemoized selectors
store.subscribe(fn)(fn) => unsubscribeSubscribe to state changes
store.getState()() => SGet full state snapshot
store.__store__internalInternal store instance (for adapters)

on(action, handler) ​

React to actions dispatched on another store.

Signature ​

ts
function on<S extends object>(
  sourceAction: Function | Function[],
  handler: (store: S, event: OnEvent) => void | Promise<void>
): () => void

Parameters ​

ParamTypeDescription
sourceActionFunction | Function[]Action(s) to listen to
handler(store, event) => voidCallback when action fires

OnEvent type ​

ts
type OnEvent = {
  name:      string          // Action name
  args:      unknown[]       // Arguments passed to the action
  status:    'success' | 'error'
  duration:  number          // Execution time in ms
  error?:    Error           // Present when status = 'error'
}

Examples ​

ts
import { on } from '@ngstato/core'

// Single action
const unsub = on(authStore.logout, (store, event) => {
  console.log('Logged out')
})

// Multiple actions
const unsub = on(
  [userStore.create, userStore.update, userStore.delete],
  (store, event) => {
    if (event.status === 'success') {
      analyticsStore.track(event.name, event.duration)
    }
  }
)

// Cleanup
unsub()

mergeFeatures(...features) ​

Compose reusable feature fragments into a single config object.

Signature ​

ts
function mergeFeatures(...features: FeatureConfig[]): MergedFeature

FeatureConfig ​

ts
interface FeatureConfig {
  state?:     Record<string, unknown>
  actions?:   Record<string, Function>
  computed?:  Record<string, Function>
  selectors?: Record<string, Function>
  effects?:   EffectEntry<any>[]
  hooks?:     Partial<StatoHooks<any>>
}

Merge rules ​

KeyStrategy
stateSpread at root level
actionsMerge object (last feature wins on conflict)
computedMerge object
selectorsMerge object
effectsConcatenate arrays
hooksMerge intelligently (all handlers for the same hook are called)

Example ​

ts
function withLoading() {
  return {
    state:    { loading: false, error: null as string | null },
    actions:  { setLoading: (s, v: boolean) => { s.loading = v } },
    computed: { hasError: (s) => s.error !== null }
  }
}

const store = createStore({
  items: [] as Item[],
  ...mergeFeatures(withLoading(), withPagination())
})

connectDevTools(store, name) ​

Connect a store instance to the built-in DevTools panel.

Signature ​

ts
function connectDevTools(store: any, name: string): void

Example ​

ts
import { connectDevTools } from '@ngstato/core'

const store = createStore({ ... })
connectDevTools(store, 'UserStore')

HTTP Client ​

configureHttp(options) ​

Configure the global HTTP client. Called internally by provideStato().

ts
import { configureHttp } from '@ngstato/core'

configureHttp({
  baseUrl: 'https://api.example.com',
  timeout: 8000,
  headers: { 'X-App-Version': '1.0' },
  auth:    () => localStorage.getItem('token')
})

http methods ​

ts
import { http } from '@ngstato/core'

// GET
const users = await http.get<User[]>('/users')
const user  = await http.get<User>('/users/1', {
  params: { include: 'posts' }
})

// POST
const created = await http.post<User>('/users', { name: 'Alice' })

// PUT
const updated = await http.put<User>('/users/1', { name: 'Bob' })

// PATCH
const patched = await http.patch<User>('/users/1', { active: false })

// DELETE
await http.delete('/users/1')

RequestOptions ​

ts
interface RequestOptions {
  params?:  Record<string, string | number | boolean>
  headers?: Record<string, string>
  signal?:  AbortSignal
}

StatoHttpError ​

Thrown on non-2xx responses:

ts
class StatoHttpError extends Error {
  status: number   // HTTP status code
  body:   string   // Response body
}

StatoHooks<S> ​

ts
interface StatoHooks<S> {
  onInit?:         (store: S) => void | Promise<void>
  onDestroy?:      (store: S) => void | Promise<void>
  onAction?:       (name: string, args: unknown[]) => void
  onActionDone?:   (name: string, duration: number) => void
  onError?:        (error: Error, actionName: string) => void
  onStateChange?:  (prev: S, next: S) => void
}

Types ​

StatoStoreConfig<S> ​

ts
interface StatoStoreConfig<S extends object> {
  actions?:   Record<string, Action<StateSlice<S>>>
  computed?:  Record<string, ComputedFn<StateSlice<S>>>
  selectors?: Record<string, SelectorFn<StateSlice<S>>>
  effects?:   EffectEntry<StateSlice<S>>[]
  hooks?:     StatoHooks<any>
  [key: string]: unknown    // state properties
}

StatoConfig (HTTP) ​

ts
interface StatoConfig {
  baseUrl?: string
  timeout?: number
  headers?: Record<string, string>
  auth?:    () => string | null | undefined
}

DevTools ​

connectDevTools(store, name) ​

Connect a store to the DevTools panel. Registers it in the store registry for time-travel support.

ts
import { connectDevTools } from '@ngstato/core'

const store = createStore({ count: 0, actions: { inc(s) { s.count++ } } })
connectDevTools(store, 'CounterStore')

devTools (singleton) ​

The global DevTools instance. Available for programmatic control.

ts
import { devTools } from '@ngstato/core'

Time-travel ​

ts
// Jump to a specific action's resulting state
devTools.travelTo(logId: number)

// Step backward — restore previous action's state
devTools.undo()

// Step forward — restore next action's state, or resume live
devTools.redo()

// Resume live state (latest action's nextState)
devTools.resume()

// Re-execute an action from history
devTools.replay(logId: number)

Fork-on-dispatch

If a new action is dispatched during time-travel, ngStato forks: future actions are truncated and live mode resumes. This is the same behavior as Git—you went back, changed something, and the future is now different.

State export/import ​

ts
// Export full snapshot — all store states + action log
const snapshot = devTools.exportSnapshot()
// Returns: { version: 1, timestamp, stores: {...}, logs: [...] }

// Import a previously exported snapshot
devTools.importSnapshot(snapshot)

Bug reports

Export snapshots when reporting bugs — they contain the exact application state and the sequence of actions that led to it. Share the JSON file with your team for instant reproduction.

Basic controls ​

ts
devTools.open()       // Show panel
devTools.close()      // Hide panel
devTools.toggle()     // Toggle visibility
devTools.clear()      // Clear action log (resumes live if time-traveling)
devTools.subscribe(cb) // Listen to DevTools state changes

DevToolsSnapshot type ​

ts
interface DevToolsSnapshot {
  version:   number                      // Always 1
  timestamp: string                      // ISO timestamp
  stores:    Record<string, unknown>     // Store name → state snapshot
  logs:      ActionLog[]                 // Full action history
}

ActionLog type ​

ts
interface ActionLog {
  id:        number
  name:      string                      // "[StoreName] actionName"
  storeName: string
  args:      unknown[]
  duration:  number                      // ms
  status:    'success' | 'error'
  error?:    string
  prevState: Record<string, unknown>
  nextState: Record<string, unknown>
  at:        string                      // ISO timestamp
}

Released under the MIT License.