@bernierllc/social-media-content-type-mastodon
v1.0.2
Published
Mastodon-specific content type definition and validation
Readme
@bernierllc/social-media-content-type-mastodon
Mastodon-specific content type definition and validation for the BernierLLC Content Management Suite.
Features
- Instance-specific configuration fetching and caching
- Content warning (CW) auto-detection and generation
- Cross-instance mention parsing (@[email protected])
- Media focal point support
- Character counting with URL normalization (23 chars per URL)
- Thread generation for long content
- Four visibility levels (public, unlisted, private, direct)
- Poll support (2-4 options, 5min-30days expiry)
- Custom emoji support
Installation
npm install @bernierllc/social-media-content-type-mastodonUsage
The package provides three main classes for working with Mastodon content:
- MastodonContentBuilder - Fluent API for building Mastodon posts
- MastodonContentValidator - Validate content against Mastodon's rules
- MastodonContentTransformer - Convert content from other formats
Quick Start
import {
MastodonContentBuilder,
MastodonContentValidator,
MastodonInstanceConfigFetcher
} from '@bernierllc/social-media-content-type-mastodon';
// Fetch instance configuration
const fetcher = new MastodonInstanceConfigFetcher();
const config = await fetcher.fetchConfig('mastodon.social');
// Build content
const builder = new MastodonContentBuilder();
const content = builder
.setStatus('Hello from @bernierllc! #Mastodon')
.setVisibility('public')
.setSensitive(false)
.build();
// Validate
const validator = new MastodonContentValidator();
const result = validator.validate(content, config);
console.log(`Valid: ${result.valid}`);
console.log(`Character count: ${result.characterCount.status}`);Core API
MastodonContentBuilder
Fluent builder for creating Mastodon content:
const content = new MastodonContentBuilder()
.setStatus('My post text')
.addMedia({ type: 'image', file: '/path/to/image.jpg', description: 'Alt text' })
.addHashtag('mastodon')
.addMention('@friend')
.setVisibility('public')
.setSpoilerText('NSFW') // Content warning
.build();MastodonContentValidator
Validates content against platform constraints:
const validator = new MastodonContentValidator();
const result = validator.validate(content, instanceConfig);
if (!result.valid) {
console.error('Validation errors:', result.errors);
}MastodonInstanceConfigFetcher
Fetches instance-specific limits from Mastodon API:
const fetcher = new MastodonInstanceConfigFetcher();
// Fetches from /api/v1/instance
const config = await fetcher.fetchConfig('mastodon.social');
console.log(`Max status length: ${config.maxStatusLength}`); // Often 500, can be 5000+
// Cached for 1 hour
const cached = fetcher.getCachedConfig('mastodon.social');Character Counting
Mastodon counts URLs as 23 characters regardless of actual length:
import { countCharacters, isWithinCharacterLimit } from '@bernierllc/social-media-content-type-mastodon';
const status = 'Check out https://example.com/very/long/url';
const count = countCharacters(status);
console.log(`Total: ${count.total}`); // "Check out " (10) + 23 (URL) = 33
console.log(`URLs: ${count.urlCount}`); // 1
const withinLimit = isWithinCharacterLimit(status, 500); // trueMention Parsing
Supports local and cross-instance mentions:
import { parseMention, extractMentionsFromStatus } from '@bernierllc/social-media-content-type-mastodon';
// Local mention
const local = parseMention('@alice');
console.log(local.isLocal); // true
console.log(local.formatted); // "@alice"
// Cross-instance mention
const remote = parseMention('@[email protected]');
console.log(remote.isLocal); // false
console.log(remote.instance); // "mastodon.social"
// Extract from status
const status = '@alice and @[email protected] are friends';
const mentions = extractMentionsFromStatus(status);
console.log(mentions.length); // 2Content Warning Generation
Auto-detect sensitive content and suggest warnings:
import { detectContentWarning, autoGenerateContentWarning } from '@bernierllc/social-media-content-type-mastodon';
const status = 'Discussion about violence and politics';
const detection = detectContentWarning(status);
console.log(detection.suggested); // true
console.log(detection.suggestedText); // "Violence, Politics"
console.log(detection.confidence); // "medium" or "high"
// Auto-generate (only for medium/high confidence, skips if explicit CW exists)
const cw = autoGenerateContentWarning(status);
console.log(cw); // "Violence, Politics"Thread Generation
Split long content into multiple posts:
import { generateThread } from '@bernierllc/social-media-content-type-mastodon';
const longContent = 'A'.repeat(800); // Exceeds 500 char limit
const thread = generateThread(longContent, instanceConfig, {
numberPosts: true, // Add "1/3", "2/3", etc.
preserveHashtags: 'both', // Keep hashtags in first and last post
splitStrategy: 'sentence' // Split at sentence boundaries
});
console.log(`Posts: ${thread.posts.length}`);
console.log(thread.posts[0]); // "1/3 First part..."Content Transformation
Transform between content types:
import { MastodonContentTransformer } from '@bernierllc/social-media-content-type-mastodon';
const transformer = new MastodonContentTransformer();
// From Twitter
const twitterContent = {
text: 'Hello Twitter!',
media: [{ type: 'photo', file: 'image.jpg', description: 'Alt text' }]
};
const mastodonContent = transformer.fromTwitter(twitterContent);
// From blog post (creates thread if needed)
const blogContent = {
title: 'My Blog Post',
excerpt: 'This is the excerpt...',
url: 'https://myblog.com/post',
featuredImage: 'cover.jpg',
tags: ['tech', 'mastodon']
};
const thread = transformer.fromBlogPost(blogContent, instanceConfig);Platform Constraints
Default constraints (instance-specific, fetchable from API):
- Max status length: 500 chars (default), up to 10,000+ on some instances
- Max media: 4 attachments
- Max poll options: 4 (2 minimum)
- Poll expiry: 5 minutes to 30 days
- Max media description: 1,500 chars
- Focal point range: -1.0 to 1.0 (x/y coordinates)
import { MASTODON_CONSTRAINTS } from '@bernierllc/social-media-content-type-mastodon';
console.log(MASTODON_CONSTRAINTS.maxStatusLength); // 500
console.log(MASTODON_CONSTRAINTS.maxMediaAttachments); // 4Visibility Levels
- public: Visible to all, appears in public timelines, federates
- unlisted: Visible to all, but not in public timelines, federates
- private: Followers only, federates to followers' instances
- direct: Mentioned users only, doesn't federate to public
Integration 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 MastodonContentValidator, MastodonContentBuilder, and MastodonContentTransformer 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: Optional
Justification: This package can optionally register itself with NeverHub for service discovery. Content type packages can 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: Optional service discovery integration - package can register content type with NeverHub for runtime discovery.
Example Integration:
import { registerMastodonContentType } from '@bernierllc/social-media-content-type-mastodon/neverhub-registration';
// Register with NeverHub (if available)
if (typeof detectNeverHub === 'function') {
registerMastodonContentType();
}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.
License
Copyright (c) 2025 Bernier LLC. All rights reserved.
See Also
- @bernierllc/social-media-mastodon - Service layer for posting
- @bernierllc/social-media-manager - Multi-platform orchestrator
- @bernierllc/content-management-suite - Complete CMS
