@sameerv99/pdf-stream-kit
v0.1.0
Published
Cross-browser PDF streaming for pdfjs-dist — fixes Chrome range request issues with automatic HEAD detection and optional proxy middleware
Maintainers
Readme
@sameerv99/pdf-stream-kit
Cross-browser PDF streaming for pdfjs-dist — fixes Chrome range request issues with automatic HEAD detection and an optional server-side proxy middleware.
The Problem
Chrome requires a server to respond with Accept-Ranges: bytes and Content-Length headers for PDF.js to stream a PDF in chunks. Without them, Chrome downloads the entire file in a single request — slow and memory-heavy. Safari works fine because it uses its native PDF viewer.
Solution
This package provides two complementary tools:
- Client (
/client): A drop-in replacement forpdfjs-dist'sgetDocument(). It sends a HEAD request to detect range support, and if the server doesn't support it, transparently rewrites the URL through your proxy. - Proxy (
/proxy): A zero-dependency Node.js middleware (Express / Fastify / raw http) that fetches the PDF from the origin and adds the missing streaming headers.
Installation
npm install @sameerv99/pdf-stream-kit
# pdfjs-dist is a peer dependency
npm install pdfjs-distUsage
Client (browser)
import { getDocument, configure } from '@sameerv99/pdf-stream-kit/client'
// Optional: set a proxy URL and custom headers once
configure({
proxyUrl: '/pdf-proxy', // your server-side proxy route
headers: { Authorization: 'Bearer token' },
rangeChunkSize: 65536, // default
})
// Drop-in replacement for pdfjs-dist's getDocument()
const loadingTask = getDocument('https://example.com/file.pdf')
loadingTask.onProgress = ({ loaded, total }) => console.log(loaded, total)
const pdf = await loadingTask.promiseIf the server already supports range requests, the URL is used as-is. If not, it is rewritten to go through proxyUrl.
Proxy middleware — Express
const express = require('express')
const { pdfProxy } = require('@sameerv99/pdf-stream-kit/proxy')
const app = express()
app.use('/pdf-proxy', pdfProxy({
allowedOrigins: ['https://your-cdn.example.com'],
}))Proxy middleware — Fastify
import Fastify from 'fastify'
import { pdfProxyFastify } from '@sameerv99/pdf-stream-kit/proxy'
const fastify = Fastify()
fastify.register(pdfProxyFastify, {
prefix: '/pdf-proxy',
allowedOrigins: ['https://your-cdn.example.com'],
})Proxy middleware — raw Node.js http
const http = require('http')
const { pdfProxy } = require('@sameerv99/pdf-stream-kit/proxy')
const handler = pdfProxy({ allowedOrigins: ['https://your-cdn.example.com'] })
http.createServer((req, res) => {
if (req.url.startsWith('/pdf-proxy')) {
req.url = req.url.replace('/pdf-proxy', '')
handler(req, res)
}
}).listen(3000)The proxy accepts GET /pdf-proxy?url=<encoded-url> and forwards the request to the origin, adding:
| Header | Value |
|---|---|
| Accept-Ranges | bytes |
| Content-Type | application/pdf |
| Access-Control-Allow-Origin | * |
| Access-Control-Expose-Headers | Content-Length, Content-Range, Accept-Ranges |
API
configure(options) — client only
| Option | Type | Default | Description |
|---|---|---|---|
| proxyUrl | string \| null | null | Proxy route to rewrite URLs through |
| headers | object | {} | HTTP headers added to every request |
| rangeChunkSize | number | 65536 | Bytes per chunk passed to pdfjs-dist |
getDocument(src) — client only
Accepts the same arguments as pdfjs-dist's getDocument(): a URL string or a DocumentInitParameters object. Returns an object with:
.promise— resolves to aPDFDocumentProxy.onProgress— setter/getter, forwarded to the inner pdfjs-dist task.destroy()— cancels loading
pdfProxy(options) — proxy only
| Option | Type | Default | Description |
|---|---|---|---|
| allowedOrigins | string[] | [] (all allowed) | Origin URLs the proxy will fetch from |
Returns a (req, res) => Promise<void> middleware.
pdfProxyFastify(fastify, options, done) — proxy only
Fastify plugin. Same options as pdfProxy.
License
MIT
