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

fdt-request-shield

v2.0.1

Published

API call shield for in-flight dedupe, TTL cache, and request control.

Readme

fdt-request-shield

Shield products are created by Future Dev Tech for modern frontend apps.

fdt-request-shield is a TypeScript-first API call shield package for modern frontend apps. It helps with:

  • API request deduplication
  • smart TTL cache for API responses
  • page-level and global request scope
  • cache invalidation and cleanup
  • retry and timeout control
  • safe wrapper usage around your existing API functions

This package is framework agnostic. You can use the same methods in:

  • Next.js
  • React
  • Vite
  • plain TypeScript frontend apps

Why Use Request Shield

Sometimes the same API call runs many times because the component renders again or the same request is triggered from more than one place. That creates extra load on the server instead of making only one API call.

This usually happens when:

  • the page renders again
  • React runs the component more than once in development
  • two or more components call the same API at the same time
  • the user clicks the same button many times
  • search, filter, or input values change

When we say the API is "triggered multiple times", we mean:

  • the same request is started again
  • the same data is fetched again
  • the browser sends extra network calls
  • the server gets unnecessary repeated requests

fdt-request-shield solves this by:

  • sending only one request for the same key at the same time
  • using cached data again if it is still fresh
  • running a new API call only when the key changes
  • sharing the same request across components when needed
  • letting you clear cache when you want fresh data

This gives you:

  • fewer duplicate API calls
  • less server load
  • faster response in the UI
  • cleaner API handling in frontend apps

Install

npm install fdt-request-shield

Public Methods

| Method | Type | Params | Use | | --- | --- | --- | --- | | requestOnce | function | (key: string, fn: () => Promise<T>) | Dedupes only in-flight requests | | cachedRequest | function | (key: string, fn: () => Promise<T>, options: { ttl: number }) | Adds TTL cache plus in-flight dedupe | | shieldRequest | function | (options: { key: string; fn: () => Promise<T>; ttl?: number; scope?: 'page' \| 'global'; retry?: number; timeout?: number; signal?: AbortSignal }) | Full wrapper with cache, scope, retry, timeout | | clearCache | function | (key?: string) | Clears one key or the full cache/in-flight store | | invalidate | function | (prefix: string) | Clears all entries that start with a prefix | | getCacheStats | function | () | Returns cache and in-flight stats |

requestOnce(key, fn)

Use this when you want only in-flight deduplication.

const data = await requestOnce('months-list', () => getMonthList());

Best for:

  • duplicate button clicks
  • repeated renders
  • multiple components requesting the same data at the same time

cachedRequest(key, fn, { ttl })

Use this when you want dedupe plus TTL-based caching.

const data = await cachedRequest(
  `location-${country}-${state}-${trip}`,
  () => locationOtherDetails(queryString),
  { ttl: 30000 },
);

Best for:

  • search results
  • filter-based API calls
  • data that should stay fresh for a short time

shieldRequest({ key, fn, ttl, scope, retry, timeout, signal })

Use this when you want the full control layer.

const data = await shieldRequest({
  key: ['travel-leads', search, budgetMin, budgetMax, interestType, sortBy].join('|'),
  fn: () => leadsList('', search),
  ttl: 30000,
  scope: 'page',
  retry: 1,
  timeout: 10000,
});

Best for:

  • production screens
  • shared component data
  • large forms
  • API calls with retry and timeout needs

Utility Methods

clearCache(key?)

Clear everything or a single key.

clearCache();
clearCache('months-list');

invalidate(prefix)

Clear all cache entries and in-flight keys that start with a prefix.

invalidate('travel-leads');

getCacheStats()

Inspect current cache and in-flight counts.

const stats = getCacheStats();
console.log(stats);

Scope

scope: 'page'

Use page scope when you want isolation inside one page or one component flow.

scope: 'global'

Use global scope when you want cache sharing across the app runtime.

Retry and Timeout

retry

Retry means try again when the request fails.

retry: 1

This means:

  • first attempt can fail
  • one more attempt is allowed

timeout

Timeout means stop waiting after a specific time.

timeout: 30000

This means:

  • wait up to 30 seconds
  • if the request is still running, treat it as timed out

If you do not pass timeout, the request can continue until it finishes.

Framework Examples

Next.js

'use client';

import { useEffect, useState } from 'react';
import { shieldRequest } from 'fdt-request-shield';

export function MonthsPanel() {
  const [items, setItems] = useState<any[]>([]);

  useEffect(() => {
    shieldRequest({
      key: 'months-list',
      fn: () => getMonthList(),
      ttl: 30000,
      scope: 'page',
    }).then(setItems);
  }, []);

  return (
    <ul>
      {items.map((month) => (
        <li key={month.id}>{month.name}</li>
      ))}
    </ul>
  );
}

React

import { useEffect, useState } from 'react';
import { cachedRequest } from 'fdt-request-shield';

export function UserList() {
  const [users, setUsers] = useState<any[]>([]);

  useEffect(() => {
    cachedRequest('users-list', () => fetchUsers(), { ttl: 60000 }).then(setUsers);
  }, []);

  return <pre>{JSON.stringify(users, null, 2)}</pre>;
}

Vite

import { requestOnce } from 'fdt-request-shield';

const data = await requestOnce('dashboard-metrics', () => fetchDashboardMetrics());

Behavior Summary

  • same key = dedupe/cache logic applies
  • different key = new API call
  • same key during an active request = same promise returned
  • expired TTL = API runs again and cache refreshes
  • page scope = isolated request memory
  • global scope = shared request memory

Keywords Cover

request dedupe package, api cache package, ttl cache frontend, in-flight request deduplication, react api caching, nextjs request cache, vite api wrapper, typescript request cache, api call shield, smart cache for frontend

License

MIT


Created by Future Dev Tech.

  • GitHub: https://github.com/futuredevtech
  • Instagram: https://www.instagram.com/futuredevtech48/
  • LinkedIn: https://www.linkedin.com/in/abhimanyu-sinhmar-672b6b2b2