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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@davis7dotsh/river-alpha

v0.3.0

Published

a trpc like experience for agents and streams

Downloads

23

Readme

river - 0.3.0

an experiment by ben davis that went WAY too far...

[!WARNING] As I said, this is alpha software that's gonna change. This is a new version from the original with almost entirely new api's. Expect this to happen again in 0.4.0...

it's TRPC, but for agents/streams...

<script lang="ts">
	import { myRiverClient } from '$lib/river/client';

	// ALL of this is type safe, feels just like TRPC
	const { start, stop, status } = myRiverClient.basicExample({
		onStart: () => {
			console.log('starting basic example');
		},
		onChunk: (chunk) => {
			// full type safety on the chunks
			console.log(chunk);
		},
		onError: (error) => {
			console.error(error);
		},
		onSuccess: () => {
			console.log('Success');
		},
		onCancel: () => {
			console.log('Canceled');
		},
		onStreamInfo: (streamInfo) => {
			console.log(streamInfo);
		}
	});
</script>
bun i @davis7dotsh/river-alpha

this is alpha software, use it at your own risk. api's will change, bugs will be fixed, features will be added, etc...

what you get

  • full type safety
  • rpc-like function calling
  • trpc mutation like interface for consuming the streams
  • ai sdk streaming support with full stack type safety
  • custom stream support with zod validation on chunks

this project does actually work right now, but it is very early in development and NOT recommended for production use. it is in alpha, the apis will change a lot...

getting started using the package

if you want to try this out, it's now available on npm!

here are a couple of examples, they're both are fully type safe, are pleasant to work in, and work great: check them out

here's a quick getting started guide for custom streams

  1. create a new sveltekit project (if you don't have one already)
bunx sv create river-demo
  1. install dependencies
bun i @davis7dotsh/river-alpha zod
  1. setup your first stream
// src/lib/river/streams.ts
import { RIVER_STREAMS } from '@davis7dotsh/river-alpha';
import { z } from 'zod';

export const myFirstNewRiverStream = RIVER_STREAMS.createRiverStream()
	.input(
		z.object({
			yourName: z.string()
		})
	)
	.runner(async (stuff) => {
		const { input, initStream, abortSignal } = stuff;

		const activeStream = await initStream(
			// this is where the type safety happens, the generic type is the chunk type
			RIVER_PROVIDERS.defaultRiverStorageProvider<{
				isVowel: boolean;
				letter: string;
			}>()
		);

		const { yourName } = input;

		activeStream.sendData(async ({ appendChunk, close }) => {
			const letters = yourName.split('');
			const onlyLetters = letters.filter((letter) => letter.match(/[a-zA-Z]/));
			for await (const letter of onlyLetters) {
				if (abortSignal.aborted) {
					break;
				}
				appendChunk({ isVowel: !!letter.match(/[aeiou]/i), letter });
				await new Promise((resolve) => setTimeout(resolve, 100));
			}
			close();
		});

		return activeStream;
	});
  1. setup your router
// src/lib/river/router.ts
import { RIVER_STREAMS } from '$lib/river/streams.js';
import { myFirstNewRiverStream } from './streams.js';

export const myFirstRiverRouter = RIVER_STREAMS.createRiverRouter({
	vowelCounter: myFirstNewRiverStream
});

export type MyFirstRiverRouter = typeof myFirstRiverRouter;
  1. setup the endpoint
// src/routes/api/river/+server.ts
import { RIVER_SERVERS } from '$lib/river/server.js';
import { myFirstRiverRouter } from './router.js';

export const { POST } = RIVER_SERVERS.createSvelteKitEndpointHandler(myFirstRiverRouter);
  1. setup the client
// src/lib/river/client.ts
import { RIVER_CLIENT_SVELTEKIT } from '$lib/index.js';
import type { MyFirstRiverRouter } from './router.js';

export const myFirstRiverClient =
	RIVER_CLIENT_SVELTEKIT.createSvelteKitRiverClient<MyFirstRiverRouter>('/examples');
  1. use your agent on the client with a client side caller
<!-- src/routes/+page.svelte -->
<script lang="ts">
	import { myFirstRiverClient } from '$lib/river/client.js';

	// this works just like mutations in trpc, it will not actually run until you call start
	// the callbacks are optional, and will fire when they are defined and the agent starts
	const { start, stop, status } = myFirstRiverClient.vowelCounter({
		onStart: () => {
			console.log('Starting');
		},
		onChunk: (chunk) => {
			console.log(chunk);
		},
		onError: (error) => {
			console.error(error);
		},
		onSuccess: () => {
			console.log('Success');
		},
		onCancel: () => {
			console.log('Canceled');
		},
		onStreamInfo: (streamInfo) => {
			console.log(streamInfo);
		}
	});
</script>

<!-- some UI to to consume and start the stream -->

project info

why make this?

  • streams went from something you touch every once and a while, to something we're using all the time
  • i want typesafety
  • mutations are awesome in tanstack query, i want them for streams
  • rpc >>>>>>
  • streams are a pain to consume out of the box (readers and encoders and raw fetch and type casting and more annoying shit)

helper types

these are a few helper types that really help with getting good type safety in your clients. the names are a bit verbose, but at least they're descriptive...

// AI SDK SPECIFIC HELPERS (for agents using Vercel AI SDK)

// gets the "tool set" type (a record of tool names to their tool types) for an ai-sdk agent
type AiSdkAgentToolSet = RiverAiSdkToolSet<typeof riverClient.exampleAiSdkAgent>;

// gets the input type for a tool call for an ai-sdk agent. pass in the tool set type and the tool name
type ImposterToolCallInputType = RiverAiSdkToolInputType<AiSdkAgentToolSet, 'imposterCheck'>;

// gets the output type for a tool call for an ai-sdk agent. pass in the tool set type and the tool name
type ImposterToolCallOutputType = RiverAiSdkToolOutputType<AiSdkAgentToolSet, 'imposterCheck'>;

// GENERAL HELPERS (for any agent)

// gets the chunk type for an agent (the thing passed to the onChunk callback)
type AgentChunkType = RiverStreamChunkType<typeof riverClient.exampleAgent>;

// gets the input type for an agent (the thing passed to the start function)
type AgentInputType = RiverStreamInputType<typeof riverClient.exampleAgent>;

// SERVER SIDE HELPERS (for use in your agent definitions)

// infers the chunk type from an AI SDK stream (useful for typing your storage provider)
type AiSdkChunkType = InferAiSdkChunkType<typeof fullStream>;

if you have feedback or want to contribute, don't hesitate. best place to reach out is on my twitter @bmdavis419