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

@doc-cheap/ai-sdk

v0.1.1

Published

doc.cheap tools for the AI SDK – read passports, ID cards and driving licences into structured fields. Free: 100 documents every month, then $0.01 each

Readme

@doc-cheap/ai-sdk

doc.cheap tools for the AI SDK: a model that has them can read a photo or scan of a passport, national ID card or driving licence and get back the printed fields – name, date of birth, document number, expiry, the machine-readable zone – as structured JSON.

One recognised document costs one credit, $0.01. Registering gives 100 free documents every month. An unreadable image, an empty frame or an unsupported document type costs nothing, and every answer says whether it was billed.

Installation · Usage · API key · Tools · Errors · Resources · Version history

Installation

npm install @doc-cheap/ai-sdk ai zod

ai (version 6 or 7) and zod (3.25.76 or later, or 4) are peer dependencies: the package uses the copies your project already has. It needs Node.js 20 or later.

Usage

import { generateText, isStepCount } from "ai";
import { docCheapTools } from "@doc-cheap/ai-sdk";

const { text } = await generateText({
  model: "openai/gpt-5-mini",
  tools: docCheapTools(),
  stopWhen: isStepCount(3),
  prompt:
    "Read the passport at https://example.com/passport.jpg and tell me " +
    "the holder's name and when the passport expires.",
});

console.log(text);

docCheapTools() returns all five tools. To give the model only some of them, build each one on its own:

import { getUsage, scanDocument } from "@doc-cheap/ai-sdk";

const tools = { scanDocument: scanDocument(), getUsage: getUsage() };

Every builder takes the same options:

| Option | Default | Meaning | | --- | --- | --- | | apiKey | DOC_CHEAP_API_KEY, then sk_sandbox_public | The key sent as a Bearer token. | | baseUrl | DOC_CHEAP_API_BASE, then https://api.doc.cheap | The API's address. | | fetch | the runtime's own | The fetch the API calls go through. |

The environment is read when a tool runs, not when it is built, so a .env file loaded after the import still applies.

API key

Set DOC_CHEAP_API_KEY to a live key (sk_live_…) from the doc.cheap cabinet.

Without a key the tools use the public sandbox key sk_sandbox_public, so they work before you have an account. The sandbox gives 10 free recognised documents per address in all, and at most 10 requests per address an hour, whatever their answer. Nothing made under a sandbox key is stored.

Tools

| Tool | API call | What it does | | --- | --- | --- | | scanDocument | POST /v1/scans | Recognises a passport, ID card or driving licence. | | getScan | GET /v1/scans/{id} | Reads back a stored result. Never charges. | | deleteScan | DELETE /v1/scans/{id} | Deletes a stored result for good. | | listScans | GET /v1/scans | Lists stored results, newest first, a page at a time. | | getUsage | GET /v1/usage | This month's free credits, the paid credits and the scan counters. |

scanDocument

| Input | Type | Meaning | | --- | --- | --- | | imageUrl | string | An https: URL of a JPEG or PNG on a public address. The package downloads it itself, 25 MiB at most. | | imageBase64 | string | The image as base64, or a data: URL. Give this or imageUrl, not both. | | expectCountry | string | Optional. The country you expect, a three-letter code such as GRC. | | returnPortrait | boolean | Optional. Whether to return the holder's photo crop (default true). | | retainHours | number | Optional. How many hours the result can be read back, 0 to 8760. Empty uses the account's setting. | | reference | string | Optional. Your own reference, up to 128 characters, echoed back. | | idempotencyKey | string | Optional. Sending the same key again returns the first answer instead of charging a second scan. |

The result is the scan as the API returns it: meta (id, status, whether it was billed, confidence), the document, the holder, every field read off the page, the machine-readable zone and the image crops. Your code gets the whole result. The copy the model sees has each image crop replaced by a short note of its size, because a model cannot look at base64 text and it would fill the context window.

Image URLs. Only https: URLs on public internet addresses are fetched. A URL that points at a private, loopback or link-local address is refused, and so is a redirect to one; each redirect is checked again, and the address is checked once more at the moment of connecting.

Stored results. A result is stored only when the scan was made with a live key under a non-zero retention window, and only until that window ends. Under a sandbox key nothing is stored, so getScan and deleteScan answer "not found" and listScans is empty.

Errors

A failed call throws a DocCheapError. The AI SDK hands the message to the model as the tool's error result, so the model can react to it. The error has status – the HTTP status, or null when no answer came back – and code, the API's own error code.

  • 401 / 403 – the API key was refused.
  • 429 – the rate limit or the sandbox allowance was reached: try later. The key itself is fine.
  • 404 – the scan does not exist, or was never stored.
  • invalid_input – the arguments were wrong, for example both imageUrl and imageBase64, or an image that is not JPEG or PNG.
  • image_refused – the image URL could not be fetched or is not allowed.
  • network_error – doc.cheap could not be reached.

Every request carries the header User-Agent: doc-cheap-ai-sdk/<version>, so the API can tell calls made through this package from other callers. Nothing else about your application is sent.

Resources

Version history

See CHANGELOG.md.

License

MIT