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

@miurajs/miura-data-flow

v0.1.4

Published

Modern, reactive state management for miura applications. Combines the best of Redux, Zustand, and modern patterns with zero boilerplate and maximum performance. **Now with optional dependencies for optimal bundle size!**

Downloads

710

Readme

miura Data Flow

Modern, reactive state management for miura applications. Combines the best of Redux, Zustand, and modern patterns with zero boilerplate and maximum performance. Now with optional dependencies for optimal bundle size!

Features

  • 🚀 Reactive State Management - Automatic updates when state changes
  • 🔧 Middleware System - Extensible with logging, persistence, API integration
  • 🌍 Global State - Application-wide state management
  • 💾 Built-in Caching - Intelligent caching with TTL
  • 🔌 API Integration - Automatic API calls with state updates
  • 🛠️ DevTools Support - Redux DevTools integration
  • 📝 TypeScript First - Full type safety and IntelliSense
  • ⚡ Performance Optimized - Efficient subscriptions and updates
  • 📦 Optional Dependencies - Only install what you need for optimal bundle size

Installation

# Core package (includes built-in providers)
npm install @miurajs/miura-data-flow

# Optional providers (install as needed)
npm install graphql-request          # For GraphQL provider
npm install @aws-sdk/client-s3       # For AWS S3 provider  
npm install firebase                 # For Firebase provider
npm install @supabase/supabase-js    # For Supabase provider
npm install grpc-web                 # For gRPC-Web provider

Quick Start

import { Store, globalState, createLoggerMiddleware } from '@miurajs/miura-data-flow';

// Create a store
const store = new Store({ count: 0, user: null });

// Add middleware
store.use(createLoggerMiddleware());

// Define actions
store.defineActions({
  increment: (state) => ({ count: state.count + 1 }),
  setUser: (state, user) => ({ user })
});

// Subscribe to changes
const unsubscribe = store.subscribe((state, prevState) => {
  console.log('State changed:', state);
});

// Dispatch actions
await store.dispatch('increment');
await store.dispatch('setUser', { id: '1', name: 'John' });

Core Concepts

Store

The main state container that manages your application state.

import { Store } from '@miurajs/miura-data-flow';

interface AppState {
  count: number;
  user: User | null;
  todos: Todo[];
}

const store = new Store<AppState>({
  count: 0,
  user: null,
  todos: []
});

Actions

Define how your state can be updated.

store.defineActions({
  // Simple state update
  increment: (state) => ({ count: state.count + 1 }),
  
  // With parameters
  setUser: (state, user: User) => ({ user }),
  
  // Async actions
  async fetchUser: async (state, userId: string) => {
    const user = await fetch(`/api/users/${userId}`).then(r => r.json());
    return { user };
  },
  
  // Complex updates
  addTodo: (state, todo: Todo) => ({
    todos: [...state.todos, todo]
  })
});

Subscriptions

React to state changes automatically.

// Subscribe to all changes
const unsubscribe = store.subscribe((state, prevState) => {
  console.log('State changed:', state);
});

// Subscribe to specific property
const unsubscribeCount = store.subscribeTo('count', (count, prevCount) => {
  console.log(`Count changed from ${prevCount} to ${count}`);
});

// Subscribe with selector
const unsubscribeUser = store.subscribe(
  (state, prevState) => {
    console.log('User changed:', state.user);
  },
  (state) => state.user // Only trigger when user changes
);

Middleware System

Built-in Middleware

Logger Middleware

import { createLoggerMiddleware } from '@miurajs/miura-data-flow';

store.use(createLoggerMiddleware());
// Logs all actions and state changes to console

Persistence Middleware

import { createPersistenceMiddleware } from '@miurajs/miura-data-flow';

store.use(createPersistenceMiddleware(['user', 'settings']));
// Automatically saves/loads specified properties to localStorage

API Middleware

import { createApiMiddleware } from '@miurajs/miura-data-flow';

store.use(createApiMiddleware({
  baseURL: 'https://api.example.com',
  headers: {
    'Authorization': 'Bearer token'
  },
  timeout: 5000
}));

// Now you can dispatch API actions
store.defineActions({
  api_fetchUsers: () => {}, // Will automatically fetch /fetchUsers
  api_createUser: () => {}  // Will automatically POST to /createUser
});

await store.dispatch('api_fetchUsers');
await store.dispatch('api_createUser', { method: 'POST', data: userData });

Cache Middleware

import { createCacheMiddleware } from '@miurajs/miura-data-flow';

store.use(createCacheMiddleware(5 * 60 * 1000)); // 5 minutes TTL
// Caches API responses for 5 minutes

DevTools Middleware

import { createDevToolsMiddleware } from '@miurajs/miura-data-flow';

store.use(createDevToolsMiddleware('MyApp'));
// Enables Redux DevTools integration

Redux DevTools Integration

Redux DevTools is a powerful browser extension that provides real-time debugging for state management. Even though miura Data Flow isn't Redux, we integrate with it because it's the industry standard for state debugging.

What Redux DevTools Provides:

  • 🔍 State Inspector - Real-time visualization of your entire state tree
  • 📜 Action Monitor - Complete log of all dispatched actions with timing
  • ⏰ Time-travel Debugging - Jump back to any previous state
  • 📊 Diff View - Before/after comparison with highlighted changes
  • ⚡ Performance Metrics - Action timing and state size monitoring

Setup Instructions:

  1. Install the Browser Extension:

  2. Enable in Your Code:

    import { createDevToolsMiddleware } from '@miurajs/miura-data-flow';
       
    store.use(createDevToolsMiddleware('MyApp'));
  3. Open DevTools:

    • Press F12 → Click the Redux tab
    • Or right-click → InspectRedux tab

What You'll See:

When you dispatch actions, they appear in DevTools like this:

Action: increment
Payload: []
State Before: { count: 0, user: null }
State After:  { count: 1, user: null }

Action: setUser  
Payload: [{ id: '1', name: 'John' }]
State Before: { count: 1, user: null }
State After:  { count: 1, user: { id: '1', name: 'John' } }

Complete Example:

import { Store, createDevToolsMiddleware } from '@miurajs/miura-data-flow';

// Create store
const store = new Store({
  user: null,
  todos: [],
  theme: 'light'
});

// Enable DevTools integration
store.use(createDevToolsMiddleware('TodoApp'));

// Define actions
store.defineActions({
  login: (state, user) => ({ user }),
  addTodo: (state, todo) => ({ todos: [...state.todos, todo] }),
  toggleTheme: (state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' })
});

// These actions will now be visible in Redux DevTools:
await store.dispatch('login', { id: '1', name: 'John' });
await store.dispatch('addTodo', { id: '1', text: 'Buy milk' });
await store.dispatch('toggleTheme');

DevTools Features:

State Inspector:

  • View your entire state tree in real-time
  • Expand/collapse nested objects
  • Search through state properties

Action Monitor:

  • See all dispatched actions with timestamps
  • Inspect action payloads and arguments
  • Monitor action execution time

Time-travel Debugging:

  • Jump to any previous state
  • Replay actions step by step
  • Compare states at different points in time

Performance Monitoring:

  • Track action execution time
  • Monitor state size changes
  • Identify performance bottlenecks

Why Use Redux DevTools?

Even though we're not using Redux, Redux DevTools has become the de facto standard for state debugging because:

  • Universal Adoption - Most developers are familiar with it
  • Rich Features - Time-travel, diff view, performance metrics
  • Browser Integration - No additional setup required
  • Community Support - Well-maintained and documented

It's like having a super-powered console.log that shows you exactly what's happening with your state in real-time! 🚀

Debug Information

// Get debug info about your store
console.log(store.getDebugInfo());
console.log(globalState.getDebugInfo());

API Reference

Store

  • new Store<T>(initialState: T) - Create a new store
  • store.getState(): T - Get current state
  • store.get<K>(key: K): T[K] - Get specific property
  • store.setState(updater) - Update state
  • store.defineActions(actions) - Define actions
  • store.dispatch(action, ...args) - Execute action
  • store.subscribe(callback, selector?) - Subscribe to changes
  • store.subscribeTo(key, callback) - Subscribe to specific property
  • store.use(middleware) - Add middleware

Global State

  • globalState.get(key) - Get global property
  • globalState.set(key, value) - Set global property
  • globalState.subscribe(componentId, properties, callback) - Subscribe
  • globalState.subscribeTo(componentId, key, callback) - Subscribe to property
  • globalState.dispatch(action, ...args) - Dispatch global action

Middleware

  • createLoggerMiddleware() - Console logging
  • createPersistenceMiddleware(keys, storageKey) - localStorage persistence
  • createApiMiddleware(config) - API integration
  • createCacheMiddleware(ttl) - Response caching
  • createDevToolsMiddleware(name) - Redux DevTools

Best Practices

  1. Use TypeScript - Define interfaces for your state
  2. Subscribe Selectively - Only subscribe to what you need
  3. Unsubscribe Always - Prevent memory leaks
  4. Use Actions - Don't mutate state directly
  5. Middleware for Side Effects - Keep actions pure
  6. Global State Sparingly - Use for truly global data
  7. Batch Updates - Group related state changes

Examples

See the examples directory for complete working examples.


miura Data Flow - Modern state management that just works! 🚀

Custom Middleware

import { StoreMiddleware } from '@miurajs/miura-data-flow';

const analyticsMiddleware: StoreMiddleware = {
  name: 'analytics',
  before: (action, args, state) => {
    // Track action before execution
    analytics.track('action_started', { action, args });
  },
  after: (action, args, state, result) => {
    // Track action completion
    analytics.track('action_completed', { action, result });
  },
  error: (action, args, error) => {
    // Track errors
    analytics.track('action_error', { action, error });
  }
};

store.use(analyticsMiddleware);

Global State Management

Using Global State

import { globalState } from '@miurajs/miura-data-flow';

// Set global properties
globalState.set('theme', 'dark');
globalState.set('user', { id: '1', name: 'John' });

// Get global properties
const theme = globalState.get('theme');
const user = globalState.get('user');

// Subscribe to global state changes
const unsubscribe = globalState.subscribeTo('my-component', 'theme', (theme) => {
  console.log('Theme changed:', theme);
});

Global State in Components

import { MiuraElement, html } from '@miurajs/miura-element';
import { globalState } from '@miurajs/miura-data-flow';

class ThemeToggle extends MiuraElement {
  static properties = {
    theme: { type: String, default: 'light' }
  };

  connectedCallback() {
    super.connectedCallback();
    
    // Subscribe to global theme changes
    this.unsubscribeTheme = globalState.subscribeTo(
      this.tagName,
      'theme',
      (theme) => {
        this.theme = theme;
        this.requestUpdate();
      }
    );
  }

  disconnectedCallback() {
    super.disconnectedCallback();
    this.unsubscribeTheme?.();
  }

  toggleTheme() {
    const newTheme = this.theme === 'light' ? 'dark' : 'light';
    globalState.set('theme', newTheme);
  }

  render() {
    return html`
      <button @click=${this.toggleTheme}>
        Current theme: ${this.theme}
      </button>
    `;
  }
}

Data Providers

miura Data Flow includes a flexible provider system for connecting to various data sources.

Built-in Providers (Always Available)

These providers are included by default and have no external dependencies:

import { 
  RestProviderFactory,
  LocalStorageProviderFactory, 
  IndexedDBProviderFactory,
  WebSocketProviderFactory 
} from '@miurajs/miura-data-flow';

// Register and use built-in providers
import { registerProvider, createProvider } from '@miurajs/miura-data-flow';

// Register REST API provider
registerProvider('api', new RestProviderFactory());

// Create provider instance
const apiProvider = createProvider('api', { 
  baseUrl: 'https://api.example.com' 
});

// Use the provider
const users = await apiProvider.get('users');

Optional Providers (Require Additional Dependencies)

These providers are available as separate imports to keep the core package lightweight:

GraphQL Provider

# Install the optional dependency
npm install graphql-request
// Import the GraphQL provider separately
import { GraphQLProviderFactory } from '@miurajs/miura-data-flow/providers/graphql';

// Register and use
registerProvider('graphql', new GraphQLProviderFactory());
const graphqlProvider = createProvider('graphql', { 
  endpoint: 'https://api.example.com/graphql' 
});

const result = await graphqlProvider.query({
  query: 'query { users { id name } }'
});

AWS S3 Provider

# Install the optional dependency
npm install @aws-sdk/client-s3
// Import the S3 provider separately
import { S3ProviderFactory } from '@miurajs/miura-data-flow/providers/s3';

// Register and use
registerProvider('s3', new S3ProviderFactory());
const s3Provider = createProvider('s3', { 
  region: 'us-east-1',
  bucket: 'my-bucket' 
});

const data = await s3Provider.get('file.json');
await s3Provider.put('file.json', jsonData);

Firebase Provider

# Install the optional dependency
npm install firebase
// Import the Firebase provider separately
import { FirebaseProviderFactory } from '@miurajs/miura-data-flow/providers/firebase';

// Register and use
registerProvider('firebase', new FirebaseProviderFactory());
const firebaseProvider = createProvider('firebase', { 
  apiKey: 'your-api-key',
  authDomain: 'your-project.firebaseapp.com',
  projectId: 'your-project-id'
});

Supabase Provider

# Install the optional dependency
npm install @supabase/supabase-js
// Import the Supabase provider separately
import { SupabaseProviderFactory } from '@miurajs/miura-data-flow/providers/supabase';

// Register and use
registerProvider('supabase', new SupabaseProviderFactory());
const supabaseProvider = createProvider('supabase', { 
  url: 'https://your-project.supabase.co',
  anonKey: 'your-anon-key'
});

gRPC-Web Provider

# Install the optional dependency
npm install grpc-web
// Import the gRPC-Web provider separately
import { GrpcWebProviderFactory } from '@miurajs/miura-data-flow/providers/grpc-web';

// Register and use
registerProvider('grpc', new GrpcWebProviderFactory());
const grpcProvider = createProvider('grpc', { 
  host: 'localhost:8080',
  protoPath: './service.proto'
});

Why This Structure?

  1. Bundle Size Optimization - Only include providers you actually use
  2. Dependency Management - Avoid forcing installation of large libraries
  3. Tree Shaking - Better optimization for production builds
  4. Flexibility - Use only what you need, when you need it

Provider Usage in Middleware

import { createApiMiddleware } from '@miurajs/miura-data-flow';

// Use any registered provider in middleware
store.use(createApiMiddleware({
  provider: 's3', // Use the S3 provider we registered
  bucket: 'my-app-data'
}));

Integration with miura Framework

Framework Setup

import { Store, createApiMiddleware, createCacheMiddleware } from '@miurajs/miura-data-flow';

class miuraFramework {
  private store: Store;

  constructor() {
    // Initialize store with app state
    this.store = new Store({
      user: null,
      settings: {},
      notifications: []
    });

    // Add middleware for API and caching
    this.store.use(createApiMiddleware({
      baseURL: process.env.API_URL,
      headers: {
        'Content-Type': 'application/json'
      }
    }));
    
    this.store.use(createCacheMiddleware());
    
    // Define global actions
    this.store.defineActions({
      setUser: (state, user) => ({ user }),
      addNotification: (state, notification) => ({
        notifications: [...state.notifications, notification]
      })
    });
  }

  // Expose store to components
  getStore() {
    return this.store;
  }
}

Component Integration

class MyComponent extends MiuraElement {
  // Define global properties this component uses
  global() {
    return {
      user: null,
      theme: 'light'
    };
  }

  connected() {
    // Subscribe to global state
    this.unsubscribeUser = globalState.subscribeTo(
      this.tagName,
      'user',
      (user) => this.handleUserChange(user)
    );
  }

  disconnected() {
    this.unsubscribeUser?.();
  }

  handleUserChange(user) {
    // React to global user changes
    this.requestUpdate();
  }
}

Performance Optimization

Selective Subscriptions

// Only subscribe to what you need
const unsubscribe = store.subscribe(
  (state, prevState) => {
    // Only trigger when user.todos changes
  },
  (state) => state.user?.todos
);

Batch Updates

// Multiple updates in one action
store.defineActions({
  updateUserProfile: (state, updates) => ({
    user: { ...state.user, ...updates },
    lastUpdated: Date.now()
  })
});

Memory Management

// Always unsubscribe to prevent memory leaks
class MyComponent {
  connectedCallback() {
    this.unsubscribe = store.subscribe(this.handleStateChange);
  }

  disconnectedCallback() {
    this.unsubscribe(); // Important!
  }
}

Debugging

Enable Debug Logging

import { enableDebug } from '@miurajs/miura-render';

enableDebug({
  element: true, // Shows data flow logs
});

DevTools Integration

// Install Redux DevTools browser extension
store.use(createDevToolsMiddleware('MyApp'));

Debug Information