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

@apie/pipe

v2.4.2

Published

A stateful pipe that pipes functions that has an object and the output from previous function

Downloads

251

Readme

What is @apie and @apie/pipe?

An eco-system for infrastructure around REST API. It's worth noting that it is designed so that it can be used in all applications besides a REST API.

@apie/pipe provides a way to create a pipe-function that has an event input. An event is considered a stateful object, that is passed through all functions, inspired by SvelteKits RequestEvent. This provides dependency injection and access to important information for each eventful trigger.

That means, this is useful for any serverless-functions, such as AWS lambdas etc.

createEventPipe<T> options

| Option | Description | Type | | ---- | ---- | ---- | | before? | Functions that will be run before the pipeline | MaybeArray<(event: T) => unknown> | | after? | Functions that will be run before the pipeline(does not run if an exception is thrown) | MaybeArray<(event: T, result: unknown) => unknown> | | finally? | Functions that will be run before the pipeline | MaybeArray<(event: T, result?: unknown, error?: unknown) => unknown> | | catch? | A function that returns a response in relation to an error being thrown(default: throw error) | catch?(event: T, error: unknown): APIResponse |

Pipes and pipelines

A pipe a function that accepts an array functions. These functions may look like

(state: T, input: any) => any

The state/event defines requirements. An example of such a state/event is SvelteKit's RequestEvent We define the state upon creating the pipe:

import { createEventPipe } from '@apie/pipe'

type State = {
	value: number
}

const pipe = createEventPipe<State>()

Now each function inside the pipe will have access to State:

const pipeline = pipe(
	(state) => {
		console.log(state.value)
		return state.value * 2
	},
	(state, input) => {
		console.log(input)
		return input * 2
	}
)

const result = pipeline({ value: 2 })
// result: 2 * 2 * 2 = 8

A pipeline requiring an input

For consistency, you can create functions by using your pipe with just one function

const double = pipe((state) => state.value * 2)
double({ value: 2 }) // 4

If we want to multiple it by an arbitrary number, we can define the input:

const multiply = pipe((state, input: number) => state.value * input)
multiply({ value: 5 }, 2) // 10

Returning Early

Our pipelines are designed around HTTP Responses. That means, if you EVER return an HTTP Response using @apie/responses, then the pipeline will exit early, resulting in that response.

import { OK } from '@apie/responses'

const fn = pipe(
	() => {
		return OK('Hi mom')
	},
	() => {
		// This will never run
		while(true) {}
	}
)

const result = fn({ value: 2 }) // OK<'Hi mom'>

Nesting Pipes

Sometimes we might want to re-use variables across multiple operations within our pipe.

In this example we use (e,v) => pipe(...) to access the variable v, within our pipe function.

const Input = z.object({...})
const $bulkWriter = createBulkWriter(...)

const pipeline = pipe( 
	zodValidator(Input), 
	(e, v) => arrayChanges(
		v.existingDocuments, 
		v.updatedDocuments, 
		t => t._id?.toString()
	),
	(e, v) => pipe(
		v.newEntries,
		$bulkWriter.insertMultiple,
		
		v.removedEntries.map(v => v._id),
		$bulkWriter.updateMany(
			v => ({ 
				filter: { _id: { $in: v } }, 
				update: { _status: 'archived' } 
			})
		),
		
		v.persistedEntries,
		$bulkWriter.updateMultiple(
			v => ({ 
				filter: { _id: v._id }, 
				update: { name: v.name } 
			})
		)
	),
	$bulkWriter.execute()
)

Re-using a result of a function

Okay, let's say you want to re-use a result, but … we can't really declare variables here, can we?

Introducing… saveResult

import { saveResult } from '@apie/pipe'

const multiply = pipe((state, input: number) => state.value * input)

const [$multiply, get$multiply] = saveResult(multiply)

const pipeline = pipe(
	2,
	$multiply,
	(state, input: number) => {
		// ...
	},
	// ... Functions later
	(state) => OK(get$multiply(state))
)

const result = pipeline({ value: 3 }) // OK<number> -> body: 6

The result is saved within the state, so by referencing the state later, we can get access to the value.

If you use $multiply again, then it returns the past result it resolved, rather than re-initializing.