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

@smalk/fastify-ads

v0.1.0

Published

Fastify plugin that serves Smalk native AI-search text ads server-side: injects the JS tracker, replaces the <div class="smalk-ads"> placeholder with live ad HTML, and fires async AI-agent tracking. The LLM-crawler view of your pages.

Readme

@smalk/fastify-ads

Fastify plugin that serves Smalk native AI-search text ads server-side — the way AI crawlers (ChatGPT, Perplexity, Claude, Gemini, Google AI Overviews) actually see your pages.

AI crawlers don't execute JavaScript. Ads must be in the HTML your server returns. This plugin does three things on every HTML response:

  1. Injects the JS tracker <script> into <head> (catches headless-browser crawlers + drives ad framing).
  2. Replaces the <div class="smalk-ads"> placeholder with live ad HTML fetched from the Smalk Ad Server (150 ms hard timeout, fail-open).
  3. Fires async AI-agent tracking after the response (never blocks rendering).

It mirrors the official WordPress (smalk-ai-analytics) and Laravel (smalk/laravel-ads) plugins — same endpoints, same env-var names, same ad-slot contract.

Not included (yet): the daily cache-freshness sweep (/active-ad-urls/ Last-Modified bump + CDN purge). Wire that as a separate cron, or register a CDN credential so Smalk purges for you.

Requirements

  • Fastify v5 (peerDependencies: fastify@^5)
  • Node ≥ 20

Install

npm install @smalk/fastify-ads

Usage

import Fastify from "fastify";
import smalkAds from "@smalk/fastify-ads";

const app = Fastify();
await app.register(smalkAds); // reads SMALK_* env vars
// ...your routes...
await app.listen({ port: 3000 });

Add exactly one empty slot in your HTML where you want the ad — class token smalk-ads, no other attributes:

<div class="smalk-ads"></div>

If you register @fastify/compress, register this plugin first so it rewrites plaintext HTML before compression.

Configuration

Pass options to register() or set env vars. Options override env. Credentials are required — register() throws at boot if they're missing.

| Option | Env var | Default | Notes | |---|---|---|---| | projectKey | SMALK_PROJECT_KEY | — (required) | Workspace project key | | apiKey | SMALK_API_KEY | — (required) | Api-Key auth | | apiBase | SMALK_API_BASE | https://api.smalk.ai/api/v1 | Ad-server + tracking base | | trackerCdn | SMALK_TRACKER_CDN | https://cdn.smalk.ai/tracker.js | Tracker script src | | trackerEnabled | SMALK_JS_TRACKER_ENABLED | true | Inject tracker <script> | | adsEnabled | SMALK_ADS_ENABLED | true | Fetch + inject ads | | trackingEnabled | SMALK_TRACKING_ENABLED | true | Fire /tracking/visit | | adsTimeoutMs | SMALK_ADS_TIMEOUT_MS | 150 | Ad-server hard timeout | | trackingTimeoutMs | SMALK_TRACKING_TIMEOUT_MS | 150 | Tracking hard timeout | | forwardIp | SMALK_TRACKING_FORWARD_IP | false | Forward X-Real-IP (GDPR-off by default) | | preview | SMALK_ADS_PREVIEW | (unset) | QA only. Forces a fixed preview frame (e.g. shadow, grey, summary_toc) on every ad request — no booking, no impression. Leave unset in production. |

await app.register(smalkAds, {
  projectKey: process.env.SMALK_PROJECT_KEY,
  apiKey: process.env.SMALK_API_KEY,
  adsTimeoutMs: 120,
});

Behavior & guarantees

  • Fail-open. Any ad-server timeout / error / empty response leaves the <div class="smalk-ads"> placeholder untouched and the page renders normally. Smalk being slow or down never breaks your site.
  • HTML-only. Only text/html, 2xx, non-HEAD responses are touched. Streamed and binary responses pass through untouched.
  • Empty ad → placeholder kept. Smalk uses div presence to verify the slot is installed — the plugin never removes it.
  • GDPR. Only User-Agent, Referer, and (opt-in) X-Real-IP are forwarded to tracking. Nothing else.
  • content-length is recomputed (Buffer.byteLength) after the rewrite.

Verify

curl -A "Mozilla/5.0 (compatible; ChatGPT-User/1.0)" https://your.site/article | grep -A2 smalk-ads

The ad HTML should appear inline (not just in DevTools — in raw curl).

Development

npm install
npm run build        # tsup → dual ESM/CJS + .d.ts
npm test             # node:test + fastify.inject() (in-process, no port)

End-to-end (docker, from repo root) — real container hitting a stub Smalk API:

docker compose -f docker-compose.fastify.yml up -d --build
cd plugins/fastify/tests && npm install && npx playwright test

End-to-end against a live Smalk ad server in preview mode (proves the plugin calls the real endpoint and injects its rendered output — no mock, no booking needed). Point it at a running ad server and pass a real project key + API key:

# boot the local FastAPI ad server (from repo root): docker compose up -d fastapi-tracking
cd plugins/fastify/tests
SMALK_API_BASE=http://localhost:8002/api/v1 \
SMALK_PROJECT_KEY=<project-uuid> SMALK_API_KEY=<api-key> SMALK_ADS_PREVIEW=shadow \
npx playwright test --config real-server/playwright.config.ts

Credentials are read from the environment and never committed.

License

MIT