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

@fonte-is/fonte

v0.5.9

Published

Open-source SDK for tracking launch links to paying customers with Fonte Cloud

Downloads

1,670

Readme

Fonte

Fonte helps technical founders track launch links to paying customers.

Install the open-source SDK before launch, create Fonte links for each channel, preserve the source through checkout, and let Fonte Cloud connect source, checkout attempts, Stripe revenue, and diagnostics.

npm i @fonte-is/fonte
npx fonte init --framework next --mode production
npx fonte campaign link --url https://example.com/launch --link-token fl_8xK2pQ9v --utm-source x --utm-medium social --utm-campaign launch
npx fonte doctor install --config fonte.checkout.json --json
npx fonte doctor checkout --config fonte.checkout.json --json

@fonte-is/fonte is the public Next.js integration kernel for Fonte Cloud.

The package captures consented browser evidence, creates server-authoritative conversion attempts, carries pointer ids through monetization paths, and posts verified revenue events from your authority system. It does not compute attribution in the browser, store provider secrets, or replace Fonte Cloud.

The SDK exposes surface adapters that emit valid Fonte events; it does not own global event semantics. The public ABI lives in docs/public-contracts.md. Fonte Cloud remains the authority for source-token meaning, event admission, revenue ledger semantics, match policy, diagnostics, and exports.

Docs

Install

npm i @fonte-is/fonte
npx fonte init

For a Next.js App Router project, fonte init creates:

  • fonte.config.ts
  • src/fonte/browser.ts or fonte/browser.ts
  • src/fonte/server.ts or fonte/server.ts
  • src/components/fonte-capture.tsx or components/fonte-capture.tsx
  • src/app/api/fonte/collect/route.ts or app/api/fonte/collect/route.ts

Render ConsentScript in your root layout head and the generated capture component in your root layout body. Then create a conversion attempt before redirecting to the external monetization path, attach pointer metadata where the provider permits it, and post verified revenue events from your authority system.

Public Imports

Use runtime-specific subpaths. Do not use a single mega import; the import path is part of the browser/server boundary.

import { createCapture } from "@fonte-is/fonte/browser";
import { createClient } from "@fonte-is/fonte/server";
import { ConsentScript, Fonte } from "@fonte-is/fonte/next";
import { collect } from "@fonte-is/fonte/next/server";
import { stripe } from "@fonte-is/fonte/checkout";

The root package exports shared types only.

Browser

"use client";

import { createCapture } from "@fonte-is/fonte/browser";

export const fonte = createCapture({
  storage: "example",
  collect: "/api/fonte/collect",
  maxAgeDays: 90,
});
fonte.page();
const context = fonte.context();
const clientAttemptId = fonte.clientAttemptId();
const conversionEventId = fonte.conversionEventId();

With no stored consent choice and no explicit defaults, Fonte starts at unknown, shows the default banner through <Fonte capture={fonte} />, and does not collect measurement or ad evidence until the visitor chooses. Consent choices are persisted in first-party browser storage and included in every collected scope.

The browser can reserve a clientAttemptId and conversionEventId while it captures touch context. Fonte Cloud remains the authority for conversionAttemptId; when supplied to attempt(...), conversionEventId is the caller-reserved export/dedupe id Fonte accepts or deduplicates. When measurement consent is not granted, the browser helper does not create Fonte device or journey identifiers and does not persist attribution context. When adStorage consent is not granted, the browser helper does not emit page_view or source_touch collection requests, because Fonte Cloud's V0 touch admission requires ad-storage consent before it accepts browser evidence. Browser capture defaults to source-touch capture: a source-changing arrival with a Fonte link token, UTM evidence, platform click ids, external referrer evidence, or the first direct landing is captured. Internal route changes do not become new source touches unless they carry fresh source evidence. Use capturePolicy.mode: "all" only when an app intentionally wants to send every route scope. Captured browser URLs are canonicalized before collection. The SDK keeps the origin, path, Fonte token, UTM parameters when measurement consent is granted, and platform click ids when ad-storage consent is granted. Other query parameters and fragments are dropped so page-view capture does not forward magic-link, reset, email, or other application-specific URL data.

The canonical Fonte source pointer is a compact link token:

https://www.example.com/promo?fonte=fl_8xK2pQ9v

Fonte Cloud owns what fl_8xK2pQ9v means for a tenant/environment/campaign. UTMs are optional compatibility labels for other tools, not Fonte's source of truth. For human and agent workflows, create the cloud campaign/link record first and use the returned trackedUrl or compatibilityUrl:

npx fonte cloud configure \
  --activation-base-url https://api.fonte.is \
  --project-id 00000000-0000-0000-0000-000000000001 \
  --environment production

FONTE_TENANT_API_KEY=fonte_live_... npx fonte campaign link \
  --url https://www.example.com/promo \
  --campaign-id camp_example_launch_20260525 \
  --name "Launch Promo" \
  --channel-type owned \
  --channel email \
  --source example_learning \
  --source-platform email \
  --link-id link_hero_cta \
  --content hero_cta \
  --utm-campaign launch_promo_20260525

When a control-plane campaign link already exists and you only need a local compiler, pass the returned linkToken and add UTMs only when needed:

npx fonte campaign link \
  --url https://www.example.com/promo \
  --link-token fl_8xK2pQ9v \
  --utm-source newsletter \
  --utm-medium email \
  --utm-campaign launch_promo_20260525 \
  --utm-content hero_cta

The same deterministic helper is available in code:

import { campaign } from "@fonte-is/fonte/campaign";

const trackedUrl = campaign.url("https://www.example.com/promo", {
  linkToken: "fl_8xK2pQ9v",
  utmSource: "newsletter",
  utmMedium: "email",
  utmCampaign: "launch_promo_20260525",
  utmContent: "hero_cta",
});

Next Consent and Capture

import { ConsentScript } from "@fonte-is/fonte/next";
import { FonteCapture } from "@/components/fonte-capture";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <ConsentScript />
      </head>
      <body>
        {children}
        <FonteCapture />
      </body>
    </html>
  );
}

The generated FonteCapture component wraps the browser capture primitive:

"use client";

import { Fonte } from "@fonte-is/fonte/next";
import { fonte } from "../fonte/browser";

export function FonteCapture() {
  return <Fonte capture={fonte} />;
}

ConsentScript sets default-denied Google Consent Mode fields before platform tags can run. The Fonte component shows the default consent UI when consent is unknown, persists accept/reject/manage choices, updates Google consent state, and runs route-aware page capture.

Server

import "server-only";
import { createClient } from "@fonte-is/fonte/server";

export const fonte = createClient({
  baseUrl: process.env.FONTE_API_BASE_URL!,
  tenantId: (process.env.FONTE_TENANT_ID ?? process.env.FONTE_PROJECT_ID)!,
  tenantApiKey:
    (process.env.FONTE_TENANT_API_KEY ?? process.env.FONTE_SECRET_KEY)!,
  environment:
    process.env.FONTE_ENVIRONMENT === "sandbox" ? "sandbox" : "production",
  timeoutMs: Number(process.env.FONTE_API_TIMEOUT_MS ?? 3000),
});
const attempt = await fonte.attempt({
  idempotencyKey: `checkout:${clientAttemptId}`,
  occurredAt: new Date().toISOString(),
  source: "example.com",
  clientAttemptId,
  conversionEventId,
  attributionContext: context,
  surface: "checkout",
  product: "example-product",
  offer: "full-pay",
  raw: { context },
});

The configured client exposes the primitives:

  • attempt(...)
  • touch(...)
  • identify(...)
  • revenue(...)

Next Collect Route

import { collect } from "@fonte-is/fonte/next/server";
import { fonte } from "@/fonte/server";

export async function POST(request: Request) {
  const origin = request.headers.get("origin");
  if (!origin) {
    return Response.json({ ok: false, error: "missing_origin" }, { status: 403 });
  }

  const body = await collect.parse(request).catch(() => null);
  if (!body) {
    return Response.json({ ok: false, error: "invalid_touch" }, { status: 400 });
  }

  const scope = collect.acceptScope(body.scope, {
    requestUrl: request.url,
    siteUrl: process.env.NEXT_PUBLIC_SITE_URL,
    userAgent: request.headers.get("user-agent"),
  });
  if (!scope) {
    return Response.json({ ok: false, error: "invalid_touch" }, { status: 400 });
  }

  const result = await fonte.touch({
    idempotencyKey: `touch:${body.eventId}`,
    occurredAt: new Date().toISOString(),
    source: "example.com",
    eventId: body.eventId,
    event: body.eventType,
    raw: {
      ...(body.eventType === "source_touch"
        ? { sourceTouch: collect.classifySourceTouch(scope) }
        : {}),
      scope,
    },
    touch: collect.toTouch(scope, body.journeyId),
  });

  return Response.json({ ok: true, result });
}

Your app owns origin policy, rate limits, funnel semantics, and checkout authority. The browser helper emits page_view for page renders only after measurement and ad-storage consent are both granted, and emits source_touch separately when attribution evidence is present. Fonte owns parsing helpers, cloud writes, and conversion lineage. A browser collect POST is not proof that Fonte Cloud accepted the touch; the control plane still applies server-side consent and evidence admission before writing rows. The Next collect helpers apply the same URL canonicalization server-side before the app writes browser evidence.

Checkout

When accepting browser attribution context in checkout routes, let the SDK normalize it while applying your route's origin policy:

import { collect } from "@fonte-is/fonte/next/server";

const context = collect.acceptContext(body.attributionContext, {
  requestUrl: request.url,
  siteUrl: process.env.NEXT_PUBLIC_SITE_URL,
  userAgent: request.headers.get("user-agent"),
});

Do not maintain an app-local allowlist of Fonte context keys. The SDK owns the source-context contract; app routes should only decide whether the request is trusted for their own origin and funnel. Pass the accepted context directly to fonte.attempt(...); the server client flattens the current URL, Fonte link token, consent state, client user agent, and browser ids into the control-plane attempt ABI. When measurement consent is denied or unknown, accepted browser attribution context may still carry a Fonte link token as checkout source context, but it does not create or forward browser journey/device ids, browser-captured client user agent, persisted attribution, or source touches. An explicit server-side clientUserAgent follows the control-plane attempt ABI: it is forwarded unless the attempt's measurement consent is denied. Meta browser identifiers (fbclid, fbc, and fbp) follow the stricter attempt ABI: the server client forwards explicit or accepted-context values only when the effective attempt consent has both measurement and adStorage granted. The control plane remains authoritative and may still drop identifiers that do not satisfy its runtime evidence rules. If an app passes explicit journeyId or deviceId together with denied or unknown measurement consent, the server client withholds those browser ids.

import { stripe } from "@fonte-is/fonte/checkout";

const metadata = stripe.metadata({
  clientAttemptId,
  conversionAttemptId: attempt.conversionAttemptId,
  conversionEventId: attempt.conversionEventId,
  journeyId: context?.current?.fonte_journey_id,
  surface: "checkout",
});

stripe.metadata(...) returns plain metadata. It has no Stripe dependency and does not store attribution blobs in Stripe. Stripe should carry pointer ids only; Fonte Cloud stores evidence custody.

For new Stripe Checkout routes, prefer stripe.checkout.sessions.create(...). It validates the provider session template, creates the Fonte attempt, attaches pointer metadata, and creates the Stripe Checkout Session in one call. The default signalMode is best_effort_revenue_safe, so checkout revenue is not blocked by a Fonte binding failure; use strict_signal_required for tests or controlled flows, and disabled only for routes with no Fonte purchase-signal expectation.

Use stripe.checkoutSessionParams(...) when creating Stripe Checkout Sessions so the same pointer reaches the Stripe objects that may later produce webhook revenue:

const checkoutParams = stripe.checkoutSessionParams({
  mode: "payment",
  pointer: metadata,
  base: {
    success_url: successUrl,
    cancel_url: cancelUrl,
    line_items: lineItems,
  },
});

For payment-mode Checkout, the helper attaches pointer metadata to:

  • metadata
  • payment_intent_data.metadata
  • invoice_creation.invoice_data.metadata, only when invoice creation already exists or includeInvoiceCreationMetadata: true is set
  • client_reference_id, defaulting to conversion_event_id

The direct Fonte Cloud Stripe webhook path currently ingests invoice-centered revenue. For one-time payment Checkout, enable Stripe invoice creation or post verified revenue from your own Stripe webhook through the server revenue helper; pointer metadata on a PaymentIntent alone is not an invoice-paid revenue event.

For subscription or payment-plan Checkout, use mode: "subscription":

const checkoutParams = stripe.checkoutSessionParams({
  mode: "subscription",
  pointer: metadata,
  base: {
    success_url: successUrl,
    cancel_url: cancelUrl,
    line_items: lineItems,
  },
});

The helper returns a plain object for Stripe's checkout.sessions.create(...). It preserves existing non-Fonte metadata and overwrites Fonte pointer keys with the current pointer values so stale conversion_event_id values cannot survive in nested Stripe objects.

For a full Next.js payment-plan route, see examples/nextjs-stripe-payment-plan.

Before live traffic, run the static export-readiness fixture:

npx fonte export-readiness \
  --fixture node_modules/@fonte-is/fonte/fixtures/simple_checkout_payment_plan_lineage.json \
  --json

The probe does not query Fonte Cloud or dispatch conversions. It checks the fixture for pointer continuity, including Stripe invoice/webhook-visible metadata, and applies the V1 Meta/Google eligibility reason vocabulary: consent_denied, missing_meta_event_source_url, missing_meta_client_user_agent, missing_meta_match_keys, and missing_google_click_or_user_data.

For customer-app install verification, add a generic checkout ownership config and run the checkout doctor:

{
  "sourceRoutes": ["/", "/blog/example"],
  "checkoutScenarios": [
    {
      "name": "premium_one_time_offer",
      "startUrl": "/offer/register",
      "expectedValue": {
        "basis": "fixed_amount",
        "amountMinor": 150000,
        "currency": "USD"
      }
    },
    {
      "name": "subscription_monthly_plan",
      "startUrl": "/subscribe",
      "expectedValue": {
        "basis": "initial_payment",
        "amountMinor": 4900,
        "currency": "USD"
      }
    }
  ],
  "browserPurchase": {
    "policy": "absent_or_paired"
  }
}
npx fonte doctor install --config fonte.checkout.json --json
npx fonte doctor checkout --config fonte.checkout.json --json

fonte doctor install reduces the local SDK/checkout checks and optional Fonte Cloud evidence-quality read model into generic first-party integration checkpoints: source/session capture wiring, consent evidence, checkout binding, pointer preservation, browser-batch ingress, projection custody, and blocked evidence frontier. Checkpoint statuses are present, missing, blocked, or not_yet_verified.

fonte doctor checkout is deliberately local and read-only. It verifies the app has an installable checkout ownership contract, detects static browser-side Purchase code that must be absent or paired with Fonte's conversionEventId, and checks that Stripe Checkout creation follows the public Fonte pointer pattern. Neither doctor creates test payments, inspects external tag-manager rules, calls providers, or claims platform delivery.

expectedValue should use the object form in new configs. fixed_amount and initial_payment require amountMinor in currency minor units, so $1,500.00 is 150000. provider_price_lookup is accepted for dynamic checks that verify a configured Stripe price instead of a hardcoded amount; the verifier resolves priceRef from the local environment and checks the Checkout Session line items include that Stripe price:

{
  "name": "provider_price_subscription",
  "startUrl": "/subscribe",
  "expectedValue": {
    "basis": "provider_price_lookup",
    "provider": "stripe",
    "priceRef": "STRIPE_SUBSCRIPTION_PRICE_ID",
    "currency": "USD"
  }
}

Numeric expectedValue remains supported as a legacy shorthand for fixed major units, but public install guides should prefer the object form.

For dynamic local verification, add dynamicVerification to each scenario. The CLI opens the local app, calls the configured checkout-start route with generated test ids, verifies the Stripe test Checkout Session metadata, and observes browser-side Purchase events on the local success path when one is configured:

{
  "name": "premium_one_time_offer",
  "startUrl": "/offer/register",
  "expectedValue": {
    "basis": "fixed_amount",
    "amountMinor": 150000,
    "currency": "USD"
  },
  "dynamicVerification": {
    "checkoutStart": {
      "path": "/api/checkout/start",
      "body": {
        "clientAttemptId": "{{clientAttemptId}}",
        "conversionEventId": "{{conversionEventId}}",
        "email": "{{smokeEmail}}"
      },
      "checkoutUrlJsonPath": "checkoutUrl"
    },
    "successPath": "/checkout/success"
  }
}

Run it only against a local app with test payment credentials and app-side measurement writes disabled or smoke-gated. The command uses a local Chrome/Chromium executable; pass --chrome-path or set CHROME_PATH if it cannot locate one automatically:

STRIPE_SECRET_KEY=sk_test_... \
npx fonte verify checkout \
  --config fonte.checkout.json \
  --base-url http://localhost:3000 \
  --json

fonte verify checkout refuses non-loopback app URLs and non-test Stripe keys. It adds x-fonte-checkout-ownership-smoke: v0 to the checkout-start request, but the customer app must enforce any write-suppression behavior for that header. The command does not complete payment, navigate to Stripe Checkout, query Fonte Cloud, query Meta Events Manager, or prove external tag-manager behavior. Browser Purchase observations are summarized in the report; raw browser event payloads are not echoed.

Use browserPurchase.policy = "absent" when the app must not contain repo-local browser Purchase code. Use "paired" only when the app intentionally owns a browser Purchase path that must share Fonte's conversionEventId/value with the server event; if the local static scan cannot find that path, the doctor warns instead of treating the policy as satisfied. Dynamic verification is stricter: "paired" must observe a matching browser Purchase during the local flow. absent_or_paired is the default V0 posture for apps that have not yet chosen between those two designs.

Vocabulary

  • context: browser attribution context
  • scope: one route/page/touch scope inside a context
  • attempt: a Fonte Cloud conversion attempt that may later become revenue
  • conversionAttemptId: Fonte Cloud canonical attempt id
  • conversionEventId: platform export and browser/server dedupe lineage id
  • revenue: verified authority event from Stripe, CRM, or another source