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

react-native-now

v0.1.0

Published

CLI for exporting and serving React Native guest apps as Gen UX static bundles

Readme

@genux/cli (genux)

Command-line tool for turning an Expo / React Native project into a Gen UX static bundle and serving it to the Gen UX iOS shell (gen-ux-shell). The shell loads guest apps at runtime from a manifest.json + Hermes bundle + assets; this CLI produces and hosts that layout.

Install

cd gen-ux-cli
bun install
bun run build        # syncs the shell catalog, compiles to dist/
bun link             # exposes `genux` globally
genux --help

Without linking: node dist/index.js <command>.

Scripts:

| script | what it does | | --- | --- | | bun run build | sync-catalog + tsc + copy catalog.json into dist/ | | bun run dev | tsc --watch | | bun run sync-catalog | copy ../gen-ux-shell/catalog/packages.json -> src/catalog.json |

Requires Node 20+. The guest project must have its dependencies installed (bun install) so npx expo export can run inside it.

Commands

All projectDir arguments default to the current directory.

genux export [projectDir]

Runs npx expo export --platform ios --dump-assetmap --output-dir <out> in the project, then post-processes the output into the static bundle contract below. doctor runs first (see below).

| option | description | | --- | --- | | -o, --out <dir> | output directory (default <project>/dist-genux) | | --dev | pass --dev to expo export (produces a .js bundle instead of .hbc) | | --clear | clear the Metro cache before exporting | | --name <name> / --slug <slug> / --bundle-id <id> | override app metadata | | --force | continue even when doctor reports missing native packages | | --skip-doctor | do not run doctor |

App metadata (name, slug, version, ios.bundleIdentifier, icon, sdkVersion, runtimeVersion) comes from npx expo config --json --type public, falling back to app.json, then package.json. Missing bundle identifiers become com.genux.guest.<slug>.

genux serve [projectDir]

Serves an exported directory over HTTP and prints the manifest URL, the deep link, a QR code encoding the deep link, and the simulator command. Runs until Ctrl-C.

| option | description | | --- | --- | | -o, --out <dir> | directory to serve (default <project>/dist-genux) | | -p, --port <n> | port (default 8790) | | -H, --host <ip> | host advertised in URLs (default: auto-detected LAN IPv4) | | --sim | also run xcrun simctl openurl booted "<deep link>" |

Server behaviour: static files only, Cache-Control: no-store, Access-Control-Allow-Origin: *, every request logged, path traversal rejected. Content types: .hbc/.js -> application/javascript, .json -> application/json, images and fonts by extension.

Example output:

Gen UX static bundle server
  serving:   /path/to/app/dist-genux
  listening: http://0.0.0.0:8790 (all interfaces)

  Manifest URL: http://192.168.86.145:8790/manifest.json
  Deep link:    nativenow://open?url=http%3A%2F%2F192.168.86.145%3A8790%2Fmanifest.json

  Simulator:    xcrun simctl openurl booted 'nativenow://open?url=http%3A%2F%2F192.168.86.145%3A8790%2Fmanifest.json'
  Or:           genux open http://192.168.86.145:8790/manifest.json

  Scan with the Gen UX shell (QR encodes the deep link):
  [QR code]

genux start [projectDir]

export followed by serve; accepts the union of both commands' options.

genux open <manifestUrl>

Opens nativenow://open?url=<encoded manifestUrl> in the shell on the booted iOS simulator via xcrun simctl openurl booted.

genux doctor [projectDir]

Compares the guest's package.json dependencies with the shell package catalog:

  • error - a native package used by the guest is not compiled into the shell (the guest would crash when it loads that module). export/start abort on this unless --force.
  • warning - version mismatch on a native package (shows the shell's version), or expo / react-native / react mismatch.

A guest dependency counts as native when node_modules/<pkg> contains an ios/ directory or a *.podspec (fallback: the catalog's native flag). Exit code 1 when errors are found.

genux catalog

Prints the shell catalog as a table (name, version, native).

Catalog resolution

bun run build copies gen-ux-shell/catalog/packages.json into the package (src/catalog.json -> dist/catalog.json). At runtime the loader tries, in order: dist/catalog.json, src/catalog.json, ../gen-ux-shell/catalog/packages.json (monorepo layout). If none exists it derives a minimal catalog from ../gen-ux-shell/package.json and prints a hint to run bun run catalog:generate in the shell.

Static bundle contract

genux export writes this layout (default <project>/dist-genux). Every URL in manifest.json is relative to the manifest's location, so the directory can be served from any base URL or copied anywhere.

manifest.json      # Expo-updates-style manifest (below)
genux.json         # app metadata = manifest.extra.genux + "id" + "manifest": "manifest.json"
assetmap.json      # from expo export --dump-assetmap
metadata.json      # from expo export
_expo/static/js/ios/index-<hash>.hbc   # Hermes bytecode (or .js with --dev)
assets/<hash>.<ext>                     # expo export writes assets/<hash> with no extension;
                                        # the CLI renames each using assetmap/metadata types
icon.png           # optional, copied from the app's icon (app.json expo.icon)

manifest.json:

{
  "id": "<uuid v4>",
  "createdAt": "2026-09-06T12:46:11.923Z",
  "runtimeVersion": "1.0.0",
  "launchAsset": {
    "hash": "<sha256 base64url, no padding>",
    "key": "bundle",
    "contentType": "application/javascript",
    "url": "_expo/static/js/ios/index-12d4ec0d97201f2eee1e7ae5a3174e84.hbc"
  },
  "assets": [
    {
      "hash": "<sha256 base64url, no padding>",
      "key": "0747a1317bbe9c6fc340b889ef8ab3ae",
      "contentType": "image/png",
      "fileExtension": "png",
      "url": "assets/0747a1317bbe9c6fc340b889ef8ab3ae.png"
    }
  ],
  "metadata": { "bundler": "metro", "version": "0", "platform": "ios", "assetsCount": "17" },
  "extra": {
    "genux": {
      "name": "hello-samples",
      "slug": "hello-samples",
      "bundleIdentifier": "com.genux.guest.hellosamples",
      "version": "1.0.0",
      "sdkVersion": "57.0.0",
      "icon": "icon.png",
      "exportedAt": "2026-09-06T12:46:11.923Z"
    }
  }
}

Rules the shell relies on:

  • Hashes are SHA-256, base64url without padding (crypto.createHash('sha256').digest('base64url')), matching StaticBundle.checkAssetIntegrity in the shell.
  • All metadata values are strings.
  • runtimeVersion comes from the app config (runtimeVersion string, or the app version for the appVersion policy), default "1.0.0".
  • Asset key is the content hash expo export assigned; the served file is assets/<key>.<fileExtension>.

Deep link format

The shell registers the genux URL scheme and accepts:

nativenow://open?url=<url-encoded manifest URL>

For example nativenow://open?url=http%3A%2F%2F192.168.86.145%3A8790%2Fmanifest.json. The QR code printed by serve/start encodes exactly this string. On a simulator: xcrun simctl openurl booted '<deep link>' (or genux open <manifestUrl>).

Typical workflow

cd my-expo-app && bun install
genux doctor                 # check native deps against the shell
genux start --sim            # export + serve + open in the booted simulator
# or step by step
genux export
genux serve --port 8790
genux open http://<lan-ip>:8790/manifest.json

Notes

  • Expo CLI refuses to bundle @react-navigation/* imports when it can resolve expo-router from any parent node_modules (this happens for sample apps nested inside the shell repo). When the guest's own package.json does not depend on expo-router, the CLI sets EXPO_ROUTER_DISABLE_RN_NAVIGATION_CHECK=1 for the export; set the variable yourself to override.
  • The output directory is cleaned of previous contract files (manifest.json, genux.json, _expo/, assets/, ...) before each export; other files in it are left alone.