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/content-project-manager

v0.3.0

Published

Service for managing relationships between content items, projects, and external sources

Readme

@bernierllc/content-project-manager

Service for managing relationships between content items, projects, and external sources.

Features

  • Project Management: Create, update, delete, and query projects
  • Content Relationships: Link content items together with typed relationships
  • Project-Content Linking: Associate content with projects with optional roles
  • Relationship Graphs: Build and traverse content relationship graphs
  • Event Emitting: Subscribe to project and content lifecycle events
  • Database Agnostic: Works with any SQL database via IDatabaseAdapter
  • Optional NeverHub Integration: Auto-detects and integrates with NeverHub service discovery

Installation

npm install @bernierllc/content-project-manager

Usage

Basic Setup

import { ContentProjectManager } from '@bernierllc/content-project-manager';
import { PostgreSQLAdapter } from '@bernierllc/database-adapter-postgresql';
import { createLogger } from '@bernierllc/logger';

const database = new PostgreSQLAdapter({
  host: 'localhost',
  port: 5432,
  database: 'mydb',
  user: 'user',
  password: 'password',
});

const logger = createLogger({ level: 'info' });

const manager = new ContentProjectManager({
  database,
  logger,
});

await manager.initialize();

Project Management

// Create a project
const result = await manager.createProject({
  name: 'Q1 Marketing Campaign',
  description: 'Content for Q1 2025 marketing initiative',
  status: 'active',
  metadata: { budget: 50000, team: 'marketing' },
});

// Get a project
const project = await manager.getProject(result.data.id);

// Update a project
await manager.updateProject(result.data.id, {
  status: 'completed',
  metadata: { actualBudget: 48000 },
});

// Delete a project
await manager.deleteProject(result.data.id);

Content-Project Linking

// Add content to a project
await manager.addContentToProject(
  'project-123',
  'content-456',
  { role: 'featured' }
);

// Get all content in a project
const content = await manager.getProjectContent('project-123', {
  role: 'featured',
  limit: 10,
});

// Remove content from project
await manager.removeContentFromProject('project-123', 'content-456');

Content Relationships

// Create a relationship
await manager.createRelationship({
  sourceId: 'blog-post-1',
  targetId: 'social-post-1',
  type: 'derived-from',
  metadata: { platform: 'twitter' },
});

// Get relationships for content
const relationships = await manager.getRelationships('blog-post-1', {
  type: 'derived-from',
  direction: 'source',
});

// Link blog to multiple social posts
await manager.linkBlogToSocialPosts('blog-post-1', [
  'twitter-post-1',
  'linkedin-post-1',
  'facebook-post-1',
]);

Relationship Graphs

// Build a content graph
const graph = await manager.getContentGraph('root-content-id', 3);

// Graph structure:
// {
//   id: 'root-content-id',
//   relationships: [...],
//   children: [
//     { id: 'child-1', relationships: [...], children: [...] },
//     { id: 'child-2', relationships: [...] }
//   ]
// }

Event Subscriptions

manager.on('project:created', (data) => {
  console.log('New project created:', data.project);
});

manager.on('project:updated', (data) => {
  console.log('Project updated:', data.project);
});

manager.on('project:deleted', (data) => {
  console.log('Project deleted:', data.projectId);
});

manager.on('content:added', (data) => {
  console.log('Content added to project:', data);
});

manager.on('content:removed', (data) => {
  console.log('Content removed from project:', data);
});

manager.on('relationship:created', (data) => {
  console.log('Relationship created:', data.relationship);
});

API Reference

ContentProjectManager

Constructor

constructor(config: ServiceConfig)
  • config.database (required): IDatabaseAdapter instance
  • config.logger (optional): Logger instance

Methods

initialize(): Promise<void>

Initialize the service and create database schema.

createProject(options: CreateProjectOptions): Promise<IServiceResult<Project>>

Create a new project.

getProject(id: string): Promise<IServiceResult<Project>>

Get project by ID.

updateProject(id: string, updates: UpdateProjectOptions): Promise<IServiceResult<Project>>

Update an existing project.

deleteProject(id: string): Promise<IServiceResult<void>>

Delete a project.

addContentToProject(projectId: string, contentId: string, metadata?: { role?: string }): Promise<IServiceResult<ContentProjectLink>>

Add content to a project.

removeContentFromProject(projectId: string, contentId: string): Promise<IServiceResult<void>>

Remove content from a project.

getProjectContent(projectId: string, filters?: ProjectContentFilters): Promise<IServiceResult<ContentProjectLink[]>>

Get all content in a project with optional filters.

createRelationship(options: CreateRelationshipOptions): Promise<IServiceResult<ContentRelationship>>

Create a relationship between two content items.

getRelationships(contentId: string, options?: GetRelationshipsOptions): Promise<IServiceResult<ContentRelationship[]>>

Get relationships for a content item.

linkBlogToSocialPosts(blogId: string, socialPostIds: string[]): Promise<IServiceResult<ContentRelationship[]>>

Convenience method to link a blog post to multiple social media posts.

getContentGraph(rootId: string, depth?: number): Promise<IServiceResult<ContentGraphNode>>

Build a relationship graph starting from a root content item.

close(): Promise<void>

Close the service and clean up resources.

Database Schema

The service creates three tables:

projects

CREATE TABLE projects (
  id UUID PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  description TEXT,
  status VARCHAR(50) DEFAULT 'active',
  metadata JSONB,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

content_projects

CREATE TABLE content_projects (
  project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
  content_id UUID NOT NULL,
  role VARCHAR(100),
  added_at TIMESTAMP DEFAULT NOW(),
  PRIMARY KEY (project_id, content_id)
);

content_relationships

CREATE TABLE content_relationships (
  id UUID PRIMARY KEY,
  source_id UUID NOT NULL,
  target_id UUID NOT NULL,
  relationship_type VARCHAR(100) NOT NULL,
  metadata JSONB,
  created_at TIMESTAMP DEFAULT NOW()
);

Events

  • initialized - Emitted when service is initialized
  • project:created - Emitted when a project is created
  • project:updated - Emitted when a project is updated
  • project:deleted - Emitted when a project is deleted
  • content:added - Emitted when content is added to a project
  • content:removed - Emitted when content is removed from a project
  • relationship:created - Emitted when a relationship is created
  • closed - Emitted when service is closed

License

Copyright (c) 2025 Bernier LLC

This file is licensed to the client under a limited-use license.