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

ryuu-client

v5.0.0

Published

Node client for ryuu services

Downloads

2,562

Readme

ryuu-client

Node.js client for the Domo Apps platform. Used by ryuu (the Domo Apps CLI) and ryuu-proxy to authenticate with Domo, manage app designs, upload assets, and proxy local development sessions.

npm version install size npm downloads

Requirements

  • Node.js >= 22.0.0
  • pnpm (package manager)

Install

pnpm add ryuu-client

Usage

import { createClient, getHomeDir, getMostRecentLogin } from 'ryuu-client';

const client = createClient({
  instance: 'mycompany.domo.com',
  refreshToken: '...',
  clientId: '...',
  devToken: false,
  proxy: { host: 'proxy.corp.com', port: 8080 }, // optional
});

Authentication

// OAuth device-code flow (opens browser for authorization)
const loginData = await client.login();
console.log(`Welcome, ${loginData.displayName}`);

// Tokens are cached automatically — subsequent API calls
// skip redundant token exchanges until the cache expires.

Designs

// Create a new design
const design = await client.designs.create(manifest);

// Get a design by ID
const design = await client.designs.get(designId, { parts: 'versions' });

// List all designs
const designs = await client.designs.list();

// Delete / undelete
await client.designs.delete(designId, true); // force=true
await client.designs.undelete(designId);

// Versions and releases
const versions = await client.designs.getVersions(designId);
await client.designs.release(designId, '2.0.0');

Assets

// Upload a single asset
await client.assets.upload(designId, version, 'dist/app.js');

// Upload all assets (reads files from cwd, respects manifest.ignore)
const uploaded = await client.assets.uploadAll(manifest);

// Download assets as a zip stream
const response = await client.assets.download(designId, version);

Apps

// Create a temporary app instance (for local dev proxying)
const { instance } = await client.apps.createInstance(designId);

// Get the full dev environment (domoapps domain, user info, etc.)
const env = await client.apps.getEnvironment(manifest, proxyId);

Escape hatch

For endpoints not covered by the namespaced API, use client.request() directly. Auth headers are injected automatically.

const result = await client.request('/api/some/endpoint', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(payload),
});

Utilities

import { getHomeDir, getMostRecentLogin, getContentType } from 'ryuu-client';

// ~/.config/configstore path
const configDir = getHomeDir();

// Most recently modified login JSON
const login = getMostRecentLogin();

// Content-type lookup with octet-stream fallback
getContentType('font.ttf');    // 'font/ttf'
getContentType('data.bin');    // 'application/octet-stream'

Error handling

All errors are typed with cause chaining support:

import { RyuuHttpError, RyuuAuthError, RyuuValidationError } from 'ryuu-client';

try {
  await client.designs.get('bad-id');
} catch (err) {
  if (err instanceof RyuuHttpError) {
    console.error(err.statusCode, err.message, err.url);
  }
}

Architecture

src/
├── index.ts              # Public barrel export
├── client.ts             # createClient() factory
├── auth/                 # OAuth device-code flow, token caching
├── http/                 # Native fetch wrapper, undici proxy, error classes
├── api/                  # Namespaced API modules (designs, assets, apps, users)
├── types/                # TypeScript interfaces and enums
└── util/                 # Content-type map, endpoints, home-dir helpers

Key design decisions

  • Native fetch — no axios. Proxy support via undici ProxyAgent.
  • Token caching — access tokens and SIDs are cached with TTL, reducing most requests from 2 extra roundtrips to 0.
  • Scoped TLS bypassdomorig.io instances use an undici Agent with rejectUnauthorized: false instead of the global NODE_TLS_REJECT_UNAUTHORIZED=0.
  • Typed errorsRyuuHttpError, RyuuAuthError, RyuuValidationError with cause chaining. No more Promise<unknown>.
  • ESM only"type": "module", targeting ES2023 with NodeNext module resolution.

Dependencies

| Runtime | Purpose | |---------|---------| | open | Launch browser for OAuth device-code flow | | tinyglobby | Lightweight glob for asset uploads | | undici | ProxyAgent for proxy support with native fetch |

Development

pnpm install
pnpm build          # TypeScript compile to dist/
pnpm test           # Run unit tests (vitest)
pnpm test:watch     # Watch mode
pnpm test:coverage  # Coverage report
pnpm format         # Prettier

v5 migration guide

v5 is a ground-up rewrite. The default export class is replaced by a createClient() factory returning a namespaced API object.

Import changes

- import Domo from 'ryuu-client';
+ import { createClient, getHomeDir, type RyuuClient } from 'ryuu-client';

Constructor

- const client = new Domo(instance, refreshToken, clientId, { host, port }, devToken);
+ const client = createClient({ instance, refreshToken, clientId, devToken, proxy: { host, port } });

Getters

- client.getInstance()
+ client.instance

- client.getRefreshToken()
+ client.refreshToken

Static methods

- Domo.getHomeDir()
+ getHomeDir()

- Domo.getMostRecentLogin()
+ getMostRecentLogin()

API methods

- client.createDesign(manifest)
+ client.designs.create(manifest)

- client.getDesign(id, params)
+ client.designs.get(id, params)

- client.getDesigns(params)
+ client.designs.list(params)

- client.deleteDesign(id, force)
+ client.designs.delete(id, force)

- client.unDeleteDesign(id)
+ client.designs.undelete(id)

- client.getVersions(id)
+ client.designs.getVersions(id)

- client.release(id, version)
+ client.designs.release(id, version)

- client.uploadAsset(designId, version, path, contents)
+ client.assets.upload(designId, version, path, contents)

- client.uploadAllAssets(manifest)
+ client.assets.uploadAll(manifest)

- client.download(designId, version)
+ client.assets.download(designId, version)

- client.createApp(designId, proxyId)
+ client.apps.createInstance(designId, proxyId)

- client.getDomoappsData(manifest, proxyId)
+ client.apps.getEnvironment(manifest, proxyId)

- client.processRequest(options)
+ client.request(url, init)

Error handling

- .catch(err => console.log(err.statusCode, err.message))
+ import { RyuuHttpError } from 'ryuu-client';
+ .catch(err => {
+   if (err instanceof RyuuHttpError) {
+     console.log(err.statusCode, err.message);
+   }
+ })