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

@proveanything/smartlinks

v1.1.13

Published

Official JavaScript/TypeScript SDK for the Smartlinks API

Readme

@proveanything/smartlinks

Official JavaScript/TypeScript SDK for the Smartlinks API.

Build Smartlinks-powered apps in Node.js or the browser: list collections and products, authenticate users, manage assets and attestations, and call admin endpoints with a clean, typed API.

• TypeScript-first types and intellisense • Works in Node.js and modern browsers • Simple auth helpers (login, verify token, request admin/public JWTs) • Rich resources: collections, products, proofs, assets, attestations, batches, variants, AI, and more • Optional iframe proxy mode for embedded apps

For the full list of functions and types, see the API summary: → API Summary (API_SUMMARY.md)

Install

npm install @proveanything/smartlinks

Quick start

Initialize once at app startup with your API base URL. Trailing slashes are optional (normalized). In Node, you can also provide an API key for server-to-server calls. You can enable an ngrok header or supply custom headers.

import { initializeApi } from '@proveanything/smartlinks'

initializeApi({
  baseURL: 'https://smartlinks.app/api/v1',            // or 'https://smartlinks.app/api/v1/'
  // logger: console,                                   // optional: verbose logging of requests/responses and proxy messages
  // apiKey: process.env.SMARTLINKS_API_KEY,            // Node/server only (optional)
  // ngrokSkipBrowserWarning: true,                    // adds 'ngrok-skip-browser-warning: true'
  // extraHeaders: { 'X-Debug': '1' }                  // merged into every request
})

List public collections and fetch products:

import { collection, product } from '@proveanything/smartlinks'

const collections = await collection.list(false) // public endpoint
const first = collections[0]
if (first) {
  const products = await product.list(first.id, false) // public endpoint
  console.log('First product:', products[0])
}

Authentication

Use the built-in helpers to log in and verify tokens. After a successful login, the SDK stores the bearer token for subsequent calls.

import { initializeApi } from '@proveanything/smartlinks'
import { auth } from '@proveanything/smartlinks'

initializeApi({ baseURL: 'https://smartlinks.app/api/v1/' }) // trailing slash OK

// Email + password login (browser or Node)
const user = await auth.login('[email protected]', 'password')
console.log('Hello,', user.name)

// Verify an existing token (and set it if valid)
const verified = await auth.verifyToken(user.bearerToken)
console.log('Token valid?', verified.valid)

// Later, clear token
auth.logout()

Admin flows:

// Request an admin JWT for a collection (requires prior auth)
const jwt = await auth.requestAdminJWT('collectionId')

// Or request a public JWT authorized for a collection/product/proof
const publicJwt = await auth.requestPublicJWT('collectionId', 'productId', 'proofId')

Common tasks

Products

import { product } from '@proveanything/smartlinks'

// Public fetch
const item = await product.get('collectionId', 'productId', false)

// Admin create/update/delete (requires auth)
await product.create('collectionId', { name: 'New product' })
await product.update('collectionId', 'productId', { description: 'Updated' })
await product.remove('collectionId', 'productId')

Assets (upload)

Browser-side upload to a proof with progress callback:

import { asset } from '@proveanything/smartlinks'

const result = await asset.uploadAsset(
  'collectionId',
  'productId',
  'proofId',
  file, // File from an <input type="file">
  { description: 'Uploaded via SDK' },
  (progress) => console.log(`Upload: ${progress}%`)
)
console.log('Uploaded asset:', result)

AI helpers

import { ai } from '@proveanything/smartlinks'

const content = await ai.generateContent('collectionId', {
  contents: 'Write a friendly product blurb for our coffee beans.',
  responseMimeType: 'text/plain',
  provider: 'openai',
  model: 'gpt-4o'
})
console.log(content)

Analytics (Actions & Broadcasts)

Track user actions and broadcast deliveries per collection. These endpoints live under admin and require valid auth (API key or bearer token).

import { actions, broadcasts } from '@proveanything/smartlinks'

// List action events for a user
const actionEvents = await actions.byUser('collectionId', {
  userId: 'user_123',
  from: '2025-01-01T00:00:00Z',
  to: '2025-12-31T23:59:59Z',
  limit: 100,
})

// Outcome counts, optionally deduping latest per actor
const counts = await actions.countsByOutcome('collectionId', {
  actionId: 'click',
  dedupeLatest: true,
  idField: 'userId',
})

// Append a single action event
await actions.append('collectionId', {
  userId: 'user_123',
  actionId: 'click',
  outcome: 'success',
})

// Broadcast recipients and filters
const recipients = await broadcasts.recipientIds('collectionId', {
  broadcastId: 'br_456',
  idField: 'contactId',
})

// Append broadcast recipients in bulk (preferred shape)
await broadcasts.appendBulk('collectionId', {
  params: { broadcastId: 'br_456', channel: 'email' },
  ids: ['contact_1','contact_2'],
  idField: 'contactId',
})

Browser and React

The SDK works in modern browsers. Initialize once and call public endpoints without an API key; authenticate to access protected/admin endpoints.

import { initializeApi } from '@proveanything/smartlinks'
import { collection } from '@proveanything/smartlinks'

initializeApi({ baseURL: 'https://smartlinks.app/api/v1' })
const collections = await collection.list(false)

For a fuller UI example, see examples/react-demo.tsx.

Iframe Integration

When embedding Smartlinks inside an iframe (set proxyMode: true in initializeApi if you need parent-proxy API calls), you can also send UI/control messages to the parent window. The SDK provides lightweight helpers in iframe.ts:

import { enableAutoIframeResize, disableAutoIframeResize, redirectParent, sendParentCustom, isIframe } from '@proveanything/smartlinks'

// Automatically push height changes to parent so it can resize the iframe.
enableAutoIframeResize({ intervalMs: 150 })

// Later disable if not needed:
disableAutoIframeResize()

// Redirect parent window to a URL (e.g. after login):
redirectParent('https://app.example.com/dashboard')

// Send any custom event + payload:
sendParentCustom('smartlinks:navigate', { url: '/profile' })

if (isIframe()) {
  console.log('Running inside an iframe')
}

Parent page can listen for these messages:

window.addEventListener('message', (e) => {
  const msg = e.data
  if (!msg || !msg._smartlinksIframeMessage) return
  switch (msg.type) {
    case 'smartlinks:resize':
      // adjust iframe height
      const iframeEl = document.getElementById('smartlinks-frame') as HTMLIFrameElement
      if (iframeEl) iframeEl.style.height = msg.payload.height + 'px'
      break
    case 'smartlinks:redirect':
      window.location.href = msg.payload.url
      break
    case 'smartlinks:navigate':
      // Custom example
      console.log('Navigate request:', msg.payload.url)
      break
  }
})

Notes:

  • Auto-resize uses ResizeObserver when available, falling back to MutationObserver + polling.
  • In non-browser or Node environments these helpers safely no-op.
  • Use sendParentCustom for any domain-specific integration events.

Configuration reference

initializeApi({
  baseURL: string, // with or without trailing slash
  apiKey?: string,      // Node/server only
  bearerToken?: string, // optional at init; set by auth.login/verifyToken
  proxyMode?: boolean   // set true if running inside an iframe and using parent proxy
  ngrokSkipBrowserWarning?: boolean // forces header 'ngrok-skip-browser-warning: true'
  extraHeaders?: Record<string,string> // custom headers merged in each request
  iframeAutoResize?: boolean // default true when embedded in an iframe
  logger?: Function | { debug?: Function; info?: Function; warn?: Function; error?: Function; log?: Function } // optional verbose logging
})

// Auto-detection: If baseURL contains '.ngrok.io' or '.ngrok-free.dev' the header is added automatically
// unless you explicitly set ngrokSkipBrowserWarning: false.
// Auto iframe resize: When in an iframe, resize messages are sent by default unless iframeAutoResize: false.
// Verbose logging: Pass a logger (e.g. console) to log outbound requests/responses and proxy postMessages.

When embedding the SDK in an iframe with proxyMode: true, you can also use:

import { sendCustomProxyMessage } from '@proveanything/smartlinks'
const data = await sendCustomProxyMessage('my-action', { foo: 'bar' })

// Toggle ngrok header or update custom headers later:
import { setNgrokSkipBrowserWarning, setExtraHeaders } from '@proveanything/smartlinks'
setNgrokSkipBrowserWarning(true)
setExtraHeaders({ 'X-Debug': '1' })

Full API surface

Explore every function, parameter, and type here:

  • API Summary (API_SUMMARY.md)

Requirements

  • Node.js 16+ or modern browsers
  • TypeScript 4.9+ (if using TS)

License

MIT © Prove Anything