npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@owlmeans/state

v0.1.2

Published

A reactive state management library for OwlMeans Common applications. This package provides a comprehensive state management system with subscription-based reactivity, resource integration, and real-time data synchronization for building responsive fullst

Downloads

17

Readme

@owlmeans/state

A reactive state management library for OwlMeans Common applications. This package provides a comprehensive state management system with subscription-based reactivity, resource integration, and real-time data synchronization for building responsive fullstack applications.

Overview

The @owlmeans/state package is a reactive state management library in the OwlMeans Common ecosystem that provides:

  • Reactive State Management: Subscribe to state changes with automatic updates
  • Resource Integration: Built on top of OwlMeans Resource system for data persistence
  • Real-time Synchronization: Live updates across multiple subscribers
  • Model-Based Architecture: Type-safe state models with built-in update methods
  • Query Subscriptions: Subscribe to filtered data sets with criteria
  • Memory Management: Automatic cleanup and unsubscription handling
  • Context Integration: Seamless integration with OwlMeans context system

Installation

npm install @owlmeans/state

Core Concepts

State Resource

The StateResource extends the standard OwlMeans Resource interface with reactive capabilities, allowing components to subscribe to data changes and receive automatic updates.

State Model

A StateModel wraps resource records with reactive capabilities, providing methods to update data and automatically notify subscribers of changes.

Subscriptions

Subscriptions connect components to state changes, automatically triggering updates when subscribed data changes.

Listeners

Functions that handle state change notifications, receiving updated state models when data changes.

API Reference

Types

StateResource<T extends ResourceRecord>

Extended resource interface with subscription capabilities.

interface StateResource<T extends ResourceRecord> extends Resource<T> {
  subscribe: (params: StateSubscriptionOption<T>) => [() => void, StateModel<T>[]]
  listen: (listener: StateListener<T>) => () => void
  erase: () => Promise<void>
}

StateModel<T extends ResourceRecord>

Reactive wrapper for resource records.

interface StateModel<T extends ResourceRecord> {
  record: T
  commit: (force?: boolean) => void
  update: (data?: Partial<T>) => void
  clear: () => void
}

StateSubscriptionOption<T>

Configuration for state subscriptions.

interface StateSubscriptionOption<T extends ResourceRecord> {
  id?: string | string[]        // Specific record IDs to subscribe to
  _systemId?: string           // System-level subscription identifier
  query?: ListCriteria         // Query criteria for filtered subscriptions
  default?: Partial<T>         // Default data for new records
  listener: StateListener<T>   // Callback function for updates
}

StateListener<T>

Function type for handling state changes.

interface StateListener<T extends ResourceRecord> {
  (record: StateModel<T>[]): void | Promise<void>
}

Factory Functions

createStateResource<R>(alias?: string): StateResource<R>

Creates a new state resource with reactive capabilities.

Parameters:

  • alias: Optional resource alias (defaults to 'state')

Returns: StateResource instance with subscription support

appendStateResource<C, T>(ctx: T, alias?: string): T & StateResourceAppend

Appends a state resource to an existing context.

Parameters:

  • ctx: OwlMeans context instance
  • alias: Optional resource alias

Returns: Context with state resource capabilities

Core Methods

subscribe(params: StateSubscriptionOption<T>): [() => void, StateModel<T>[]]

Subscribes to state changes for specific records or queries.

Parameters:

  • params: Subscription configuration with listener and criteria

Returns: Tuple of [unsubscribe function, current state models]

listen(listener: StateListener<T>): () => void

Adds a global listener for all state changes.

Parameters:

  • listener: Function to handle state changes

Returns: Unsubscribe function

erase(): Promise<void>

Clears all state data and notifies subscribers.

State Model Methods

commit(force?: boolean): void

Persists model changes to the underlying resource.

update(data?: Partial<T>): void

Updates model data and notifies subscribers.

clear(): void

Clears model data while maintaining subscription.

Error Types

StateToolingError

Base error for state management tooling issues.

StateListenerError

Error related to listener management and execution.

Usage Examples

Basic State Subscription

import { createStateResource } from '@owlmeans/state'

interface User extends ResourceRecord {
  id?: string
  name: string
  email: string
  status: 'active' | 'inactive'
}

// Create state resource
const userState = createStateResource<User>('users')

// Subscribe to a specific user
const [unsubscribe, models] = userState.subscribe({
  id: 'user123',
  listener: (models) => {
    const user = models[0]
    console.log('User updated:', user.record)
  }
})

// Get current state immediately
if (models.length > 0) {
  console.log('Current user:', models[0].record)
}

// Update user data
models[0].update({ status: 'inactive' })
models[0].commit()

// Cleanup
unsubscribe()

Multiple Record Subscription

// Subscribe to multiple users
const [unsubscribe, models] = userState.subscribe({
  id: ['user1', 'user2', 'user3'],
  listener: (models) => {
    console.log(`Received updates for ${models.length} users`)
    models.forEach(model => {
      console.log(`User ${model.record.id}: ${model.record.name}`)
    })
  }
})

Query-Based Subscription

// Subscribe to active users
const [unsubscribe, models] = userState.subscribe({
  query: {
    status: 'active',
    role: ['admin', 'moderator']
  },
  listener: (models) => {
    console.log(`Active admin/moderator users: ${models.length}`)
  }
})

Global State Listening

// Listen to all state changes
const unsubscribe = userState.listen((models) => {
  console.log('Global state change detected')
  // Handle any user state changes
})

React Integration Example

import React, { useEffect, useState } from 'react'

const UserProfile: React.FC<{ userId: string }> = ({ userId }) => {
  const [user, setUser] = useState<StateModel<User> | null>(null)

  useEffect(() => {
    const [unsubscribe, models] = userState.subscribe({
      id: userId,
      default: { name: '', email: '', status: 'active' },
      listener: (models) => {
        setUser(models[0] || null)
      }
    })

    // Set initial state
    if (models.length > 0) {
      setUser(models[0])
    }

    return unsubscribe
  }, [userId])

  const handleUpdate = (data: Partial<User>) => {
    if (user) {
      user.update(data)
      user.commit()
    }
  }

  if (!user) {
    return <div>Loading...</div>
  }

  return (
    <div>
      <h2>{user.record.name}</h2>
      <p>Email: {user.record.email}</p>
      <p>Status: {user.record.status}</p>
      <button onClick={() => handleUpdate({ status: 'inactive' })}>
        Deactivate User
      </button>
    </div>
  )
}

Context Integration

import { createBasicContext } from '@owlmeans/context'
import { appendStateResource } from '@owlmeans/state'

// Create context with state capabilities
const context = createBasicContext()
appendStateResource(context, 'user-state')

// Access state resource from context
const stateResource = context.getStateResource<User>('user-state')

Bulk Operations

// Subscribe to system-level changes
const [unsubscribe, models] = userState.subscribe({
  _systemId: 'bulk-operations',
  listener: async (models) => {
    // Handle bulk updates
    console.log(`Processing ${models.length} records`)
    
    // Batch commit changes
    models.forEach(model => model.commit())
  }
})

// Perform bulk updates
await userState.create({ name: 'User 1', email: '[email protected]' })
await userState.create({ name: 'User 2', email: '[email protected]' })

Default Data Handling

// Subscribe with default data for new records
const [unsubscribe, models] = userState.subscribe({
  id: 'new-user',
  default: {
    name: 'New User',
    email: '',
    status: 'active'
  },
  listener: (models) => {
    const user = models[0]
    if (!user.record.email) {
      // User still needs email
      console.log('User needs email address')
    }
  }
})

Error Handling

import { StateListenerError } from '@owlmeans/state'

try {
  const [unsubscribe, models] = userState.subscribe({
    id: 'user123',
    listener: async (models) => {
      // Async listener that might throw
      await processUserData(models[0].record)
    }
  })
} catch (error) {
  if (error instanceof StateListenerError) {
    console.error('Listener error:', error.message)
  }
}

Advanced Features

Custom Subscription Patterns

// Conditional subscriptions
const subscribeToUser = (userId: string, condition: (user: User) => boolean) => {
  return userState.subscribe({
    id: userId,
    listener: (models) => {
      const user = models[0]
      if (user && condition(user.record)) {
        // Handle conditional updates
        console.log('Condition met for user:', user.record.id)
      }
    }
  })
}

// Subscribe only to active users
const [unsubscribe] = subscribeToUser('user123', user => user.status === 'active')

Memory Management

class UserManager {
  private subscriptions: (() => void)[] = []

  subscribeToUser(userId: string) {
    const [unsubscribe] = userState.subscribe({
      id: userId,
      listener: this.handleUserUpdate.bind(this)
    })
    
    this.subscriptions.push(unsubscribe)
  }

  cleanup() {
    // Clean up all subscriptions
    this.subscriptions.forEach(unsubscribe => unsubscribe())
    this.subscriptions = []
  }

  private handleUserUpdate(models: StateModel<User>[]) {
    // Handle updates
  }
}

Performance Optimization

// Debounced updates
let updateTimeout: NodeJS.Timeout

const [unsubscribe] = userState.subscribe({
  id: 'user123',
  listener: (models) => {
    clearTimeout(updateTimeout)
    updateTimeout = setTimeout(() => {
      // Process updates after debounce
      console.log('Processing debounced update')
    }, 100)
  }
})

Integration with OwlMeans Ecosystem

The @owlmeans/state package integrates with:

  • @owlmeans/resource: Built on the resource system for data persistence
  • @owlmeans/context: Context-based service registration and access
  • @owlmeans/client: React hooks and component integration
  • @owlmeans/error: Error handling and reporting
  • @owlmeans/client-resource: Client-side resource management

Best Practices

Subscription Management

  • Always store unsubscribe functions and call them during cleanup
  • Use specific IDs when possible instead of broad queries
  • Implement proper error handling in listeners
  • Avoid creating subscriptions in render loops

Performance

  • Use query-based subscriptions for filtered data sets
  • Implement debouncing for high-frequency updates
  • Clean up unused subscriptions promptly
  • Use default data to avoid loading states

Memory Management

  • Implement proper cleanup in component unmount
  • Use weak references for large object graphs
  • Monitor subscription count in development
  • Clean up system subscriptions when no longer needed

Error Handling

  • Wrap async listeners in try-catch blocks
  • Implement fallback UI for failed state updates
  • Log subscription errors for debugging
  • Use defensive programming for model access

Fixes #32.