New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@profullstack/footer

Package Overview
Dependencies
Maintainers
2
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@profullstack/footer

Profullstack's distributed footer engine for remote, agent-friendly site branding and navigation.

latest
Source
npmnpm
Version
0.6.14
Version published
Weekly downloads
5.8K
272.66%
Maintainers
2
Weekly downloads
 
Created
Source

@profullstack/footer

Profullstack Distributed Footer Engine serves one versioned template to every site. Apps fetch the remote JSON template at render time, pass their own links and optional OpenIcon publisher marks, and receive sanitized HTML. Agents can use the same small options object from React, Node, or the CLI.

One footer for every Profullstack site: your links, the copyright line, and the << Profullstack >> webring nav (previous, ring, next).

Publish once, every site updates. The markup and CSS ship as data (template.json). At render time each site fetches https://cdn.jsdelivr.net/npm/@profullstack/footer@latest/template.json (15 min cache, 1.5 s timeout, the bundled copy as the fallback), so a release reaches every site within about an hour (sooner on sites without a page cache) with no bump, rebuild or redeploy. Install it as "@profullstack/footer": "latest" too, so the render code follows on the next install.

It renders on the server: the ring's verifier reads your HTML and never runs script, so a client-only footer would never count as a ring member.

Install

pnpm add @profullstack/footer@latest   # or npm i / bun add

The shared template lives in src/template.js; npm run build produces the public template.json. Sites and agents fetch that JSON with read-only requests. Only an npm publisher for @profullstack/footer can publish a version and move the latest tag, so runtime apps never need a publish key.

Next.js (App Router)

// app/layout.jsx (a server component)
import { Footer } from '@profullstack/footer/react';

<Footer site="https://example.com/" links={[{ label: 'Docs', href: '/docs' }]} since={2025} />

and the ring descriptor:

// app/.well-known/openwebring.json/route.js
import { descriptorResponse } from '@profullstack/footer';
export const GET = () => descriptorResponse({ site: 'https://example.com/', name: 'Example' });

Hono / Express / Bun / SvelteKit

import { footerHtml } from '@profullstack/footer';
const footer = await footerHtml({ site: 'https://example.com/', links: [{ label: 'Docs', href: '/docs' }] });
// Svelte: {@html footer}   Hono: c.html(`...${footer}`)

Static HTML (no server)

Print the footer once and keep it in the page (that is what the verifier sees), then let the embed swap in the @latest one in the browser:

npx @profullstack/footer html --site https://example.com/ --link Docs=/docs
<footer data-profullstack-footer data-site="https://example.com/" data-links='[{"label":"Docs","href":"/docs"}]'>
  …output of the command above…
</footer>
<script type="module" src="https://cdn.jsdelivr.net/npm/@profullstack/footer@latest/src/embed.js"></script>

Options

optiondefault
siterequiredyour homepage; from= on every hop
links[]{ label, href, rel? }[], shown before house links
sincefirst year: © 2024–2026
ownerProfullstack, Inc. → profullstack.com{ name, url }
taglineafter the copyright, e.g. MIT licensed
ring{ slug: 'profullstack', name: 'Profullstack', host: 'https://rssamplifier.com' }
csstruefalse drops the <style>; style .pfs-footer* yourself
houseLinkstruefalse hides the shared Terms, Privacy, Media, GitHub, Discord, X, Events, event registration, PairUX and Moshcoding links
subscribetruefalse hides the newsletter form
badges[]{ href, src, alt, width?, height? }[]: optional badges shown only on this site
pwamartHrefOpt in to a PwaMart icon badge and set its destination
builtIndieHrefOpt in to a built.indie icon badge and set its destination
nonceCSP nonce for the inline <style>; or css: false and style .pfs-footer* yourself
versionlatestwhich CDN template to render: '0.6.13' pins one (see below), 'bundled' never fetches
templateUrlfull template URL; wins over version

Pinning the template version

By default every site follows @latest, which is the point of the package, but it also means a bad or compromised npm publish reaches every site within the cache window. A site that holds secrets (a secret manager, an admin app) should pin an exact version instead. jsDelivr serves an exact version immutably, so later publishes cannot change that site's footer:

When using the moving alias, an edge cache that serves a version older than the installed bundle is ignored; the bundled template stays in use until the edge catches up. Explicit version pins remain honored.

import { footerHtml } from '@profullstack/footer';
const footer = await footerHtml({ site: 'https://app.example.com/' });
<Footer site="https://app.example.com/" />

Or for a whole deployment without code changes: PROFULLSTACK_FOOTER_VERSION=0.6.13 (PROFULLSTACK_FOOTER_VERSION=bundled renders the copy in the install and never fetches). latestTemplate({ version }) and templateUrl(version) are exported too; the CLI takes --template-version 0.6.13. Bump the pin when you want a new footer.

Theme it with --pfs-footer-muted, --pfs-footer-gap and --pfs-footer-size on .pfs-footer; colors otherwise inherit from the page.

Newsletter form

Every footer carries a small email field and a Subscribe button that posts the site's hostname to pit.world. pit.world runs the double opt-in (confirmation email, nothing kept until the click) and records which property each subscriber came from (https://pit.world/admin/subscribers). The endpoint is fixed in render.js, never in the template.

The email control is labeled “Email” and uses the example address placeholder you@example.com. Its form and input set autocomplete="off"; the input also includes ignore hints for Bitwarden, 1Password, and LastPass so it is not mistaken for a login field.

Since 0.4.0 a small inline script inside the form (wireSubscribe) sends it as JSON to https://pit.world/api/subscribe and reports in place: "Email confirmation sent to you@x. Check your inbox." or "Failed: " (bad address, domain takes no mail, rate limit, mail provider down, or the request was blocked). With no script it is a plain POST to https://pit.world/subscribe, which answers with a "check your inbox" page that links back to the site. embed.js wires the form itself.

CSP: pass the page's nonce so the script runs, and allow pit.world: connect-src 'self' https://pit.world; form-action 'self' https://pit.world. If the request is blocked anyway, the form says "Failed: could not reach pit.world" instead of doing nothing. Turn it off with subscribe: false (--no-subscribe). Installs before 0.3.0 cannot render the form; their footer shows a plain "Newsletter" link to the same page instead, from the @latest template.

CLI

profullstack-footer html --site https://example.com/ [--link Docs=/docs] [--since 2024] [--offline] [--no-css]
profullstack-footer json --site https://example.com/          # the four ring URLs
profullstack-footer descriptor --site https://example.com/    # /.well-known/openwebring.json
profullstack-footer template                                  # the @latest template
profullstack-footer check https://example.com/                # does the live page link the ring?

Every site gets a CrawlProof Surveys link, plus links to Profullstack's Terms, Privacy and Media pages, GitHub, Discord and X, the Events calendar on Luma, a Luma event registration link, and the PairUX and Moshcoding profiles. The copyright line includes the small Profullstack icon. Publisher badges are off by default. Publisher and app pages can opt into the OpenIcon HQ SVG marks:

<Footer
  site="https://example.com/"
  pwamartHref="https://pwamart.com/publishers/example"
  builtIndieHref="https://built.indie.pit.world/p/example"
/>

The shared footer keeps the site's navigation, house links, newsletter, webring and copyright. Its compact layout leaves publisher marks on the pages that opt in. The Profullstack homepage uses the two service icons for its publisher profiles. The global phone line remains a click-to-call link.

Edit src/template.js, bump the version in it and in package.json, npm run build, open a PR, merge, and publish a GitHub release vX.Y.Z. The publish workflow puts it on npm and purges jsDelivr's @latest so sites pick it up on their next cache refresh. Bump renderer (and RENDERER in render.js) only when the template needs a placeholder older installs cannot fill; they keep their bundled template until reinstalled.

Safety: since 0.5.0 the filled template goes through an allowlist sanitizer (sanitizeHtml), not a regex blacklist. It tokenizes the HTML the way a browser does and rebuilds it: only footer div nav section aside header p span small strong em b i ul ol li a img br hr h2-h6 survive; attributes are limited to class title role lang dir aria-* data-pfs-* plus href rel target hreflang on a and src alt width height loading decoding on img; every value is entity-decoded, checked and re-escaped, so what was checked is what the browser sees; href accepts http:, https:, mailto:, tel: or relative URLs; src accepts http:, https:, mailto: or relative URLs, after decoding and removing control characters. Comments, unknown tags (text kept, escaped), and script/style/iframe/ svg/math/noscript/template/... with their contents are dropped. The only <style> and <form> in the output are the ones render.js builds. CSS (sanitizeCss) loses markup, escapes, comments, @import, expression(, behavior:, -moz-binding and any url() that is not https or relative. Option values are always escaped.

Env: PROFULLSTACK_FOOTER_OFFLINE=1 never fetches; PROFULLSTACK_FOOTER_VERSION pins the template version; PROFULLSTACK_FOOTER_TEMPLATE_URL overrides the CDN URL.

MIT © Profullstack, Inc.

Keywords

footer

FAQs

Package last updated on 31 Oct 2026

Related posts