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

@someimportantcompany/utils

v1.3.1

Published

A collection of handy utility functions for you & your projects.

Downloads

7

Readme

@someimportantcompany/utils

NPM Test Typescript

A collection of handy utility functions for you & your projects.

Install

$ npm install --save @someimportantcompany/utils
# or
$ yarn add @someimportantcompany/utils

Functions

To import each function, import/require as needed:

import { assert } from '@someimportantcompany/utils';
// or
const { assert } = require('@someimportantcompany/utils');

assert

Shorthand assertion function, based on http-assert-plus but with none of the additional logic or HTTP status code support.

export function assert(
  condition: any,
  err: Error | string | unknown,
  opts?: Record<string, any> | undefined,
): asserts condition;
import { assert } from '@someimportantcompany/utils';

assert(value, new Error('An error occurred'));
assert(value, 'An error occurred');

try {
  const a = 1;
  assert(a === 2, 'Something bad happened');
} catch (err) {
  assert(false, err, { something: 'bad' });
}

promiseEachSeries

Loop over an array in sequence - supporting async functions. A functional cross between Promise.map & Array.prototype.forEach, which iterates in-sequence rather than in-parallel.

export function promiseEachSeries<T>(
  items: T[],
  eachFn: (item: T, i: number, items: T[]) => (void | Promise<void>),
): Promise<void>;
import { promiseEachSeries } from '@someimportantcompany/utils';

const urls = [
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/README.md',
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/LICENSE.md',
];

const results = [];

await promiseEachSeries(urls, async url => {
  const res = await fetch(url);
  results.push(await res.text());
});

promiseMapSeries

Map an array in sequence - supporting async functions. A functional cross between Promise.map & Array.prototype.map, which iterates in-sequence rather than in-parallel.

export function promiseMapSeries<T, U>(
  items: T[],
  mapFn: (item: T, i: number, items: T[]) => (U | Promise<U>),
): Promise<U[]>;
import { promiseMapSeries } from '@someimportantcompany/utils';

const urls = [
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/README.md',
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/LICENSE.md',
];

const results = await promiseMapSeries(urls, async url => {
  const res = await fetch(url);
  return await res.text();
});

promiseReduceSeries

Map an array in sequence - supporting async functions. A functional cross between Promise.map & Array.prototype.reduce, which iterates in-sequence rather than in-parallel.

export function promiseReduceSeries<T>(
  items: T[],
  reduceFn: (acc: T, item: T, i: number, items: T[]) => (T | Promise<T>),
): Promise<T>;
export function promiseReduceSeries<T, U>(
  items: T[],
  reduceFn: (acc: U, item: T, i: number, items: T[]) => (U | Promise<U>),
  initialValue: U,
): Promise<U>;
import { promiseReduceSeries } from '@someimportantcompany/utils';

const urls = [
  '',
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/README.md',
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/LICENSE.md',
];

const results = await promiseReduceSeries(urls, async (list, url) => {
  const res = await fetch(url);
  return list + (await res.text());
});
import { promiseReduceSeries } from '@someimportantcompany/utils';

const urls = [
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/README.md',
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/LICENSE.md',
];

const results = await promiseReduceSeries(urls, async (list, url) => {
  const res = await fetch(url);
  return list.concat([ await res.text() ]);
}, []);
  • You can optionally pass an initialValue for your reducing function.

promiseAllSettled

Loop through all promises with Promise.allSettled, throw an error if one or more rejected.

export function promiseAllSettled<T>(
  input: Iterable<T | PromiseLike<T>>,
): Promise<Awaited<T>[]>;
import { assert, promiseAllSettled } from '@someimportantcompany/utils';

const urls = [
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/README.md',
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/LICENSE.md',
];

const results = await promiseAllSettled(urls.map(async (url, i) => {
  const res = await fetch(url);
  assert(i === 0, new Error('An error occurred with promiseAllSettled'));
  return await res.text();
}));

// First URL will throw an error, but the other one will fetch successfully
// But then the assert error will be thrown cleanly.
import { assert, promiseAllSettled, PromiseSettledManyErrors } from '@someimportantcompany/utils';

const urls = [
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/README.md',
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/LICENSE.md',
  'https://raw.githubusercontent.com/someimportantcompany/utils/main/package.json',
];

const results = await promiseAllSettled(urls.map(async url => {
  const res = await fetch(url);
  assert(url.endsWith('.json'), new Error('An error occurred with promiseAllSettled'));
  return await res.text();
}));

// The first two URLs will throw an error, but the final one will fetch successfully
// But then the PromiseSettledManyErrors error will be thrown cleanly
// With both errors under `err.inner`

createHashMd5

Hash a string or Buffer with MD5.

export function createHashMd5(input: string | Buffer): string
import { createHashMd5 } from '@someimportantcompany/utils';

const value = createHashMd5('hello world');
// value === '6f5902ac237024bdd0c176cb93063dc4'
const value = createHashMd5(Buffer.from('hello world', 'utf8'));
// value === '6f5902ac237024bdd0c176cb93063dc4'

createHashSha1

Hash a string or Buffer with Sha1.

export function createHashSha1(input: string | Buffer): string
import { createHashSha1 } from '@someimportantcompany/utils';

const value = createHashSha1('hello world');
// value === '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'
const value = createHashSha1(Buffer.from('hello world', 'utf8'));
// value === '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'

createHashSha256

Hash a string or Buffer with Sha256.

export function createHashSha256(input: string | Buffer): string
import { createHashSha256 } from '@someimportantcompany/utils';

const value = createHashSha256('hello world');
// value === 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
const value = createHashSha256(Buffer.from('hello world', 'utf8'));
// value === 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'

attempt

Attempt to execute a function, returning null if it throws. Optionally retry a fixed number of times.

export function attempt<T>(
  fn: () => T,
  retries?: number,
): T | null;
export function attempt<T>(
  fn: () => Promise<T>,
  retries?: number,
): Promise<T> | null;
import { assert, attempt } from '@someimportantcompany/utils';

const value = attempt(() => 1 + 1);
// value === 2

const value = attempt(() => {
  assert(Math.random() > 0.5, new Error('Errors half the time (ish)'));
  return 5;
}, 3);
// value === 5 || value === null
// Depending on if the `assert` call throws the error 3 times in a row
  • If you pass an async function or a function that returns a Promise, you'll need to await attempt(...). Otherwise, you can freely drop the extra await.

tryCatch

Attempt to execute a function, and should it throw transform the error before returning. By default, if an error throws then null is returned.

export function tryCatch<T>(
  tryFn: () => T,
): T | null;
export function tryCatch<T>(
  tryFn: () => Promise<T>,
): Promise<T | null>;
export function tryCatch<T>(
  tryFn: () => T,
  catchFn?: (err: any) => U,
): T | U;
export function tryCatch<T, U>(
  tryFn: () => Promise<T>,
  catchFn?: (err: any) => U,
): Promise<T | U>;
import { assert, tryCatch } from '@someimportantcompany/utils';

const value = tryCatch(() => 1 + 1);
// value === 2

const value = tryCatch(() => {
  assert(Math.random() > 0.5, new Error('Errors half the time (ish)'));
  return 5;
}, err => {
  err.title = 'An error occurred';
  throw err;
});
// value === 5 or throws

const value = tryCatch(() => {
  assert(Math.random() > 0.5, new Error('Errors half the time (ish)'));
  return 5;
}, err => {
  return 0;
});
// value === 5 or value === 0
  • If you pass an async function or a function that returns a Promise, you'll need to await tryCatch(...). Otherwise, you can freely drop the extra await.

wait

Using a Promise, wait a specific amount of milliseconds.

export function wait(timeout: number): Promise<void>;
import { wait } from '@someimportantcompany/utils';
await wait(1000); // 1s

// Pairs really well with ms
import ms from 'ms';
await wait(ms('5s'));

aesEncrypt/aesDecrypt

Encrypt/decrypt a string/Buffer using aes-256-ctr. Optionally transform the data before encrypting/decrypting.

export function aesEncrypt(
  key: string,
  plain: string,
): string;
export function aesEncrypt(
  key: string,
  plain: Buffer,
): Buffer;
export function aesEncrypt<T>(
  key: string,
  plain: T,
  transform: (input: T) => string,
): string;
export function aesEncrypt<T>(
  key: string,
  plain: T,
  transform: (input: T) => Buffer,
): Buffer;

export function aesDecrypt(
  key: string,
  encrypted: string,
): string;
export function aesDecrypt(
  key: string,
  encrypted: Buffer,
): Buffer;
export function aesDecrypt<T>(
  key: string,
  encrypted: string,
  transform: (input: string) => T,
): T;
export function aesDecrypt<T>(
  key: string,
  encrypted: Buffer,
  transform: (input: Buffer) => T,
): T;
import { aesEncrypt, aesDecrypt } from '@someimportantcompany/utils';

const key = 'FORTY_TWO';
const plain = 'It\'s an important and popular fact that things are not always what they seem.';
const encrypted = aesEncrypt(key, plain);
const decrypted = aesDecrypt(key, encrypted);
// decrypted === plain

import fs from 'fs'
const key = 'FORTY_TWO';
const plain = fs.readFileSync('./image.jpg');
const encrypted = aesEncrypt(key, plain);
const decrypted = aesDecrypt(key, encrypted);
// decrypted.toString('base64') === plain.toString('base64')

const key = 'FORTY_TWO';
const plain = {
  data: [
    'Space is big. Really big.',
    'You won\'t believe how vastly, hugely, mind-bogglingly big it is.',
  ],
  links: {
    wikiquote: 'https://en.wikiquote.org/wiki/The_Hitchhiker%27s_Guide_to_the_Galaxy_(film)',
  },
};
const encrypted = aesEncrypt(key, plain, JSON.stringify);
const decrypted = aesDecrypt(key, encrypted, JSON.parse);
// decrypted === plain

createAwsCloudwatchLogGroupUrl

Build a URL to a specific CloudWatch Log Group. Optionally set a filter/timeframe to help limit the number of logs loaded.

export function createAwsCloudwatchLogGroupUrl(params: {
  // Required, specify the `groupName`
  groupName: string,

  // Set the stream name to filter logs by a specific Log Stream, if known
  streamName?: string | undefined,
  // Set the AWS region, falls back to process.env.AWS_REGION or "us-east-1"
  region?: string | undefined,
  // Set a filter query (matching CloudWatch syntax) to filter logs on page load
  filterPattern?: string | undefined,

  // Pass two dates to automatically filter between two dates on page load
  between?: [Date, Date] | undefined,
  // Or pass a number of milliseconds to lazily build a window around "now"
  around?: number,
  // But note: `between`/`around` are mutually exclusive

  // Optionally overwrite the base CloudWatch Logs URL
  baseUrl?: string | undefined,
}): string;
const url = createAwsCloudwatchLogGroupUrl({
  groupName: '/ecs/my-service',
});
// https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups
// /log-group/$252Fecs$252Fmy-service/log-events

const url = createAwsCloudwatchLogGroupUrl({
  groupName: '/ecs/my-service',
  streamName: 'SOME-IDENTIFIER',
  around: 500,
});
// 'https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups
// /log-group/$252Fecs$252Fmy-service/log-events/SOME-IDENTIFIER
// $3Fstart$253D1688739366071$2526end$253D1688739367071

const url = createAwsCloudwatchLogGroupUrl({
  groupName: '/ecs/my-service',
  streamName: 'SOME-IDENTIFIER',
  filterPattern: '"REQUEST-ID"',
});
// https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups
// /log-group/$252Fecs$252Fmy-service/log-events/SOME-IDENTIFIER
// $3FfilterPattern$253D$252522REQUEST-ID$252522
  • Useful for error monitoring tools like Sentry or Slack alerts, especially where the environment doesn't natively support this out-of-the-box (e.g. AWS ECS).
  • You can pass a filterPattern if you attach a "request ID" to your logs.
  • If you're looking for a decent logger, check out bunyan.