@bernierllc/social-media-content-type-linkedin
v1.2.0
Published
LinkedIn-specific content type definition and validation
Readme
@bernierllc/social-media-content-type-linkedin
LinkedIn-specific content type definition and validation
A pure content type definition package that defines LinkedIn-specific content constraints, validation rules, and transformation requirements. Designed for use by social media service packages requiring platform-specific content processing.
Installation
npm install @bernierllc/social-media-content-type-linkedinFeatures
- Platform-specific constraints - All LinkedIn API limits and rules
- LinkedIn article support - Long-form content with HTML preservation
- Document sharing - PDF, PPTX, DOCX format support
- Multi-image carousel - Up to 9 images per post
- Poll configuration - 2-4 options with variable durations
- Link preview optimization - Structured link metadata
- Targeted audience - Industry/location/job title targeting
- Hashtag optimization - 3 recommended, 30 absolute max
- Type-safe builder API - Fluent interface for content construction
- Comprehensive validation - Platform constraint checking
- Content transformation - Generic to LinkedIn conversion
Usage
Basic Post Creation
import { LinkedInContentBuilder } from '@bernierllc/social-media-content-type-linkedin';
const builder = new LinkedInContentBuilder();
const content = builder
.setText('Excited to share our latest product launch!')
.addHashtag('innovation')
.addHashtag('tech')
.addHashtag('startup')
.setVisibility('public')
.build();
console.log(content);
// {
// text: "Excited to share our latest product launch!\n\n#innovation #tech #startup",
// shareType: "post"
// }LinkedIn Article Publishing
import { LinkedInContentBuilder } from '@bernierllc/social-media-content-type-linkedin';
const article = builder
.setText('Read my latest article on sustainable technology')
.setArticle({
title: 'The Future of Sustainable Tech',
subtitle: 'How green innovation is reshaping our industry',
content: '<h1>Introduction</h1><p>In recent years...</p>',
coverImage: 'https://example.com/cover.jpg',
canonicalUrl: 'https://blog.example.com/sustainable-tech'
})
.build();
console.log(article.shareType); // "article"Image Carousel Post
import { LinkedInContentBuilder } from '@bernierllc/social-media-content-type-linkedin';
const carousel = builder
.setText('Our journey in 9 images')
.addMedia({
type: 'image',
url: 'https://example.com/image1.jpg',
title: 'Beginning'
})
.addMedia({
type: 'image',
url: 'https://example.com/image2.jpg',
title: 'Growth'
})
// Add up to 9 images total
.build();Video Post
import { LinkedInContentBuilder } from '@bernierllc/social-media-content-type-linkedin';
const video = builder
.setText('Watch our product demo')
.addMedia({
type: 'video',
url: 'https://example.com/demo.mp4',
thumbnailUrl: 'https://example.com/thumb.jpg',
description: 'Full product walkthrough'
})
.setShareType('video')
.build();Document Sharing
import { LinkedInContentBuilder } from '@bernierllc/social-media-content-type-linkedin';
const document = builder
.setText('Download our latest whitepaper')
.setDocument({
type: 'pdf',
url: 'https://example.com/whitepaper.pdf',
title: 'Industry Trends 2025',
description: 'Comprehensive analysis of market trends'
})
.build();
console.log(document.shareType); // "document"Poll Creation
import { LinkedInContentBuilder } from '@bernierllc/social-media-content-type-linkedin';
const poll = builder
.setText('What matters most to you in a workplace?')
.addPoll({
question: 'What matters most to you in a workplace?',
options: [
'Work-life balance',
'Career growth',
'Compensation',
'Company culture'
],
durationDays: 7
})
.build();Content Validation
import { LinkedInContentValidator } from '@bernierllc/social-media-content-type-linkedin';
const validator = new LinkedInContentValidator();
const result = validator.validate(content);
if (!result.valid) {
console.error('Validation errors:', result.errors);
// [{
// field: "text",
// message: "Text exceeds 3000 characters",
// constraint: "maxTextLength",
// value: 3150
// }]
}
// Check warnings and suggestions
console.log('Warnings:', result.warnings);
console.log('Suggestions:', result.suggestions);Content Transformation
From Generic Social Content
import { LinkedInContentTransformer } from '@bernierllc/social-media-content-type-linkedin';
const transformer = new LinkedInContentTransformer();
const genericContent = {
text: 'Check out our new product!',
images: ['https://example.com/product.jpg'],
hashtags: ['tech', 'innovation', 'startup', 'business']
};
const linkedInContent = transformer.fromGeneric(genericContent);
console.log(linkedInContent);
// {
// text: "Check out our new product!\n\n#tech #innovation #startup",
// shareType: "post",
// media: [{ type: "image", url: "https://example.com/product.jpg" }]
// }
// Note: Only first 3 hashtags recommended for LinkedInFrom Blog Post
import { LinkedInContentTransformer } from '@bernierllc/social-media-content-type-linkedin';
const transformer = new LinkedInContentTransformer();
// Short blog post becomes regular post with link
const shortBlog = {
title: 'Quick Tips for Success',
excerpt: '5 practical tips every professional should know',
content: 'Tip 1: ...', // < 1000 chars
url: 'https://blog.example.com/tips',
featuredImage: 'https://blog.example.com/featured.jpg',
tags: ['productivity', 'career']
};
const linkedInPost = transformer.fromBlogPost(shortBlog);
console.log(linkedInPost.shareType); // "post"
console.log(linkedInPost.link?.url); // "https://blog.example.com/tips"
// Long blog post becomes LinkedIn article
const longBlog = {
title: 'The Complete Guide to Digital Transformation',
excerpt: 'Everything you need to know about digital transformation',
content: '<h1>Chapter 1</h1><p>...' // > 1000 chars
+ // Long content...
url: 'https://blog.example.com/guide',
featuredImage: 'https://blog.example.com/guide-cover.jpg'
};
const linkedInArticle = transformer.fromBlogPost(longBlog);
console.log(linkedInArticle.shareType); // "article"
console.log(linkedInArticle.article?.title); // "The Complete Guide to..."LinkedIn Optimization
import { LinkedInContentTransformer } from '@bernierllc/social-media-content-type-linkedin';
const transformer = new LinkedInContentTransformer();
const content = {
text: 'this is a post #tech #business #marketing #sales #startup #innovation',
shareType: 'post' as const
};
// Optimize for LinkedIn best practices
const optimized = transformer.optimizeForLinkedIn(content);
console.log(optimized.text);
// "This is a post\n\n#tech #business #marketing"
// - Capitalized first letter
// - Limited to 3 hashtags (recommended)API Reference
LinkedInContent
Main content structure for LinkedIn posts.
interface LinkedInContent {
text: string; // Post text (max 3000 chars)
shareType: 'post' | 'article' | 'video' | 'document';
article?: LinkedInArticle; // Long-form article
media?: LinkedInMedia[]; // Up to 9 images or 1 video
document?: LinkedInDocument; // PDF/PPTX/DOCX
link?: LinkedInLink; // Link preview
poll?: LinkedInPoll; // Poll configuration
}LinkedInArticle
LinkedIn article (long-form content).
interface LinkedInArticle {
title: string; // Max 100 chars
subtitle?: string; // Max 250 chars
content: string; // Rich HTML content (max 125K chars)
coverImage?: string; // Article cover image URL
canonicalUrl?: string; // Original article URL
}LinkedInMedia
Image or video media item.
interface LinkedInMedia {
type: 'image' | 'video';
url: string;
title?: string; // Max 200 chars
description?: string; // Max 2000 chars
thumbnailUrl?: string; // Video thumbnail (required for video)
}LinkedInDocument
Document attachment (PDF, PowerPoint, Word).
interface LinkedInDocument {
type: 'pdf' | 'pptx' | 'docx';
url: string;
title: string; // Max 255 chars
description?: string;
}LinkedInPoll
Poll configuration.
interface LinkedInPoll {
question: string; // Max 140 chars
options: string[]; // 2-4 options, max 255 chars each
durationDays: 1 | 3 | 7 | 14; // Poll duration
}LINKEDIN_CONSTRAINTS
Platform-specific limits and rules.
export const LINKEDIN_CONSTRAINTS = {
maxTextLength: 3000, // Post text limit
maxArticleContentLength: 125000, // Article content limit
maxMediaItems: 9, // Max images in carousel
maxVideoCount: 1, // Only 1 video per post
maxHashtags: 3, // Recommended hashtag count
maxAbsoluteHashtags: 30, // Technical hashtag limit
supportedMediaTypes: ['image/png', 'image/jpeg', 'video/mp4'],
supportedDocumentTypes: ['application/pdf', ...],
// ... more constraints
};LinkedInContentValidator
Validates content against LinkedIn constraints.
Methods:
validate(content: LinkedInContent): LinkedInValidationResult- Validate complete contentvalidateText(text: string): boolean- Validate text lengthvalidateArticle(article: LinkedInArticle): boolean- Validate article structurevalidateMedia(media: LinkedInMedia[]): boolean- Validate media arrayvalidateDocument(doc: LinkedInDocument): boolean- Validate documentvalidatePoll(poll: LinkedInPoll): boolean- Validate poll configurationvalidateHashtags(hashtags: string[]): boolean- Validate hashtag array
LinkedInContentBuilder
Fluent builder for constructing LinkedIn content.
Methods:
setText(text: string): this- Set post textsetShareType(type: 'post' | 'article' | 'video' | 'document'): this- Set content typeaddMedia(media: LinkedInMedia): this- Add media itemsetArticle(article: LinkedInArticle): this- Set article contentsetDocument(doc: LinkedInDocument): this- Set documentsetLink(link: LinkedInLink): this- Set link previewaddPoll(poll: LinkedInPoll): this- Add pollsetVisibility(visibility: 'public' | 'connections' | 'private'): this- Set visibilityaddHashtag(tag: string): this- Add hashtagaddMention(username: string): this- Add user mentionsetScheduledFor(date: Date): this- Set scheduled publish datebuild(): LinkedInContent- Build final contentvalidate(): LinkedInValidationResult- Validate current statereset(): this- Reset builder to initial state
LinkedInContentTransformer
Transforms content between LinkedIn and other formats.
Methods:
fromGeneric(content: GenericSocialContent): LinkedInContent- Transform generic social contentfromBlogPost(post: BlogPostContent): LinkedInContent- Transform blog posttoGeneric(content: LinkedInContent): GenericSocialContent- Convert to generic formatoptimizeForLinkedIn(content: LinkedInContent): LinkedInContent- Optimize for platformconvertToArticle(post: BlogPostContent): LinkedInArticle- Convert blog to article
Platform Best Practices
Hashtag Optimization
LinkedIn recommends using 1-3 hashtags for optimal visibility. While the technical limit is 30, posts with more than 3 hashtags see reduced engagement.
// Good - 3 hashtags
builder.addHashtag('tech').addHashtag('innovation').addHashtag('startup');
// Too many - reduces visibility
builder.addHashtag('tag1').addHashtag('tag2')...(10 more)...Professional Tone
LinkedIn favors professional, industry-focused content:
// Good professional tone
"Excited to announce our new product launch. This innovation addresses key challenges in the healthcare industry. #healthcare #innovation #technology"
// Too casual for LinkedIn
"OMG!!! You guys have to check this out 🔥🔥🔥 #amazing #awesome"Long-Form Articles
Use LinkedIn articles for content over 1000 characters for better formatting and engagement:
// Short content (< 1000 chars) - regular post
const shortContent = builder.setText('Quick tip: ...').build();
// Long content (> 1000 chars) - article
const longContent = builder
.setText('Read my full analysis')
.setArticle({
title: 'Complete Analysis',
content: '...' // Full content here
})
.build();Media Best Practices
- Images: Use 1200x627px for optimal preview
- Videos: Include thumbnail for better engagement
- Carousels: Use 2-9 images to tell a story
- Documents: Use for whitepapers, reports, presentations
Configuration
No runtime configuration required. This is a pure content type definition package with static constraints and validation rules.
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 LinkedInContentValidator, LinkedInContentBuilder, and LinkedInContentTransformer 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 content type registration. 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 { registerLinkedInContentType } from '@bernierllc/social-media-content-type-linkedin/neverhub-registration';
// Register with NeverHub (if available)
if (typeof detectNeverHub === 'function') {
registerLinkedInContentType();
}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
- @bernierllc/crypto-utils (^1.0.2) - Document hash generation
- validator (^13.12.0) - String validation utilities
Related Packages
- @bernierllc/social-media-content-type-twitter - Twitter content types
- @bernierllc/social-media-content-type-facebook - Facebook content types
- @bernierllc/social-media-content-type-instagram - Instagram content types
- @bernierllc/social-media-linkedin - LinkedIn service integration
- @bernierllc/social-media-manager - Multi-platform orchestration
Examples
See the /examples directory for more comprehensive usage examples:
basic-post.ts- Simple text postarticle-publishing.ts- Long-form articledocument-sharing.ts- PDF/PPTX sharingblog-transformation.ts- Blog to LinkedIn conversion
TypeScript Support
This package is written in TypeScript and includes complete type definitions. All interfaces and types are exported for use in your TypeScript projects.
Testing
This package maintains 98%+ test coverage with comprehensive unit and integration tests.
# Run tests
npm test
# Run with coverage
npm run test:coverage
# Build package
npm run build
# Lint code
npm run lintLicense
Copyright (c) 2025 Bernier LLC. All rights reserved.
This package is part of the BernierLLC tools monorepo.
