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

@aoexl/sign

v1.2.23

Published

Embeddable PDF eSignature SDK by Aoexl

Readme

@aoexl/sign

Embed Aoexl's PDF signing experience directly inside your product.

Install

npm install @aoexl/sign

Production model

Use pk_test_demo for local evaluation and move to your own pk_live_* key for production. Production embeds are expected to use the managed Aoexl engine after license validation.

Recommended production auth order:

  • easiest: licenseEndpoint="/api/aoexl-token" so the browser talks only to your backend
  • advanced SPA: getEngineToken={async () => ...} for custom fetch logic
  • SSR / one-off page: engineToken="..." for a pre-minted short-lived token
  • legacy compatibility: licenseKey="pk_live_..." directly in the browser

base and engineUrl can be used for localhost development or for same-origin app-hosted engine assets in production. Arbitrary cross-origin engine URLs stay blocked by the SDK.

React

import { AoexlViewer } from "@aoexl/sign";

export default function EmbeddedSigner() {
  return (
    <AoexlViewer
      licenseEndpoint="/api/aoexl-token"
      pdfUrl="/Merchant.pdf"
      mode="embedded-signing"
      signerInfo={{ name: "Taylor Merchant", email: "[email protected]" }}
      completionRedirectUrl="/done?session={{sessionId}}&completedAt={{completedAt}}"
      onComplete={(result) => console.log(result)}
      onError={(error) => console.error(error)}
    />
  );
}

Vanilla JS

import AoexlSign from "@aoexl/sign";

const viewer = await AoexlSign.init({
  licenseEndpoint: "/api/aoexl-token",
  container: "#signer",
  pdfUrl: "/Merchant.pdf",
  mode: "embedded-signing",
});

// later
viewer.destroy();

Props

All configuration for AoexlSign.init() or <AoexlViewer /> is passed via the config object:

| Prop | Type | Description | | :--- | :--- | :--- | | licenseKey | string | Legacy browser-validation path (pk_test_* or pk_live_*). | | engineToken | string | Pre-minted short-lived engine token from your backend. | | getEngineToken | Function | Async function that returns a short-lived engine token. | | licenseEndpoint | string | Easiest production path. SDK POSTs { domain, timestamp } to your backend route and expects { engineToken, refreshAfterSeconds? }. | | pdfUrl | string | URL of the PDF to load. | | pdfData | Uint8Array \| Blob \| string | Raw bytes or data-URL (alternative to pdfUrl). | | mode | AoexlMode | 'prepare', 'sign', or 'view'. | | theme | Theme | Customise colors (primaryColor) and container layout. | | signers | Signer[] | Define signer roles and identities. | | fields | Field[] | Restore a previously saved field layout. | | completionRedirectUrl | string | Optional redirect after completion. Supports {{sessionId}}, {{fileName}}, {{completedAt}}, {{signerName}}, {{signerEmail}}. | | base | string | Asset base for localhost development or same-origin app-hosted engine assets. | | ui | UIConfig | Hide specific buttons or sidebars using hide: []. | | config | Config | Behavior flags such as first-load zoom, field order, auto-flattening, and flattened banner customization. | | onComplete | Function | Fired when signing is finished and document is ready. |

At least one auth prop is required: licenseKey, engineToken, getEngineToken, or licenseEndpoint.

For the full prop contract, responsive behavior notes, and embed recipes, see PROPS.md.

First-load zoom and flattened banner

Use config.initialViewMode when an embedded PDF should open responsively instead of at a fixed zoom percentage.

<AoexlViewer
  licenseEndpoint="/api/aoexl-token"
  pdfUrl="/Merchant.pdf"
  mode="sign"
  initialScale={1}
  config={{
    initialViewMode: "fit-width",
    flattenedBanner: {
      text: "This document is locked for review.",
      backgroundColor: "#0f172a",
      textColor: "#ffffff",
      actionLabel: "Edit again",
      showUnlock: true
    }
  }}
/>

initialViewMode supports 'scale', 'fit-width', and 'fit-page'. Set flattenedBanner: false to hide the flattened-document banner entirely.

Responsive signing behavior

The SDK supports two common embedded experiences:

  • mode="view" for read-only disclosures or consent PDFs
  • mode="sign" / mode="signing" for signer-facing flows

For signing embeds, prefer:

<AoexlViewer
  mode="sign"
  ui={{ hide: ["toolbar"] }}
  config={{
    initialViewMode: "fit-width",
    enableSignatureIndicator: true,
  }}
/>

That combination is the supported way to:

  • hide the header row
  • show the signing progress widget instead of the centered header tabs
  • keep the bottom signing-progress footer on widths below 960px

For read-only embeds, keep mode="view" and use config.initialViewMode: "fit-width" so the PDF fills the container on first load.

Backend token route example

The secure-but-easy production model is:

  1. frontend uses licenseEndpoint="/api/aoexl-token"
  2. your backend stores the long-lived pk_live_* key
  3. your backend calls Aoexl server-to-server
  4. your backend returns only the short-lived engine token

Example backend route:

app.post('/api/aoexl-token', async (req, res) => {
  const upstream = await fetch('https://aoexl.com/api/v1/license_verification', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      licenseKey: process.env.AOEXL_LICENSE_KEY,
      domain: req.body.domain,
      timestamp: req.body.timestamp,
    }),
  })

  const data = await upstream.json()
  if (!upstream.ok || !data?.engineToken) {
    return res.status(400).json({ error: data?.error || 'Failed to mint engine token' })
  }

  res.json({
    engineToken: data.engineToken,
    refreshAfterSeconds: data.refreshAfterSeconds,
  })
})

Loading and rendering guarantees

The SDK validates the license first and only then fetches the managed Aoexl engine for production use.

To avoid scroll stutter in short onboarding packets and consent forms, PDFs with 5 pages or fewer render every page up front at high canvas quality. Larger PDFs render on demand while showing an in-view preparing state instead of leaving a blank page.

When a user uploads or opens a different PDF inside the viewer, previously supplied fields are cleared for that new document. If you want fields on the replacement PDF, pass the saved field layout for that PDF when you initialize or reinitialize the viewer.

API

The init() method returns a viewer instance with the following methods:

  • destroy(): Unmount and cleanup.
  • savePdf(options): Triggers a download/save of the current PDF state.
  • getPdfBytes(options): Returns the signed PDF as a Uint8Array.
  • flattenPdf(): Merges all annotations and signatures into the base PDF.
  • setScale(value): Sets the zoom level (e.g. 1.5 for 150%).
  • fitWidth() / fitPage(): Auto-scale to fill the viewport.

How It Works

  • The npm package is the public shell package (~400KB).
  • The heavier managed engine (~4MB) is fetched dynamically after license validation.
  • Live keys are enforced server-side and authorized origins are validated.

Docs