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

@withmateza/sdk

v0.1.3

Published

Framework-agnostic TypeScript client for the [Mateza Platform API](https://api.mateza.rw/docs) — translation, speech, multimodal, uploads, glossary, usage, request logs, feedback, and the supported language catalog.

Downloads

283

Readme

@withmateza/sdk

Framework-agnostic TypeScript client for the Mateza Platform API — translation, speech, multimodal, uploads, glossary, usage, request logs, feedback, and the supported language catalog.

  • API reference (OpenAPI): https://api.mateza.rw/docs
  • API base URL: https://api.mateza.rw
  • Source-language pivot: English ⇄ Kinyarwanda (with growing direct/pivot support for Swahili, Amharic, Oromo, Tigrinya, Somali, Luganda).

Install

npm install @withmateza/sdk
pnpm add @withmateza/sdk
yarn add @withmateza/sdk

Requires Node.js 18+ (or any runtime that exposes a global fetch and FormData). Inside this monorepo, depend on @withmateza/sdk via workspace:*.

What's in the box

  • createClient / createPublicClient — server-side and browser-safe API client factories. Both return the same surface; pick the name that matches your context.
  • ApiError, API_ERROR_CODES, isApiErrorCode, isRetryableErrorCode — a canonical error taxonomy and a default retry table, both overridable per response.
  • request, ClientOptions, FetchFn — low-level helpers for advanced custom transports.
  • Re-exported Zod schemas and TypeScript types for every response (translateResponseSchema, speechJobResponseSchema, i18nBundleResponseSchema, *Schema, …).
  • Lang, langValues, LANGUAGE_CATALOG, TranslationSupport — language enum and capability metadata.
  • model-exposure helpers describing which model variants are publicly callable.

Quick Start (server)

import { createClient } from "@withmateza/sdk";

const mateza = createClient({
  baseUrl: "https://api.mateza.rw",
  apiKey: process.env.MATEZA_API_KEY, // server-only secret
});

const result = await mateza.translate({
  text: "Hello world",
  source_lang: "en",
  target_lang: "rw",
  model_intent: "fast",
});

console.log(result.data.translation, result.request_id);

Quick Start (browser / mobile)

import { createPublicClient } from "@withmateza/sdk";

const mateza = createPublicClient({
  baseUrl: "https://api.mateza.rw",
  clientKey: process.env.NEXT_PUBLIC_MATEZA_CLIENT_KEY, // browser-safe
});

const langs = await mateza.listLanguages();

createPublicClient is an alias of createClient; the difference is intent. Use a clientKey from any context that ships to a user device, and reserve apiKey for trusted servers.

Auth and configuration

ClientOptions (see http.ts):

| Option | Type | Notes | | ----------- | ----------- | --------------------------------------------------------------------------------------- | | baseUrl | string | Required. Use https://api.mateza.rw in production. | | apiKey | string? | Default server API key. Sent as Authorization: Bearer …. | | clientKey | string? | Default browser client key. Sent as Authorization: Bearer …. | | fetch | FetchFn? | Custom fetch implementation. Defaults to globalThis.fetch. |

Per-call overrides: every method that accepts auth supports api_key and client_key properties on the payload. The first non-empty value wins, falling back to the constructor defaults.

All requests send cache: "no-store" and JSON-encode the body when body is a string. Multipart bodies (FormData) are forwarded untouched so the runtime can set the boundary header.

Methods

Every method returns Promise<{ data: …, request_id: string }> (except getUsage and listRequests, which mirror the API shape directly). All responses are validated with Zod schemas before being returned, so unknown server fields are stripped at the client boundary.

The full request and response schema for every endpoint below lives at https://api.mateza.rw/docs.

Translation

translate(payload)POST /api/v1/translate

await mateza.translate({
  text: "Mwiriwe",
  source_lang: "rw",
  target_lang: "en",
  // optional:
  model_variant: "rw_en_adapter_v1",
  model_intent: "fast", // "auto" | "fast" | "best_quality" | "advanced"
});

If the API decides to queue the request (HTTP 202), the client transparently polls /api/v1/translate/jobs/:id until the job completes, fails, or 10 minutes elapse. The returned shape is always the synchronous TranslateResponse.

translateBatch(payload)POST /api/v1/translate/batch

Translate up to 50 items in one call. Each item carries its own source_lang / target_lang so a batch may be heterogeneous.

translateI18n(payload)POST /api/v1/translate/i18n

Translate an i18n-style key→value bundle and benefit from server-side caching:

const bundle = await mateza.translateI18n({
  source_lang: "en",
  target_lang: "rw",
  namespace: "marketing-site",
  messages: {
    "nav.home": "Home",
    "hero.title": "Translate your site instantly",
  },
  // optional:
  model_intent: "fast",
  refresh: false,
});

bundle.data.stats.bundle_hit; // true on subsequent identical calls
bundle.data.messages["nav.home"]; // "Ahabanza"

Re-submitting the same bundle returns immediately (bundle_hit: true). When a bundle evolves, only changed keys are rerun through the model. This is the engine that powers @withmateza/website.

startTranslateJob(payload) / getTranslateJob(jobId)POST /api/v1/translate/jobs, GET /api/v1/translate/jobs/:id

Explicitly enqueue a translation job and poll it yourself. Useful when you want full control over backoff, observability, or progress UI.

Speech

startSpeechTranslate(payload)POST /api/v1/speech/translate

Three input modes are supported via discriminated unions:

// 1. URL input
await mateza.startSpeechTranslate({
  media_url: "https://example.com/clip.mp4",
  mode: "auto",
});

// 2. Base64 input (small clips)
await mateza.startSpeechTranslate({
  audio_base64: encoded,
  file_name: "demo.wav",
  mime_type: "audio/wav",
});

// 3. Multipart upload (large clips, browser/Node Blob)
await mateza.startSpeechTranslate({
  file: blob,
  file_name: "demo.wav",
  analysis_outputs: ["subtitles", "summary"],
});

mode accepts "auto" | "sync" | "async". In auto / async mode the response is a pending job; pair it with waitForSpeechJob below.

getSpeechJob(jobId, apiKey?, clientKey?)GET /api/v1/speech/jobs/:id

waitForSpeechJob(params) — long-poll helper

Polls until the job reaches completed or failed. Defaults: interval_ms: 2000, timeout_ms: 120000. Throws ApiError("UPSTREAM_TIMEOUT", 504, …) on timeout.

const final = await mateza.waitForSpeechJob({
  job_id: started.data.job_id,
  interval_ms: 2000,
  timeout_ms: 5 * 60 * 1000,
});

Multimodal

processMultimodal(payload)POST /api/v1/multimodal

One entry point for text, audio, image, video, and document inputs. Provide either text, media_url, or audio_base64 depending on input_kind. Supports the same analysis_outputs (subtitles, ocr, summary) as the speech endpoint.

Uploads

uploadMedia(payload)POST /api/v1/uploads

Upload a Blob (or File) for reuse across speech / multimodal jobs without re-uploading the bytes. Returns a StoredMediaResponse containing an asset_id and a fresh signed download URL.

getUploadedMedia(payload)GET /api/v1/uploads/:asset_id

Refresh the signed download URL for a previously uploaded asset.

Feedback

createTranslationFeedback(payload)POST /api/v1/feedback/translation

Record a corrected translation that feeds the next training refresh. domain and reviewer are required for traceability; model_variant lets you target a specific adapter.

listTranslationFeedback({ limit })GET /api/v1/feedback/translation

Visibility

getUsage()GET /api/v1/usage

Aggregate request, character, and minute counters for the credential's project.

listRequests()GET /api/v1/requests

Recent request log entries scoped to the current credential.

listGlossary()GET /api/v1/glossary

listLanguages()GET /api/v1/languages

Supported language catalog with per-modality coverage (translation, asr, tts, vision).

guide({ topic, api_key? })POST /api/v1/guide

Optional, unauthenticated Rwanda visitor guide endpoint. Provides curated phrases, recommendations, and cost hints for a topic.

Errors

Every non-2xx response is normalized into ApiError:

import { ApiError, isRetryableErrorCode } from "@withmateza/sdk";

try {
  await mateza.translate({ text: "…", source_lang: "en", target_lang: "rw" });
} catch (err) {
  if (err instanceof ApiError) {
    err.code;        // "RATE_LIMITED" | "VALIDATION_ERROR" | …
    err.statusCode;  // 429
    err.requestId;   // server-issued correlation id
    err.retryable;   // server hint; falls back to default table
    err.details;     // structured payload (e.g. validation issues)

    if (err.retryable || isRetryableErrorCode(err.code)) {
      // back off and retry
    }
  }
}

Canonical codes (see errors.ts):

UNAUTHORIZED, FORBIDDEN, NOT_FOUND, VALIDATION_ERROR, RATE_LIMITED, CONFLICT, IDEMPOTENCY_REPLAY, UPSTREAM_TIMEOUT, UPSTREAM_UNAVAILABLE, UNSUPPORTED_MEDIA, MEDIA_TOO_LONG, MEDIA_FETCH_FAILED, ASR_FAILED, SPEECH_FAILED, TRANSLATION_FAILED, JOB_NOT_FOUND, JOB_FAILED, PAYMENT_REQUIRED, INTERNAL_ERROR, UNKNOWN.

Default retryable codes: RATE_LIMITED, UPSTREAM_TIMEOUT, UPSTREAM_UNAVAILABLE, MEDIA_FETCH_FAILED, ASR_FAILED. The server may override retryable per response.

Languages

import { LANGUAGE_CATALOG, langValues, type Lang } from "@withmateza/sdk";

langValues; // ["en","rw","sw","am","om","ti","so","lg","sid","wal"]
const directLanguages = LANGUAGE_CATALOG.filter((entry) => entry.translation === "direct");

LANGUAGE_CATALOG is the offline mirror of GET /api/v1/languages and is safe to bundle in a static UI. Use listLanguages() when you need live capability flags.

Schemas and types

All response schemas are exported as Zod schemas plus inferred TypeScript types — for example translateResponseSchema / TranslateResponse, speechJobResponseSchema / SpeechJobResponse, i18nBundleResponseSchema / I18nBundleResponse, usageSchema / Usage, languageCatalogResponseSchema / LanguageCatalogResponse. Import them when you need to validate cached payloads or reuse the input shapes:

import {
  type Lang,
  type TranslateResponse,
  i18nBundleResponseSchema,
} from "@withmateza/sdk";

const cached = i18nBundleResponseSchema.parse(JSON.parse(disk));

Custom transport

Inject a custom fetch to add observability, circuit breaking, or to run inside a non-standard runtime:

const mateza = createClient({
  baseUrl: "https://api.mateza.rw",
  apiKey: process.env.MATEZA_API_KEY,
  fetch: async (input, init) => {
    const response = await traced(input, init);
    return response;
  },
});

Lower-level access is available via request(baseUrl, path, init, fetchFn) if you need to call an endpoint that isn't yet exposed by a high-level method.

Common mistakes

  • Passing a server apiKey into browser code. Use clientKey instead.
  • Calling translate from a browser without setting clientKey.
  • Forgetting baseUrl (the constructor throws as soon as the first request fires).
  • Hand-escaping placeholders ({name}, %s, URLs, HTML). The API protects them automatically.
  • Importing from internal source files (@withmateza/sdk/src/...). Always import from the package entry point.
  • Treating responses as untyped JSON. Every method returns a Zod-validated, fully typed shape.

Related packages

Reference