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

@alivelabs/expo-orchestrator-react-client

v0.2.1

Published

React client for Expo CI Orchestrator — streaming logs, live simulator video, and interactive controls.

Downloads

200

Readme

@alivelabs/expo-orchestrator-react-client

React client for the Expo CI Orchestrator. Renders a live build session in the browser: streaming logs, live iOS simulator video, session status, and interactive controls (tap, swipe, type, keypress).

Install

npm install @alivelabs/expo-orchestrator-react-client
# peer deps
npm install react react-dom

Quick start

import { SessionViewer } from "@alivelabs/expo-orchestrator-react-client";

function App() {
  return (
    <SessionViewer
      sessionId="abc-123"
      apiToken="your-api-token"
      baseUrl="https://your-orchestrator.example.com"
    />
  );
}

Hook usage

The live screen is an H.264 stream decoded with WebCodecs onto a <canvas>. The hook owns the decoder — pass attachCanvas to a <canvas ref>:

import { useExpoCiSession } from "@alivelabs/expo-orchestrator-react-client";

function BuildPage() {
  const { status, logs, attachCanvas, videoSupported, connected, sendInput, reconnect } =
    useExpoCiSession({
      sessionId: "abc-123",
      apiToken: "your-api-token",
      baseUrl: "https://your-orchestrator.example.com",
      autoConnect: true, // default
      maxLogs: 2000,     // default
    });

  return (
    <div>
      <p>Status: {status} — {connected ? "live" : "disconnected"}</p>
      {videoSupported ? <canvas ref={attachCanvas} /> : <p>Video not supported in this browser.</p>}
      <button onClick={() => sendInput({ type: "button", button: "home" })}>Home</button>
      {!connected && <button onClick={reconnect}>Reconnect</button>}
    </div>
  );
}

WebCodecs needs a modern browser (Chrome/Edge, Safari 16.4+, recent Firefox) and a secure context (HTTPS or localhost); videoSupported is false otherwise. For full control you can import SimulatorDecoder and drive your own canvas.

Exports reference

| Export | Kind | Description | |---|---|---| | SessionViewer | Component | All-in-one: status badge, simulator screen, log console, interaction controls | | SimulatorScreen | Component | Renders the live H.264 stream to a canvas; click = tap, click-drag = swipe | | LogConsole | Component | Scrollable, color-coded, auto-scrolling log viewer | | StatusBadge | Component | Colored pill showing session status | | useExpoCiSession | Hook | React hook wrapping ExpoCiClient + the WebCodecs decoder | | ExpoCiClient | Class | Framework-agnostic client: REST + WebSocket with auto-reconnect | | SimulatorDecoder | Class | WebCodecs H.264 decoder painting to a <canvas> (advanced) |

<SessionViewer> props

| Prop | Type | Required | Default | Description | |---|---|---|---|---| | sessionId | string | yes | — | The session to display | | apiToken | string | yes | — | Bearer token for the API | | baseUrl | string | no | http://localhost:3000 | Orchestrator base URL | | className | string | no | — | CSS class applied to the root element |

<SimulatorScreen> props

| Prop | Type | Required | Description | |---|---|---|---| | canvasRef | (canvas: HTMLCanvasElement \| null) => void | yes | Ref callback wiring the canvas to the decoder (pass attachCanvas) | | videoSupported | boolean | yes | Whether WebCodecs is available; shows a notice when false | | hasFrame | boolean | yes | Whether a frame has painted yet (drives the placeholder) | | onTap | (input: { type: "tap"; x: number; y: number }) => void | no | Called on click | | onSwipe | (input: { type: "swipe"; startX; startY; endX; endY }) => void | no | Called on drag | | onKeyInput | (input: { type: "type" \| "key"; … }) => void | no | Called for keystrokes while focused | | maxHeight | number \| string | no | Cap on rendered height (default 80vh) |

<LogConsole> props

| Prop | Type | Required | Default | Description | |---|---|---|---|---| | logs | LogEntry[] | yes | — | Array of log entries | | maxHeight | string \| number | no | 400 | CSS max-height of the scroll area |

<StatusBadge> props

| Prop | Type | Required | Description | |---|---|---|---| | status | SessionStatus \| null | yes | Session status to display |

useExpoCiSession options

| Option | Type | Default | Description | |---|---|---|---| | sessionId | string | — | Required | | apiToken | string | — | Required | | baseUrl | string | http://localhost:3000 | Orchestrator base URL | | autoConnect | boolean | true | Open WebSocket immediately on mount | | maxLogs | number | 2000 | Max log lines retained in state |

ExpoCiClient API

const client = new ExpoCiClient({ sessionId, apiToken, baseUrl });

client.getSession()              // GET /api/sessions/:id → SessionDetail
client.getLogs()                 // GET /api/sessions/:id/logs → SessionLogs
client.sendInput(input)          // POST /api/sessions/:id/simulator/input
client.getScreenshotObjectUrl()  // GET /api/sessions/:id/screenshot → object URL (fetch + blob)

client.connect()                 // Open WebSocket (auto-reconnect with exponential backoff)
client.disconnect()              // Close WebSocket and remove all listeners

// Typed event emitter. Video arrives as raw encoded chunks (ArrayBuffer) —
// feed them to a SimulatorDecoder, or let the hook do it for you.
const off = client.on("video-chunk", (chunk) => decoder.push(chunk));
off(); // unsubscribe

Events: open, close, connected, log, video-chunk, status, error.