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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@bernierllc/content-workflow-service

v0.1.3

Published

Workflow orchestration service for content management

Downloads

213

Readme

@bernierllc/content-workflow-service

Workflow orchestration service for content management.

Overview

This package provides a service layer for orchestrating editorial workflows in content management systems. It builds on top of the @bernierllc/content-editorial-workflow core package to provide workflow execution, permission checking, notifications, and event handling.

Features

  • Workflow Orchestration: Execute and manage editorial workflows
  • Permission Checking: Enforce permissions for stage transitions
  • Event Handling: Comprehensive event system for workflow operations
  • Notifications: Send notifications for workflow events
  • Statistics: Track workflow performance and usage
  • Hooks System: Extensible hooks for custom processing
  • TypeScript Support: Full type safety and IntelliSense

Installation

npm install @bernierllc/content-workflow-service

Quick Start

import { ContentWorkflowService } from '@bernierllc/content-workflow-service';
import { WorkflowTemplates } from '@bernierllc/content-editorial-workflow';

// Create workflow service
const service = new ContentWorkflowService({
  enabled: true,
  permissions: {
    enabled: true,
    defaultPermissions: ['content.edit', 'content.publish']
  },
  notifications: {
    enabled: true,
    channels: ['email', 'internal']
  }
});

// Register a workflow
const workflow = WorkflowTemplates.writeAndPublish();
await service.registerWorkflow(workflow);

// Create content in workflow
const content = await service.createContent('content-1', 'write-and-publish', {
  contentId: 'content-1',
  userId: 'user-123',
  userPermissions: ['content.edit', 'content.publish'],
  contentMetadata: { type: 'text', title: 'My Article' }
});

// Transition content to next stage
const result = await service.transitionStage({
  contentId: 'content-1',
  targetStageId: 'publish',
  userId: 'user-123',
  reason: 'Ready to publish'
});

if (result.success) {
  console.log('Content moved to publish stage');
}

API Reference

ContentWorkflowService

The main service class for managing content workflows.

Constructor

new ContentWorkflowService(config?: Partial<ContentWorkflowServiceConfig>)

Configuration Options

interface ContentWorkflowServiceConfig {
  enabled: boolean;                    // Whether the service is enabled
  defaultWorkflowId?: string;          // Default workflow for new content
  publishEvents: boolean;              // Whether to publish events
  logOperations: boolean;              // Whether to log operations
  permissions: {
    enabled: boolean;                   // Whether to enforce permissions
    defaultPermissions: string[];     // Default permissions
  };
  notifications: {
    enabled: boolean;                   // Whether to send notifications
    channels: string[];                 // Notification channels
  };
}

Methods

registerWorkflow(workflow)

Register a new workflow.

const workflow = WorkflowTemplates.writeAndPublish();
await service.registerWorkflow(workflow);
createContent(contentId, workflowId, context)

Create content in a workflow.

const content = await service.createContent('content-1', 'workflow-1', {
  contentId: 'content-1',
  userId: 'user-123',
  userPermissions: ['content.edit'],
  contentMetadata: { type: 'text', title: 'My Article' }
});
transitionStage(request)

Transition content to a different stage.

const result = await service.transitionStage({
  contentId: 'content-1',
  targetStageId: 'publish',
  userId: 'user-123',
  reason: 'Ready to publish'
});
getContentStatus(contentId)

Get workflow status for content.

const status = service.getContentStatus('content-1');
console.log('Current stage:', status.currentStageId);
console.log('Can publish:', status.canPublish);
console.log('Available transitions:', status.availableTransitions);
checkPermissions(contentId, targetStageId, userId)

Check permissions for stage transition.

const permissionCheck = await service.checkPermissions('content-1', 'publish', 'user-123');
if (!permissionCheck.allowed) {
  console.log('Missing permissions:', permissionCheck.missingPermissions);
}

Event System

Listen to workflow service events.

service.onEvent((event) => {
  switch (event.type) {
    case 'workflow_registered':
      console.log('Workflow registered:', event.data.workflowId);
      break;
    case 'stage_transitioned':
      console.log('Stage transitioned:', event.data.contentId);
      break;
    case 'permission_denied':
      console.log('Permission denied:', event.data.reason);
      break;
  }
});

Hooks System

Add custom processing for workflow events.

service.addHook({
  name: 'audit-log',
  hook: async (event) => {
    // Log workflow events for audit
    auditLogger.log(event.type, {
      timestamp: event.timestamp,
      userId: event.userId,
      data: event.data
    });
  },
  priority: 1,
  enabled: true,
  eventTypes: ['stage_transitioned', 'permission_denied']
});

Examples

Basic Workflow Management

import { ContentWorkflowService } from '@bernierllc/content-workflow-service';
import { WorkflowTemplates } from '@bernierllc/content-editorial-workflow';

class ContentManager {
  private workflowService: ContentWorkflowService;

  constructor() {
    this.workflowService = new ContentWorkflowService({
      enabled: true,
      permissions: {
        enabled: true,
        defaultPermissions: ['content.edit', 'content.publish']
      }
    });

    // Set up event handling
    this.workflowService.onEvent((event) => {
      this.handleWorkflowEvent(event);
    });
  }

  async initialize() {
    // Register default workflow
    const workflow = WorkflowTemplates.writeAndPublish();
    await this.workflowService.registerWorkflow(workflow);
  }

  async createContent(contentId: string, userId: string, contentData: any) {
    const content = await this.workflowService.createContent(contentId, 'write-and-publish', {
      contentId,
      userId,
      userPermissions: await this.getUserPermissions(userId),
      contentMetadata: contentData
    });

    return content;
  }

  async publishContent(contentId: string, userId: string) {
    const result = await this.workflowService.transitionStage({
      contentId,
      targetStageId: 'publish',
      userId,
      reason: 'Publishing content'
    });

    if (result.success) {
      // Update UI to show published status
      this.updateContentStatus(contentId, 'published');
    }

    return result;
  }

  private handleWorkflowEvent(event: any) {
    switch (event.type) {
      case 'stage_transitioned':
        this.notifyUser(`Content ${event.data.contentId} moved to ${event.data.newStageId}`);
        break;
      case 'permission_denied':
        this.notifyUser(`Permission denied: ${event.data.reason}`);
        break;
    }
  }
}

Advanced Permission Management

class PermissionAwareContentManager {
  constructor(private workflowService: ContentWorkflowService) {}

  async transitionWithPermissionCheck(
    contentId: string,
    targetStageId: string,
    userId: string,
    reason: string
  ) {
    // Check permissions first
    const permissionCheck = await this.workflowService.checkPermissions(
      contentId,
      targetStageId,
      userId
    );

    if (!permissionCheck.allowed) {
      return {
        success: false,
        error: `Permission denied: ${permissionCheck.error}`,
        missingPermissions: permissionCheck.missingPermissions
      };
    }

    // Proceed with transition
    return this.workflowService.transitionStage({
      contentId,
      targetStageId,
      userId,
      reason
    });
  }

  async getUserPermissions(userId: string): Promise<string[]> {
    // In a real implementation, this would fetch from a permissions service
    const user = await this.getUser(userId);
    return user.permissions || [];
  }
}

Notification Integration

class NotificationEnabledContentManager {
  constructor(private workflowService: ContentWorkflowService) {
    // Set up notification hooks
    this.workflowService.addHook({
      name: 'notification-hook',
      hook: async (event) => {
        if (event.type === 'stage_transitioned') {
          await this.sendNotification(event);
        }
      },
      priority: 1,
      enabled: true,
      eventTypes: ['stage_transitioned']
    });
  }

  private async sendNotification(event: any) {
    const { contentId, newStageId, userId } = event.data;
    
    // Send email notification
    await this.emailService.send({
      to: await this.getUserEmail(userId),
      subject: 'Content Status Changed',
      body: `Your content ${contentId} has moved to stage ${newStageId}`
    });

    // Send internal notification
    await this.internalNotificationService.send({
      userId,
      type: 'content_status_changed',
      data: { contentId, newStageId }
    });
  }
}

Statistics and Analytics

class ContentAnalytics {
  constructor(private workflowService: ContentWorkflowService) {}

  getWorkflowReport() {
    const stats = this.workflowService.getStatistics();
    
    return {
      totalWorkflows: stats.totalWorkflows,
      totalContent: stats.totalContent,
      contentByStage: stats.contentByStage,
      recentActivity: {
        transitionsLast24h: stats.transitionsLast24h,
        permissionDenialsLast24h: stats.permissionDenialsLast24h,
        notificationsSentLast24h: stats.notificationsSentLast24h
      },
      performance: {
        averageStageTime: stats.averageStageTime
      }
    };
  }

  getStagePerformanceAnalysis() {
    const stats = this.workflowService.getStatistics();
    
    return Object.entries(stats.contentByStage).map(([stageId, count]) => ({
      stageId,
      contentCount: count,
      percentage: (count / stats.totalContent) * 100,
      averageTime: stats.averageStageTime[stageId] || 0
    }));
  }
}

Integration with Existing Services

class IntegratedContentManager {
  constructor(
    private workflowService: ContentWorkflowService,
    private contentService: ContentService,
    private userService: UserService
  ) {
    // Set up integration hooks
    this.workflowService.addHook({
      name: 'content-sync',
      hook: async (event) => {
        if (event.type === 'stage_transitioned') {
          await this.syncContentStatus(event.data.contentId, event.data.newStageId);
        }
      },
      priority: 1,
      enabled: true,
      eventTypes: ['stage_transitioned']
    });
  }

  async createContentWithWorkflow(contentData: any, userId: string) {
    // Create content in content service
    const content = await this.contentService.create(contentData);
    
    // Create workflow entry
    const workflowContent = await this.workflowService.createContent(
      content.id,
      'default-workflow',
      {
        contentId: content.id,
        userId,
        userPermissions: await this.userService.getPermissions(userId),
        contentMetadata: content
      }
    );

    return { content, workflow: workflowContent };
  }

  private async syncContentStatus(contentId: string, stageId: string) {
    // Update content status in content service
    await this.contentService.updateStatus(contentId, stageId);
    
    // Update user notifications
    await this.userService.addNotification(contentId, `Content moved to ${stageId}`);
  }
}

Integration Status

  • Logger: integrated - Uses @bernierllc/logger for operation logging and event tracking
  • NeverHub: integrated - Provides service discovery and event bus capabilities when available
  • Docs-Suite: ready - Full API documentation and examples available in markdown format

TypeScript Support

This package is written in TypeScript and provides full type definitions. All interfaces and types are exported for use in your own code.

License

UNLICENSED - See LICENSE file for details.

Contributing

Contributions are welcome! Please see the contributing guidelines for more information.

Support

For support and questions, please open an issue on GitHub.