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

@reflog-io/client

v0.1.2

Published

TypeScript client for Reflog with runtime protobuf type generation

Downloads

127

Readme

@reflog/client

TypeScript client for Reflog with runtime protobuf type generation. This client automatically generates type-safe methods from your custom protobuf definitions at runtime.

Installation

npm install @reflog/client

Or if developing locally:

npm install
npm run build

Running the Example

To run the example file, you need to use ts-node (included as a dev dependency):

npm install
npm run example

Or directly with ts-node:

npx ts-node example.ts

Make sure to set the required environment variables:

export REFLOG_HOST=localhost:50051
export REFLOG_CLIENT_ID=my-client-id
npm run example

Note: You cannot run node example.ts directly because it's a TypeScript file. You must use ts-node or compile it first with npm run build and then run the compiled JavaScript from the dist folder.

Configuration

The client requires two environment variables:

  • REFLOG_HOST: The gRPC server host (e.g., localhost:50051)
  • REFLOG_CLIENT_ID: Your client identifier

Alternatively, you can pass these as configuration options when creating the client.

Usage

Basic Example

import { createClient } from '@reflog/client';

async function main() {
  // Initialize the client (reads REFLOG_HOST and REFLOG_CLIENT_ID from env)
  const reflog = await createClient();

  // Insert a user
  await reflog.insert.user({
    entity_id: 'user-123',
    payload: {
      id: 'user-123',
      name: 'John Doe',
      email: '[email protected]',
    },
  });

  // Update an article
  await reflog.update.article({
    entity_id: 'article-456',
    payload: {
      id: 'article-456',
      title: 'Updated Title',
      body: 'Updated body content',
    },
  });

  // Delete a user
  await reflog.delete.user({ entity_id: 'user-123' });

  // Close the connection when done (waits for pending background retries for 5 seconds)
  await reflog.close();
}

main().catch(console.error);

With Custom Configuration

import { createClient } from '@reflog/client';

const reflog = await createClient({
  host: 'localhost:50051',
  clientId: 'my-client-id',
  retry: {
    maxRetries: 5,
    initialBackoffMs: 200,
    maxBackoffMs: 3000,
  },
});

Type Safety

The client automatically generates methods based on your protobuf definitions. For example, if your custom.proto defines:

message User {
  string id = 1;
  string name = 2;
  string email = 3;
}

message Article {
  string id = 1;
  string author_id = 2;
  string title = 3;
  string body = 4;
}

The client will automatically provide:

  • reflog.insert.user()
  • reflog.insert.article()
  • reflog.update.user()
  • reflog.update.article()
  • reflog.delete.user()
  • reflog.delete.article()

All methods are fully typed based on your protobuf schema.

API

createClient(config?: Partial<ReflogConfig>): Promise<ReflogClient>

Creates and initializes a new Reflog client. The client will automatically parse your custom.proto file and generate type-safe methods.

ReflogClient

Methods

  • insert.<entityType>(options: IngestOptions): Promise<IngestResponse> - Insert/create a new entity (uses background retries)
  • update.<entityType>(options: IngestOptions): Promise<IngestResponse> - Update an existing entity (uses background retries)
  • delete.<entityType>(options: DeleteOptions): Promise<IngestResponse> - Delete an entity (uses background retries)
  • close(waitForRetries?: boolean, timeoutMs?: number): Promise<void> - Close the gRPC connection and optionally wait for pending background retries

Types

interface IngestOptions {
  entity_id: string;
  payload: Record<string, any>; // Must match your protobuf message definition
  created_at?: number; // Optional Unix timestamp for create operations (milliseconds)
  updated_at?: number; // Optional Unix timestamp for update operations (milliseconds)
  deleted_at?: number; // Optional Unix timestamp for update operations (milliseconds)
}

interface DeleteOptions {
  entity_id: string;
  deleted_at?: number; // Optional Unix timestamp for delete operations (milliseconds)
}

interface IngestResponse {
  ok: boolean;
  message: string;
}

Retries

The client automatically retries certain transient gRPC errors (such as UNAVAILABLE or DEADLINE_EXCEEDED) using an exponential backoff strategy with jitter. You can configure retry behavior via the optional retry field on ReflogConfig:

interface RetryOptions {
  maxRetries?: number;       // default: Infinity (retry forever)
  initialBackoffMs?: number; // default: 100
  maxBackoffMs?: number;     // default: 2000
}

Retries are applied to:

  • initialize() when calling the GetProtos RPC
  • All ingest operations (insert.<entityType>, update.<entityType>, delete.<entityType>)

Requirements

  • Node.js 16+
  • TypeScript 4.5+ (for TypeScript projects)
  • Access to the Reflog gRPC server

Proto Files

The client includes the necessary proto files (custom.proto, ingest.proto, options.proto) in the package. These are automatically loaded at runtime to generate the type-safe API.

Error Handling

Background Retries

All ingest operations (insert, update, delete) use background retries for maximum reliability:

  1. First attempt: The operation tries once immediately
  2. On failure: If the first attempt fails with a retryable error (network issues, server unavailable, etc.), the promise resolves immediately with { ok: true, message: 'Request queued for background retry' }
  3. Background retries: The client continues retrying in the background until:
    • The operation succeeds, OR
    • Maximum retries are exhausted, OR
    • The client is closed

This ensures your application doesn't block waiting for the service to come back online, while still guaranteeing eventual delivery of your messages.

Note: The initialize() method uses synchronous retries (it must complete before the client is usable).

Error Types

  • Non-retryable errors (thrown immediately): Invalid payload, authentication failures, validation errors
  • Retryable errors (background retries): Network issues, server unavailable, timeouts
// This resolves immediately even if the service is down
// Retries continue in the background automatically
const result = await reflog.insert.user({
  entity_id: 'user-123',
  payload: { id: 'user-123', name: 'John' },
});
// result.ok === true (even if service was down - retries happening in background)

// When closing, wait for pending retries to complete
await reflog.close(); // Waits up to 5 seconds for background retries
// Or close immediately without waiting
reflog.close(false); // Closes immediately, background retries are cancelled