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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@fimbul-works/runa

v0.3.0

Published

Runa is a TypeScript library for creating elegant, bidirectional, and type-safe data transformations

Readme

@fimbul-works/runa

Runa is a TypeScript library for creating elegant, bidirectional, and type-safe data transformations.

At its core, a Runa is a composable object with two fundamental methods: encode and decode. This design ensures that your data transformations are always reversible and perfectly type-safe, whether you're working with synchronous or asynchronous operations.

Key Features

  • 🔄 Bidirectional by Design: Every transformation comes with an encode and a decode method, guaranteeing reversibility.
  • ⛓️ Type-Safe Chaining: Seamlessly compose transformations together with the .chain() and .chainAsync() methods. TypeScript infers the new input and output types at every step.
  • ✨ Sync & Async: Full support for both synchronous (RunaSync) and asynchronous (RunaAsync) transformations, which can be chained together.
  • 🧩 Functional & Composable: Built with a functional, factory-based approach, making it easy to create and share reusable transformation logic.

Installation

npm install @fimbul-works/runa
# or
yarn add @fimbul-works/runa
# or
pnpm install @fimbul-works/runa

Basic Usage

Start by creating a simple bidirectional transformation using createRuna.

import { createRuna } from '@fimbul-works/runa';

const numberToHex = createRuna(
  (n: number) => n.toString(16),
  (s: string) => parseInt(s, 16)
);

numberToHex.encode(255) // "ff"
numberToHex.decode("ff") // 255

Chaining: String to Buffer to Array

One of the features of Runa is the ability to chain multiple transformations. Here's an example that converts a string to a buffer, and then converts the buffer to an array:

import { runaStringToBuffer, runaBufferToArray } from '@fimbul-works/runa';

// 1. Create a string to buffer converter
const stringToBuffer = runaStringToBuffer();

// 2. Create a buffer to array converter
const bufferToArray = runaBufferToArray();

// 3. Chain them together to create a string to array converter
const stringToArray = stringToBuffer.chain(bufferToArray);

// Use the chained converter
const originalString = "Hello, Runa!";
const array = stringToArray.encode(originalString);
const reconstructedString = stringToArray.decode(array);

console.log(array); // [72, 101, 108, 108, 111, 44, 32, 82, 117, 110, 97, 33]
console.log(reconstructedString); // "Hello, Runa!"

This example demonstrates how Runa enables you to build complex transformation pipelines while maintaining type safety and bidirectional transformations at each step.

Available Converters

Below is a comprehensive list of pre-built converters provided by the library:

Core Conversion Utilities

createRuna<TIn, TOut>(encode, decode)RunaSync<TIn, TOut>

Creates a bidirectional synchronous transformation between any two types.

createRunaAsync<TIn, TOut>(encode, decode)Promise<RunaAsync<TIn, TOut>>

Creates a bidirectional asynchronous transformation between any two types.

String & Text Processing

runaBase64()RunaSync<string, string>

Converts between plain text and Base64 encoding. Handles Unicode characters correctly and works in both Node.js and browser environments.

runaJSON<T>(useSuperJSON?: boolean)RunaSync<T, string>

Converts between TypeScript objects and JSON strings with enhanced capabilities. Uses SuperJSON by default to handle complex data types like Dates, Maps, Sets, and custom classes, ensuring perfect bidirectional conversion. Set useSuperJSON to false for standard JSON behavior.

runaURI()RunaSync<string, string>

Encodes and decodes URI components using encodeURIComponent and decodeURIComponent.

runaStringSplit(delimiter: string)RunaSync<string, string[]>

Splits strings into arrays and rejoins them with a specified delimiter.

runaStringToNumber(radix?: number)RunaSync<string, number>

Converts strings to numbers and back using specified radix (base).

runaStringToBuffer()RunaSync<string, Uint8Array>

Converts UTF-8 strings to Uint8Array buffers and back.

runaStringPadStart(maxLength: number, fillString: string)RunaSync<string, string>

Adds padding to the beginning of strings to reach a specified maximum length. Handles multi-character fill strings and Unicode characters.

runaStringPadEnd(maxLength: number, fillString: string)RunaSync<string, string>

Adds padding to the end of strings to reach a specified maximum length. Handles multi-character fill strings and Unicode characters.

Arithmetic Operations

runaAdd(additive: number)RunaSync<number, number>

Adds a constant value during encoding and subtracts it during decoding.

runaMultiply(multiplier: number)RunaSync<number, number>

Multiplies by a constant value during encoding and divides by the same value during decoding. Throws error if multiplier is zero.

runaPower(exponent: number)RunaSync<number, number>

Raises to a power during encoding and takes the corresponding root during decoding. Handles negative values with odd exponents and throws error for invalid combinations.

Number & Array Processing

runaNumberCharset(alphabet: string, minLength = 1)RunaSync<number, string>

Converts numbers to strings using a custom character set (alphabet) and back.

runaNumberArrayCharset(alphabet: string, minLength = 1)RunaSync<number[], string>

Converts arrays of numbers to strings using a custom character set and back.

runaNumberToChar()RunaSync<number, string>

Converts single numbers to their corresponding character representation and back.

runaCantorPair()RunaSync<[number, number], number>

Encodes two numbers into a single number using the Cantor pairing function and back.

runaCantorPairArray()RunaSync<[number, number][], number[]>

Applies Cantor pairing to arrays of number pairs.

runaArraySplit<T>(chunkSize: number)RunaSync<T[], T[][]>

Splits arrays into chunks of specified size and rejoins them.

runaArrayFlatten<T>(chunkSize: number)RunaSync<T[][], T[]>

Flattens 2D arrays into 1D arrays and re-chunks them. Validates chunk sizes.

runaArrayJoin(separator = "")RunaSync<number[], string>

Converts arrays of numbers to strings using specified separator and back. Note: Uses different parsing for empty vs custom separators.

runaBufferToArray()RunaSync<Uint8Array, number[]>

Converts Uint8Array buffers to number arrays and back.

Cryptographic & Security

runaAesGcm(key: string | BufferSource, salt?: BufferSource)Promise<RunaAsync<string, Uint8ArrayLike>>

Asynchronous AES-256-GCM encryption/decryption with key derivation.

runaFF1(key: string | Buffer, tweak: string | Buffer, alphabet?: string, minLength?: number, maxLength?: number)RunaAsync<string, string>

Format-Preserving Encryption (FF1) for strings. Encrypts data while maintaining the same format and length.

License

MIT License - See LICENSE file for details.


Built with 🔮 by FimbulWorks