Skip to content

Add zero-dependency SMS utilities - #3

Merged
vernu merged 1 commit into
mainfrom
feat/sms-utils
Aug 9, 2026
Merged

Add zero-dependency SMS utilities#3
vernu merged 1 commit into
mainfrom
feat/sms-utils

Conversation

@vernu

@vernu vernu commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Adds a small set of pure SMS helpers to the SDK. No API key, no network calls, no new dependencies, and useful with any SMS provider rather than only textbee.

What is new

Segments and encoding. Carriers bill per segment, and one emoji or curly quote silently flips a message from GSM-7 (160 chars) to UCS-2 (70 chars). countSmsSegments reports encoding, encoded length, segment count, and remaining room, following the standards-default split including the rule that a two-unit character never straddles a segment boundary. getSmsEncoding and findNonGsm7Characters cover the "why is this suddenly 3 segments" case.

GSM-7 sanitization. sanitizeForGsm7 swaps curly quotes, ellipses, exotic spaces, and dash variants for plain equivalents so pasted copy does not quietly triple in cost. Best effort by design: unmapped characters pass through, and an optional transliterateAccents strips accents GSM-7 does not carry while leaving the ones it does (é, ü, ñ, à) alone. Zero-width joiners are deliberately preserved so emoji sequences survive.

Phone numbers. isValidE164 and normalizePhoneNumber handle format-level validation and cleanup, including a leading 00 and an optional default country code. Documented plainly as format-only helpers, not libphonenumber: bad input returns null, a bad defaultCountryCode throws.

Everything is exported from the existing entry point and lives in one src/sms-utils.ts, so the surface stays tree-shakeable and the GSM table helpers stay module-private.

Notes

  • Version bumped to 0.2.0 since this adds public API.
  • The GSM 03.38 tables and the sanitizer's replacement map are written as unicode escapes so lookalike characters cannot sneak in and the file does not carry the very characters it replaces.
  • 41 new tests, including segment boundary cases at 160/161/306/307 and 70/71, no-straddle cases where a wasted unit changes the segment count, lone surrogates, and transliteration behavior.
  • Example numbers across the README and existing tests were refreshed at the same time.

Verification

pnpm run typecheck, pnpm test (64 passing), and pnpm run build all pass. Every code sample in the new README section was executed against the built output and produces exactly the documented result.

Adds pure helpers for SMS text and phone numbers, usable without an API
key and with any provider: segment counting with GSM-7 vs UCS-2 detection,
GSM-7 sanitization for pasted smart punctuation, and E.164 validation and
normalization.

Also refreshes the example numbers used across the README and tests.
@vernu vernu self-assigned this Aug 9, 2026
@vernu
vernu merged commit b69c442 into main Aug 9, 2026
1 check passed
@vernu
vernu deleted the feat/sms-utils branch August 21, 2026 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant