dual-floor
v0.2.2
Published
Dual-stage performance utilities for JavaScript and TypeScript.
Downloads
29
Maintainers
Readme
dual-floor
dual-floor is a performance toolkit for JavaScript and TypeScript.
The idea behind Dual Floor is simple:
- Floor 1 reduces entry cost by simplifying keys, inputs, and scheduling.
- Floor 2 reduces repeat cost by reusing work through cache, pooling, batching, and transform reuse.
It is useful for bots, APIs, CLIs, loaders, and build pipelines where the same work tends to happen over and over.
Included utilities
createLRUCache: bounded cache for hot-path lookups.memoize: fast memoization with unboundedMapby default or bounded LRU mode.createBatcher: merges many async calls into fewer operations.createObjectPool: reuses objects to reduce allocation pressure.createTransformCache: skips repeated compile/transform work when the source fingerprint has not changed.createParallelRunner: limits concurrency so builds and transforms stay saturated without overloading the event loop.createFingerprint: fast fingerprint helper for source text, config strings, or cache keys.createNumberCache: array-backed cache for dense integer keys.createSingleFlight: merges duplicate concurrent work into one execution.createPersistentTransformCache: stores transform results on disk for repeated builds and CLI runs.createCompiler:esbuild-powered transform engine with cache and parallel execution built in.createHybridCache: local memory cache + shared cache with stampede protection, tag invalidation, and circuit breaker support.createRedisCompatibleStore: adapts a Redis-like client todual-floorshared cache.createMemorySharedStore: local mock/shared store for tests and single-node deployments.
Install
npm install dual-floorUsage
import {
createBatcher,
createCompiler,
createHybridCache,
createRedisCompatibleStore,
createPersistentTransformCache,
createSingleFlight,
createParallelRunner,
createTransformCache,
memoize
} from "dual-floor";
const compileCache = createTransformCache<string, string>();
async function compileModule(id: string, source: string) {
return compileCache.run({
key: id,
source,
transform: async () => source.toUpperCase()
});
}
const runParallel = createParallelRunner({ concurrency: 4 });
const compileMany = async (files: Array<{ id: string; source: string }>) =>
runParallel(files, (file) => compileModule(file.id, file.source));
const commandLookup = memoize((name: string) => name.trim().toLowerCase());
const batchedFetch = createBatcher(async (ids: readonly string[]) => {
return ids.map((id) => `resolved:${id}`);
});
const singleFlight = createSingleFlight<string, string>();
const compileShared = (id: string, source: string) =>
singleFlight.run(id, () =>
compileCache.run({
key: id,
source,
transform: async () => source.toUpperCase()
})
);
const persistent = createPersistentTransformCache<string, string>({
dir: ".dual-floor-cache"
});
const compilePersistent = (id: string, source: string) =>
persistent.run({
key: id,
source,
transform: async () => source.toUpperCase()
});
const compiler = createCompiler({
cacheDir: ".dual-floor-compile",
concurrency: 4
});
const output = await compiler.compile({
source: "const answer: number = 42",
loader: "ts",
format: "esm",
target: "es2020"
});
const builtFile = await compiler.compileFile({
inputPath: "src/index.ts",
outputPath: "dist/index.js",
format: "esm",
target: "es2020",
sourcemap: true
});
const builtProject = await compiler.compileProject({
rootDir: "src",
outDir: "build",
format: "esm",
target: "es2020",
cleanOutDir: true
});
const shared = createRedisCompatibleStore(redisClient);
const cache = createHybridCache({
ttl: 5_000,
staleTtl: 30_000,
shared,
breaker: {
failureThreshold: 3,
cooldownMs: 10_000
}
});
const profile = await cache.get(
"user:42",
() => fetchUserProfile(42),
{ tags: ["users", "user:42"] }
);
await cache.invalidateTag("users");Build acceleration
createTransformCache is aimed at loaders, code generators, bundler hooks, and command compilers.
- If the source and fingerprint are unchanged, it reuses the previous output.
- If the content changes, it recompiles only that unit.
- You can include compiler options in the fingerprint to invalidate safely when config changes.
- If the same file is requested concurrently, in-flight work is reused instead of recompiled multiple times.
- If you use
createPersistentTransformCache, cached outputs can survive process restarts and speed up repeated builds.
createCompiler is the higher-level entry point when you want dual-floor to handle transform caching and parallel execution for TS/JS code directly.
compile: transforms a source string.compileFile: reads one file, compiles it, and optionally writes the output.compileProject: walks a directory and writes compiled output while preserving relative paths.
createNumberCache is the stronger hot-path option when your keys are integer IDs such as shard IDs, opcode IDs, command IDs, or compact enum indexes.
Distributed caching
createHybridCache is the enterprise cache layer for multi-instance services.
- L1 local memory cache minimizes network round trips.
- L2 shared cache lets instances share hot data.
- Single-flight loading helps prevent cache stampedes.
- Tag invalidation supports broad cache busts like
users,products, ortenant:123. - Circuit breaker logic keeps shared-cache outages from cascading through the app.
- Built-in stats expose hit rates, stale hits, shared errors, invalidations, and breaker state.
To use Redis, pass a Redis-like client to createRedisCompatibleStore. Any client exposing get, set, del, and optionally sAdd, sMembers, sRem, expire will work.
Benchmark
npm run benchThis compares dual-floor against common alternatives in the same local environment. Real performance depends on key shape, hit rate, transform cost, and workload pattern, so benchmark with your own input before making speed claims.
