@bernierllc/social-media-content-type-twitter
v1.0.4
Published
Twitter/X-specific content type definition and validation
Readme
@bernierllc/social-media-content-type-twitter
Twitter/X-specific content type definition and validation package for BernierLLC social media management system.
Installation
npm install @bernierllc/social-media-content-type-twitterFeatures
- Platform-specific Constraints - Twitter/X character limits, media rules, poll configuration
- Accurate Character Counting - Handles Twitter's URL shortening (23 chars), emojis, and media
- Thread Generation - Automatically split long content into threaded tweets
- Content Validation - Comprehensive validation against Twitter's platform rules
- Content Transformation - Convert between generic social content and Twitter format
- Fluent Builder API - Easy content creation with method chaining
- TypeScript First - Full type safety with strict mode
Usage
Basic Tweet Creation
import { TwitterContentBuilder } from '@bernierllc/social-media-content-type-twitter';
const builder = new TwitterContentBuilder();
const tweet = builder
.setText('Hello, Twitter! Check out our new product.')
.addImage('https://example.com/product.jpg', 'Product screenshot')
.addHashtag('product')
.addHashtag('launch')
.build();
console.log(tweet);
// {
// text: 'Hello, Twitter! Check out our new product.',
// media: [{ type: 'image', url: '...', altText: '...' }]
// }Content Validation
import { TwitterContentValidator } from '@bernierllc/social-media-content-type-twitter';
const validator = new TwitterContentValidator();
const result = validator.validate({
text: 'My tweet text with https://example.com',
media: [
{ type: 'image', url: 'https://example.com/image.jpg' }
]
});
if (result.valid) {
console.log('Tweet is valid!');
console.log('Character count:', result.textLength);
} else {
console.error('Validation errors:', result.errors);
}Character Counting
import {
countCharacters,
getCharacterBreakdown
} from '@bernierllc/social-media-content-type-twitter';
// Simple character count (URLs = 23 chars)
const count = countCharacters('Check https://example.com for info');
console.log(count); // "Check " (6) + 23 + " for info" (9) = 38
// Detailed breakdown
const breakdown = getCharacterBreakdown(
'Visit https://example.com and https://test.com',
true // has media
);
console.log(breakdown);
// {
// total: 61,
// text: 15,
// urls: 46, // 2 URLs × 23 chars
// urlCount: 2,
// media: 23,
// remaining: 219
// }Thread Generation
import { splitIntoThread } from '@bernierllc/social-media-content-type-twitter';
const longText = `
This is a very long blog post that exceeds Twitter's 280 character limit.
It will be automatically split into multiple tweets while preserving
sentence boundaries and hashtags. The thread generator is smart enough
to handle URLs, emojis, and special characters correctly.
`;
const thread = splitIntoThread(longText, {
numberTweets: true, // Add "1/5", "2/5", etc.
preserveHashtags: 'both', // Add hashtags to first and last
maxLength: 280
});
console.log(thread);
// [
// { text: 'This is a very long blog post... 1/3' },
// { text: 'It will be automatically split... 2/3' },
// { text: 'to handle URLs, emojis... 3/3' }
// ]Content Transformation
import { TwitterContentTransformer } from '@bernierllc/social-media-content-type-twitter';
const transformer = new TwitterContentTransformer();
// From generic social content
const generic = {
text: 'Check out my blog post',
links: ['https://blog.example.com/post'],
hashtags: ['blog', 'tech'],
images: ['https://blog.example.com/image.jpg']
};
const twitter = transformer.fromGeneric(generic);
// {
// text: 'Check out my blog post https://blog.example.com/post #blog #tech',
// media: [{ type: 'image', url: 'https://blog.example.com/image.jpg' }]
// }
// From blog post to thread
const blog = {
title: 'My Awesome Blog Post',
excerpt: 'A detailed look at...',
url: 'https://blog.example.com/post',
featuredImage: 'https://blog.example.com/image.jpg',
tags: ['tech', 'tutorial']
};
const blogThread = transformer.fromBlogPost(blog);
// [
// {
// text: 'My Awesome Blog Post https://blog.example.com/post #tech #tutorial',
// media: [{ type: 'image', url: '...' }]
// },
// { text: 'A detailed look at...' }
// ]Poll Creation
const builder = new TwitterContentBuilder();
const pollTweet = builder
.setText('What is your favorite programming language?')
.createPoll(
['JavaScript', 'TypeScript', 'Python', 'Go'],
1440 // Duration in minutes (24 hours)
)
.build();
console.log(pollTweet);
// {
// text: 'What is your favorite programming language?',
// poll: {
// options: ['JavaScript', 'TypeScript', 'Python', 'Go'],
// durationMinutes: 1440
// }
// }Reply and Quote Tweets
// Reply to a tweet
const reply = builder
.setText('Great point! I completely agree.')
.setReplyTo('1234567890') // Tweet ID to reply to
.build();
// Quote tweet
const quote = builder
.setText('This is exactly what I was thinking!')
.setQuoteTweet('9876543210') // Tweet ID to quote
.build();API Reference
Types
TwitterContent
interface TwitterContent {
text: string;
media?: TwitterMedia[];
quoteTweet?: string;
replyTo?: string;
poll?: TwitterPoll;
}TwitterMedia
interface TwitterMedia {
type: 'image' | 'video' | 'gif';
url: string;
altText?: string;
dimensions?: {
width: number;
height: number;
};
}TwitterPoll
interface TwitterPoll {
options: string[]; // 2-4 options
durationMinutes: number; // 5-10080 (7 days)
}Classes
TwitterContentBuilder
Fluent builder for creating Twitter content.
Methods:
setText(text: string): this- Set tweet textaddImage(url: string, altText?: string): this- Add imageaddVideo(url: string, altText?: string): this- Add videoaddGif(url: string, altText?: string): this- Add GIFcreatePoll(options: string[], durationMinutes: number): this- Add pollsetReplyTo(tweetId: string): this- Set reply-to tweetsetQuoteTweet(tweetId: string): this- Set quote tweetaddHashtag(tag: string): this- Add hashtag to metadataaddMention(username: string): this- Add mention to metadatabuild(): TwitterContent- Build contentbuildWithMetadata()- Build content with metadatavalidate(): TwitterValidationResult- Validate current contentreset(): this- Reset builderclone(): TwitterContentBuilder- Clone builder state
TwitterContentValidator
Validates Twitter content against platform constraints.
Methods:
validate(content: TwitterContent): TwitterValidationResult- Full validationvalidateText(text: string, hasMedia?: boolean): TwitterValidationError[]validateMedia(media: TwitterMedia[]): TwitterValidationError[]validatePoll(poll: TwitterPoll): TwitterValidationError[]countCharacters(text: string): number
TwitterContentTransformer
Transforms content between formats.
Methods:
fromGeneric(content: GenericSocialContent): TwitterContenttoGeneric(content: TwitterContent): GenericSocialContentfromBlogPost(content: BlogPostContent): TwitterContent[]optimizeForTwitter(content: TwitterContent): TwitterContentsplitIntoThread(longText: string): TwitterContent[]
Functions
Character Counting
countCharacters(text: string): number- Count characters with Twitter rulescountCharactersWithMedia(text: string, hasMedia: boolean): numberextractUrls(text: string): string[]- Extract URLs from textgetCharacterBreakdown(text, hasMedia, maxLength): CharacterBreakdownexceedsLimit(text, hasMedia, maxLength): boolean
Thread Generation
splitIntoThread(longText: string, options?: ThreadOptions): TwitterContent[]estimateTweetCount(text: string, options?: ThreadOptions): numberneedsThread(text: string, maxLength?: number): boolean
Constants
TWITTER_CONSTRAINTS
{
maxTextLength: 280,
maxTextLengthLongForm: 25000,
maxMediaItems: 4,
maxPollOptions: 4,
minPollOptions: 2,
maxPollDuration: 10080, // 7 days
minPollDuration: 5,
maxAltTextLength: 1000,
maxHashtags: 30,
urlLength: 23, // t.co shortening
mediaLength: 23,
supportedMediaTypes: ['image/png', 'image/jpeg', 'image/gif', 'video/mp4'],
maxImageSize: 5242880, // 5MB
maxVideoSize: 536870912, // 512MB
imageDimensions: {
minWidth: 4,
minHeight: 4,
maxWidth: 8192,
maxHeight: 8192
}
}Twitter Character Counting Rules
Twitter has specific rules for character counting:
- URLs - Always count as 23 characters (due to t.co shortening)
- Media - Counts as 23 characters when attached
- Emojis - Count based on their Unicode encoding (1-4 characters)
- Mentions - Count full length including @ symbol
- Hashtags - Count full length including # symbol
Example:
const text = 'Check out https://example.com 👋 #awesome';
// Character count breakdown:
// "Check out " = 10
// "https://example.com" = 23 (not actual length!)
// " " = 1
// "👋" = 2 (emoji)
// " " = 1
// "#awesome" = 8
// Total = 45 charactersIntegration Status
Logger Integration
Status: Not applicable
Justification: This is a pure content type definition package with no runtime operations, side effects, or error conditions that require logging. The TwitterContentValidator, TwitterContentBuilder, and TwitterContentTransformer classes are stateless utility classes that perform validation, building, and transformation operations. All errors are thrown as exceptions that calling code can handle, and there are no background operations, network calls, or state changes that would benefit from structured logging.
Pattern: Pure functional utility - no logger integration needed. Logging is handled by consuming packages that use this content type.
NeverHub Integration
Status: Integrated
Justification: This package provides NeverHub service discovery integration through the neverhub-registration.ts module. Content type packages register themselves with NeverHub so that services can discover available content types at runtime. This enables dynamic content type discovery and allows services to adapt to available content types without hard-coded dependencies.
Pattern: Service discovery integration - package registers content type with NeverHub for runtime discovery.
Example Integration:
import { registerTwitterContentType } from '@bernierllc/social-media-content-type-twitter/neverhub-registration';
// Register with NeverHub (if available)
if (typeof detectNeverHub === 'function') {
registerTwitterContentType();
}Docs-Suite Integration
Status: Ready
Format: TypeDoc-compatible JSDoc comments are included throughout the source code. All public APIs are documented with examples and type information.
Dependencies
validator- URL and data validation utilities@bernierllc/crypto-utils- For URL shortening hash generation (future use)
Related Packages
- @bernierllc/social-media-twitter - Twitter API service layer
- @bernierllc/social-media-manager - Multi-platform orchestration
- @bernierllc/content-management-suite - Complete content system
- @bernierllc/social-media-content-type-linkedin
- @bernierllc/social-media-content-type-facebook
- @bernierllc/social-media-content-type-instagram
License
Copyright (c) 2025 Bernier LLC. All rights reserved.
This code is licensed to the client under a limited-use license. The client may use and modify this code only within the scope of the project it was delivered for. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
