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

cached-proxy

v0.1.2

Published

A cached Proxy with optional timeouts per property to simplify complex remote scenarios

Readme

cached-proxy

build status Coverage Status

Social Media Photo by Bozhin Karaivanov on Unsplash

A cached Proxy with optional timeouts per property to simplify complex remote scenarios.

import CachedProxy from 'https://esm.run/cached-proxy';

const remote = new CachedProxy({ id: 123 }, {
  // optional: 0 means ASAP, otherwise cached for N milliseconds
  timeout: 0,

  // example: compute some remote value synchronously
  get(target, property) {
    const xhr = new XMLHttpRequest;
    xhr.open('GET', 'end/point', false);
    xhr.send(JSON.stringify({ trap: 'get', args: [target.id, property] }));
    return JSON.parse(xhr.responseText);
  }
});

// executes the XHR once, returns whatever value was cached
remote.test === remote.test;

setTimeout(() => {
  remote.test; // runs the XHR again
}, 10);

The example is there to explain that given enough amount of traps, it is possible via Atomics or synchronous / asynchronous behavior to retrieve once properties and values from elsewhere, similarly to how reflected-ffi memoized cache works but in an easier to orchestrate way.

Traps

| | cached | timeout | drop | reset | | :----------------------- | :----: | :-----: | :--: | :---: | | apply | | | | | | construct | | | | | | defineProperty | | | ☑️ | | | deleteProperty | | | ☑️ | | | get | ☑️ | ☑️ | | | | getOwnPropertyDescriptor | ☑️ | ☑️ | | | | getPrototypeOf | ☑️ | | | | | has | ☑️ | ☑️ | | | | isExtensible | ☑️ | | | | | ownKeys * | ☑️ | ✔️ | | | | preventExtensions | | | | | | set | | | ☑️ | | | setPrototypeOf | | | | ☑️ |

Traps Explainer

  • cached means each trap result is weakly stored
  • timeout means that, if a timeout optional integer is passed as proxy handler field, get, getOwnPropertyDescriptor and has will be dropped after that amount of time (in milliseconds)
  • drop means that the eventually stored value for that property or accessor will be instantly removed from the cache, affecting also ownKeys but without affecting isExtensible and getPrototypeOf
  • reset means that all weakly related values will be erased per property or target reference, effectively invalidating the whole cache for any trap that has one

The drop and reset utilities are also exposed via the module where drop(ref, property) will invalidate both ownKeys and the cache per specific property while reset(ref) will invalidate the whole cache per specific reference.

Please note: the reference is not the proxied one, it's the original one you must own, otherwise nothing will happen/work as expected, example:

import Proxy, { drop, reset  } from 'https://esm.run/cached-proxy';

const ref = { my: 'reference' };
const proxied = Proxy(ref);

// when/if needed, this works:
drop(ref, 'property');
// ... or ...
reset(ref);

// while this will not work:
drop(proxied, 'property');
// ... or ...
reset(proxied);

This is to avoid leaking the cache intent of the proxy owner/creator.

Special Cases + Cached suffix

  • arrays have a get trap that resets the cache if the retrieved property is neither length nor an index (an unsigned integer, 0 to max array length). This makes usage of a timeout almost irrevelant because methods that mutate the array should drop properties as needed.
  • dom nodes should likely use no cache due their highly mutable nature, however it is possible to use a handler that checks the returned value by specifying a getCached(target, property, value) that if returns true will cache the entry, otherwise it won't cache anything and, if the value is a function able to mutate the instance, it should likely reset(target) reference to avoid any undesired cache.

The Cached suffix can be used for each of these traps:

  • getCached, to skip caching undesired results or reset the cache in case the value is a function with side effects (i.e. methods that mutate internally the proxied reference)
  • getOwnPropertyDescriptorCached, to skip caching a descriptor or reset the cache in case it is an accessor with side effects (i.e. textContent or others)
  • has, to skip caching a specific key in proxy check