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

@vality/tsthrift

v0.2.0

Published

Thrift client, transport, and runtime for TypeScript and the web.

Readme

@vality/tsthrift

Pure TypeScript Thrift Binary Protocol runtime, dynamic metadata RPC clients, and HTTP transport for browsers and modern JavaScript/TypeScript runtimes.

@vality/tsthrift provides client execution directly from schema metadata without requiring an Apache Thrift compiler, Node.js runtime globals, or Buffer polyfills.

Features

  • Metadata-driven runtime: Create dynamic RPC clients with createMetadataClient using schema metadata arrays, loader functions, or pre-built MetadataIndex snapshots.
  • Pure TypeScript Binary Protocol: Native BinaryReader and BinaryWriter implementing Thrift Binary Protocol over Uint8Array.
  • Zero Node/Buffer dependencies: Runs in browsers, web workers, Node.js, and edge runtimes.
  • Configurable i64 precision: Support for exact bigint (default) or safe number mode.
  • Native JavaScript values: Plain objects for structs/unions/exceptions, Map (with support for struct keys), Set, arrays, and Base64 strings for binary data by default (binaryMode: "uint8array" selects raw bytes).
  • HTTP transport: Fetch-based transport with configurable timeouts, request cancellation (AbortSignal), custom headers, and Woody distributed tracing headers.
  • Typed error handling: Clear distinction between transport/system failures (ThriftSystemError) and declared Thrift IDL exceptions (ThriftServiceError).
  • Safe call semantics: Support for ThriftResult<TData, TError> pattern alongside throwing clients.

Installation

npm install @vality/tsthrift
# or
pnpm add @vality/tsthrift

Quick Start

Dynamic client from metadata

import { createMetadataClient } from "@vality/tsthrift";

// metadata can be an array, Promise, or loader function
const client = await createMetadataClient({
  metadata, // or pre-built index: metadataIndex
  namespace: "payment_processing",
  serviceName: "PaymentProcessing",
  endpoint: "/rpc/payment",
  i64Mode: "bigint", // "bigint" (default) or "number"
  binaryMode: "base64", // Base64 (default); "uint8array" for raw bytes
  timeoutMs: 15_000,
});

// Invoke methods
const result = await client.getPayment(123456789n);

Metadata selection

createMetadataLoader returns a loader accepting a required namespace name or readonly list of names. List calls combine dependency closures into one Metadata[], deduplicated by module name in selection/dependency order. An empty list returns []; unknown names reject the call. Allowed names are inferred from the dependency keys. Loads are cached per namespace, and rejected loads can be retried. For the metadata option of createMetadataClient, select a known namespace in a zero-argument callback: metadata: () => loadThriftMetadataByNamespaces("payment").

Generated package roots export loadThriftMetadataByNamespaces; pass their THRIFT_NAMESPACES list to load all namespaces. Namespace subpaths export zero-argument loadThriftMetadata().

Typed client with generated descriptors

When schemas are compiled using @vality/tsthrift-cli, service definitions provide typed client factories and descriptors:

import { createPaymentProcessing } from "./generated/payment_processing/index.js";

const client = createPaymentProcessing({
  endpoint: "https://api.example.com/rpc/payment",
  headers: {
    Authorization: "Bearer token",
  },
  timeoutMs: 10_000,
});

const payment = await client.getPayment(123456789n, {
  headers: { "X-Request-Id": "req-123" },
});

Non-throwing calls (toThriftResult)

Wrap any call in toThriftResult to receive a { data, error } object instead of throwing:

import { toThriftResult } from "@vality/tsthrift";

const { data, error } = await toThriftResult(client.getPayment(123456789n));

if (error) {
  console.error("Call failed:", error);
} else {
  console.log("Payment:", data);
}

Error Handling

ThriftSystemError is a TypeScript union of the system error classes below, not a runtime constructor. Direct RPC clients reject declared exceptions as ThriftServiceError with a qualified module.Exception type and original payload in data. Error guards work across copies of the runtime.

Errors raised by the runtime carry the stack of the RPC call site instead of internal transport frames, including calls through lazy metadata clients.

ThriftError (base class)
├── ThriftSystemError
│   ├── ThriftHttpError         // Non-200 HTTP status
│   ├── ThriftTimeoutError      // Request timeout
│   ├── ThriftConnectionError   // Network or socket failure
│   ├── ThriftProtocolError     // Wire format or decoding violation
│   └── ThriftApplicationError  // TApplicationException returned by server
└── ThriftServiceError          // Declared IDL service exception

Distinguishing system errors and service errors

import {
  catchServiceError,
  catchSystemError,
  isThriftServiceError,
  isThriftSystemError,
} from "@vality/tsthrift";

try {
  await client.createPayment(params);
} catch (err) {
  // Handle declared Thrift service exceptions
  const handledService = catchServiceError(
    err,
    "payment_processing.PaymentNotFound",
    (serviceErr) => {
      console.warn("Payment not found:", serviceErr.data);
      return true;
    },
  );

  if (handledService) return;

  // Handle system and transport failures
  catchSystemError(err, (systemErr) => {
    console.error("System or network failure:", systemErr.message);
  });
}

Configuration

HttpTransportConfig options:

| Option | Type | Description | | ------------- | --------------------------------------------- | ------------------------------------------------------------------------ | | endpoint | string \| (() => string \| Promise<string>) | Target endpoint URL or sync/async URL factory. | | headers | HeaderProvider | Static header object or async factory receiving base headers. | | timeoutMs | number | Request timeout in milliseconds (default: 60_000). | | fetch | typeof fetch | Custom fetch implementation or framework bridge. | | loggingFn | (params: ThriftLogParams) => void | Lifecycle logging callback for call, success, and error events. | | logPayloads | boolean | Include arguments, responses, and declared exception data in log events. |

Per-call options

Every service method accepts an optional trailing RequestOptions object:

const result = await client.process(data, {
  signal: abortController.signal,
  timeoutMs: 5_000,
  headers: { "X-Custom-Header": "value" },
});

Woody & Wachter Headers

The package includes built-in helpers for Woody RPC tracing and Vality Wachter Gateway headers:

import { createWoodyHeaders, createWachterHeaders } from "@vality/tsthrift";

// Standalone Woody headers with customizable prefixes
const woodyHeaders = createWoodyHeaders({
  prefix: "x-woody-",
  meta: { "client-app": "admin-panel" },
});

// Compose both in client headers provider:
const client = await createMetadataClient({
  endpoint: "/rpc",
  namespace: "example",
  serviceName: "Example",
  metadata,
  headers: () => ({
    ...createWoodyHeaders(),
    ...createWachterHeaders({
      service: "Example",
      token: auth.getToken(),
      user: { id: user.id, email: user.email },
    }),
  }),
});

Logging

loggingFn receives call, success, and error events with the service, method, namespace, sequence ID, duration, and trace ID. Error events carry a ThriftLogError summary: name, message, call-site stack, HTTP status, and TApplicationException code. Arguments, responses, and declared exception data are included only with logPayloads: true. Headers and HTTP response bodies are never logged.

@vality/tsthrift/devtools provides a console logger for development. Use combineLoggers to add application loggers; falsy entries are skipped and each logger is isolated from failures of the others.

import { combineLoggers } from "@vality/tsthrift";
import { createConsoleLogger } from "@vality/tsthrift/devtools";

const config = {
  endpoint: "/wachter",
  logPayloads: isDev,
  loggingFn: combineLoggers(isDev && createConsoleLogger(), reportErrors),
};

createConsoleLogger options: console (output sink, default globalThis.console), success (log successful calls, default true), and calls (log call starts, default false). Failures are printed as an Error whose stack points to the call site, followed by any status, code, or data details.

Binary values

IDL string remains UTF-8 text. IDL binary is a Base64 string by default (binaryMode: "base64"); binaryMode: "uint8array" selects raw bytes for direct metadata clients. Generated factories bind the CLI's --binary mode and cannot override it at runtime. Both modes send identical raw bytes in Binary Protocol; Base64 is not sent as text. Use binaryToString(bytes, "base64") and toBinary(value, "base64") for conversion. IDL binary constants/defaults encode the literal as UTF-8 bytes before converting to the selected representation. Low-level readBinary/writeBinary still use Uint8Array. Regenerate protocol packages when adopting the new default. Older build markers without a binary mode describe uint8array; unversioned metadata needs an explicit binaryMode: "uint8array" to retain the earlier metadata runtime behavior.

Low-Level Runtime API (@vality/tsthrift/runtime)

For applications that need direct access to Binary Protocol serialization or wire types:

import {
  BinaryReader,
  BinaryWriter,
  MessageType,
  WireType,
  i64ToNumber,
  numberToI64,
} from "@vality/tsthrift/runtime";

// Writing
const writer = new BinaryWriter();
writer.writeMessageBegin("ping", MessageType.Call, 1);
writer.writeFieldBegin(WireType.String, 1);
writer.writeString("hello");
writer.writeFieldStop();
const bytes = writer.finish();

// Reading
const reader = new BinaryReader(bytes);
const header = reader.readMessageBegin(); // { name: "ping", type: MessageType.Call, sequenceId: 1 }
const field = reader.readFieldBegin(); // { type: WireType.String, id: 1 }
const value = reader.readString(); // "hello"
reader.readFieldBegin(); // Consume WireType.Stop; it has no value to skip.
reader.assertDone();

License

Apache-2.0

Runtime policy

Packages are ESM-only and use ES2023/Web APIs. Consumer declarations require TypeScript 5.1+ and node16, nodenext, or bundler resolution. No polyfills or automatic RPC retries are included. timeoutMs: 0 means an immediate timeout. Logging never receives headers and only includes argument/result payloads when logPayloads: true; logger failures are isolated. HTTP error details are capped at 1 KiB and excluded from message. RPC errors and completion logs include service, method, sequence ID, and duration. The built-in HTTP transport also captures the final x-woody-trace-id when present; custom transports and header prefixes must provide their own trace correlation.

generateId produces backend-compatible 64-bit Flake IDs in the legacy base64 alphabet. generateId uses a shared FlakeId with a random 10-bit generator id chosen per runtime instance, so independent clients rarely collide; new FlakeId() keeps generator id 0 like flake-idgen. FlakeId.next() never throws by default: after a clock rollback it keeps the last timestamp, and after 4096 IDs in one millisecond it borrows the next one, so tracing never fails a call. Output matches flake-idgen wherever upstream succeeds; new FlakeId({ strict: true }) reproduces its exceptions. Woody deadlines are optional absolute times; use a deadline callback or header provider to refresh them and account for client/server clock skew.