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

@xprem/control-center

v3.2.5

Published

A branch picker that appears on builds whose channel allows surfing. JS-only, for xprem branch surfing.

Readme

@xprem/control-center

See which branch this build is running, and switch to another — from the build itself.

Built for acceptance testing: one TestFlight or Play build becomes a shell for every branch that is compatible with it, so five people can test five branches in parallel without five builds.

import { ControlCenter } from '@xprem/control-center';

export default function App() {
  return (
    <>
      <YourApp />
      <ControlCenter />
    </>
  );
}

That is the whole integration. There is nothing to configure: the panel reads the update URL, app id, channel and runtime version from the config the build already carries.

It turns itself on

At launch, once the first frame has painted, the component asks the server one question — is branch surfing allowed on this build's channel? On no, it renders null and registers nothing. On yes, a small blue marker appears on the right edge; press it and the panel opens, branches already in hand. One request per app session, answered from the server's cache.

Turn branch surfing on for a channel from the xprem dashboard and the panel is there at the next launch of every build on that channel — nothing to republish. Turn it off and it disappears the same way. A production channel never shows it.

Footprint

JavaScript only. No native module, no config plugin, no prebuild. It ships in the JS bundle, which means it can be delivered over the air to a build that is already in testers' hands — the picker itself is an update.

The only dependencies are expo-updates and expo-constants, which the app has already. The edge marker is the built-in way in; your own trigger works from anywhere:

import { openControlCenter } from '@xprem/control-center';

What a tester sees

The panel opens on the branch currently running — live dot, channel and runtime under it — then the branches this build can switch to, drawn as a rail of branch dots, newest first. Only branches with an update built for this binary's runtime version are listed: a branch that changed native code cannot be reached without a new build, so offering it would be a dead end.

When a branch crashes on launch, expo-updates falls back on its own and the server refuses to serve that branch again. The panel says so, names the branch, and says what unblocks it — publishing a fix to that same branch.

Requirements

  • Expo SDK 54 or newer (setUpdateRequestHeadersOverride)
  • expo-app-id, expo-channel-name and xprem-branch declared in updates.requestHeaders at build time
updates: {
  requestHeaders: {
    'expo-channel-name': 'staging',
    'expo-app-id': '...',
    'xprem-branch': '',
  },
}

Those three are not optional, and the panel refuses to appear without them — switching branches replaces the whole header set, and expo-updates only accepts an override for keys that existed when the app was built. A build missing one of them would drop it from every poll from then on, which the server answers with a 400, which means no update can reach the device to undo it. Reinstalling is the only way out, so the package checks first and logs which header is missing. eoas init writes them for you.

Declare expo-channel-name as a literal, not process.env.SOMETHING. The config is evaluated when the JS bundle is exported, so an unset variable silently removes the key — and an export run with the wrong value would bake in the wrong channel. Only the key matters here: the value sent at runtime is always the build's real channel.

If a build gets stuck

It cannot be bricked. A branch that fails to launch is rolled back by expo-updates itself, onto the bundle embedded in the binary. To get moving again, in order of preference:

  1. publish a fix to the branch being tested
  2. turn branch surfing off for the channel, which returns every device
  3. reinstall the app, which clears the stored choice