Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

search-optimizer

N1ghtHunter234MIT2.0.2TypeScript support: included

An optimized, framework-agnostic solution for handling search-as-you-type functionality

search, debounce, search-optimizer, autocomplete, search-input, race-condition, input-optimization

readme

🔍 SearchOptimizer

npm version build status coverage license

An optimized, framework-agnostic solution for handling search-as-you-type functionality.

📖 Table of Contents

  1. Overview
  2. Installation
  3. Quick Start
  4. API Reference
  5. Adapters & Hooks
  6. Examples
  7. Contributing
  8. Changelog
  9. License

📋 Overview

SearchOptimizer is a lightweight, framework-agnostic library that helps optimize search inputs with real-time results (search-as-you-type). It provides a clean, efficient way to:

  • Debounce user input to reduce unnecessary API calls
  • Prevent race conditions by automatically canceling outdated requests
  • Apply minimum character limits before triggering searches
  • Process input uniformly (trim, lowercase, etc.)
  • Works with any request library or framework

⚙️ Installation

npm install search-optimizer
# or
yarn add search-optimizer

🚀 Quick Start

Basic Usage

import { createSearchOptimizer } from 'search-optimizer';
import { createFetchExecutor } from 'search-optimizer/adapters/fetch';

// Create a search executor using fetch
const searchExecutor = createFetchExecutor({
  baseUrl: 'https://api.example.com/search',
  queryParam: 'q',
});

// Create the search optimizer
const searchOptimizer = createSearchOptimizer(searchExecutor, {
  debounceDelay: 500,
  minChars: 3,
});

// Get the search input element
const searchInput = document.getElementById('search-input');

// Connect the input to the search optimizer
searchInput.addEventListener('input', event => {
  searchOptimizer.setQuery(event.target.value);
});

// Subscribe to changes in the search state
setInterval(() => {
  console.log('Loading:', searchOptimizer.loading);
  console.log('Results:', searchOptimizer.results);
  console.log('Error:', searchOptimizer.error);
}, 1000);

React Hook Usage

import React from 'react';
import { useSearchOptimizer } from 'search-optimizer/adapters/react';
import { createFetchExecutor } from 'search-optimizer/adapters/fetch';

function SearchComponent() {
  // Create the search executor
  const searchExecutor = React.useMemo(
    () =>
      createFetchExecutor({
        baseUrl: 'https://api.example.com/search',
        queryParam: 'q',
      }),
    [],
  );

  // Use the hook to manage search state
  const { inputProps, loading, results, error } = useSearchOptimizer(searchExecutor, {
    debounceDelay: 400,
    minChars: 2,
  });

  return (
    <div>
      <input type="text" placeholder="Search..." {...inputProps} />

      {loading && <div>Loading...</div>}

      {results && (
        <ul>
          {results.map(item => (
            <li key={item.id}>{item.name}</li>
          ))}
        </ul>
      )}

      {error && <div>Error: {error.message}</div>}
    </div>
  );
}

📖 API Reference

Core

createSearchOptimizer(executor, options)

Creates a new SearchOptimizer instance.

Parameters:

  • executor: A SearchExecutor implementation
  • options: Configuration options

Returns: A SearchOptimizerResult object with methods and state properties

Options:

  • debounceDelay: Debounce delay in milliseconds (default: 500)
  • minChars: Minimum characters required before triggering search (default: 3)
  • trimInput: Whether to trim the input value (default: true)
  • lowercaseInput: Whether to convert the input to lowercase (default: true)
  • enableCancellation: Whether to enable request cancellation (default: true)
  • inputProcessor: Custom function to process input
  • onSearchStart: Callback when search starts
  • onSearchSuccess: Callback when search succeeds
  • onSearchError: Callback when search fails
  • onSearchCanceled: Callback when search is canceled

🔌 Adapters & Hooks

Import Paths

Each adapter is now available as a separate import:

// Core functionality
import { createSearchOptimizer } from 'search-optimizer';

// Fetch adapter
import { createFetchExecutor } from 'search-optimizer/adapters/fetch';

// Axios adapter
import { createAxiosExecutor } from 'search-optimizer/adapters/axios';

// GraphQL adapter
import { createGraphQLExecutor } from 'search-optimizer/adapters/graphql';

// Generic adapter for custom implementations
import { createGenericExecutor } from 'search-optimizer/adapters/generic';

// React hook
import { useSearchOptimizer } from 'search-optimizer/adapters/react';

Adapters

createFetchExecutor(options)

Creates a SearchExecutor using the Fetch API.

Options:

  • baseUrl: Base URL for the search endpoint (required)
  • queryParam: Query parameter name for the search term (default: 'q')
  • fetchOptions: Additional fetch request options
  • responseTransformer: Function to transform the fetch response

createAxiosExecutor(options)

Creates a SearchExecutor using Axios.

Options:

  • axios: Axios instance to use for requests (required)
  • baseUrl: Base URL for the search endpoint (required)
  • queryParam: Query parameter name for the search term (default: 'q')
  • axiosOptions: Additional axios request options

createGraphQLExecutor(options)

Creates a SearchExecutor for GraphQL clients.

Options:

  • client: GraphQL client instance (required)
  • query: GraphQL query document (required)
  • queryVariableName: Name of the variable to pass the search term (default: 'query')
  • resultExtractor: Function to extract search results from the GraphQL response
  • additionalVariables: Additional variables to include with every GraphQL request

createGenericExecutor(searchFn, options)

Creates a SearchExecutor using any custom search implementation.

Parameters:

  • searchFn: Function that performs the search, with signature (query: string, signal?: AbortSignal) => Promise<T>
  • options: Additional configuration options
    • name: Name for this custom executor (optional, useful for debugging)
    • errorHandler: Optional custom error handler function

Example:

// Create a custom executor with any search implementation
const myCustomExecutor = createGenericExecutor(
  async (query, signal) => {
    // Custom implementation using any API/library
    const results = await customSearchLibrary.search(query, { signal });
    return results.items;
  },
  { name: 'CustomLibraryExecutor' },
);

// Use with SearchOptimizer
const searchOptimizer = createSearchOptimizer(myCustomExecutor);

Creating a Custom Adapter (Direct Implementation)

You can also implement the SearchExecutor interface directly for complete control:

import { SearchExecutor, createSearchOptimizer } from 'search-optimizer';

// Implement the SearchExecutor interface directly
const myCustomExecutor: SearchExecutor = {
  execute: async (query, signal) => {
    // Your custom implementation here
    // Full control over error handling, request formatting, etc.
    const response = await fetch(`https://api.example.com/search?term=${query}`, {
      headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
      signal
    });

    if (!response.ok) {
      throw new Error(`Search failed: ${response.status}`);
    }

    const data = await response.json();
    return data.results;
  }
};

// Use with SearchOptimizer
const searchOptimizer = createSearchOptimizer(myCustomExecutor);

React Hook

useSearchOptimizer(executor, options)

React hook for using SearchOptimizer in functional components.

Returns:

  • query: Current search query string
  • loading: Boolean indicating if a search is in progress
  • results: Search results (null if no search has been performed)
  • error: Error object (null if no error occurred)
  • setQuery: Function to update the search query
  • search: Function to manually trigger a search
  • cancel: Function to cancel the current search
  • reset: Function to reset the search state
  • inputProps: Props object for easy React input element integration

🧪 Examples

Check out the examples directory for complete working demos:

🤝 Contributing

We welcome contributions to SearchOptimizer! If you'd like to contribute, please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please make sure to update tests as appropriate.

📝 Changelog

See the CHANGELOG.md file for details on version updates.

📄 License

This project is licensed under the MIT License. See the LICENSE file for details.

changelog

2.0.2 (2025-05-22)

2.0.1 (2025-05-16)

Bug Fixes

  • trigger patch version release (a9a35f6)

2.0.0 (2025-05-07)

⚠ BREAKING CHANGES

  • This release includes breaking changes.

Features

  • add dist-after and dist-before to .cursorignore (8a1d1ba)
  • add examples for SearchOptimizer with SWR, Axios, and Fetch in respective frameworks (4b80a37)
  • add generic adapter for SearchOptimizer with customizable search executors (5766c26)
  • add generic executor for custom search implementations in README (8293840)
  • add GitHub Actions workflow for dev release automation (2390970)

Miscellaneous Chores

  • release breaking change (af59098)

2.0.0-dev.1 (2025-05-07)

⚠ BREAKING CHANGES

  • This release includes breaking changes.

Miscellaneous Chores

  • release breaking change (af59098)

1.2.0-dev.1 (2025-05-07)

Features

  • add dist-after and dist-before to .cursorignore (8a1d1ba)
  • add examples for SearchOptimizer with SWR, Axios, and Fetch in respective frameworks (4b80a37)
  • add generic adapter for SearchOptimizer with customizable search executors (5766c26)
  • add generic executor for custom search implementations in README (8293840)
  • add GitHub Actions workflow for dev release automation (2390970)

1.1.0 (2025-04-22)

Features

  • add release preview workflow for pull requests (d071831)

Bug Fixes

  • update tsconfig to remove source maps from build and add tslib as a dependency (bc208d6)

1.0.1 (2025-04-21)

Bug Fixes

  • add descriptive name for install dependencies and build step in release workflow (6299e0c)

1.0.0 (2025-04-21)

Bug Fixes

  • add debug step for NPM authentication in release workflow (8bdac9c)
  • add permissions section to release workflow for commit and npm publish (a648a70)
  • disable no-this-alias rule in ESLint configuration (537cc73)
  • ensure always-auth is enabled for NPM registry in release workflow (9b903bd)
  • refactor release workflow to improve environment variable handling and step organization (4776da1)
  • streamline build step in release workflow by removing unnecessary name (3673d03)
  • update Node.js version in CI and release workflows to 20.x (65035ea)
  • update npm install command to include legacy-peer-deps option (c5be97d)
  • update README.md with correct GitHub links and improve code formatting (ef67844)
  • updates tsconfig and package.json to fix build result (c0818ef)