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

@vync/grpcx

v0.1.0

Published

A React Native/Expo module for gRPC with full streaming support (unary, client, server, bidirectional)

Readme

grpcx

A React Native/Expo module for gRPC with full streaming support (unary, client streaming, server streaming, and bidirectional streaming).

Features

  • All Streaming Types: Unary, Server Streaming, Client Streaming, and Bidirectional Streaming
  • Runtime Proto Loading: No build-time code generation required
  • Dynamic Service Discovery: Automatically discovers services and methods from proto files
  • TypeScript Support: Full type definitions for all APIs
  • Native Performance: Uses native gRPC libraries (gRPC-Java, gRPC-Swift)
  • Connection Management: Automatic channel pooling and reconnection
  • Metadata Support: Custom headers and trailers
  • Error Handling: Proper gRPC status codes mapped to JavaScript errors

Installation

npm install grpcx
# or
yarn add grpcx

iOS Setup

cd ios && pod install

Android Setup

No additional steps required - Gradle dependencies are automatically handled.

Prerequisites

Proto Descriptor Files

This library requires proto descriptor files (.desc) alongside your .proto files. Generate them using protoc:

protoc --descriptor_set_out=service.desc --include_imports service.proto

Include both .proto and .desc files in your app bundle.

Quick Start

import { GrpcClient } from 'grpcx';

// Create a client
const client = new GrpcClient({
  host: 'api.example.com',
  port: 50051,
  protoPath: '/path/to/service.proto',
  useTls: true,
});

// Load the proto file
await client.load();

// Make a unary call
const response = await client.call(
  'mypackage.MyService/MyMethod',
  { field1: 'value1', field2: 42 }
);

console.log(response);

// Clean up
await client.close();

Usage Examples

Unary Calls

Single request, single response:

const response = await client.call(
  'mypackage.MyService/MyMethod',
  { field1: 'value1', field2: 42 },
  {
    metadata: { 'authorization': 'Bearer token' },
    timeout: 5000,
  }
);

console.log(response);

Server Streaming

Single request, stream of responses:

const stream = client.serverStream(
  'mypackage.MyService/StreamMethod',
  { query: 'search term' }
);

stream.on('data', (data) => {
  console.log('Received:', data);
});

stream.on('error', (error) => {
  console.error('Stream error:', error);
});

stream.on('end', () => {
  console.log('Stream completed');
});

// Cancel the stream if needed
// await stream.cancel();

Client Streaming

Stream of requests, single response:

const stream = client.clientStream('mypackage.MyService/UploadMethod');

// Listen for the final response
stream.on('data', (response) => {
  console.log('Final response:', response);
});

stream.on('error', (error) => {
  console.error('Stream error:', error);
});

stream.on('end', () => {
  console.log('Stream completed');
});

// Send multiple messages
await stream.write({ chunk: 1, data: '...' });
await stream.write({ chunk: 2, data: '...' });
await stream.write({ chunk: 3, data: '...' });

// Close the stream (triggers server to send final response)
await stream.end();

Bidirectional Streaming

Stream of requests and responses:

const stream = client.bidiStream('mypackage.MyService/ChatMethod');

// Listen for responses
stream.on('data', (message) => {
  console.log('Received:', message);
});

stream.on('error', (error) => {
  console.error('Stream error:', error);
});

stream.on('end', () => {
  console.log('Stream ended');
});

// Send messages
await stream.write({ message: 'Hello' });
await stream.write({ message: 'World' });

// Close when done
await stream.end();

Service Discovery

// Get all available services
const services = client.getServices();
console.log(services);

// Get a specific service
const service = client.getService('mypackage.MyService');
console.log(service.methods);

// Get a specific method
const method = client.getMethod('mypackage.MyService/MyMethod');
console.log(method.type); // UNARY, SERVER_STREAMING, etc.

API Reference

GrpcClient

Constructor

new GrpcClient(config: GrpcClientConfig)

Config Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | host | string | required | Server hostname | | port | number | 443 | Server port | | protoPath | string | required | Path to .proto file in app bundle | | useTls | boolean | true | Use TLS/SSL | | timeout | number | 30000 | Default timeout in milliseconds | | maxRetries | number | 3 | Max retry attempts | | metadata | object | {} | Default metadata for all calls |

Methods

load(): Promise<void>

Load and parse the proto file. Must be called before making any RPC calls.

call<TRequest, TResponse>(method: string, request: TRequest, options?: CallOptions): Promise<TResponse>

Make a unary call.

Parameters:

  • method - Full method name (e.g., 'package.Service/Method')
  • request - Request object
  • options - Optional call options (metadata, timeout)

Returns: Promise resolving to response object

serverStream<TRequest>(method: string, request: TRequest, options?: CallOptions): ServerStream

Create a server streaming call.

Parameters:

  • method - Full method name
  • request - Request object
  • options - Optional call options

Returns: ServerStream instance

clientStream<TResponse>(method: string, options?: CallOptions): ClientStream

Create a client streaming call.

Parameters:

  • method - Full method name
  • options - Optional call options

Returns: ClientStream instance

bidiStream(method: string, options?: CallOptions): BidiStream

Create a bidirectional streaming call.

Parameters:

  • method - Full method name
  • options - Optional call options

Returns: BidiStream instance

getServices(): GrpcServiceDescriptor[]

Get all available services from the loaded proto.

Returns: Array of service descriptors

getService(serviceName: string): GrpcServiceDescriptor | undefined

Get a specific service descriptor.

Parameters:

  • serviceName - Full service name

Returns: Service descriptor or undefined

getMethod(fullMethodName: string): GrpcMethodDescriptor | undefined

Get a specific method descriptor.

Parameters:

  • fullMethodName - Full method name (e.g., 'package.Service/Method')

Returns: Method descriptor or undefined

close(): Promise<void>

Close the client and cleanup all resources.

GrpcStream

Base class for all stream types. Extends EventEmitter.

Events

  • data: Emitted when data is received
  • error: Emitted on error
  • end: Emitted when stream completes
  • metadata: Emitted when metadata is received
  • status: Emitted with gRPC status

Methods

write(data: any): Promise<void>

Write data to the stream (client/bidi streams only).

end(): Promise<void>

End the stream (half-close).

cancel(): Promise<void>

Cancel the stream.

getId(): string

Get the stream ID.

TypeScript Support

Full TypeScript definitions are included. All types are exported from the main package:

import {
  GrpcClient,
  GrpcClientConfig,
  GrpcMethodType,
  GrpcStatusCode,
  GrpcError,
  ServerStream,
  ClientStream,
  BidiStream,
} from 'grpcx';

Error Handling

Errors follow gRPC status codes:

import { GrpcStatusCode } from 'grpcx';

try {
  const response = await client.call('MyService/MyMethod', request);
} catch (error) {
  if (error.code === GrpcStatusCode.UNAUTHENTICATED) {
    // Handle auth error
  } else if (error.code === GrpcStatusCode.NOT_FOUND) {
    // Handle not found
  }
  console.error(error.message);
}

gRPC Status Codes

| Code | Name | Description | |------|------|-------------| | 0 | OK | Success | | 1 | CANCELLED | Operation cancelled | | 2 | UNKNOWN | Unknown error | | 3 | INVALID_ARGUMENT | Invalid argument | | 4 | DEADLINE_EXCEEDED | Deadline exceeded | | 5 | NOT_FOUND | Not found | | 7 | PERMISSION_DENIED | Permission denied | | 14 | UNAVAILABLE | Service unavailable | | 16 | UNAUTHENTICATED | Unauthenticated |

Advanced Usage

Custom Metadata

Send custom headers with any call:

const response = await client.call(
  'Service/Method',
  request,
  {
    metadata: {
      'authorization': 'Bearer token',
      'x-custom-header': 'value'
    }
  }
);

Timeout Configuration

Set custom timeouts per call:

const response = await client.call(
  'Service/Method',
  request,
  {
    timeout: 5000 // 5 seconds
  }
);

Connection Management

The client automatically manages gRPC channels with:

  • Connection pooling
  • Automatic reconnection
  • Keep-alive (30s interval)
  • Proper cleanup on close

File Organization

Place proto files in your app bundle:

app/
  assets/
    protos/
      auth.proto
      auth.desc
      feed.proto
      feed.desc

Reference them in your code:

import * as FileSystem from 'expo-file-system';

const client = new GrpcClient({
  host: 'api.example.com',
  port: 50051,
  protoPath: `${FileSystem.documentDirectory}protos/auth.proto`,
  useTls: true,
});

Complete Example

import { GrpcClient } from 'grpcx';
import * as FileSystem from 'expo-file-system';

async function example() {
  // Create client
  const client = new GrpcClient({
    host: 'grpc.example.com',
    port: 50051,
    protoPath: `${FileSystem.documentDirectory}protos/service.proto`,
    useTls: true,
  });

  try {
    // Load proto
    await client.load();
    console.log('Services:', client.getServices());

    // Unary call
    const user = await client.call('users.UserService/GetUser', { id: 123 });
    console.log('User:', user);

    // Server streaming
    const stream = client.serverStream('users.UserService/StreamUsers', {});

    stream.on('data', (user) => {
      console.log('User:', user);
    });

    stream.on('end', () => {
      console.log('All users received');
    });

    stream.on('error', (error) => {
      console.error('Stream error:', error);
    });

  } catch (error) {
    console.error('Error:', error);
  } finally {
    await client.close();
  }
}

Platform Support

  • iOS: 15.1+
  • Android: API 24+ (Android 7.0+)
  • React Native: 0.70+
  • Expo: SDK 50+

Dependencies

Runtime Dependencies

None! This is a zero-dependency package (peer dependencies only).

Peer Dependencies

  • expo
  • react
  • react-native

Native Dependencies

Android:

  • gRPC-Java 1.65.0
  • Protobuf-Java 3.25.3

iOS:

  • gRPC-Swift 1.23.0
  • SwiftProtobuf 1.27.0

Troubleshooting

Proto files not found

Ensure proto and desc files are in your app bundle and the path is correct:

// Check file exists
const fileInfo = await FileSystem.getInfoAsync(protoPath);
console.log('File exists:', fileInfo.exists);

Connection refused

For development:

  • iOS Simulator: Use localhost
  • Android Emulator: Use 10.0.2.2 instead of localhost
  • Physical devices: Use your computer's IP address
const client = new GrpcClient({
  // For Android Emulator
  host: '10.0.2.2',
  port: 50051,
  useTls: false, // For development
});

Descriptor errors

Ensure you include imports when generating descriptors:

protoc --descriptor_set_out=service.desc --include_imports service.proto

Build errors on iOS

Run pod install:

cd ios && pod install

Build errors on Android

Clean and rebuild:

cd android && ./gradlew clean
cd .. && npx expo run:android

Development

Building from source

# Clone the repository
git clone https://github.com/soorajpandey/grpcx.git
cd grpcx

# Install dependencies
npm install

# Build
npm run build

# Run example
cd example
npm install
npx expo run:ios

Running tests

npm test

Contributing

Contributions are welcome! Please read the contributing guidelines before submitting a PR.

Areas for contribution

  • Additional documentation and examples
  • Unit and integration tests
  • Web support (gRPC-Web)
  • Interceptor support
  • Advanced retry policies
  • Performance optimizations

Resources

License

MIT

Author

Sooraj Pandey

Changelog

0.1.0 (Initial Release)

  • Complete gRPC client implementation
  • All 4 streaming types supported
  • Runtime proto loading
  • TypeScript support
  • iOS and Android support
  • Connection management
  • Error handling

Acknowledgments

  • Built with Expo Modules API
  • Uses gRPC-Java and gRPC-Swift
  • Inspired by the need for native gRPC support in React Native

Support

For issues, questions, or feature requests:


Made with care for the React Native community.