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

@echoes-io/utils

v1.4.0

Published

Utilities and types for Echoes - Multi-POV storytelling platform. Provides shared timeline configuration, content parsing, word counting, and validation schemas.

Downloads

470

Readme

@echoes-io/utils

Utilities and types for Echoes - a multi-POV digital storytelling platform.

Overview

This package provides shared utilities used across the Echoes ecosystem:

  • Web application (Next.js)
  • CLI tools
  • MCP server
  • LaTeX/PDF builder

Installation

npm install @echoes-io/utils

Features

Markdown Parser

Parse markdown files with YAML frontmatter to extract chapter metadata and content.

import { parseMarkdown, stripMarkdown } from '@echoes-io/utils';

const markdown = `---
pov: "alice"
title: "First Meeting"
date: "2024-01-01"
timeline: "main"
arc: "introduction"
episode: 1
part: 1
chapter: 1
summary: "Alice meets Bob for the first time"
location: "coffee shop"
outfit: "red dress"
kink: "slow burn"
---

# Chapter 1

Alice walked into the coffee shop...`;

const { metadata, content } = parseMarkdown(markdown);
console.log(metadata.pov); // "alice"
console.log(content); // "# Chapter 1\n\nAlice walked..."

// Remove markdown syntax
const plainText = stripMarkdown(content);
console.log(plainText); // "Chapter 1\n\nAlice walked..."

Functions:

  • parseMarkdown() - Extract frontmatter and content from markdown
  • stripMarkdown() - Remove markdown syntax from text

Metadata Fields:

  • pov - Point of view character
  • title - Chapter title
  • date - Chapter date
  • timeline - Timeline identifier
  • arc - Story arc
  • episode, part, chapter - Numeric identifiers
  • summary - Brief description
  • location - Setting location
  • outfit - Character outfit (optional)
  • kink - Content tags (optional)

Text Statistics

Calculate word count and reading statistics from markdown content.

import { getTextStats } from '@echoes-io/utils';

const markdown = `
# Chapter Title

This is **bold** and *italic* text with [a link](https://example.com).
`;

const stats = getTextStats(markdown);
console.log(stats);
// {
//   words: 9,
//   characters: 52,
//   charactersNoSpaces: 43,
//   paragraphs: 1,
//   sentences: 1,
//   readingTimeMinutes: 1
// }

Features:

  • Automatically removes markdown syntax using stripMarkdown()
  • Removes HTML tags and comments
  • Removes frontmatter YAML
  • Counts words, characters (with/without spaces), paragraphs, sentences
  • Calculates reading time (based on 200 words/minute)

Path Utilities

Generate chapter files following Echoes naming conventions.

import { generateChapterFile } from '@echoes-io/utils';

const metadata = {
  pov: 'Alice',
  title: 'First Meeting',
  date: '2024-01-01',
  timeline: 'main',
  arc: 'Introduction Arc',
  episode: 1,
  part: 1,
  chapter: 5,
  summary: 'Alice meets Bob for the first time',
  location: 'Coffee Shop',
  outfit: 'Red dress',
  kink: 'Slow burn'
};

const file = generateChapterFile(metadata, 'Alice walked into the coffee shop...');

console.log(file.path);
// → content/introduction-arc/ep01-first-meeting/ep01-ch005-alice-first-meeting.md

console.log(file.content);
// → ---
//   pov: "Alice"
//   title: "First Meeting"
//   episode: 1
//   chapter: 5
//   ...
//   ---
//   
//   Alice walked into the coffee shop...

File Structure Convention:

content/
├── <arc-name>/
│   └── <ep01-episode-title>/
│       └── <ep01-ch001-pov-title>.md

Features:

  • Automatic path generation from metadata
  • Complete file with frontmatter and content
  • Handles special characters in titles (slugification)
  • Proper padding for episode (01) and chapter (001) numbers

Content Publishing Workflow

This repository provides a reusable GitHub Actions workflow for processing and publishing timeline content.

Usage in Timeline Repositories

  1. Create workflow file in your timeline repo at .github/workflows/publish.yml:
name: Publish Timeline Content

on:
  push:
    branches: [main]
    paths: ['content/**/*.md']
  workflow_dispatch:

jobs:
  publish:
    uses: echoes-io/utils/.github/workflows/publish-content.yml@main
    with:
      timeline-name: 'main'  # Change this for each timeline
      content-path: 'content/'
      web-app-url: 'https://your-web-app.com'
    secrets:
      WEB_APP_TOKEN: ${{ secrets.WEB_APP_TOKEN }}
  1. Add secret in your timeline repo:

    • Go to Settings → Secrets and variables → Actions
    • Add WEB_APP_TOKEN with your web app authentication token
  2. Organize content in your timeline repo:

timeline-repo/
├── content/
│   ├── arc1/
│   │   ├── chapter1.md
│   │   └── chapter2.md
│   └── arc2/
│       └── chapter3.md
└── .github/workflows/publish.yml

What the Workflow Does

  • Processes all .md files in the specified directory
  • Extracts frontmatter metadata using parseMarkdown()
  • Calculates text statistics using getTextStats()
  • Uploads processed content to your web app via API
  • Triggers automatically on content changes or manually

API Payload Format

The workflow sends processed content as JSON:

[
  {
    "file": "content/arc1/chapter1.md",
    "metadata": {
      "pov": "alice",
      "title": "First Meeting",
      "timeline": "main",
      "arc": "introduction",
      "episode": 1,
      "part": 1,
      "chapter": 1
    },
    "content": "# Chapter 1\n\nContent here...",
    "stats": {
      "words": 150,
      "readingTimeMinutes": 1
    },
    "lastModified": "2024-01-01T12:00:00.000Z"
  }
]

Project Structure

utils/
├── lib/              # Source code
│   ├── index.ts      # Public API exports
│   ├── types.ts      # TypeScript interfaces
│   ├── markdown-parser.ts  # Markdown parsing & stripping
│   ├── text-stats.ts # Text statistics calculation
│   └── path-utils.ts # Chapter file generation
├── test/             # Tests
│   ├── index.test.ts
│   ├── markdown-parser.test.ts
│   ├── text-stats.test.ts
│   └── path-utils.test.ts
└── package.json

Development

Scripts

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Lint code
npm run lint

# Fix linting issues
npm run lint:format

# Release (automated via GitHub Actions)
npm run release

Commit Convention

This project uses Conventional Commits for automated versioning:

  • feat: - New features (minor version bump)
  • fix: - Bug fixes (patch version bump)
  • feat!: or BREAKING CHANGE: - Breaking changes (major version bump)
  • docs:, style:, refactor:, test:, chore: - No version bump

Examples:

git commit -m "feat: add stripMarkdown function"
git commit -m "fix: handle empty frontmatter correctly"
git commit -m "feat!: change parseMarkdown return type"

Tech Stack

  • Language: TypeScript (strict mode)
  • Testing: Vitest
  • Linting: Biome
  • Git Hooks: Husky + lint-staged

Adding New Utilities

  1. Create file in lib/
  2. Create test in test/
  3. Export from index.ts
  4. Run tests: npm test
  5. Lint: npm run lint:format

Dependencies

Runtime

  • gray-matter - Parse YAML frontmatter from markdown
  • remove-markdown - Strip markdown syntax for text analysis

Development

  • typescript - Type checking and compilation
  • vitest - Testing framework
  • @biomejs/biome - Linting and formatting
  • husky - Git hooks
  • lint-staged - Pre-commit linting

License

MIT