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

fearless-io

v16.2.1

Published

A type-safe functional module that solves practical IO problems for node and the browser.

Downloads

71

Readme

Build Status npm

A type-safe, functional, performant, lawful, composable data structure that solves practical problems of effect-full code in node and browser.

Index

Installation

npm i fearless-io

Usage

import {IO, defaultRuntime} from 'fearless-io'

// Create a pure version of `console.log` called `putStrLn`
const putStrLn = IO.encase((str: string) => console.log(str))

const hello = putStrLn('Hello World!')

const runtime = defaultRuntime()
runtime.unsafeExecute(hello)

Getting Started

Type Signature

interface FIO<R, E, A> {
  // ... Operators
}

FIO takes in three type params viz. —

  1. R Represents the type of environment needed to execute this IO (more).
  2. E The error types that can be emitted while this IO is executing.
  3. A The type of the success value that will be emitted by the IO on completion.

Using these three type params you can fairly represent any side-effect. For example lets say there is function Greet which simply prints "Hello World" —

  const Greet = () => console.log('Hello World!')

To represent Greet

  1. R could be unknown: since console.log works everywhere.
  2. E could be never: Printing anything on console never fails.
  3. A could be void: The output of running the program is basically nothing.
const GreetIO: FIO<unknown, never, void>

Creating a FIO

There are multiple ways through which you can create an instance of FIO viz. FIO.from or FIO.encase etc. Refer to the API documentation to learn about all the ways.

Once of the easiest ways to create a FIO is through FIO.encase.

+ import {FIO} from 'fearless-io'

  const Greet = () => console.log('Hello World!')
+ const GreetIO = FIO.encase(Greet)

Calling GreetIO() returns a pure data structure which represents a side-effect, that —

  1. Can execute in any environment without any special needs.
  2. Never fails.
  3. Resolves with a void.

Executing FIO

Execution of FIO happens through a Runtime.

- import {FIO} from 'fearless-io'
+ import {FIO, defaultRuntime} from 'fearless-io'

  const Greet = () => console.log('Hello World!')
  const GreetIO = FIO.encase(Greet)
+ defaultRuntime().unsafeExecute(GreetIO())

Serial Execution

Since these data structures don't specify how or when they are going to be executed, writing them one after the other in procedural style will not guarantee any order of execution, for Eg —

+  import {FIO} from 'fearless-io'
+  const putStrLn = FIO.encase((msg: string) => console.log(msg))
+
+  const foo = putStrLn('foo')
+  const bar = putStrLn('bar')

In the above code either foo or bar can be printed first depending on internal prioritization and scheduling algorithms that FIO uses. To ensure that foo is printed first and bar is printed second one must use the and operator.

  import {FIO} from 'fearless-io'
  const putStrLn = FIO.encase((msg: string) => console.log(msg))

  const fooIO = putStrLn('foo')
  const barIO = putStrLn('bar')

+ const fooBar = fooIO.and(barIO)

fooBar is a new FIO object of type FIO<unknown, never, void>.

- import {FIO} from 'fearless-io'
+ import {FIO, defaultRuntime} from 'fearless-io'
  const putStrLn = FIO.encase((msg: string) => console.log(msg))

  const fooIO = putStrLn('foo')
  const barIO = putStrLn('bar')

  const fooBar = fooIO.and(barIO)
+ defaultRuntime().unsafeExecute(fooBar)

Parallel Execution

Similar to the and operator, the par operator runs the two IOs in parallel. For eg.

Create the two IOs

+  import {FIO} from 'fearless-io'
+
+  const foo = FIO.timeout('foo', 1000)
+  const bar = FIO.timeout('bar', 1500)

Combine them using par

- import {FIO} from 'fearless-io'

  const foo = FIO.timeout('foo', 1000)
  const bar = FIO.timeout('bar', 1500)
+ const fooBar = foo.par(bar)

Execute the created IO

- import {FIO} from 'fearless-io'
+ import {FIO, defaultRuntime} from 'fearless-io'

  const foo = FIO.timeout('foo', 1000)
  const bar = FIO.timeout('bar', 1500)
  const fooBar = foo.zip(bar)

+ defaultRuntime().unsafeExecute(fooBar)

The program fooBar will complete in 1500ms because both are executed in parallel.

Other more powerful operators can be found at API Documentation.

Cancellation

Executing an IO returns a cancel callback. Essentially a function that when called, aborts the IO from any further execution and synchronously releases all the acquired resources.

Create an IO

+ import {FIO} from 'fearless-io'
+ const delayIO = FIO.timeout('Hello World', 1000)

Execute by passing it to defaultRuntime

- import {FIO} from 'fearless-io'
+ import {FIO, defaultRuntime} from 'fearless-io'
  const delayIO = FIO.timeout('Hello World', 1000)
+ const cancel = defaultRuntime().unsafeExecute(delayIO)

Calling the cancelling callback.

  import {FIO, defaultRuntime} from 'fearless-io'
  const delayIO = FIO.timeout('Hello World', 1000)
  const cancel = defaultRuntime().execute(delayIO)
+ cancel()

As soon as cancel is called internally the timeout is cancelled.

Custom Environment

By default any FIO instance would not need any env. This can be customized based on what the program needs to perform. For example, if a program needs to read a config and print out the port set in it one could do something like this —

Config

Say we already have a Config interface, with only one property —

+ interface Config {
+   port: number
+ }

ConfigEnv

Next we create an Environment that returns a config

  interface Config {
    port: number
  }
+ interface ConfigEnv {
+   config: Config
+ }

Helper functions

We add getPort which picks the port and putStrLn which is a wrapper over console.log to make it pure.

+ import {FIO} from 'fearless-io'
  interface Config {
    port: number
  }
  interface ConfigEnv {
    config: Config
  }
+ const getPort = FIO.access((config: Config) => config.port)
+ const putStrLn = FIO.encase((message: string) => console.log(message))

Create program

Using the chain operator one can now chain them one after the other —

  import {FIO} from 'fearless-io'
  interface Config {
    port: number
  }
  interface ConfigEnv {
    config: Config
  }
  const getPort = FIO.access((config: Config) => config.port)
  const putStrLn = FIO.encase((message: string) => console.log(message))

+ const program = getPort().chain(putStrLn)

Provide Env

You can provide the env directly to a FIO instance without executing it using the provide method.

  import {FIO} from 'fearless-io'
+ import config from 'node-config'
  interface Config {
    port: number
  }
  interface ConfigEnv {
    config: Config
  }
  const getPort = FIO.access((config: Config) => config.port)
  const putStrLn = FIO.encase((message: string) => console.log(message))

  const program = getPort().chain(putStrLn)

+ const env = {
+   config: config
+ }
+ const program0 = program.provide(env)

Running the program

Running the program can be done by using the runtime.

- import {FIO} from 'fearless-io'
+ import {FIO, defaultRuntime} from 'fearless-io'
  import config from 'node-config'
  interface Config {
    port: number
  }
  interface ConfigEnv {
    config: Config
  }
  const getPort = FIO.access((config: Config) => config.port)
  const putStrLn = FIO.encase((message: string) => console.log(message))

  const program = getPort().chain(putStrLn)

  const env = {
    config: config
  }
  const program0 = program.provide(env)
+ defaultRuntime().unsafeExecute(program0)

Next Steps

Checkout a fully functional example here.

Credits

FIO is heavily inspired by the following libraries —