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

markdown-notes-engine

v2.0.1

Published

A complete markdown note-taking engine with Git-like version control (PostgreSQL) or GitHub integration and media hosting (R2/S3)

Downloads

34

Readme

Markdown Notes Engine

npm version License: MIT

A complete, production-ready markdown note-taking engine with Git-like version control (PostgreSQL) or GitHub integration and media hosting (Cloudflare R2/AWS S3). Add powerful note-taking capabilities to any Node.js application with just a few lines of code.

Features

  • Full Markdown Support - Rich markdown editing with live preview
  • Git-Like Version Control - Choose between PostgreSQL (recommended) or GitHub for version control
    • PostgreSQL: Content-addressable storage with SHA-256 hashing, commit history, and branching
    • GitHub: Traditional GitHub-based storage (legacy support)
  • Content-Addressable Storage - Deduplication and integrity verification
  • Full Commit History - Track every change with parent references and timestamps
  • Media Hosting - Image and video uploads to Cloudflare R2 or AWS S3
  • Full-Text Search - PostgreSQL tsvector search or GitHub code search
  • Syntax Highlighting - Beautiful code blocks with highlight.js
  • Auto-save - Never lose your work with automatic saving
  • Dark Mode - Built-in dark mode support with persistence
  • Responsive - Works beautifully on mobile and desktop
  • Keyboard Shortcuts - Boost productivity with keyboard shortcuts
  • Drag & Drop - Upload media with drag and drop
  • File History - Get complete commit history for any file

Quick Start

Installation

npm install markdown-notes-engine

Basic Usage

This package is ESM-only. Use ES module import statements:

import express from 'express';
import { createNotesRouter } from 'markdown-notes-engine';

const app = express();

async function startServer() {
  const notesRouter = await createNotesRouter({
    database: {
      host: 'localhost',
      port: 5432,
      database: 'markdown_notes',
      user: 'postgres',
      password: 'your_password',
      branch: 'main',
      author: 'your_name'
    },
    storage: {
      type: 'r2',
      accountId: process.env.R2_ACCOUNT_ID,
      accessKeyId: process.env.R2_ACCESS_KEY_ID,
      secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
      bucketName: process.env.R2_BUCKET_NAME,
      publicUrl: process.env.R2_PUBLIC_URL
    }
  });

  app.use('/api/notes', notesRouter);
  app.listen(3000, () => {
    console.log('Notes engine running on http://localhost:3000');
  });
}

startServer();

Version Control Options

Option 1: PostgreSQL (Recommended)

PostgreSQL-backed version control with Git-like architecture:

import { createNotesRouter } from 'markdown-notes-engine';

const notesRouter = await createNotesRouter({
  database: {
    // Option A: Connection string (Supabase, Heroku, etc.)
    connectionString: process.env.DATABASE_URL,
    branch: 'main',
    author: 'your_name'

    // Option B: Individual parameters (local PostgreSQL)
    // host: 'localhost',
    // port: 5432,
    // database: 'markdown_notes',
    // user: 'postgres',
    // password: 'your_password',
    // branch: 'main',
    // author: 'your_name'
  },
  storage: {
    type: 'r2',  // or 's3'
    accountId: process.env.R2_ACCOUNT_ID,
    accessKeyId: process.env.R2_ACCESS_KEY_ID,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
    bucketName: process.env.R2_BUCKET_NAME,
    publicUrl: process.env.R2_PUBLIC_URL
  },
  options: {
    autoInitSchema: true,      // Auto-initialize database schema
    autoUpdateReadme: true      // Auto-update README.md with note list
  }
});

PostgreSQL Features:

  • Content-addressable storage (SHA-256 hashing)
  • Full commit history with parent references
  • Branches support
  • No size limits
  • Full-text search with PostgreSQL tsvector
  • Automatic schema migrations
  • Works with local PostgreSQL, Supabase, Heroku Postgres, etc.

Option 2: GitHub (Legacy)

GitHub-based version control:

import { createNotesRouter } from 'markdown-notes-engine';

const notesRouter = await createNotesRouter({
  github: {
    token: process.env.GITHUB_TOKEN,
    owner: process.env.GITHUB_OWNER,
    repo: process.env.GITHUB_REPO,
    branch: 'main'
  },
  storage: {
    type: 'r2',
    accountId: process.env.R2_ACCOUNT_ID,
    accessKeyId: process.env.R2_ACCESS_KEY_ID,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
    bucketName: process.env.R2_BUCKET_NAME,
    publicUrl: process.env.R2_PUBLIC_URL
  }
});

Note: GitHub mode requires the optional @octokit/rest dependency:

npm install @octokit/rest

Remote Database Support

Works with any PostgreSQL database:

Supabase

{
  database: {
    connectionString: process.env.DATABASE_URL,  // Use Connection Pooling URL (port 6543)
    branch: 'main',
    author: 'your_name'
  }
}

See docs/SUPABASE.md for detailed Supabase setup instructions.

Heroku Postgres

{
  database: {
    connectionString: process.env.DATABASE_URL,
    ssl: 'require',
    branch: 'main',
    author: 'your_name'
  }
}

Local PostgreSQL

{
  database: {
    host: 'localhost',
    port: 5432,
    database: 'markdown_notes',
    user: 'postgres',
    password: 'your_password',
    branch: 'main',
    author: 'your_name'
  }
}

Frontend Integration

Using the Bundled Editor

<!DOCTYPE html>
<html>
<head>
  <title>My Notes App</title>
  <link rel="stylesheet" href="node_modules/markdown-notes-engine/lib/frontend/styles.css">
</head>
<body>
  <div id="notes-app"></div>

  <script type="module">
    import { NotesEditor } from 'markdown-notes-engine/frontend';

    const editor = new NotesEditor({
      container: '#notes-app',
      apiEndpoint: '/api/notes',
      theme: 'dark',
      autoSave: true,
      autoSaveDelay: 2000
    });
  </script>
</body>
</html>

Custom Frontend

Build your own frontend using the API endpoints:

// Get file structure
const structure = await fetch('/api/notes/structure').then(r => r.json());

// Get note content
const note = await fetch('/api/notes/note?path=my-note.md').then(r => r.json());

// Save note
await fetch('/api/notes/note', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ path: 'my-note.md', content: '# Hello World' })
});

// Delete note (supports both query params and body)
await fetch('/api/notes/note?path=my-note.md', { method: 'DELETE' });
// or
await fetch('/api/notes/note', {
  method: 'DELETE',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ path: 'my-note.md' })
});

// Get file history (PostgreSQL only)
const history = await fetch('/api/notes/history?path=my-note.md').then(r => r.json());

// Search notes
const results = await fetch('/api/notes/search?q=hello').then(r => r.json());

API Reference

Complete API Endpoints

| Method | Endpoint | Description | Params | |--------|----------|-------------|--------| | GET | /structure | Get file tree | - | | GET | /note | Get note content | ?path=file.md | | POST | /note | Save/update note | { path, content } | | DELETE | /note | Delete note | ?path=file.md or { path } | | POST | /folder | Create folder | { path } | | DELETE | /folder | Delete folder | { path } | | GET | /history | Get file commit history | ?path=file.md (PostgreSQL only) | | GET | /search | Full-text search | ?q=query | | POST | /upload-image | Upload image | FormData with image file | | POST | /upload-video | Upload video | FormData with video file | | POST | /upload-image-base64 | Upload base64 image | { image, filename, folder } | | POST | /render | Render markdown | { markdown } |

Response Formats

Structure Response:

{
  "structure": [
    {
      "name": "folder",
      "type": "folder",
      "path": "folder",
      "children": [
        {
          "name": "note.md",
          "type": "file",
          "path": "folder/note.md"
        }
      ]
    }
  ]
}

Note Response:

{
  "path": "my-note.md",
  "content": "# Hello World\n\nThis is my note.",
  "sha": "abc123..."
}

Save Response:

{
  "success": true,
  "path": "my-note.md",
  "sha": "def456...",
  "commit": {
    "sha": "commit-sha",
    "message": "Update my-note.md"
  }
}

History Response (PostgreSQL):

[
  {
    "sha": "commit-id",
    "message": "Update note",
    "author": "user",
    "date": "2025-01-03T12:00:00.000Z",
    "blobHash": "content-hash",
    "changed": true
  }
]

Search Response:

{
  "results": [
    {
      "path": "my-note.md",
      "content": "# Hello World",
      "score": 0.95,
      "preview": "...matching text..."
    }
  ]
}

Upload Response:

{
  "success": true,
  "url": "https://your-bucket.r2.dev/images/abc123.jpg",
  "path": "images/abc123.jpg",
  "filename": "abc123.jpg"
}

Configuration Options

Database Configuration

{
  database: {
    // Connection string (recommended for remote databases)
    connectionString: 'postgresql://user:pass@host:5432/db',

    // Or individual parameters
    host: 'localhost',
    port: 5432,
    database: 'markdown_notes',
    user: 'postgres',
    password: 'your_password',

    // Connection pool settings
    maxConnections: 20,
    idleTimeout: 30,
    connectionTimeout: 10,

    // SSL configuration
    ssl: 'prefer',  // 'require', 'prefer', or false

    // Version control settings
    branch: 'main',
    author: 'your_name'
  }
}

Storage Configuration

Cloudflare R2:

{
  storage: {
    type: 'r2',
    accountId: 'your-account-id',
    accessKeyId: 'your-access-key-id',
    secretAccessKey: 'your-secret-key',
    bucketName: 'your-bucket',
    publicUrl: 'https://pub-xxxxx.r2.dev'
  }
}

AWS S3:

{
  storage: {
    type: 's3',
    region: 'us-east-1',
    accessKeyId: 'your-access-key-id',
    secretAccessKey: 'your-secret-key',
    bucketName: 'your-bucket',
    publicUrl: 'https://your-bucket.s3.amazonaws.com'
  }
}

Options

{
  options: {
    autoInitSchema: true,      // Automatically initialize database schema
    autoUpdateReadme: true     // Auto-update README.md with note list
  }
}

Database Schema

The PostgreSQL version control uses a Git-like architecture:

  • blobs: Content storage (content-addressable by SHA-256)
  • commits: Commit records with messages, authors, and timestamps
  • trees: File path to blob hash mappings for each commit
  • branches: Named pointers to commits (like Git branches)
  • media: Uploaded media file references
  • search_index: Full-text search index using PostgreSQL tsvector

See lib/backend/db/schema.sql for the complete schema.

Migration Guide

If you have an existing database from an older version, the schema includes automatic migrations. Simply restart your application with autoInitSchema: true and the migrations will run automatically.

See MIGRATION.md for detailed migration instructions.

Examples

Check out the /examples directory for complete working examples:

Version Control Comparison

| Feature | PostgreSQL | GitHub | |---------|-----------|--------| | Storage Limits | Unlimited | 100GB per repo | | API Dependencies | None | GitHub API required | | Speed | Fast (local or pooled DB) | Network dependent | | Search | PostgreSQL full-text | GitHub code search | | Control | Full ownership | External service | | Cost | Database hosting | Free for public repos | | Version History | Full Git-like history | Native Git history | | File History | ✅ Built-in | ❌ Not available | | Branching | ✅ Supported | ✅ Supported | | Content Deduplication | ✅ SHA-256 hashing | ❌ No |

Architecture

Backend Modules

  • createNotesRouter(config) - Express router factory (async function)
  • VersionControlClient - PostgreSQL-backed Git-like version control
  • DatabaseConnection - PostgreSQL connection pool manager (uses postgres package)
  • GitHubClient - GitHub API wrapper for note storage (legacy, requires @octokit/rest)
  • StorageClient - R2/S3 client for media uploads (uses AWS SDK)
  • MarkdownRenderer - Markdown to HTML renderer with syntax highlighting

Frontend Component

  • NotesEditor - Complete note-taking UI component with:
    • Markdown editor with live preview
    • File tree navigation
    • Dark mode support
    • Keyboard shortcuts
    • Drag & drop media uploads
    • Auto-save functionality

Project Structure

markdown-notes-engine/
├── lib/                        # NPM package source (ESM)
│   ├── backend/               # Express router and API
│   │   ├── db/               # Database schema and connection
│   │   │   ├── connection.js # PostgreSQL connection manager
│   │   │   └── schema.sql    # Database schema with migrations
│   │   ├── routes/           # API route handlers
│   │   │   ├── notes.js      # Note CRUD operations
│   │   │   ├── search.js     # Search functionality
│   │   │   └── upload.js     # Media upload handlers
│   │   ├── index.js          # Main backend entry point
│   │   ├── github.js         # GitHub client (legacy)
│   │   ├── version-control.js # PostgreSQL version control
│   │   ├── storage.js        # S3/R2 storage client
│   │   └── markdown.js       # Markdown renderer
│   ├── frontend/             # Editor UI component
│   │   ├── index.js          # NotesEditor class
│   │   └── styles.css        # Styles and dark mode
│   └── index.js              # Main package entry point
├── examples/                 # Usage examples
│   ├── postgres-example.js   # PostgreSQL example
│   ├── .env.example          # Environment template
│   └── express-app/          # GitHub integration example
├── docs/                     # Documentation
│   └── SUPABASE.md          # Supabase setup guide
├── MIGRATION.md             # Database migration guide
└── package.json             # Package configuration (ESM)

Requirements

  • Node.js >= 16.0.0
  • For PostgreSQL version control (recommended):
    • PostgreSQL database (version 12 or higher)
    • Works with local PostgreSQL, Supabase, Heroku Postgres, etc.
  • For GitHub version control (legacy):
    • GitHub personal access token with repo scope
    • Install optional dependency: npm install @octokit/rest
  • For media hosting:
    • Cloudflare R2 or AWS S3 account

Keyboard Shortcuts

  • Ctrl/Cmd + S - Save note
  • Ctrl/Cmd + P - Toggle preview mode
  • Ctrl/Cmd + N - New note
  • Ctrl/Cmd + U - Upload image
  • Ctrl/Cmd + Shift + U - Upload video

Development

Running the Demo

# Install dependencies
npm install

# Copy environment template
cp examples/.env.example .env

# Edit .env with your credentials
# Set up PostgreSQL database or GitHub token
# Configure R2/S3 storage

# Start the development server
npm run dev

Open http://localhost:3000 to see the demo application.

Building the Package

The package is already built and ready to use. All source files are in the lib/ directory and use ES modules.

Environment Variables

PostgreSQL Setup

# Database Configuration
DB_HOST=localhost
DB_PORT=5432
DB_NAME=markdown_notes
DB_USER=postgres
DB_PASSWORD=your_password_here

# Or use connection string (Supabase, Heroku, etc.)
# DATABASE_URL=postgresql://postgres:password@host:6543/postgres

# Storage Configuration (R2 or S3)
R2_ACCOUNT_ID=your_account_id
R2_ACCESS_KEY_ID=your_access_key_id
R2_SECRET_ACCESS_KEY=your_secret_access_key
R2_BUCKET_NAME=your_bucket_name
R2_PUBLIC_URL=https://pub-xxxxxx.r2.dev

GitHub Setup (Legacy)

# GitHub Configuration
GITHUB_TOKEN=ghp_xxxxxxxxxxxx
GITHUB_OWNER=your-username
GITHUB_REPO=your-notes-repo
GITHUB_BRANCH=main

# Storage Configuration
R2_ACCOUNT_ID=your_account_id
R2_ACCESS_KEY_ID=your_access_key_id
R2_SECRET_ACCESS_KEY=your_secret_access_key
R2_BUCKET_NAME=your_bucket_name
R2_PUBLIC_URL=https://pub-xxxxxx.r2.dev

Troubleshooting

Database Connection Issues

Error: "connect ETIMEDOUT"

  • For Supabase: Use Connection Pooling URL (port 6543), not Direct Connection
  • Increase connectionTimeout in database config
  • Check firewall settings

Error: "column does not exist"

  • The schema has automatic migrations
  • Restart your app with autoInitSchema: true
  • See MIGRATION.md for manual migration steps

Error: "UNSAFE_TRANSACTION"

  • This is handled automatically by the postgres package
  • Ensure you're using the latest version

Import/Module Issues

Error: "Cannot use import statement outside a module"

  • Add "type": "module" to your package.json
  • This package is ESM-only

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE for details

Support

Acknowledgments

Built with:

Changelog

v1.0.1

  • Migrated to ESM-only package
  • Added PostgreSQL version control with Git-like architecture
  • Added file history endpoint
  • Improved database connection handling with postgres package
  • Added support for Supabase and other remote PostgreSQL databases
  • Added automatic schema migrations
  • Flexible DELETE endpoint (supports query params or body)
  • Built-in JSON body parser middleware

Made with ❤️ for markdown lovers everywhere