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 🙏

© 2025 – Pkg Stats / Ryan Hefner

i45

v3.0.0

Published

A powerful, type-safe wrapper for browser storage (localStorage, sessionStorage) with built-in logging, validation, and error handling. Simplifies storing and retrieving collections in web applications.

Readme

i45

Type-safe browser storage wrapper for localStorage and sessionStorage

npm version TypeScript License: MIT

NodeJS package | GitHub Repository

A powerful, type-safe wrapper for browser storage (localStorage and sessionStorage) with built-in logging, validation, and error handling. Built with TypeScript for maximum type safety and developer experience.

Version 3.0.0-alpha.1 - Complete TypeScript rewrite with architectural refactoring (December 2025)

Features

  • Full TypeScript support with generic types: DataContext<T>
  • 🔒 Type-safe operations - catch errors at compile time
  • 🏗️ Modern architecture - modular design with service orchestration
  • 📦 Simple API - config object pattern or legacy constructor
  • 🎯 Zero code duplication - 300+ lines eliminated through refactoring
  • Comprehensive validation - centralized with ValidationUtils
  • 🚨 6 custom error classes - specific, actionable error handling
  • 🪵 Built-in logging via i45-jslogger
  • 🧪 Well tested - 172 tests with 92% coverage
  • 🎯 Zero dependencies (except i45-jslogger and i45-sample-data)
  • 📝 Sample data included via i45-sample-data
  • 🌳 Tree-shakeable ESM build
  • 📖 Comprehensive type definitions (.d.ts)

📚 Documentation: Migration Guide | API Reference | TypeScript Guide | Examples

Installation

npm install i45

Quick Start

TypeScript (Recommended)

import { DataContext, StorageLocations, Logger } from "i45";

// Define your data type
interface User {
  id: number;
  name: string;
  email: string;
}

// Create a type-safe context with config object (modern approach)
const context = new DataContext<User>({
  storageKey: "Users",
  storageLocation: StorageLocations.LocalStorage,
  loggingEnabled: true,
  logger: new Logger(),
});

// Or use legacy constructor (still supported)
const legacyContext = new DataContext<User>(
  "Users",
  StorageLocations.LocalStorage
);

// Store data (fully typed!)
await context.store([
  { id: 1, name: "Alice", email: "[email protected]" },
  { id: 2, name: "Bob", email: "[email protected]" },
]);

// Retrieve data (returns User[])
const users = await context.retrieve();
console.log(users);

📖 More examples: EXAMPLES.md | TypeScript Guide

JavaScript

import { DataContext, SampleData } from "i45";

// Create an instance of the datacontext
// The default storage location is localStorage
const context = new DataContext();

// Store data using sample data
await context.store(SampleData.Lists.Astronomy);

// Retrieve data
const data = await context.retrieve();
console.log("Astronomy terms:", data);

Architecture

i45 v3.0.0 features a completely refactored, modular architecture (December 2025).

📖 See also: Migration Guide - Architecture | API Reference

/src
  /core                      # Core application logic
    DataContext.ts           # Main storage context
    StorageManager.ts        # Service orchestration
  /services
    /base                    # Abstract base classes
      IStorageService.ts     # Service interface
      BaseStorageService.ts  # Shared service logic
    LocalStorageService.ts
    SessionStorageService.ts
  /errors                    # Custom error classes
    StorageKeyError.ts
    StorageLocationError.ts
    DataRetrievalError.ts
    StorageQuotaError.ts
    PersistenceServiceNotEnabled.ts
    DataServiceUnavailable.ts
  /models                    # Data models
    DataContextConfig.ts
    storageItem.ts
    storageLocations.ts
  /utils                     # Shared utilities
    ValidationUtils.ts       # Centralized validation
    ErrorHandler.ts          # Error management

Architecture Benefits

  • Single Responsibility: Each module has one clear purpose
  • Zero Duplication: 300+ lines of duplicate code eliminated
  • Easy Testing: Isolated modules with 92% test coverage
  • Type Safe: Strong typing throughout
  • Extensible: Add new storage services by implementing interface

Usage

TypeScript Usage

i45 v3.0 is built with TypeScript and provides full type safety.

📖 See TYPESCRIPT.md for comprehensive TypeScript usage guide

import { DataContext, StorageLocations, type StorageItem } from "i45";

// Generic type for your data
interface Product {
  id: string;
  name: string;
  price: number;
}

// Type-safe context
const context = new DataContext<Product>(
  "products",
  StorageLocations.SessionStorage
);

// Store - TypeScript ensures correct types
await context.store([
  { id: "1", name: "Widget", price: 9.99 },
  { id: "2", name: "Gadget", price: 19.99 },
]);

// Retrieve - returns Product[]
const products = await context.retrieve();
products.forEach((p) => console.log(`${p.name}: $${p.price}`));

Default Storage Settings

import { DataContext, SampleData } from "i45";

// Create an instance - uses localStorage by default with key "i45"
const context = new DataContext();

// Store data
await context.store(SampleData.Lists.Astronomy);

// Retrieve data
const data = await context.retrieve();
console.log(data);

Custom Storage Settings

Modern Config Object (Recommended)

import { DataContext, StorageLocations, Logger } from "i45";

// Create context with configuration object
const context = new DataContext<BookType>({
  storageKey: "Books",
  storageLocation: StorageLocations.SessionStorage,
  loggingEnabled: true,
  logger: new Logger(),
});

// Store books collection
await context.store(SampleData.JsonData.Books);

// Retrieve data
const books = await context.retrieve();
console.log(books);

Legacy Constructor (Still Supported)

import { DataContext, StorageLocations, SampleData } from "i45";

// Create context with positional parameters
const context = new DataContext("Books", StorageLocations.SessionStorage);

// Store books collection
await context.store(SampleData.JsonData.Books);

// Retrieve data
const books = await context.retrieve();
console.log(books);

Retrieving Data

import { DataContext, SampleData } from "i45";

// Create context
const context = new DataContext();

// Store data
await context.store(SampleData.JsonData.States);

// Retrieve and use
const states = await context.retrieve();
console.log("State data:", states);

Explicit Method Signatures

v3.0.0 provides clear, explicit methods (no confusing overloads):

import { DataContext, StorageLocations } from "i45";

const context = new DataContext<MyType>();

// Store with different scopes
await context.store(items); // Default key/location
await context.storeAs("customKey", items); // Custom key
await context.storeAt("key", StorageLocations.SessionStorage, items); // Full control

// Retrieve with different scopes
const data1 = await context.retrieve(); // Default
const data2 = await context.retrieveFrom("customKey"); // Custom key
const data3 = await context.retrieveAt("key", StorageLocations.SessionStorage); // Full control

// Remove with different scopes
await context.remove(); // Default
await context.removeFrom("customKey"); // Custom key
await context.removeAt("key", StorageLocations.SessionStorage); // Full control

Retrieving Data from Custom Data Stores

import { DataContext, StorageLocations, SampleData } from "i45";

// Create context with custom settings
const context = new DataContext("Questions", StorageLocations.SessionStorage);

// Store questions
await context.store(SampleData.JsonData.TriviaQuestions);

// Retrieve by key
const questions = await context.retrieve("Questions");
console.log(questions);

// Retrieve with specific location
const data = await context.retrieve("MyItems", StorageLocations.LocalStorage);

Removing Items and Clearing the Data Store

// Delete a specific data store by key
await context.remove("Questions");

// Clear all data from current storage location
await context.clear();

To clear all entries in all storage locations, call the clear() method.

Warning: Calling the clear() method will clear all entries in all storage locations.

import { DataContext } from "i45";

var dataContext = new DataContext();

// create an array of countries using sample data.
var countries = SampleData.KeyValueLists.Countries;

// save the collection
dataContext.store("Countries", countries);

// removes the item from storage.
dataContext.remove("Countries");

// removes all items from all storage locations.
// *** WARNING *** calling clear() will clears all entries.
datacontext.clear();

Storage Locations

StorageLocations is an enum of available storage options:

import { StorageLocations } from "i45";

// Available options
StorageLocations.LocalStorage; // Uses window.localStorage (default)
StorageLocations.SessionStorage; // Uses window.sessionStorage

Using StorageLocations

import { DataContext, StorageLocations } from "i45";

// Specify storage location in constructor
const context = new DataContext("MyItems", StorageLocations.SessionStorage);

// Or use properties
context.storageLocation = StorageLocations.LocalStorage;

Using Sample Data

The i45-sample-data package provides sample datasets for development and testing:

import { SampleData } from "i45";

// Access various sample datasets
const books = SampleData.JsonData.Books;
const states = SampleData.JsonData.States;
const astronomy = SampleData.Lists.Astronomy;
const countries = SampleData.KeyValueLists.Countries;

console.log(books);

Logging

i45 integrates i45-jslogger for comprehensive logging support.

📖 See also: EXAMPLES.md - Custom Logger

Built-In Logging

import { DataContext } from "i45";

const context = new DataContext();

// Enable logging
context.loggingEnabled = true;

// Operations will now be logged
await context.store([{ id: 1, name: "Test" }]);

When enabled, log messages are written to the console and stored in localStorage.

Using a Custom Logger

Add custom logging clients to receive DataContext events:

import { DataContext, Logger } from "i45";

// Create or use your existing logger
const customLogger = new Logger({
  logToConsole: true,
  logToStorage: false,
});

// Add to context
const context = new DataContext();
context.addClient(customLogger);

// Multiple loggers supported
context.addClient(fileSystemLogger);
context.addClient(apiLogger);

API Reference

📖 Complete API documentation: API.md

DataContext

Main class for managing browser storage operations.

class DataContext<T = any> {
  // Constructor - Config object (recommended)
  constructor(config?: DataContextConfig);

  // Constructor - Legacy (still supported)
  constructor(storageKey?: string, storageLocation?: StorageLocation);

  // Properties
  storageKey: string;
  storageLocation: StorageLocation;
  loggingEnabled: boolean;
  logger: Logger | null;

  // Store methods
  async store(items: T[]): Promise<DataContext<T>>;
  async storeAs(storageKey: string, items: T[]): Promise<DataContext<T>>;
  async storeAt(
    storageKey: string,
    storageLocation: StorageLocation,
    items: T[]
  ): Promise<DataContext<T>>;

  // Retrieve methods
  async retrieve(): Promise<T[]>;
  async retrieveFrom(storageKey: string): Promise<T[]>;
  async retrieveAt(
    storageKey: string,
    storageLocation: StorageLocation
  ): Promise<T[]>;

  // Remove methods
  async remove(): Promise<DataContext<T>>;
  async removeFrom(storageKey: string): Promise<DataContext<T>>;
  async removeAt(
    storageKey: string,
    storageLocation: StorageLocation
  ): Promise<DataContext<T>>;

  // Other methods
  async clear(): Promise<DataContext<T>>;
  addClient(logger: Logger): DataContext<T>;
  getCurrentSettings(): {
    storageKey: string;
    storageLocation: StorageLocation;
  };
  getData(): any[];
  printLog(): any[];
}

DataContextConfig

Configuration object for DataContext (v3.0.0+):

interface DataContextConfig {
  storageKey?: string; // Default: "Items"
  storageLocation?: StorageLocation; // Default: localStorage
  logger?: Logger | null; // Optional logger instance
  loggingEnabled?: boolean; // Default: false
}

Types

// Storage location type
export enum StorageLocations {
  SessionStorage = "sessionStorage",
  LocalStorage = "localStorage",
}
export type StorageLocation = `${StorageLocations}`;

// Storage item interface
export interface StorageItem {
  name: string;
  value: string;
}

// Database settings
export interface DatabaseSettings {
  storageKey: string;
  storageLocation: StorageLocation;
  loggingEnabled: boolean;
}

Error Types

v3.0.0 provides 6 custom error classes for specific error handling.

📖 Full error documentation: API.md - Error Classes | Examples

import {
  PersistenceServiceNotEnabled,
  DataServiceUnavailable,
  StorageKeyError,
  StorageLocationError,
  DataRetrievalError,
  StorageQuotaError, // NEW in December 2025
} from "i45";

try {
  await context.store(data);
} catch (error) {
  if (error instanceof StorageKeyError) {
    console.error("Invalid storage key:", error.key);
  } else if (error instanceof StorageQuotaError) {
    console.error("Storage full:", error.key, error.storageType);
  } else if (error instanceof DataRetrievalError) {
    console.error("Failed to retrieve:", error.key, "Cause:", error.cause);
  } else if (error instanceof StorageLocationError) {
    console.error(
      "Invalid location:",
      error.location,
      "Valid:",
      error.validLocations
    );
  }
}

Migration from v2.x

v3.0.0 includes breaking changes and major architectural improvements. See MIGRATION.md for the complete migration guide.

Key Changes

  1. New Architecture: Modular design with service orchestration (December 2025)
  2. Config Object Pattern: New recommended way to initialize DataContext
  3. TypeScript First: Full TypeScript rewrite with generic types
  4. Explicit Methods: store(), storeAs(), storeAt() instead of overloaded signatures
  5. 6 Custom Errors: Specific error classes for better error handling
  6. Centralized Validation: ValidationUtils for consistent validation
  7. Zero Duplication: 300+ lines of duplicate code eliminated
  8. Property Names: StorageItem.Namename, StorageItem.Valuevalue (camelCase)
  9. Async Operations: All storage operations return Promises

Quick Migration Example

// v2.x (Old)
const context = new DataContext();
context.setStorageKey("MyData");
context.store(data); // May not be async

// v3.x (New - Config Object)
const context = new DataContext({
  storageKey: "MyData",
  loggingEnabled: true,
});
await context.store(data); // Always async

// v3.x (New - Legacy Constructor)
const context = new DataContext("MyData");
await context.store(data); // Always async

For detailed migration steps, error handling examples, and troubleshooting, see MIGRATION.md.

Browser Support

  • Chrome/Edge: Latest 2 versions
  • Firefox: Latest 2 versions
  • Safari: Latest 2 versions
  • Modern browsers with ES2015+ support

Requirements

  • Node.js 16+ (for development)
  • Modern browser with localStorage/sessionStorage support

Framework Integration

Testing

i45 v3.0.0 includes comprehensive testing:

  • 172 tests with Jest
  • 92.08% statement coverage
  • Unit tests for all components
  • Type safety tests
  • Error handling tests
# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Watch mode
npm run test:watch

📖 Testing examples: EXAMPLES.md - Testing Examples

Documentation

Core Documentation

  • README.md - This file (getting started and quick reference)
  • API.md - Complete API reference with all methods, properties, and error classes
  • TYPESCRIPT.md - TypeScript usage guide with patterns and best practices
  • EXAMPLES.md - 20+ comprehensive examples including React/Vue integration
  • MIGRATION.md - Complete v2.x → v3.x migration guide

Additional Resources

License

MIT © CIS Guru

Links

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Changelog

See CHANGES.md for version history and release notes.