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

@lumina-study/user-settings-redux

v1.0.0

Published

Redux store for Lumina Study user settings with unstorage persistence

Readme

@lumina-study/user-settings-redux

Redux store for Lumina Study user settings with unstorage persistence.

This package provides a ready-to-use Redux store that manages user settings (language, degree ID) with automatic persistence using unstorage. Changes to the store are automatically synced to your chosen storage backend (localStorage, IndexedDB, file system, etc.).

Features

  • Redux Toolkit-based store for user settings
  • Automatic persistence with unstorage
  • TypeScript support with full type safety
  • React hooks for easy integration
  • Debounced storage writes for performance
  • Support for any unstorage driver

Installation

pnpm add @lumina-study/user-settings-redux
# or
npm install @lumina-study/user-settings-redux

Quick Start

1. Create the Store

import { createStorage } from 'unstorage';
import localStorageDriver from 'unstorage/drivers/localstorage';
import { createUserSettingsStore } from '@lumina-study/user-settings-redux';

// Create an unstorage instance with your preferred driver
const storage = createStorage({
  driver: localStorageDriver({ base: 'lumina:' })
});

// Create the Redux store (async - loads persisted settings)
const store = await createUserSettingsStore({ storage });

2. Integrate with React

import { Provider } from 'react-redux';
import { createStorage } from 'unstorage';
import localStorageDriver from 'unstorage/drivers/localstorage';
import { createUserSettingsStore } from '@lumina-study/user-settings-redux';

// Create storage and store
const storage = createStorage({
  driver: localStorageDriver({ base: 'lumina:' })
});

const store = await createUserSettingsStore({ storage });

// Wrap your app with the Provider
function App() {
  return (
    <Provider store={store}>
      <YourApp />
    </Provider>
  );
}

3. Use in Components

import {
  useUserSettings,
  useLanguage,
  useDegreeId,
} from '@lumina-study/user-settings-redux';

function UserSettingsComponent() {
  // Get all settings
  const settings = useUserSettings();

  // Or use specific hooks
  const [language, setLanguage] = useLanguage();
  const [degreeId, setDegreeId] = useDegreeId();

  return (
    <div>
      <p>Current Language: {language}</p>
      <button onClick={() => setLanguage('he')}>עברית</button>
      <button onClick={() => setLanguage('en')}>English</button>

      <p>Degree ID: {degreeId || 'Not set'}</p>
      <button onClick={() => setDegreeId('degree-123')}>
        Set Degree
      </button>
    </div>
  );
}

Storage Drivers

You can use any unstorage driver. Here are some examples:

Browser localStorage

import { createStorage } from 'unstorage';
import localStorageDriver from 'unstorage/drivers/localstorage';

const storage = createStorage({
  driver: localStorageDriver({ base: 'lumina:' })
});

Browser IndexedDB

import { createStorage } from 'unstorage';
import indexedDbDriver from 'unstorage/drivers/indexedb';

const storage = createStorage({
  driver: indexedDbDriver({ base: 'lumina:' })
});

Node.js File System

import { createStorage } from 'unstorage';
import fsDriver from 'unstorage/drivers/fs';

const storage = createStorage({
  driver: fsDriver({ base: './.data' })
});

Memory (for testing)

import { createStorage } from 'unstorage';

const storage = createStorage(); // Uses memory driver by default

API Reference

Store Creation

createUserSettingsStore(options)

Creates and initializes the Redux store with persistence.

Parameters:

  • options.storage (required): The unstorage instance to use for persistence
  • options.devTools (optional): Enable Redux DevTools (default: true)

Returns: Promise - The configured Redux store

Actions

setUserSettings(settings: UserSettings)

Set the complete user settings state.

import { setUserSettings } from '@lumina-study/user-settings-redux';

dispatch(setUserSettings({ language: 'he', degreeId: 'degree-123' }));

setLanguage(language: 'he' | 'en')

Update the user interface language.

import { setLanguage } from '@lumina-study/user-settings-redux';

dispatch(setLanguage('he'));

setDegreeId(degreeId: string | null)

Update the user's degree identifier.

import { setDegreeId } from '@lumina-study/user-settings-redux';

dispatch(setDegreeId('degree-123'));

resetUserSettings()

Reset settings to default values.

import { resetUserSettings } from '@lumina-study/user-settings-redux';

dispatch(resetUserSettings());

Hooks

useUserSettings()

Access the complete user settings state.

const settings = useUserSettings();
// { language: 'en', degreeId: null }

useLanguage()

Access and update the language setting.

const [language, setLanguage] = useLanguage();
setLanguage('he');

useDegreeId()

Access and update the degree ID setting.

const [degreeId, setDegreeId] = useDegreeId();
setDegreeId('degree-123');

useAppDispatch()

Typed dispatch hook.

const dispatch = useAppDispatch();
dispatch(setLanguage('en'));

useAppSelector(selector)

Typed selector hook.

const language = useAppSelector((state) => state.userSettings.language);

Utilities

loadPersistedSettings(storage)

Manually load settings from storage.

import { loadPersistedSettings } from '@lumina-study/user-settings-redux';

const settings = await loadPersistedSettings(storage);

clearPersistedSettings(storage)

Clear persisted settings from storage.

import { clearPersistedSettings } from '@lumina-study/user-settings-redux';

await clearPersistedSettings(storage);

TypeScript

The package is fully typed and exports all necessary types:

import type {
  UserSettings,
  RootState,
  AppDispatch,
  UserSettingsStore,
  CreateStoreOptions,
} from '@lumina-study/user-settings-redux';

How Persistence Works

  1. Initialization: When you create the store, it automatically loads any previously saved settings from the storage driver
  2. Auto-save: Any action that modifies the user settings state triggers an automatic save to storage (debounced by 300ms)
  3. Persistence Key: Settings are stored under the key 'user-settings' in your storage backend

Advanced Usage

Direct Store Usage (without React)

import { createUserSettingsStore, setLanguage } from '@lumina-study/user-settings-redux';

const store = await createUserSettingsStore({ storage });

// Subscribe to changes
store.subscribe(() => {
  console.log('Settings updated:', store.getState().userSettings);
});

// Dispatch actions
store.dispatch(setLanguage('he'));

Custom Middleware

import { configureStore } from '@reduxjs/toolkit';
import { userSettingsReducer, createPersistenceMiddleware } from '@lumina-study/user-settings-redux';

const store = configureStore({
  reducer: {
    userSettings: userSettingsReducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware()
      .concat(createPersistenceMiddleware(storage))
      .concat(yourCustomMiddleware),
});

Development

Building

pnpm install
pnpm run build

This will compile TypeScript files to the dist directory.

Publishing

Automated Publishing (Recommended)

The package is automatically published to npm when pushing to the main branch via GitHub Actions.

Setup:

  1. Create an npm access token:

    • Go to https://www.npmjs.com/settings/YOUR_USERNAME/tokens
    • Click "Generate New Token" → "Automation"
    • Copy the token
  2. Add the token to GitHub:

    • Go to your repository settings → Secrets and variables → Actions
    • Click "New repository secret"
    • Name: NPM_TOKEN
    • Value: Paste your npm token
  3. Update the version in package.json

  4. Push to main:

    git add package.json CHANGELOG.md
    git commit -m "chore: bump version to x.x.x"
    git push origin main

The CI/CD workflow will:

  • Run tests
  • Build the package
  • Publish to npm (if version changed)
  • Create a git tag
  • Create a GitHub release

Manual Publishing

You can also publish manually using release-it:

# Dry run
pnpm run release:dry

# Create a release
pnpm run release

License

MIT

Related Packages