A secure, local-only Node.js application for editing markdown files with a live split-pane preview. Edit markdown on the left, see rendered HTML on the right in real-time. Runs entirely on your local machine with zero external data transmission.
- ✅ Split-pane interface - Edit markdown on left, view rendered HTML on right
- ✅ Live preview - Preview updates in real-time as you type (debounced for performance)
- ✅ Draft auto-save - Browser local storage preserves unsaved work between sessions
- ✅ File management - Load, edit, and save markdown files directly from disk
- ✅ Local-only operation - All files stay on your computer; zero data sent externally
- ✅ Secure file handling - Path validation, directory whitelisting, XSS prevention
- ✅ TypeScript - Full type safety prevents common bugs
- ✅ Security scanning - ESLint security plugin + npm audit checks
- ✅ Code quality - Prettier formatting + ESLint with strict rules enforced
- ✅ Responsive design - Works on desktop, tablet, and mobile
- ✅ Dark mode support - Automatic system preference detection
- ✅ Pre-commit hooks - Code quality validated automatically (for developers)
This is a local-only application designed for trusted environments. See SECURITY.md for full details.
- Directory traversal attacks - Path validation prevents accessing files outside allowed directories
- XSS injection - Content sanitization and HTML escaping prevent script injection
- Credential leakage -
.envis git-ignored, secrets never committed - Dependency vulnerabilities - npm audit checks prevent known vulnerabilities
- Network attacks (app is local-only by design)
- Multi-user scenarios (single-user local tool)
- OS-level exploits (update your operating system)
Read SECURITY.md for complete information.
- Node.js 18+ (LTS recommended)
- npm 9+
# Clone or download the project
cd markdown-editor
# Install dependencies
npm install
# Start the app
npm run devCreate a .env file based on .env.example:
# Copy template
cp .env.example .env
# Edit .env with your settings
nano .envRequired configuration:
# Comma-separated list of absolute paths to allow
ALLOWED_DIRECTORIES=/Users/you/Documents,/Users/you/Projects
# Optional: Maximum file size in bytes (default: 5MB)
MAX_FILE_SIZE=5242880
# Server port (default: 3000)
PORT=3000
# Environment (development or production)
NODE_ENV=development# Start development server with hot reload
npm run dev
# Open in browser
# http://localhost:3000# Build TypeScript to JavaScript
npm run build
# Run production build
npm start-
Start the server
npm run dev
-
Open in browser
- Navigate to
http://localhost:3000
- Navigate to
-
Load a markdown file
- Enter the absolute file path (e.g.,
/Users/you/Documents/note.md) - Click "Load File"
- Enter the absolute file path (e.g.,
-
Edit and preview
- Left pane: Edit markdown
- Right pane: Live preview updates as you type
-
Save changes
- Click "Save File" when ready
- Changes are written to the original file
-
Draft recovery
- Browser automatically saves drafts to local storage
- Drafts restored when you return to the editor
markdown-editor/
├── src/
│ ├── server.ts # Express server with security middleware
│ └── utils/
│ └── security.ts # Path validation, sanitization, auth
├── public/
│ ├── index.html # HTML interface
│ ├── style.css # Responsive styling
│ └── app.js # Frontend application logic
├── dist/ # Compiled JavaScript (generated)
├── .husky/ # Git pre-commit hooks
├── .env.example # Configuration template
├── .editorconfig # Editor settings
├── .eslintrc.js # ESLint configuration with security plugin
├── .gitignore # Git ignore rules
├── .lintstagedrc.json # Lint-staged configuration
├── eslint.config.js # ESLint flat config
├── package.json # Dependencies and scripts
├── prettier.config.js # Prettier formatter config
├── tsconfig.json # TypeScript configuration
└── README.md # This file
# Run all quality checks
npm run validate
# Type checking only
npm run type-check
# Linting
npm run lint
# Fix linting issues
npm run lint:fix
# Format code
npm run format
# Check formatting
npm run format:check
# Security audit
npm run security:auditBefore committing changes, run the validation checks:
# Run all checks (type, lint, format, security)
npm run validate
# Auto-fix issues
npm run lint:fix && npm run formatThis runs:
- Type checking (tsc)
- Linting (eslint) - must pass with zero warnings
- Formatting check (prettier)
- Security audit (npm audit)
-
Create a branch
git checkout -b feature/your-feature
-
Make changes and test
npm run dev
-
Run quality checks
npm run validate
-
Commit (hooks run automatically)
git add . git commit -m "Add your feature description"
- Only run on trusted machines - This app is for local use only
- Keep Node.js updated - Regular security patches are important
- Review ALLOWED_DIRECTORIES - Only whitelist directories you need
- Don't expose to network - Never port-forward this application
- Regular audits - Run
npm auditregularly and update dependencies
- Follow code standards - ESLint/Prettier enforce consistency
- Never commit credentials - .env is in .gitignore
- Type everything - TypeScript strict mode is enabled
- Validate all input - Use security utilities for file paths
- Test security changes - Run full validation suite
- Keep dependencies updated - Run
npm auditbefore committing
Load a markdown file from disk.
Request:
"absolute/path/to/file.md"Response:
{
"content": "# Hello\nMarkdown content...",
"name": "file.md",
"path": "absolute/path/to/file.md"
}Errors:
400- Invalid file path format403- Access denied (outside allowed directories)500- Server error
Save markdown content to a file.
Request:
{
"filePath": "absolute/path/to/file.md",
"content": "# Hello\nMarkdown content..."
}Response:
{
"success": true,
"message": "File saved successfully",
"path": "absolute/path/to/file.md"
}Errors:
400- Invalid request format or content too large403- Access denied (outside allowed directories)500- Server error
Health check endpoint.
Response:
{
"status": "ok",
"timestamp": "2025-10-19T10:30:00.000Z"
}Application information.
Response:
{
"version": "1.0.0",
"environment": "development",
"sessionId": "uuid-string",
"requestCount": 42
}# Find process using port 3000
lsof -i :3000
# Kill the process
kill -9 <PID>
# Or use a different port
PORT=3001 npm run dev- Ensure the path is absolute (not relative)
- Verify the file exists:
ls -la /path/to/file - Check the directory is in ALLOWED_DIRECTORIES
- Check file permissions:
ls -la /path/to/file - Ensure user has read/write permissions
- On macOS, check System Preferences > Security & Privacy
- Clear browser cache (Cmd+Shift+R on macOS)
- Check browser console for errors (F12)
- Try refreshing the page
# Run full validation to see what's wrong
npm run validate
# Auto-fix linting issues
npm run lint:fix
# Format code
npm run format
# Try committing again
git add .
git commit -m "Your message"- Large files - Preview rendering is debounced (300ms) for performance
- File size limit - Set via MAX_FILE_SIZE environment variable
- Rate limiting - 100 requests per minute per IP
- Memory - In-memory rate limit store (cleaned periodically)
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- Mobile browsers (responsive design)
MIT - See LICENSE file for details
- Syntax highlighting with Prism.js
- Drag-and-drop file loading
- Multiple file tabs
- Auto-save with file watcher
- Search and replace
- Collaborative editing (with caution)
- Custom theme support
- Markdown export to HTML/PDF
- Keyboard shortcuts customization
This is a personal project designed to be simple, self-contained, and easy to customize.
- Clone or fork this repository
- Follow the Quick Start instructions
- Configure
.envfor your directories - Run
npm run devand start editing
We encourage you to fork this project and modify it for your specific needs:
- Add features you want
- Change the UI/styling
- Adjust security settings for your use case
- Deploy to your own server (local recommended)
This is a "low-maintenance" project - you're welcome to use and modify it, but we don't accept pull requests or offer ongoing support. Fork it, customize it, make it yours!
If you discover a security vulnerability, please email directly rather than using issue tracker.
For issues and questions:
- Check the troubleshooting section above
- Review GitHub Issues
- Check existing discussions
Built with security and developer experience in mind 🔒