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 🙏

© 2024 – Pkg Stats / Ryan Hefner

cumcord-tools

v8.0.2

Published

A set of absolutely tiny utilities to add to your Discord plugins.

Downloads

2

Readme

CC Tools

A set of absolutely tiny utilities to add to your Discord plugins.

Type checked with Flow, but no type removal needed, as annotations comments are used exclusively over standard annotations.

These cannot be built with a standard bundler, they must be imported by sperm.

This is tree-shakable by sperm, so you only get what you use. Even importing and not using will tree shake it. So no matter how many tools I stuff into this NPM pkg, your plugin will never be bloaty because of it. :)

See each tool documented below.

Cumcache

Current bundled size: 1033 bytes

A keyval store that sits on top of your persist nest (or any other nest!) and allows setting expiry times for each pair.

Init the store as follows:

import { cumcache } from "cumcord-tools";

// calling cumcache inits the store, only do this ONCE unless you uninit/cleanup it afterwards
// cumcache takes the key in the nest to use, defaults to cumcache, and a nest, defaults to the persist nest.
// as should be obvious by the fact they have defaults, both these args are optional.

// as JS array destructuring works, feel free to just destructure to [cleanup, timeOut, store]
// use of forceStoreClear is not recommended.
let [cleanup, timeOut, store, forceStoreClear] = cumcache("my-epic-keyval");

Then call cleanup() once you're done with the store, MAKE SURE YOU DO THIS (usually in your onUnload)

Call forceStoreClear() to force removing expired entries. This is almost never necessary as cumcache clears for you periodically (as of writing this, 5 seconds).

Call timeOut(key, val, time) to set a key in the store - it sets key to val, and sets the pair to delete after time.

It has an optional 4th parameter: the time to start counting from. This is useful if you have past data you need to apply a consistent expiry to. It defaults to the current time.

The acceptable time values are any number, int or float, followed by a one letter suffix:

  • 1s = 1 second
  • 1m = 1 minute
  • 1h = 1 hour
  • 1d = 1 day
  • 1w = 1 week
  • 1y = 1 year

store is a proxy allowing you to get values and delete values. Setting is not allowed.

import { cumcache } from "cumcord-tools";

let [cleanup, timeOut, store] = cumcache("my-epic-keyval");

/* 
nest.ghost: {
    cumcache: {
        // this isnt the actual content, for simplicity's sake just the keys and values are shown
    }
}
*/

// sets key hello to value {world:5}, and clears after 10 seconds
timeOut("hello", { world: 5 }, "10s");

let val = store.hello; // val = { world: 5 }

/* 
nest.ghost: {
    cumcache: {
        hello: { world: 5 }
    }
}
*/

// after waiting 10 seconds

/* 
nest.ghost: {
    cumcache: {
    }
}
*/

// im done
cleanup();
// the nest will remain in the state it was in at the time of cleanup
// keys will persist in memory and any that expire while cumcache
// is inactive will be cleared the next time cumcache is inited on the same key.

Bound Cumcache

Current bundled size: 1191 bytes

Cumcache packs a huge amount of flexibility into its small footprint, however much of it is likely to go unused.

Specifically, in actual usage, most people do not set a custom since date (it can be left blank anyway), and most will want to use the same expiry for everything in that particular cache.

Bound cumcache takes these two freedoms away from individual key-val pairs, instead allowing just the expiry time to be set when initing the cache.

In return, the timeout method is replaced by making the store you read from also writable. The stock cumcache store allows deleting but not setting. Bound cumcache allows setting, which will use the expiry set in the init.

Just as in stock cumcache, you can also get a func to force remove expired functions, but it is not recommended: let [cleanup, store, forceStoreClear] = boundCumcache(...).

import { boundCumcache } from "cumcord-tools";

let [cleanup, store] = boundCumcache("my-epic-keyval", "10s");

// set key "hello" to value {world: 5}
store.hello = { world: 5 };
// get key
let x = store.hello; // x === {world: 5}

Find by DOM node

Current bundled size: 229 bytes

This tool is highly discouraged except for testing - you should use a better method to locate modules and not rely on the DOM, but its here if you need it.

This tool finds a react component from the DOM element. It optionally gets the module containing the component.

You may optionally require that the element must have a display name. This will ignore any anonymous components and only get named elements.

import { findByDomNode } from "cumcord-tools"
let domNode = /* get a dom node of a component */
let Component = findByDomNode(domNode);
<Component />

// allow strings (div etc)
let ComponentParent = findByDomNode(domNode, true);
ComponentParent === { default: Component }

// must have display name
let ActualComponent = findByDomNode(domNode, false, true);
// <ActualComponent><Component /></ActualComponent>
// where Component is anonymous and ActualComponent is exported

Depend

Current bundled size: 370 bytes

Depend is a tool to depend on another plugin's side effects, while allowing both your code and the depended upon plugin to unload and re-load freely.

A good use case is where plugins export an API on window thats only there while the plugin is loaded.

import { depend } from "cumcord-tools";
let pluginsToDependOn = [
	"https://example.com/cool-plugin/",
	"https://cumcordplugins.github.io/Condom/example.com/cool-plugin/",
];

let undepend = depend(pluginsToDependOn, () => {
	console.log(
		"One of the plugins listed has been loaded, or already was loaded"
	);
	// let unpatch = after("cool_function", obj, () => {/* ... */});

	// this return is optional, returning nothing will simply not bother
	return () => {
		console.log("One of the plugins listed has been unloaded.");
		// cleanup stuff in here.
		// unpatch();
	};
});

// i'm done with this code and wish to stop listening for dep un/load events, and cleanly finish
undepend();

Settings

Current bundled size: 1522 bytes, tree-shakes down further

CC tools has a full api designed to make working with settings as easy as possible.

Use the tools here correctly and then simply read from the ghost, and write to the store if you need any more complex settings modification.

setDefaults

This allows you to set defaults for any undefined nest keys:

import { setDefaults } from "cumcord-tools";
setDefaults({
	anOption: true,
	anotherOption: false,
	aValue: 5,
});

dependPersist

Makes a given component rerender on nest change

import { dependPersist } from "cumcord-tools";

export const settings = dependPersist(() => <>{/* settings here */}</>);

Settings components

All settings components have the following props:

  • k (string) - The key on the nest
  • children (React component) - The label text
  • depends (optional string) - If present, the key to require to be truthy to enable this setting

The select component also has

  • options ({value:any, label:string}) - The list of options to select from. No selection = undefined

They are as follows:

  • SSwitch: a switch.
  • SText: a textbox.
  • SSelect: a dropdown selection box.
export const Settings = (
	<SettingsRoot>
		<SSwitch k="details">Show user details</SSwitch>
		<SText k="name" depends="details">
			User name
		</SText>

		<SSelect
			k="utype"
			depends="details"
			options={[
				{ value: "NORMAL", label: "Normal user" },
				{ value: "ADMIN", label: "Administrator" },
				{ value: "SADMIN", label: "Super Admin" },
			]}
		>
			User type
		</SSelect>
	</SettingsRoot>
);