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

@t-0/provider-sdk

v1.1.44

Published

Provider SDK for the T-0 Network

Readme

T-0 Provider SDK -- TypeScript

TypeScript SDK for building provider integrations with the T-0 Network. All communication is Protobuf-encoded and secp256k1-signed. Provides signature verification for inbound requests and typed clients for all T-0 Network APIs.

Quick Start

Scaffold a new provider project:

t0-init init --lang=node my-provider

Installation and options: cli/README.md. What init creates: starter template README.

Installation

npm install @t-0/provider-sdk

Usage

Provider Service

Implement the ProviderService interface to receive callbacks from the T-0 Network (payment updates, payout requests, etc.):

import http from "node:http";
import {
  createHandler,
  ProviderService,
  PayoutRequest,
  PayoutResponse,
  UpdatePaymentRequest,
  UpdatePaymentResponse,
  HandlerContext,
} from "@t-0/provider-sdk";

const networkPublicKey = process.env.NETWORK_PUBLIC_KEY!;

const server = http.createServer(
  createHandler(networkPublicKey, (r) => {
    r.service(ProviderService, {
      async payOut(req: PayoutRequest, ctx: HandlerContext): Promise<PayoutResponse> {
        // Handle payout requests from counterparts
        return { result: { case: "accepted", value: {} } } as PayoutResponse;
      },
      async updatePayment(req: UpdatePaymentRequest, ctx: HandlerContext): Promise<UpdatePaymentResponse> {
        // Handle payment status updates
        return {} as UpdatePaymentResponse;
      },
    });
  })
);

server.listen(3000);

createHandler composes the full middleware chain in one call: signature validation (raw byte capture), Connect-Node adapter, and service registration with signature verification.

For cases where you need to customize the middleware chain, the individual components are also exported:

import { createService, nodeAdapter, signatureValidation } from "@t-0/provider-sdk";

const server = http.createServer(
  signatureValidation(nodeAdapter(createService(networkPublicKey, registerRoutes)))
);

signatureValidation captures raw request bytes for hashing, nodeAdapter bridges the RPC transport to Node.js HTTP, and createService registers your handlers with signature verification.

Standalone Request Decoding

For frameworks that don't use Node's http.createServer (Hono, Effect, Koa, Fastify, etc.), use createRequestDecoder for one-call signature verification + Content-Type-aware decoding + protovalidation. It returns an either-type result: success with the decoded message and a response encoder, or failure with a ready-to-send HTTP error.

import { createRequestDecoder, PayoutRequestSchema, PayoutResponseSchema } from "@t-0/provider-sdk";

const decode = createRequestDecoder({
  networkPublicKey: process.env.NETWORK_PUBLIC_KEY!,
});

// Hono / fetch-shaped framework — route by Connect procedure path:
app.post("/tzero.v1.payment.ProviderService/PayOut", async (c) => {
  const body = new Uint8Array(await c.req.arrayBuffer());
  const result = decode(PayoutRequestSchema, { body, headers: c.req.raw.headers });

  if (!result.ok) {
    return new Response(result.error.body, {
      status: result.error.status,
      headers: result.error.headers,
    });
  }

  const response = await handlePayout(result.request);

  // encodeResponse validates + encodes in the matching wire format (JSON or proto)
  const wire = result.encodeResponse(PayoutResponseSchema, response);
  return new Response(wire.body, { status: wire.status, headers: wire.headers });
});
// Raw Node http example:
import http from "node:http";
import { createRequestDecoder, PayoutRequestSchema, PayoutResponseSchema } from "@t-0/provider-sdk";

const decode = createRequestDecoder({
  networkPublicKey: process.env.NETWORK_PUBLIC_KEY!,
});

http.createServer((req, res) => {
  const chunks: Buffer[] = [];
  req.on("data", (c) => chunks.push(c));
  req.on("end", async () => {
    const body = Buffer.concat(chunks);
    const result = decode(PayoutRequestSchema, { body, headers: req.headers });

    if (!result.ok) {
      res.writeHead(result.error.status, result.error.headers);
      res.end(result.error.body);
      return;
    }

    const response = await handlePayout(result.request);
    const wire = result.encodeResponse(PayoutResponseSchema, response);
    res.writeHead(wire.status, wire.headers);
    res.end(wire.body);
  });
}).listen(3000);

The decoder accepts both fetch Headers and Node's Record<string, string | string[] | undefined>. It normalizes header case internally, detects Content-Type (application/json or application/proto / application/protobuf / application/x-protobuf), and the returned encodeResponse closure responds in the matching format.

For custom proto registries (e.g. non-network schemas with custom predefined rules), use the generic createRequestDecoder from @t-0/provider-sdk/crypto and pass your own registry.

createRequestDecoder accepts the same logger option as createService. Response-validation failures from encodeResponse are logged at error level (response_type, violations, sdk_version) and returned as 500 with violations in the body. Each Violation includes field, message, and ruleId (the buf.validate rule identifier). Request-validation failures are returned in the 400 body but not logged, consistent with the Connect path.

import pino from "pino";

const pinoLogger = pino();

const decode = createRequestDecoder({
  networkPublicKey: process.env.NETWORK_PUBLIC_KEY!,
  logger: {
    error: (msg, fields) => pinoLogger.error(fields, msg),
  },
});

If omitted, the SDK logs to stderr as a single JSON line per event (same default as createService).

Important constraints for standalone integrations:

  • Raw body bytes only. Pass the exact wire bytes — no body parsers, no auto-decompression, never re-serialized protobuf. Protobuf encoding is not canonical; re-encoding produces different bytes and breaks verification.
  • Health endpoint. The T-0 Network probes /grpc.health.v1.Health/Check on every endpoint. The probe is signed. Standalone integrations must route this path and return a valid health response. See docs/HEALTH_SERVICE.md for the wire contract.
  • DecodeRequestFailure is an open union. New error shapes may be added without a major version bump. Handle unknown failures as generic errors.

The individual building blocks are also exported: createRequestVerifier, rejectRequest, verifySignature, computeDigest, keccak256, parsePublicKey, publicKeyFromPrivateKey, publicKeysEqual, and the NetworkHeaders header-name enum. You can import just the crypto module via the ./crypto subpath: import { createRequestVerifier } from "@t-0/provider-sdk/crypto".

Provider Public Key

Derive the uncompressed public key to register with the T-0 team from the same private key used by your client:

import { publicKeyFromPrivateKey } from "@t-0/provider-sdk";

const publicKey = publicKeyFromPrivateKey(process.env.PROVIDER_PRIVATE_KEY!);
console.log(publicKey); // 0x04-prefixed uncompressed public key

The input may be bare hexadecimal or use the lowercase 0x prefix; output is canonical lowercase 0x04....

Network Client

Use createClient to call T-0 Network APIs. The client handles request signing automatically:

import { createClient, NetworkService } from "@t-0/provider-sdk";

const privateKey = process.env.PROVIDER_PRIVATE_KEY!;
const endpoint = process.env.TZERO_ENDPOINT || "https://api-sandbox.t-0.network";

const networkClient = createClient(privateKey, endpoint, NetworkService);

// Publish quotes
await networkClient.updateQuote({
  payOut: [
    {
      currency: "EUR",
      quoteType: 1, // REALTIME
      paymentMethod: 1,
      bands: [{ clientQuoteId: "q1", maxAmount: { value: "10000" }, rate: { value: "0.92" } }],
      expiration: { seconds: BigInt(Math.floor(Date.now() / 1000) + 30) },
      timestamp: { seconds: BigInt(Math.floor(Date.now() / 1000)) },
    },
  ],
});

// Get a quote
const quote = await networkClient.getQuote({
  amount: { payOutAmount: { value: "100" } },
  payOutCurrency: "EUR",
  payOutMethod: 1,
  quoteType: 1,
});

Development

npm ci               # Install dependencies
npm run build        # Build (ESM + CJS dual output)
npm test             # Run tests