{"_id":"@adatechnology/text-moderation","_rev":"2-e861ee8dfd743fd787d0cc2c84c2c756","name":"@adatechnology/text-moderation","dist-tags":{"rc":"0.2.0-rc.0","latest":"0.2.0"},"versions":{"0.2.0-rc.0":{"name":"@adatechnology/text-moderation","version":"0.2.0-rc.0","keywords":["profanity","moderation","pt-br","whatsapp","content-moderation"],"author":{"name":"Ada Technology"},"license":"MIT","_id":"@adatechnology/text-moderation@0.2.0-rc.0","maintainers":[{"name":"miyazaki","email":"andersonfrfilho@gmail.com"}],"dist":{"shasum":"9c0690f4fa5e7ee3152be4769c183c0b69b9d509","tarball":"https://registry.npmjs.org/@adatechnology/text-moderation/-/text-moderation-0.2.0-rc.0.tgz","fileCount":3,"integrity":"sha512-0zlCABG2mqklwQihkt7fKXVDyiCTye39fjIqvDI/hH0akxVQqUatGcgYrExc7HWSz0kijBqCV7TZcmx41s01Gg==","signatures":[{"sig":"MEUCIBFjow1nE+oDqXj5+uc4QEUYZI78J7wyOfW/QaSLc06YAiEAqT6msXHRkpCEn/HyiAqpNed9RVzArEWHJqbYY5r/keo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6502},"main":"dist/index.js","type":"module","_from":"file:adatechnology-text-moderation-0.2.0-rc.0.tgz","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"scripts":{"test":"bun test","build":"tsup","check":"tsc --noEmit"},"_npmUser":{"name":"miyazaki","email":"andersonfrfilho@gmail.com"},"_resolved":"/tmp/d611dc287a0708b509e13402667419e4/adatechnology-text-moderation-0.2.0-rc.0.tgz","_integrity":"sha512-0zlCABG2mqklwQihkt7fKXVDyiCTye39fjIqvDI/hH0akxVQqUatGcgYrExc7HWSz0kijBqCV7TZcmx41s01Gg==","_npmVersion":"10.9.8","description":"Offensive language detection for pt-BR conversational products, extensible by the host","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{"@2toad/profanity":"^3.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","@types/bun":"1.3.14","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/text-moderation_0.2.0-rc.0_1785180701950_0.2525833815351508","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@adatechnology/text-moderation","version":"0.2.0","description":"Offensive language detection for pt-BR conversational products, extensible by the host","type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"sideEffects":false,"keywords":["profanity","moderation","pt-br","whatsapp","content-moderation"],"author":{"name":"Ada Technology"},"license":"MIT","publishConfig":{"access":"public"},"dependencies":{"@2toad/profanity":"^3.3.0"},"devDependencies":{"@types/bun":"1.3.14","tsup":"^8.5.1","typescript":"^5.9.3"},"scripts":{"build":"tsup","check":"tsc --noEmit","test":"bun test"},"_id":"@adatechnology/text-moderation@0.2.0","_integrity":"sha512-21bF/ANotnG6+yLCl8t3YpImCnepgw+lUDnlXoWMHeWxL70F5mAZ0toJ53KnD3OCDGvGSUF2NTz/egRC2rZlwQ==","_resolved":"/tmp/da07d94f790929a5bcd7c182b4d5fdae/adatechnology-text-moderation-0.2.0.tgz","_from":"file:adatechnology-text-moderation-0.2.0.tgz","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-21bF/ANotnG6+yLCl8t3YpImCnepgw+lUDnlXoWMHeWxL70F5mAZ0toJ53KnD3OCDGvGSUF2NTz/egRC2rZlwQ==","shasum":"d5737359534dc278493fd286486142755e8b1517","tarball":"https://registry.npmjs.org/@adatechnology/text-moderation/-/text-moderation-0.2.0.tgz","fileCount":4,"unpackedSize":9424,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICl8pSdXPYSgl7g8KmzLjcEp2Ow14MYhaVTCXVIQVoHEAiEAzh07vAQF3bS4yNd8fPODOFQjHXFIgfvs0nh63YGF+WI="}]},"_npmUser":{"name":"miyazaki","email":"andersonfrfilho@gmail.com"},"directories":{},"maintainers":[{"name":"miyazaki","email":"andersonfrfilho@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/text-moderation_0.2.0_1788318109604_0.5033665018644864"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-27T19:31:41.782Z","modified":"2026-09-02T03:01:49.932Z","0.2.0-rc.0":"2026-07-27T19:31:42.145Z","0.2.0":"2026-09-02T03:01:49.748Z"},"author":{"name":"Ada Technology"},"license":"MIT","keywords":["profanity","moderation","pt-br","whatsapp","content-moderation"],"description":"Offensive language detection for pt-BR conversational products, extensible by the host","maintainers":[{"name":"miyazaki","email":"andersonfrfilho@gmail.com"}],"readme":"# @adatechnology/text-moderation\n\nOffensive language detection for pt-BR conversational products, extensible by the host.\n\n## Contract\n\n- word-boundary matching with unicode support — `Paulo`, `Paula`, `Ana Cunha`, `Marcus`\n  and `Rolando` are never flagged, and `desgraça`/`otário` are;\n- curated pt-BR core list, not a third-party translated dictionary;\n- host extends with `extraTerms` and rescues false positives with `allowedTerms`;\n- `isEnabled: false` returns a clean verdict for every input and leaves text untouched;\n- channel-agnostic: the boundary takes a string and knows nothing about WhatsApp, web\n  chat or e-mail;\n- no logging, no environment reads, no I/O.\n\n```ts\nimport { createTextModerator, parseTermList } from '@adatechnology/text-moderation'\n\nconst moderator = createTextModerator({\n  isEnabled: environment.MODERATION_ENABLED,\n  extraTerms: parseTermList(environment.MODERATION_EXTRA_TERMS),\n  allowedTerms: parseTermList(environment.MODERATION_ALLOWED_TERMS),\n})\n\nmoderator.inspect('seu babaca')\n// { isOffensive: true, matchedTerms: ['babaca'] }\n\nmoderator.inspect('coloca 2kg de arroz no carrinho')\n// { isOffensive: false, matchedTerms: [] }\n\nmoderator.censor('seu babaca')\n// 'seu @#$%&!'  — display only, never stored in place of the original\n```\n\n`parseTermList` exists so products don't reimplement the comma-split; reading\n`process.env` stays in each product's validated config module.\n\n## Why not the library's `pt` dictionary\n\nThe engine is `@2toad/profanity`, but only the engine. Its `pt` dictionary (322 terms in\nv3.3.0) is a machine translation of an English list and is unusable: it contains `no`,\n`o quê`, `boa sorte`, `amigos`, `bolo`, `osso` and `sangrento` as profanity, and omits\n`cu`. Measured against ordinary e-commerce sentences, 4 of 5 were flagged — including\n\"coloca no carrinho por favor\". It is loaded and immediately dropped with `removeWords`,\nand only the curated list applies.\n\nWhat the library does provide, and why it is still here: `wholeWord` plus\n`unicodeWordBoundaries`. A hand-rolled blocklist reaches for `includes`, and substring\nmatching rejects legitimate customers — `pau` inside `Paulo`, `cu` inside `Cunha` and\n`Marcus`, `rola` inside `Rolando`.\n\n## Deliberate omissions\n\nTerms that are legitimate words in commerce are **not** in the core list: `pau` (pau de\ncanela), `rola` (verb), `pinto` (poultry), `piranha` (fish) and `bunda`. A product that\nwants them blocked adds them through `extraTerms`, accepting the false positives in its\nown catalogue.\n\nEvasion is not covered — `p0rra`, `porrrra` and `m e r d a` pass. For a name field this\nrarely matters, since a letters-only charset rule and a minimum word length already reject\nthem. For free-form message moderation, an engine with leet/stretched/spaced transformers\n(such as `obscenity`) is the answer; the dictionary would still be ours, so the swap does\nnot change this package's API.\n","readmeFilename":"README.md"}