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

@mirawision/wings

v1.0.0

Published

Advanced state management library for TypeScript with deep merge, request lifecycle tracking, event-driven updates, and local storage caching.

Readme

@mirawision/wings

Advanced state management library for TypeScript with deep merge, request lifecycle tracking, event-driven updates, and local storage caching. Built on top of the observer pattern, Wings provides a sophisticated yet simple way to manage complex application state.

Features

  • Deep Merge State Updates: Support for nested structures and complex state updates
  • Request Lifecycle Management: Automatic tracking of API requests (loading, success, error, finished)
  • Event-Driven Updates: Named events with conditions for fine-grained state change handling
  • Local Storage Caching: Selective data persistence with version control
  • Type Safety: Full TypeScript support with generics
  • Observer Pattern Integration: Reactive state updates
  • Concurrent Request Tracking: Manage multiple simultaneous operations
  • Cache Versioning: Automatic cache migration and invalidation

Installation

npm install @mirawision/wings

or

yarn add @mirawision/wings

Note: Wings depends on @mirawision/observer. It will be installed automatically.

Usage

Basic Example

import { Wing } from '@mirawision/wings';

interface UserState {
  users: User[];
  settings: Settings;
  requests?: RequestsState;
}

class UserService extends Wing<UserState> {
  constructor() {
    super({
      users: [],
      settings: {},
      requests: {}
    });
    
    // Define named events
    this.defineEvent('userAdded', (prev, curr) => 
      curr.users.length > prev.users.length
    );
    
    this.defineEvent('settingsChanged', (prev, curr) => 
      JSON.stringify(prev.settings) !== JSON.stringify(curr.settings)
    );
  }

  async fetchUsers() {
    return this.executeRequest('fetchUsers', 
      () => api.getUsers(),
      (users) => this.setState({ users }),
      (error) => console.error(error)
    );
  }

  updateSettings(newSettings: Partial<Settings>) {
    this.setState({ settings: { ...this.getState().settings, ...newSettings } });
  }
}

Request Lifecycle Management

class DataService extends Wing<DataState> {
  async fetchData() {
    // Automatically manages loading, success, error states
    return this.executeRequest('fetchData', 
      () => api.getData(),
      (data) => this.setState({ data }),
      (error) => console.error('Failed to fetch data:', error)
    );
  }

  // Check request states
  isDataLoading() {
    return this.isRequestLoading('fetchData');
  }

  getDataError() {
    return this.getRequestError('fetchData');
  }

  isDataSuccess() {
    return this.isRequestSuccess('fetchData');
  }
}

Event-Driven State Management

class NotificationService extends Wing<NotificationState> {
  constructor() {
    super({ notifications: [], requests: {} });
    
    // Define events with conditions
    this.defineEvent('newNotification', (prev, curr) => 
      curr.notifications.length > prev.notifications.length
    );
    
    this.defineEvent('notificationRead', (prev, curr) => {
      const prevUnread = prev.notifications.filter(n => !n.read).length;
      const currUnread = curr.notifications.filter(n => !n.read).length;
      return currUnread < prevUnread;
    });
  }

  // Subscribe to events
  setupEventListeners() {
    this.subscribeToEvent('newNotification', (prev, curr) => {
      console.log('New notification received!');
      this.showNotificationBadge();
    });

    this.subscribeToEvent('notificationRead', (prev, curr) => {
      console.log('Notification marked as read');
      this.updateUnreadCount();
    });
  }

  addNotification(notification: Notification) {
    this.setState({
      notifications: [...this.getState().notifications, notification]
    });
  }
}

Deep Merge State Updates

class ComplexStateService extends Wing<ComplexState> {
  // Deep nested state updates
  setLoadingState() {
    this.setState({
      requests: {
        fetchNotebooks: {
          loading: true,
          success: false,
          error: null,
          finished: false
        }
      }
    });
  }

  updateUserProfile(userId: string, updates: Partial<UserProfile>) {
    this.setState({
      users: {
        [userId]: {
          ...this.getState().users[userId],
          ...updates
        }
      }
    });
  }
}

Local Storage Caching

class CachedService extends Wing<CachedState> {
  constructor() {
    super({
      users: [],
      settings: {},
      requests: {}
    }, {
      enabled: true,
      cacheKeys: ['users', 'settings'], // Only cache users and settings
      storageKey: 'user-service-cache',
      version: '1.0.0'
    });
  }

  // Cache will be automatically saved and loaded
  // Clear cache when needed
  clearCache() {
    this.clearCache();
  }

  // Check cache status
  isCacheEnabled() {
    return this.isCacheEnabled();
  }
}

React Integration

import React, { useEffect, useState } from 'react';
import { Wing } from '@mirawision/wings';

interface AppState {
  theme: 'light' | 'dark';
  user: User | null;
  requests?: RequestsState;
}

class AppService extends Wing<AppState> {
  constructor() {
    super({
      theme: 'light',
      user: null,
      requests: {}
    });
  }

  toggleTheme() {
    const currentTheme = this.getState().theme;
    this.setState({ theme: currentTheme === 'light' ? 'dark' : 'light' });
  }
}

// React Hook
function useWing<T>(wing: Wing<T>): T {
  const [state, setState] = useState<T>(wing.getState());

  useEffect(() => {
    const unsubscribe = wing.subscribe((message) => {
      setState(message.payload.currentState);
    });

    return unsubscribe;
  }, [wing]);

  return state;
}

// Usage in component
function App() {
  const appService = new AppService();
  const state = useWing(appService);

  return (
    <div>
      <button onClick={() => appService.toggleTheme()}>
        Current theme: {state.theme}
      </button>
    </div>
  );
}

API Reference

Wing

Advanced state management class that extends the Observer pattern.

Constructor

constructor(initialState: T, cacheConfig?: CacheConfig)

Methods

  • setState(newState: T | Partial<T>): void

    • Updates state with deep merge support
    • Triggers event notifications
    • Persists to cache if enabled
  • getState(): T

    • Returns current state
  • defineEvent(eventName: string, condition: EventCondition<T>): void

    • Defines a named event with condition
  • subscribeToEvent(eventName: string, callback: (prev: T, curr: T) => void): () => void

    • Subscribes to a named event
    • Returns unsubscribe function
  • executeRequest<TResult>(requestName: string, apiCall: () => Promise<TResult>, onSuccess?: (result: TResult) => void, onError?: (error: string) => void): Promise<TResult | null>

    • Executes API request with automatic state management
  • isRequestLoading(requestName: string): boolean

    • Checks if request is loading
  • isRequestSuccess(requestName: string): boolean

    • Checks if request succeeded
  • getRequestError(requestName: string): string | null

    • Gets request error message
  • clearCache(): void

    • Clears cached data

Type Definitions

interface BaseState {
  requests?: RequestsState;
}

interface RequestState {
  loading: boolean;
  success: boolean;
  error: string | null;
  finished: boolean;
}

interface CacheConfig {
  enabled: boolean;
  cacheKeys: (keyof any)[];
  storageKey?: string;
  version?: string;
}

Contributing

Contributions are always welcome! Feel free to open issues or submit pull requests.

License

This project is licensed under the MIT License.