Skip to content

storkenjs/storken

Repository files navigation

Storken Logo

Storken v3.0

The LLM-Native State Management Library for React 18+

πŸš€ 5KB LLM-native state management for React 18+ with TypeScript, universal API, and plugin system

npm version TypeScript React Bundle Size License

Storken is a minimal, type-safe, and LLM-friendly state management library for React 18+ with unique features like getter/setter patterns, plugin system, and industry-first unified server-client API.

✨ Features

  • πŸš€ React 18 Ready - Built with useSyncExternalStore for optimal performance
  • πŸ“ Full TypeScript - Complete type safety and IntelliSense support
  • πŸ€– LLM-Native - Predictable patterns perfect for AI-assisted development
  • πŸ”„ Universal API - Same code works in Server Components, Client Components, and API Routes
  • 🎯 Getter/Setter Patterns - Async data fetching with built-in loading states
  • πŸ”Œ Plugin System - Extend functionality with minimal overhead
  • πŸ“¦ Tiny Bundle - Only 5KB minified + gzipped
  • ⚑ Zero Dependencies - Pure React implementation

πŸ“¦ Installation

# npm
npm install storken

# yarn
yarn add storken

# pnpm
pnpm add storken

# bun
bun add storken

πŸš€ Quick Start

πŸ’‘ New to Storken? Check out our comprehensive examples for real-world usage patterns!

Basic Usage

import { create } from 'storken'

// Create your store
const [useStorken] = create({
  initialValues: {
    counter: 0,
    user: null
  }
})

// Use in your components
function Counter() {
  const [count, setCount] = useStorken<number>('counter')
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={() => setCount(prev => prev - 1)}>Decrement</button>
    </div>
  )
}

TypeScript Usage

interface User {
  id: string
  name: string
  email: string
}

function UserProfile() {
  const [user, setUser, resetUser] = useStorken<User | null>('user', null)
  
  const updateName = (name: string) => {
    if (user) {
      setUser({ ...user, name })
    }
  }
  
  return (
    <div>
      {user ? (
        <>
          <h1>{user.name}</h1>
          <input 
            value={user.name} 
            onChange={(e) => updateName(e.target.value)}
          />
          <button onClick={resetUser}>Logout</button>
        </>
      ) : (
        <button onClick={() => setUser({ id: '1', name: 'John', email: '[email protected]' })}>
          Login
        </button>
      )}
    </div>
  )
}

🎯 Advanced Features

Getter Pattern - Async Data Fetching

const [useStorken] = create({
  getters: {
    // Automatic data fetching with loading state
    user: async () => {
      const response = await fetch('/api/user')
      return response.json()
    },
    
    // With parameters
    posts: async (storken, userId: string) => {
      const response = await fetch(`/api/posts?userId=${userId}`)
      return response.json()
    }
  }
})

function UserDashboard() {
  const [user, setUser, resetUser, loading, update] = useStorken<User>('user')
  
  if (loading) return <div>Loading...</div>
  
  return (
    <div>
      <h1>Welcome {user?.name}</h1>
      <button onClick={update}>Refresh</button>
    </div>
  )
}

Setter Pattern - Side Effects

const [useStorken] = create({
  setters: {
    // Automatically sync with backend
    user: async (storken, user: User) => {
      await fetch(`/api/user/${user.id}`, {
        method: 'PUT',
        body: JSON.stringify(user)
      })
    },
    
    // Local storage persistence
    theme: (storken) => {
      localStorage.setItem('theme', storken.value)
    }
  }
})

Plugin System

// Create a custom plugin
const persistencePlugin: StorkenPlugin = (storken) => {
  // Load from localStorage on init
  const saved = localStorage.getItem(`storken_${storken.key}`)
  if (saved) {
    storken.set(JSON.parse(saved))
  }
  
  // Save on every change
  storken.on('set', (value) => {
    localStorage.setItem(`storken_${storken.key}`, JSON.stringify(value))
  })
  
  return {
    clear: () => localStorage.removeItem(`storken_${storken.key}`)
  }
}

// Use the plugin
const [useStorken] = create({
  plugins: {
    persistence: persistencePlugin
  }
})

function Settings() {
  const [settings, setSettings, , , , plugins] = useStorken('settings')
  
  return (
    <button onClick={() => plugins?.persistence.clear()}>
      Clear Cache
    </button>
  )
}

🌟 Universal Server-Client API (Experimental)

Storken v3.0 introduces an industry-first unified API that works seamlessly across Server Components, Client Components, and API Routes:

// storken.config.ts
import { createUniversalStorken } from 'storken/universal'

export const { useStorken, get, set } = createUniversalStorken({
  user: {
    server: {
      get: async (id) => await db.user.findUnique({ where: { id } }),
      set: async (user) => await db.user.update({ where: { id: user.id }, data: user })
    },
    client: {
      get: async (id) => await fetch(`/api/user/${id}`).then(r => r.json()),
      set: async (user) => await fetch(`/api/user/${user.id}`, { method: 'PUT', body: JSON.stringify(user) })
    }
  }
})

// Server Component - Direct DB access
export async function ServerProfile({ userId }) {
  const user = await get('user', userId)
  return <div>Server: {user.name}</div>
}

// Client Component - API calls
'use client'
export function ClientProfile({ userId }) {
  const [user, setUser] = useStorken('user')
  return <div>Client: {user?.name}</div>
}

πŸ€– LLM-Native Development

Storken's predictable patterns make it perfect for AI-assisted development:

// LLMs can easily generate this pattern
const [todos, setTodos] = useStorken<Todo[]>('todos', [])

const addTodo = (title: string) => {
  setTodos(prev => [...prev, { id: Date.now(), title, completed: false }])
}

const toggleTodo = (id: number) => {
  setTodos(prev => prev.map(todo => 
    todo.id === id ? { ...todo, completed: !todo.completed } : todo
  ))
}

πŸ“Š Performance

  • 5KB minified + gzipped - 39% smaller than v2
  • Zero dependencies - Pure React implementation
  • Tree-shakeable - Only import what you use
  • React 18 optimized - Uses useSyncExternalStore for optimal performance
  • TypeScript native - No runtime overhead

πŸ”„ Migration from v2

// v2 (JavaScript)
const [count, setCount] = useStorken('counter', 0)

// v3 (TypeScript)
const [count, setCount] = useStorken<number>('counter', 0)
// Full type safety! ✨

Key changes:

  • Full TypeScript rewrite
  • React 18 useSyncExternalStore instead of custom subscription
  • Improved bundle size (39% smaller)
  • Better tree-shaking support
  • Enhanced type safety

πŸ“š Documentation

πŸ› οΈ Roadmap

  • React Suspense integration - Automatic loading states with Suspense boundaries (currently manual loading states)
  • DevTools browser extension - Redux DevTools-like experience for Storken state inspection
  • Performance monitoring built-in - Runtime metrics and optimization insights
  • Community-driven plugin ecosystem - Let the community guide which plugins to build next

🀝 Contributing

Issues and Pull Requests are welcome!

# Clone the repo
git clone https://github.com/storkenjs/storken.git

# Install dependencies
pnpm install

# Run tests
pnpm test

# Build
pnpm build

πŸ“„ License

MIT License


Built with ❀️ for the React community
Code with AI, State with Storken