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

kahn

v0.2.1

Published

Adam's utility functions

Downloads

178

Readme

Kahn

My current collection of Typescript utility functions. Some of these will be stripped out as I find what functions I use the most. In the future I plan to make the exports more modular, like how lodash has lodash/ for individual functions.

Categories

Packages

Reexports

import { _ } from 'kahn' // lodash
import { id } from 'kahn' // nanoid
import { ky } from 'kahn' // ky

Bytes

import { bytes } from 'kahn'

// conversions
// buffer
bytes.fromBuffer(buffer: ArrayBuffer): Bytes
bytes.toBuffer(data: Bytes): ArrayBuffer
// hex
bytes.fromHex(hex: string): Bytes
bytes.toHex(data: Bytes): string
// number
bytes.fromNumber(num: number): Bytes
bytes.toNumber(data: Bytes): number
// string
bytes.fromString(str: string): Bytes
bytes.toString(data: Bytes): string
// base32
bytes.fromBase32(base32: string): Bytes
bytes.toBase32(data: Bytes): string
// base58 (xmr)
bytes.fromBase58(base58: string): Bytes
bytes.toBase58(data: Bytes): string
bytes.alphabetBase58(): string
// base64 (url-safe, no padding)
bytes.fromBase64(base64: string): Bytes
bytes.toBase64(data: Bytes): string
bytes.alphabetBase64(): string
// timestamps
bytes.fromTimestamp(date: Date): Bytes
bytes.toTimestamp(data: Bytes): Date
bytes.nowTimestamp(): Bytes
// objects (JSON)
bytes.fromObject(obj: object): Bytes
bytes.toObject(data: Bytes): object

// comparisons
bytes.xor(b1: Bytes, b2: Bytes): Bytes
bytes.hamming(b1: Bytes, b2: Bytes): number
bytes.isEqual(b1: Bytes, b2: Bytes): boolean
bytes.compare(b1: Bytes, b2: Bytes): Comparison // -1, 0, 1

// manipulation
bytes.concat(...data: Bytes[]): Bytes
bytes.chunk(data: Bytes, chunkSize: number): ChunkedBytes
bytes.unchunk(data: ChunkedBytes): Bytes

// misc
bytes.random(length: number): Bytes
bytes.ByteMap<V>: Map<Bytes, V> // a map that uses Bytes as keys, not recommended due to having to convert to strings

// Types
type Bytes = Uint8Array;
type EncryptedBytes = Uint8Array;
type DecryptedBytes = Uint8Array;
type HashedBytes = Uint8Array;
type SignedBytes = Uint8Array;
type ChunkedBytes = Uint8Array[];
type ByteLength = number; // the length of a Bytearray
enum ByteLengthOf {
	Uint8 = 1,
	Uint16 = 2,
	Uint32 = 4,
	Uint64 = 8,
}

Krypto

(named weirdly to avoid conflict with Node/browser crypto packages)

Checksums

import { krypto } from "kahn";

// Checksum - CRC32
krypto.Checksum.digest(data: Bytes): Checksum
krypto.Checksum({value: number}).verify(data: Bytes): boolean

Hashes

import { krypto } from "kahn";

// FastHash - Blake3
krypto.FastHash.digest(data: Bytes): FastHash
krypto.FastHash({bytes: Bytes}).verify(data: Bytes): boolean

// SaltHash - Blake3
krypto.SaltHash.digest(data: Bytes, salt?: Salt): SaltHash
krypto.SaltHash({bytes: Bytes}).verify(data: Bytes): boolean

// SlowHash - Argon2 (always salted, has to be async because it's slow)
krypto.SlowHash.digestAsync(data: Bytes): Promise<SlowHash>
krypto.SlowHash({bytes: Bytes}).verifyAsync(data: Bytes): Promise<boolean>

Signatures

import { krypto } from "kahn";

// Signatures (contains the publickey)
krypto.Signature.sign(data: Bytes, keyPair: KeyPair): Signature
krypto.Signature({bytes: Bytes}).verify(data: Bytes, publicKey: PublicKey): boolean

Keys

import { krypto } from 'kahn'

// HKDF - sha256
// PublicKey, PrivateKey, and SharedKey are all extended from Key
krypto.Key({bytes: Bytes}).derive(salt: Bytes): SharedKey

// Public Key - curve25519
krypto.PublicKey({bytes: Bytes}): PublicKey

// Private Key - leave empty to generate a new private key
krypto.PrivateKey({bytes: Bytes}): PrivateKey
krypto.PrivateKey().toPublicKey()

// Keypair - leave empty to generate a new keypair
krypto.KeyPair({
  privateKey?: PrivateKey,
  privateKeyBytes?: Bytes
  })
krypto.Keypair.vanity(prefix: string, timeout? Milliseconds): KeyPair

// Signatures
krypto.Keypair().sign(data: Bytes): Signature // wraps Signature.sign
krypto.Keypair().sharedKey(publicKey: PublicKey, salt?: Salt): SharedKey

// Shared Key - Stream Cipher - ChaCha20
krypto.SharedKey({bytes: Bytes}).encrypt(data: Bytes): EncryptedBytes
krypto.SharedKey({bytes: Bytes}).decrypt(data: EncryptedBytes): Bytes

Protobufs

This is mostly just a reexport of protobufjs with a few extra functions.

import { proto } from 'kahn'

// proto reexports from protobufjs/light
// it has the following aliases for decorators
proto.type // proto.Type.d
proto.field // proto.Field.d
proto.oneOf // proto.OneOf.d
proto.map // proto.MapField.d

import { ProtoType } from 'kahn'
// ProtoType<T> is a shim for proto.Message<T>
// usage:
//    class MyClass extends ProtoType<MyClass>{}
// it adds the following serializion and deserializion functions:
//   - toBytes() and fromBytes() - Uint8Array
//   - toString() and fromString() - base32
ProtoType<T>


import { Timestamp } from 'kahn'
// Timestamp is a representation of google.protobuf.Timestamp
// it has the following serializion and deserializion functions:
Timestamp.fromDate()
Timestamp.fromNow()
Timestamp().toDate()

Iterating

Renamed iterator functions from it.

import { iterating } from 'kahn'

/* Create */

// Create an iterable that can be pushed to
iterating.Pushable(): Pushable<T>
/*
  const iter = iterating.Pushable().push(0)
*/

// Allows peeking at the next value
iterating.Peekable(iterable: Iterable<T>): AsyncIterable<T>
/*
  const nextValue = iterating.Peekable([0, 1, 2]).peek()
*/

// Allows recovering from errors
iterating.Recoverable(err => {
  // Called with no error when the iteration starts
  if (!err) {
    return myIterable
  } else {
    throw err // or return a new iterable
  }
})

// Emits events for each value
iterating.Emitter(iterable: AsyncIterable<any>)
/*
  const emitter = iterating.Emitter([0, 1, 2])
  emitter.on('value', (v) => console.log(v))
  emitter.on('end', () => console.log('done'))
  emitter.on('error', (err) => console.error(err))
  await emitter.cancel() // to end early
*/

// Unidirecctional duplex stream
iterating.Portal()
/*
  const [orange, blue] = iterating.portal()
  iterating.pipe(emitter, orange)
  iterating.pipe(blue, consumer)

*/

// Bidirectional duplex streams
iterating.Portals()
/*
  const [orange, blue] = iterating.portals()

  iterating.pipe(emitter, orange)
  iterating.pipe(blue, consumer)
  // and
  iterating.pipe(emitter, blue)
  iterating.pipe(orange, consumer)

*/

/* Actions */

// Collects all the values into an array
iterating.collect(iterable: Iterable<T>): Promise<T[]>

// Empties the iterable
iterating.drain(iterable: Iterable<T>): Promise<void>

// Returns the next value
iterating.first(iterable: Iterable<T>): Promise<T>

// Returns the last value
iterating.last(iterable: Iterable<T>): Promise<T>

// Takes the first n items from an iterable
iterating.take(iterable: Iterable<T>, n: number): AsyncIterable<T>

// Skip n items
iterating.skip(iterable: Iterable<T>, n: number): AsyncIterable<T>

// Merges multiple iterables into a single iterable
iterating.merge(...iterables: Iterable<T>[]): AsyncIterable<T>

// Empties and counts the number of items in an iterable
iterating.count(iterable: Iterable<T>): Promise<number>

/* Flow */

// Filters the passed iterable by the filter function
iterating.filter(iterable: Iterable<T>, filter: (value: T) => boolean): AsyncIterable<T>

// Maps the values by a function
iterating.map(iterable: Iterable<T>, map: (value: T) => U): AsyncIterable<U>

// Reduces the values by a function
iterating.reduce(
	iterable: Iterable<T>,
	reducer: (acc: U, curr: T, index: number) => U,
	initialValue: U
	): Promise<U>

// Sorts the values by a function
iterating.sort(iterable: Iterable<T>, sorter: (a: T, data: T) => number): AsyncIterable<T>

// Applies a function to each item in the iterable
iterating.apply(source: Iterable<T>,
	fn: (thing: T, index: number) => Promise<void>
): AsyncGenerator<T>

// Invokes each incoming function in parallel
// Batched jobs are always ordered and ignore concurrency
iterating.process(
	source: Iterable<() => Promise<T>> | AsyncIterable<() => Promise<T>>,
  options: {concurrency: 1, ordered: true, batchSize: 0}): AsyncIterable<T>

/* Pipes */

// Pipes (tees) the iterable into multiple sinks
iterating.pipe(source: Iterable<T>, ...sinks: Iterable<T>[]): AsyncIterable<T>

/* Batches */

// Split the values by a delimiter
iterating.split(iterable: Iterable<Uint8Array>, delimiter?: Uint8Array): AsyncIterable<Uint8Array>

// Batch values into chunks of a certain size
iterating.batch(iterable: Iterable<T>, size: number): AsyncIterable<T[]>
/*
  iterating.batch([0, 1, 2, 3, 4], 2) => [[0, 1], [2, 3], [4]]
*/

// Regularize values into chunks of a certain size
iterating.rebatch(iterable: Iterable<T[]>): AsyncIterable<T>
/*
  iterating.rebatch([[0, 1, 2], [3], [4]], 2) => [[0, 1], [2, 3], [4]]
*/

Promising

Renamed promise functions from sindresorhus and wbinnssmith.

import { promising } from 'kahn'

/* Create */

// Converts a callback function to a promise
promising.Callback(func: () => Promise<T>): Promise<T>

// Create a mutex
promising.Mutex()
/*
  const mutex = promising.Mutex();
  const sharedArray = [];
  async function addToSharedArray(item) {
    await mutex.withLock(async () => {
      const item = await getItem();
      sharedArray.push(item);
    });
  }
*/

// Memoize promise-returning & async functions
promising.Memoize(func: () => Promise<T>): () => Promise<T>

// create a promise that can be canceled
promising.Cancelable<T>(promise: Promise<T>): CancelablePromise<T>

// Create a lazy promise that defers execution until it's awaited
// or when .then() or .catch() is called
promising.Lazy<T>(func: () => Promise<T>): LazyPromise<T>

// Returns a promise resolved in the next event loop - think setImmediate()
promising.Immediately<T>(func: () => Promise<T>): Promise<T>

// Promise queue with concurrency control
promising.Queue<T>(concurrency: number): Queue<T>

// Wait for the next emission in the stream
promising.Listen<T>(stream: AsyncIterable<T>, event: string): Promise<T>
/*
  const result = await promising.Listen(emitter, 'finish');
*/

// Run multiple promise-returning & async functions with limited concurrency
promising.Limit<T>(concurrency: number, tasks: Function[]): Promise<T[]>
/*
const limit = promising.Limit(1);

const input = [
	limit(() => fetchSomething('foo')),
	limit(() => fetchSomething('bar')),
	limit(() => doSomething())
];

// Only one promise is run at once
const result = await Promise.all(input);
*/

// rate limit a promise
promising.Throttle<T>(func: () => Promise<T>, limit: number, interval: number): Promise<T>
/*
const throttle = promising.Throttle({
	limit: 2,
	interval: 1000
});
const throttled = throttle(async index => {...});
*/

/* Flow */

// Compose promise-returning & async functions into a reusable pipeline
promising.pipe(source: () => Promise<T>, ...sinks: Function[]): () => Promise<T>

// Run promise-returning & async functions in series, each passing its result to the next
promising.chain(tasks: Function[]): () => Promise<T>

// While a condition returns true, calls a function repeatedly, and then resolves the promise
promising.while(condition: () => boolean, func: () => Promise<T>): Promise<T>

// Run promise-returning & async functions until you end it with .end()
promising.forever(condition: () => boolean, func: () => Promise<T>): Promise<T>

// Start a promise chain without needing an initial promise
promising.then(func: () => Promise<T>): Promise<T>

// Run promise-returning & async functions in series
promising.serial(tasks: Function[]): Promise<T>

// Break out of a promise chain, returning a value
promising.break(value: any): Promise<T>
/*
  getData()
    .then(promising.break('done'))
    .catch(promising.break.end)
*/

// Conditional promise chains, for use inside .then()
promising.if(condition: () => boolean, func: () => Promise<T>): Promise<T>
/*
  getData()
    .then(promising.if(process.env.NODE_ENV !== 'production', addDebugInfo))
*/

// Tap into a promise chain without affecting its value or state
promising.peek(func: () => void): Promise<T>
/*
  getData()
    .then(promising.peek(console.log)) // logs the data
    .then(doSomething)
*/

// Log the value/error of a promise, shortcut for peek(console.log)
promising.log(): Promise<T>

// Check if a value is a promise
promising.isPromise(value: any): boolean

/* Mapping */

// Map over promises concurrently
promising.map<T>(iterable: Iterable<T>, func: (item: T) => Promise<T>, options: {concurrency: number}): Promise<T[]>
/*
  await promising.map(sites, mapper, {concurrency: 2});
*/

// Run multiple promises concurrently and keep track of the fulfilled values by name
promising.props(promises: { [key: string]: Promise<T> }): Promise<{ [key: string]: T }>

// Have a promise to fulfill no matter what
promising.anyways<T>(promise: Promise<T>, fallback: T): Promise<T>
/*
const promises = [...];
const results = await Promise.all(promises.map(promising.anyways));
*/

// Filter out values that don't satisfy a condition
promising.filter<T>(iterable: Iterable<T>, func: (item: T) => Promise<boolean>, options: {concurrency: number}): Promise<T[]>

// Reduce a list of values using promises into a promise for a value
promising.reduce<T, U>(iterable: Iterable<T>, func: (acc: U, item: T) => Promise<U>, initialValue: U): Promise<U>

// Create an array of the results of a list of promises
promising.list<T>(iterable: Iterable<Promise<T>>): Promise<T[]>
/*
const promises = [...]
console.log(await promising.collect(files));
*/

// Apply a function to each item in the iterable
promising.apply<T>(source: Iterable<T>, func: (item: T) => Promise<void>): Promise<void>

// Run promise-returning & async functions a specific number of times concurrently
promising.times<T>(count: number, func: () => Promise<T>): Promise<T[]>

/* Resolving */

// Wait for all promises to be resolved
promising.collect<T>(iterable: Iterable<Promise<T>>): Promise<T[]>

// get the first promise that resolves
promising.first<T>(iterable: Iterable<Promise<T>>): Promise<T>

// get the first n promises that resolve
promising.firstCount<T>(iterable: Iterable<Promise<T>>, n: number): Promise<T[]>

// Get the first fulfilled promise that satisfies the provided testing function
promising.firstMatch<T>(iterable: Iterable<Promise<T>>, func: (item: T) => boolean): Promise<T>

/* Timing */
// Retries a promise a number of times
promising.retry<T>(func: (attemptCount: number) => PromiseLike<T> | T, options?: Options): Promise<T>

// Wait for a promise to resolve, with a timeout
promising.wait(milliseconds: number): Promise<T>

// debounce a promise
promising.debounce<T>(func: () => Promise<T>, wait: number): Promise<T>

// timeout a promise
promising.timeout<T>(promise: Promise<T>, milliseconds: number): Promise<T>

// Wait for a condition to be true
promising.when(condition: () => boolean, options?: Options): Promise<void>

// Delay a promise a minimum amount of time
promising.delay<T>(promise: Promise<T>, milliseconds: number): Promise<T>

// Measure the time a promise takes to resolve
promising.time<T>(promise: Promise<T>): Promise<{ value: T, time: number }>k

Constants

// Bytes
export const B = 1
export const KB = 1024
export const MB = 1024 * KB
export const GB = 1024 * MB
export const TB = 1024 * GB
export const PB = 1024 * TB

// Time
export const NS = 1
export const MS = 1
export const SECONDS = 1000 * MS
export const MINUTES = 60 * SECONDS
export const HOURS = 60 * MINUTES
export const DAYS = 24 * HOURS
export const WEEKS = 7 * DAYS
export const YEARS = 365 * DAYS

Types

// Comparison
enum Comparison {
  LessThan = -1,
  Equal = 0,
  GreaterThan = 1,
}
export enum Ternary {
  False = -1,
  Unknown = 0,
  True = 1,
}

// Time
export type Nanoseconds = number
export type Milliseconds = number
export type Seconds = number
export type Minutes = number
export type Hours = number
export type Days = number
export type Weeks = number
export type Years = number