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

@hanzo/pdf

v1.0.0

Published

Hanzo AI for PDFs — a self-contained web PDF workspace (PDF.js viewer + Hanzo AI side panel). Read, ask, summarize, and extract over filings, discovery, and executed contracts, wired to the same api.hanzo.ai gateway as the Office add-in.

Downloads

196

Readme

Hanzo AI for PDFs

A self-contained web PDF workspace: a PDF.js viewer on the left, a Hanzo AI panel on the right. Open a filing, an executed contract, or a discovery document, then ask, summarize, and extract over it. This is the surface a lawyer spends the most time in — and unlike Acrobat's C++/Windows plugin SDK, this runs anywhere a browser does, with no Adobe license.

It reuses the same backend as the rest of the Hanzo productivity suite: model calls go through api.hanzo.ai/v1 (OpenAI-compatible, streamed over SSE), the same gateway the Office add-in (@hanzo/office-addin) uses. No new API surface.

What it does

  • Renders the PDF (PDF.js) with page navigation and text selection.
  • Extracts the selectable text of every page in the browser.
  • Answers questions grounded in that text, streaming the reply — with a legal-analyst system prompt that cites page numbers and refuses to guess.
  • Law-office quick actions: Summarize · Extract parties, dates & obligations · Find & explain risky clauses · Explain the selection plainly · Draft a summary memo.

Nothing leaves the browser except the pages sent with a question. Scanned image PDFs (no text layer) are detected and reported honestly — there is no OCR here.

Large PDFs — honest context windowing

A 500-page filing does not fit a model context window and is never sent wholesale. buildContext (in src/config.ts, pure and unit-tested) caps the attached text at CONTEXT_CHAR_BUDGET (48 000 chars) and:

  • Whole document scope windows from page 1, including as many whole pages as fit the budget, in order.
  • Current page only scope windows from the page you're viewing, so a question about what's on screen sends that page and its neighbours, not the top of the document.
  • The first line of every request is a context note stating the exact page range sent and, when pages were dropped, telling the model to answer only from what it sees and to say so if a full answer needs the omitted pages. The model is never told it has the whole document when it doesn't.

An oversized single page is hard-cut to the budget (and flagged truncated) rather than silently overflowing.

Auth

Paste a Hanzo API key (hk-…); it is validated by a real /v1/models call before it is saved to localStorage, so a dead key is rejected at paste time, not at first question. An empty key still reaches the gateway's public models. OAuth via hanzo.id (device login) is the documented future upgrade — the bearer plumbing already tolerates any token, so it slots in without a rewrite.

Build

pnpm --filter @hanzo/pdf build      # production (base https://pdf.hanzo.ai)
pnpm --filter @hanzo/pdf test        # vitest — pure logic
pnpm --filter @hanzo/pdf typecheck   # tsc --noEmit

build.js (esbuild → dist/) bundles app.ts as ESM and copies PDF.js's worker (pdf.worker.mjs) beside it — app.js resolves it at runtime via new URL('./pdf.worker.mjs', import.meta.url), so the worker must sit next to app.js. dist/ is fully static: index.html, app.js, pdf.worker.mjs, styles.css, assets/. Override the hosting base for local dev:

HANZO_PDF_BASE=https://localhost:8080 pnpm --filter @hanzo/pdf build

Run / host

dist/ is a static site — serve it over HTTPS from any static host. Locally:

pnpm --filter @hanzo/pdf build
cd packages/pdf/dist && python3 -m http.server 8080   # then open http://localhost:8080

Deploy target: pdf.hanzo.ai over hanzoai/static (the k8s-native static plugin behind hanzoai/ingress — no nginx/caddy). Point the static plugin at the built dist/; there is no server-side component. CORS is not needed — api.hanzo.ai is same-origin-policy-friendly for the browser fetch; the gateway sets the response headers.

The engine is small, pure, and tested

The logic-heavy parts live in their own modules with vitest coverage (tests/):

  • config.ts — endpoints, pickBearer, and buildContext/contextNote (the large-PDF windowing and the honest scope note).
  • chat.ts — request/response shaping (buildMessages, requestBody, extractContent, streamDelta, ask, askStream, listModels) — the same wire contract as the Office add-in.
  • pdf-view.ts — the PDF.js binding; itemsToText (the text-flattening helper) is isolated and unit-tested without a real PDF.

app.ts is the thin, browser-only DOM glue that binds them together.