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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@clavata/sdk

v0.4.1

Published

This directory contains the JS version of our SDK.

Downloads

1,121

Readme

Clavata JavaScript SDK

This directory contains the Clavata JavaScript SDK with type definitions.

Getting started

Email [email protected] if you do not already have an API key/token.

Initialize the SDK to get started making requests to the Clavata API.

import Clavata from "@clavata/sdk";

// API key can be provided directly or via environment variable
const clavata = new Clavata({ apiKey: "<YOUR_CLAVATA_API_KEY>" } as Options);

Configuration

The client constructor accepts the following options:

interface Options {
  // Your API key. If not provided you _must_ then set CLAVATA_API_KEY as an environment variable
  apiKey?: string;
  // Optional
  server?: string; // Server endpoint (default: "gateway.app.clavata.ai:443")
  insecure?: boolean; // Use insecure connection. (default: false)
  keepalive?: {
    // Connection keepalive settings
    timeout: number; // How long to wait for a response to a keepalive ping before considering the connection dead (in ms). (default: 10000)
    permitWithoutCalls: boolean; // Allows keepalive pings to maintain idle connections. (default: true)
    time: number; // How frequently to send keepalive pings to check if the connection is alive (in ms). (default: 10000)
  };
  maxMessageLength?: number; // Max message size (default: 100MB)
  retryConfig:
    | {
        // Configuration for automatic retries. Will retry by default. Set to `false` to disable this. See https://grpc.io/docs/guides/retry for more info.
        maxAttempts?: number; // Maximum number of retry attempts (default: 5)
        initialBackoff?: string; // Initial backoff time in milliseconds (default: "1s")
        maxBackoff?: string; // Maximum backoff time (default: "30s")
        backoffMultiplier?: number; // Multiplier for backoff time after each retry (default: 2.0)
        jitter?: number; // Jitter factor between 0 and 1 (default: 0.2, 0 = no jitter, 1 = full jitter)
      }
    | false;
}

If neither an API key is provided to the constructor nor is a process.env.CLAVATA_API_KEY environment variable set then the constructor will throw an error.

RPC Methods

getJob(jobId: string): Promise<Job | undefined>

  • Retrieves a job by its UUID.

listJobs(request: ListJobsRequest): Promise<ListJobsResponse>

  • Lists jobs with filtering parameters.

createJob(request: CreateJobRequest): Promise<CreateJobResponse[]>

  • Creates a new job with the provided content data and returns the id and status of the job that can be requested at a later point in time. If you need to await the result use evaluate instead.

evaluate(request: EvaluateRequest): Promise<AsyncIterable<EvaluateMessage | StreamError>>

  • Evaluates each input and returns a stream of responses or errors. Order is not guaranteed, so using metadata or a contentHash is advised when sending multiple pieces to evaluate in a single call.
  • Example:
const stream = clavata.evaluate({
  contentData: [
    {
      metadata: { id: "1" },
      content: { value: "Hello, world!", $case: "text" },
      contentType: "text",
    },
    {
      metadata: { id: "2" },
      content: { value: Buffer.from("<BASE64_DATA>", "base64"), $case: "image" },
      contentType: "image/png",
    },
    {
      metadata: { id: "3" },
      content: { value: "<IMAGE_URL>", $case: "imageUrl" },
      contentType: "image/jpeg",
    },
  ],
  policyId: "00000000-0000-0000-0000-000000000000",
});

for await (const item of stream) {
  if (item instanceof StreamError) throw item;

  const { metadata, report } = item;
  console.log({ id: metadata?.id, matches: report?.matches });
}

Refusals

Under certain circumstances, the Clavata API will refuse to evaluate content as requested. There are only a few possible reasons for this:

  1. The content (image) matches a known hash in our CSAM database. This can be either an exact match or a perceptual hash match.
  2. The content (image) is in an unsupported format. Currently, Clavata supports webp, png and jpg images.
  3. The content was corrupt. Usually because the content was incomplete or the encoding (for images) was incorrect.

When a refusal occurs, a StreamError will be returned (for evaluate) or thrown (for createJob). You can check whether the error was caused by a refusal using the getRefusalReason() method on the StreamError type. If the error was not caused by a refusal, this method will return undefined. If the error is due to a refusal, a RefusalReason will be returned.

The RefusalReason type is a enum with strings matching one of:

  • "CSAM"
  • "UNSUPPORTED_IMAGE_FORMAT"
  • "INVALID_IMAGE"

There is also an "UNKNOWN" option, but this case indicates something went wrong decoding the "reason" information in the response.


import { RefusalReason } from "@clavata/sdk";

const stream = clavata.evaluate(...)

for await (const item of stream) {
  if (item instanceof StreamError) {
    const reason = item.getRefusalReason();
    if (!reason) {
      // Not a refusal, you can check the other possible identification methods like
      if (item.isTransient()) {
        // Transient error so we can retry
      }
    }

    // It was a refusal, so we can use a switch statement to figure out why
    switch (reason) {
      case RefusalReason.CSAM:
        // Handle CSAM appropriately
        break;
      case RefusalReason.UNSUPPORTED_IMAGE_FORMAT:
        // Convert image and try again
        break;
      case RefusalReason.INVALID_IMAGE:
        // data corruption, maybe try to re-download from CDN and try again?
        break;
      default:
        // unknown reason for refusal
    }
  }
}

Getting the Refusal Error

If you prefer, you can convert a StreamError into a RefusalError with the toRefusalError() method. Once again, if the error was not caused by a refusal, this method will return undefined. If, however, a refusal did occur the RefusalError type that is returned has the following interface that you can use to understand why:

interface RefusalError {
  isCSAM(): boolean;
  isUnsupportedImageFormat(): boolean;
  isInvalidImage(): boolean;
  isUnknown(): boolean;
  getReason(): RefusalReason;
}

// So you can do this:
if (item instanceof StreamError) {
  const refusalErr = item.toRefusalError();
  if (refusalErr.isCSAM()) {
    // Take action based on the content having been CSAM
  }
}

Which interface you use to determine the reason is up to you, they are functionally equivalent.

Refusals and createJob

When calling createJob, a promise is returned. If an error occurs, that error is automatically converted to a StreamError by the SDK and re-thrown. You can then catch the StreamError and check for refusals the same way.

Contributing

Update the version with npm version to the next SEMVER then run npm publish.