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 🙏

© 2025 – Pkg Stats / Ryan Hefner

ocev

v0.25.0

Published

event library support promise/stream and can proxy all web element

Downloads

39

Readme

Jest coverage github workflow typescript license npm

What is ocev

ocev is an event library designed to simplify the complexity of event processing. while supporting promise/stream to handle events.

supporting all events of proxy web elements, and processing with ocev api.

all api are maximized support typescript, providing the most complete type prompt

Install

npm install ocev
# or
yarn add ocev
# or
pnpm i ocev

Basic Usage

import { SyncEvent } from "ocev"

// define event type
type EventHandlerMap = {
  event1: (arg1: string, arg2: number) => void
  event2: (arg1: number, arg2: string) => void
}

const syncEvent = SyncEvent.new<EventHandlerMap>()

queueMicrotask(() => {
  syncEvent.emit("event1", "1", 2)
  syncEvent.emit("event2", 3, "4")
})

// register
const cancel = syncEvent
  .on("event1", (arg1, arg2) => {})
  .once("event2", (arg1, arg2) => {})
  .on("event1", (arg1, arg2) => {}, {
    debounce: {
      waitMs: 200,
      maxWaitMs: 500,
    },
  })

// cancel()

// waitUtil event emit
await syncEvent.waitUtil("event1")

// create event stream
const eventStream = syncEvent.createEventStream(["event1", "event2"])

What can ocev do

From the above example, you can see that ocev is essentially a (pub/sub) library, but ocev can also proxy all events of web element, and use ocev to handle all events with promise/stream.

ocev has two class,SyncEvent,EventProxy, the following example is mainly based on EventProxy

1. Simplified Web Event Handling

I've always felt that web event handling is too complex, and if you're using react, you're probably going to write this code. I have written a lot of template code like this, it is very complicated

useEffect(() => {
  const callback = () => {}

  target.addEventListener("event", callback) // any event target

  return () => {
    target.removeEventListener("event", callback)
  }
}, [target])

for multiple events

useEffect(() => {
  const callback1 = () => {}
  target.addEventListener("event1", callback1)

  const callback2 = () => {}
  target.addEventListener("event2", callback2)
  // ....
  return () => {
    target.removeEventListener("event1", callback1)
    target.removeEventListener("event2", callback2)
    // ....
  }
}, [target])

You have to clean up as many as you register, which is very cumbersome to write.

If you are using ocev, your code will be something like this, infinite calls, one-time cleanup

import { EventProxy } from "ocev"

useEffect(() => {
  return EventProxy.new(target)
    .on("event1", (...args) => {}) // type hint!
    .once("event2", (...args) => {})
    .on("event3", (...args) => {})
}, [target])

ocev's method on/once returns a clean function, which can be called once,on as an object. For more details, please see the documentation.

all examples in current section base on EventProxy, EventProxy is wrapper of SyncEvent, more detail see documentation.

2. Promise/Stream

Consider a scenario where you want to establish a websocket connection, wait for the connection to open, set the maximum wait time for the connection, and then handle messages and exceptions. To ensure the correct release of resources, you might write the following code

async function setupWebSocket(
  url: string,
  successCallback: (ws: WebSocket) => void,
  errorCallback: (err: Error) => void,
  timeout: number
) {
  const ws = new WebSocket(url)

  const timeID = setTimeout(() => {
    errorCallback(new Error("timeout"))
    ws.removeEventListener("open", onOpen)
    ws.removeEventListener("error", onError)
  }, timeout)

  function onOpen() {
    successCallback(ws)
    clearTimeout(timeID)
  }

  function onError() {
    errorCallback(new Error("can't connect to server"))
    clearTimeout(timeID)
  }

  ws.addEventListener("open", onOpen)
  ws.addEventListener("error", onError)
}

ocev supports Promise to handle events. If you use ocev to handle events, the code will be like this

 import { EventProxy } from "ocev"

async function setupWebSocket(url: string, timeout: number) {
  const ws = new WebSocket(url)
  //  Wait for the 'open' event to trigger or timeout throws an exception
  await EventProxy.new(ws).waitUtil("open", { timeout })
  //  or Race waits for either an 'open' event or an 'error' to trigger first see docs
  //  await EventProxy.new(ws).waitUtilRace([
  //     { event: "open", timeout },
  //     { event: "error",
  //       mapToError: () => new Error("websocket connect error"),
  //     },
  //   ])

  return ws
}

Promise makes event handling simple and elegant, and using Promise to process code makes logic clearer

Take it a step further and see how to implement message processing (Stream) with ocev

import { EventProxy } from "ocev"

async function setupWebSocket(url: string, timeout: number) {
  const ws = EventProxy.new(new WebSocket(url))

  await ws.waitUtilRace([
    { event: "open", timeout },
    {
      event: "error",
      mapToError: () => new Error("websocket connect error"),
    },
  ])

  // convert to Event Stream
  const eventStream = ws.createEventStream(["close", "message", "error"])
  // another way(ReadableStream)
  // const readableStream = ws.createEventReadableStream(["close", "message", "error"])

  // all events are pushed into a queue
  for await (const { event, value } of eventStream) {
    switch (event) {
      case "error": {
        throw Error("websocket connect error")
      }
      case "close": {
        throw Error("websocket connection closed")
      }
      case "message": {
        // support type prompt
        const message = value[0].data
        // handle message
        break
      }
      default:
        throw new Error("unreachable")
    }
  }
}

With asyncIterator, you can convert events into stream, and you can use the strategy to drop messages when faced with backpressure

With Promise/Stream, when you convert all the code to async/await, you can handle the reconnection logic like this

let reconnectCount = 0
for (;;) {
  try {
    await setupWebSocket("", 1000)
  } catch (error) {
    reconnectCount += 1
  }
}

If you want to establish a WebRTC connection, you can use where

import { EventProxy } from "ocev"

async function connect(timeout: number) {
  const connection = new RTCPeerConnection()

  await EventProxy.new(connection).waitUtil("connectionstatechange", {
    timeout,
    // resolve when where return true
    where: (ev) => connection.connectionState === "connected",
  })

  return connection
}

Observe all the events of a web object

Do you know what events video triggers when it plays?

import { EventProxy } from "ocev"
// 或者  EventProxy.new(videoDom).proxyAllEvent()
EventProxy.new(videoDom, { proxyAllEvent: true }).any((eventName, ...args) => {
  console.log(eventName)
})

real example in react

import { EventProxy } from "ocev"
import { useEffect, useRef } from "react"

function Video() {
  const videoDomRef = useRef<HTMLVideoElement>(null)
  useEffect(() => {
    return EventProxy.new(videoDomRef.current!, { proxyAllEvent: true }).any((eventName, ...args) => {
      console.log(eventName)
    })
  }, [])

  const url = "" // your  video  link

  return <video muted autoPlay src={url} ref={videoDomRef} />
}

open the console and you will see the order of all the 'video' events

Almost all web elements can be proxied by EventProxy. codesandbox example

More

If you want to know more about EventProxy and SyncEvent, see docs