# Keywords — `@suaveplan/sms-providers` _(no submodules)_ ## Purpose Universal classifier mapping an inbound SMS body to the canonical `OptOutAction` enum used by `@suaveplan/sms`'s `OptOutRegistry`. CTIA's Short Code Monitoring Handbook (and the parallel TCPA / GDPR opt-out frameworks) mandate that outbound SMS programs recognise STOP / STOPALL / UNSUBSCRIBE / CANCEL / END / QUIT as opt-out, START / YES / UNSTOP as opt-in, and HELP / INFO as help-info requests, in every market. Every provider's `parseInbound` runs the raw body through this classifier so the higher-level service layer never has to re-implement the vocabulary. ## Features - Canonical six-keyword opt-out set: `STOP`, `STOPALL`, `UNSUBSCRIBE`, `CANCEL`, `END`, `QUIT`. - Canonical three-keyword opt-in set: `START`, `YES`, `UNSTOP`. - Canonical two-keyword help set: `HELP`, `INFO`. - Recognition is case-insensitive and ignores surrounding whitespace — `" Stop "`, `"STOP\n"`, `"stop"` all match. - Multi-word bodies do not match (the canonical CTIA contract is single-keyword); they fall through to `"none"`. ## Usage: Basic ```ts import { parseOptOutKeyword } from "@suaveplan/sms-providers"; const action = parseOptOutKeyword(" Stop "); // action === "opt_out" ``` ## Usage: Advanced ```ts import { parseOptOutKeyword, type OptOutAction, } from "@suaveplan/sms-providers"; function handleInbound(from: string, body: string): void { const action: OptOutAction = parseOptOutKeyword(body); switch (action) { case "opt_out": // optOutRegistry.recordOptOut({ phoneNumber: from, optedOutAt: new Date() }); return; case "opt_in": // optOutRegistry.recordOptIn({ phoneNumber: from }); return; case "help": // outbound auto-reply with HELP text required by CTIA return; case "none": // forward to the conversational handler return; } } ``` ## API Reference | Symbol | Kind | Notes | |---|---|---| | `OptOutAction` | union | `"opt_out" \| "opt_in" \| "help" \| "none"`. | | `parseOptOutKeyword(body)` | function | Returns the classification. | ## Implementation Notes The keyword sets are frozen `Set` instances at module load so lookup is O(1). Trim + upper-case the input once and compare against all three sets in sequence — short-circuiting on the first match means an opt-out check beats opt-in beats help (no overlap exists in the canonical vocabulary; sequencing is for stability rather than correctness).