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

@atomiqlabs/storage-memory-indexed-kv

v2.0.5

Published

An abstract storage implementation for atomiqlabs SDK, uses in-memory indexes and any provided key-value store as a backend

Downloads

55

Readme

@atomiqlabs/storage-memory-indexed-kv

@atomiqlabs/storage-memory-indexed-kv provides key-value-backed storage adapters for the Atomiq SDK.

  • swaps are persisted as plain key-value records in your backend
  • during init(), the adapter reads the stored swaps and rebuilds the required simple and composite indexes in memory
  • queries are then served from those in-memory indexes
  • writes are serialized through a single write queue and update both the backend and the in-memory indexes

Because the indexes live in RAM, this adapter is intended for single-user, client-side datasets. In practice this means it is suitable for swap stores with fewer than roughly 10,000 saved swaps.

What this package provides

  • MemoryIndexedKeyValueUnifiedStorage: SDK-compatible unified swap storage built on top of any key-value backend that implements IKeyValueStorage.
  • KeyValueStorageManager: simple IStorageManager adapter for chain storage built on top of IKeyValueStorage.
  • IKeyValueStorage<Async>: the backend interface you implement for your own persistent key-value store.

When to use

Use this package when you:

  • want to plug the Atomiq SDK into a custom persistent key-value store
  • are storing swaps for a single client or device
  • expect a relatively small local swap history
  • need a lightweight adapter for browser-like, mobile, or embedded client environments

Do not use this package for:

  • backend services with many users
  • shared databases
  • long-lived services where swap counts can grow large
  • environments where multiple processes need to coordinate on the same storage

For backend-scale storage, prefer @atomiqlabs/storage-sqlite or another adapter with database-native indexing.

Installation

npm install @atomiqlabs/sdk @atomiqlabs/base @atomiqlabs/storage-memory-indexed-kv

Most applications should not need this package directly unless they are implementing a custom storage backend.

How to use

Implement IKeyValueStorage

Wrap your storage backend with the IKeyValueStorage interface:

export interface IKeyValueStorage<Async extends boolean> {
    async: Async;

    init(): Promise<void>;

    get(key: string): Async extends true ? Promise<string | null> : (string | null);
    set(key: string, value: string): Async extends true ? Promise<void> : void;
    remove(key: string): Async extends true ? Promise<void> : void;
    getKeys(): Async extends true ? Promise<string[]> : string[];

    //Batch methods are optional, but implementing them is recommended because they reduce read and write overhead.
    getAll?(keys: string[]): Async extends true ? Promise<(string | null)[]> : (string | null)[];
    setAll?(values: { key: string, value: string }[]): Async extends true ? Promise<void> : void;
    removeAll?(keys: string[]): Async extends true ? Promise<void> : void;
}

The interface supports both synchronous and asynchronous storage backends, hence the Async generic.

Example custom backend

import {
    IKeyValueStorage,
    KeyValueStorageManager,
    MemoryIndexedKeyValueUnifiedStorage
} from "@atomiqlabs/storage-memory-indexed-kv";

class MyKeyValueStorage implements IKeyValueStorage<true> {
    readonly async = true as const;

    constructor(private readonly prefix: string) {}

    async init(): Promise<void> {
        // Initialize your backend if needed.
    }

    async get(key: string): Promise<string | null> {
        return myKeyValueBackend.get(this.prefix + key);
    }

    async set(key: string, value: string): Promise<void> {
        await myKeyValueBackend.set(this.prefix + key, value);
    }

    async remove(key: string): Promise<void> {
        await myKeyValueBackend.remove(this.prefix + key);
    }

    async getKeys(): Promise<string[]> {
        const keys = await myKeyValueBackend.getKeysWithPrefix(this.prefix);
        return keys.map(key => key.substring(this.prefix.length));
    }

    async getAll(keys: string[]): Promise<(string | null)[]> {
        return Promise.all(keys.map(key => this.get(key)));
    }

    async setAll(values: { key: string; value: string }[]): Promise<void> {
        await Promise.all(values.map(value => this.set(value.key, value.value)));
    }

    async removeAll(keys: string[]): Promise<void> {
        await Promise.all(keys.map(key => this.remove(key)));
    }
}

const swapStorage = new MemoryIndexedKeyValueUnifiedStorage(
    new MyKeyValueStorage("atomiq_sdk_chain_SOLANA_")
);
const storageManager = new KeyValueStorageManager(
    new MyKeyValueStorage(`atomiq_sdk_store_SOLANA_`)
);

SDK Usage

Use your custom storage as the SDK's swapStorage:

import {BitcoinNetwork, SwapperFactory, TypedSwapper} from "@atomiqlabs/sdk";
import {MemoryIndexedKeyValueUnifiedStorage} from "@atomiqlabs/storage-memory-indexed-kv";

const chains = [SolanaInitializer] as const;
type SupportedChains = typeof chains;

const Factory = new SwapperFactory<SupportedChains>(chains);

const swapper: TypedSwapper<SupportedChains> = Factory.newSwapper({
    chains: {
        ...
    },
    bitcoinNetwork: BitcoinNetwork.MAINNET,
    swapStorage: chainId => new MemoryIndexedKeyValueUnifiedStorage(
        new MyKeyValueStorage(`atomiq_sdk_chain_${chainId}_`)
    ),
    chainStorageCtor: name => new KeyValueStorageManager(
        new MyKeyValueStorage(`atomiq_sdk_store_${name}_`)
    )
});

await swapper.init();

Options

MemoryIndexedKeyValueUnifiedStorage accepts optional configuration:

  • maxBatchItems: maximum number of items processed per batch during initialization, reads, and bulk writes. Default: 100.
  • allowQueryWithoutIndexes: allows fallback full-scan queries when no configured index matches. Default: false.

Leaving allowQueryWithoutIndexes disabled is usually the right choice, because full scans negate the point of the in-memory index model and can become expensive as the stored swap count grows.