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

@adatechnology/text-moderation

v0.2.0

Published

Offensive language detection for pt-BR conversational products, extensible by the host

Readme

@adatechnology/text-moderation

Offensive language detection for pt-BR conversational products, extensible by the host.

Contract

  • word-boundary matching with unicode support — Paulo, Paula, Ana Cunha, Marcus and Rolando are never flagged, and desgraça/otário are;
  • curated pt-BR core list, not a third-party translated dictionary;
  • host extends with extraTerms and rescues false positives with allowedTerms;
  • isEnabled: false returns a clean verdict for every input and leaves text untouched;
  • channel-agnostic: the boundary takes a string and knows nothing about WhatsApp, web chat or e-mail;
  • no logging, no environment reads, no I/O.
import { createTextModerator, parseTermList } from '@adatechnology/text-moderation'

const moderator = createTextModerator({
  isEnabled: environment.MODERATION_ENABLED,
  extraTerms: parseTermList(environment.MODERATION_EXTRA_TERMS),
  allowedTerms: parseTermList(environment.MODERATION_ALLOWED_TERMS),
})

moderator.inspect('seu babaca')
// { isOffensive: true, matchedTerms: ['babaca'] }

moderator.inspect('coloca 2kg de arroz no carrinho')
// { isOffensive: false, matchedTerms: [] }

moderator.censor('seu babaca')
// 'seu @#$%&!'  — display only, never stored in place of the original

parseTermList exists so products don't reimplement the comma-split; reading process.env stays in each product's validated config module.

Why not the library's pt dictionary

The engine is @2toad/profanity, but only the engine. Its pt dictionary (322 terms in v3.3.0) is a machine translation of an English list and is unusable: it contains no, o quê, boa sorte, amigos, bolo, osso and sangrento as profanity, and omits cu. Measured against ordinary e-commerce sentences, 4 of 5 were flagged — including "coloca no carrinho por favor". It is loaded and immediately dropped with removeWords, and only the curated list applies.

What the library does provide, and why it is still here: wholeWord plus unicodeWordBoundaries. A hand-rolled blocklist reaches for includes, and substring matching rejects legitimate customers — pau inside Paulo, cu inside Cunha and Marcus, rola inside Rolando.

Deliberate omissions

Terms that are legitimate words in commerce are not in the core list: pau (pau de canela), rola (verb), pinto (poultry), piranha (fish) and bunda. A product that wants them blocked adds them through extraTerms, accepting the false positives in its own catalogue.

Evasion is not covered — p0rra, porrrra and m e r d a pass. For a name field this rarely matters, since a letters-only charset rule and a minimum word length already reject them. For free-form message moderation, an engine with leet/stretched/spaced transformers (such as obscenity) is the answer; the dictionary would still be ours, so the swap does not change this package's API.