npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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-linkedin

Features

  • 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 LinkedIn

From 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 content
  • validateText(text: string): boolean - Validate text length
  • validateArticle(article: LinkedInArticle): boolean - Validate article structure
  • validateMedia(media: LinkedInMedia[]): boolean - Validate media array
  • validateDocument(doc: LinkedInDocument): boolean - Validate document
  • validatePoll(poll: LinkedInPoll): boolean - Validate poll configuration
  • validateHashtags(hashtags: string[]): boolean - Validate hashtag array

LinkedInContentBuilder

Fluent builder for constructing LinkedIn content.

Methods:

  • setText(text: string): this - Set post text
  • setShareType(type: 'post' | 'article' | 'video' | 'document'): this - Set content type
  • addMedia(media: LinkedInMedia): this - Add media item
  • setArticle(article: LinkedInArticle): this - Set article content
  • setDocument(doc: LinkedInDocument): this - Set document
  • setLink(link: LinkedInLink): this - Set link preview
  • addPoll(poll: LinkedInPoll): this - Add poll
  • setVisibility(visibility: 'public' | 'connections' | 'private'): this - Set visibility
  • addHashtag(tag: string): this - Add hashtag
  • addMention(username: string): this - Add user mention
  • setScheduledFor(date: Date): this - Set scheduled publish date
  • build(): LinkedInContent - Build final content
  • validate(): LinkedInValidationResult - Validate current state
  • reset(): this - Reset builder to initial state

LinkedInContentTransformer

Transforms content between LinkedIn and other formats.

Methods:

  • fromGeneric(content: GenericSocialContent): LinkedInContent - Transform generic social content
  • fromBlogPost(post: BlogPostContent): LinkedInContent - Transform blog post
  • toGeneric(content: LinkedInContent): GenericSocialContent - Convert to generic format
  • optimizeForLinkedIn(content: LinkedInContent): LinkedInContent - Optimize for platform
  • convertToArticle(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

Examples

See the /examples directory for more comprehensive usage examples:

  • basic-post.ts - Simple text post
  • article-publishing.ts - Long-form article
  • document-sharing.ts - PDF/PPTX sharing
  • blog-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 lint

License

Copyright (c) 2025 Bernier LLC. All rights reserved.

This package is part of the BernierLLC tools monorepo.