Mayavi
A lightweight proof-of-work challenge system to protect against AI crawlers and bots. Built with TypeScript, React, and inspired by the original Anubis project.
✅ FIXED: All import and module issues have been resolved! The package now works correctly as an external dependency. See Working Examples for verified usage instructions.
🚀 Features
- Proof-of-Work Challenges: SHA-256 based computational puzzles
- Configurable Difficulty: Adjustable challenge complexity
- Real-time Progress: Live updates during challenge solving
- Server Verification: Backend validation of solutions
- Modern UI: Beautiful, responsive interface with dark mode
- TypeScript: Full type safety and excellent developer experience
- Lightweight: Minimal dependencies and efficient implementation
- Framework Agnostic: Works with Next.js, React, Express, Fastify, and more
- ✅ Production Ready: All issues fixed and thoroughly tested
🛡️ How It Works
- Challenge Generation: Server generates a unique challenge with timestamp and difficulty
- Client-side Solving: Browser computes SHA-256 hashes until finding one with required leading zeros
- Server Verification: Solution is verified on the server to ensure validity
- Access Control: Successful verification grants access to protected content
🏃♂️ Quick Start
NPM Package Installation
npm install mayavi
# or
yarn add mayavi
# or
pnpm add mayavi
✅ Verified Working: Package tested and confirmed working in external projects. See test results in Working Examples.
Development Setup (Clone Repository)
# Clone the repository
git clone https://github.com/intincrab/mayavi.git
cd mayavi
# Install dependencies
npm install
# Start development server
npm run dev
Open http://localhost:3000 to see the demo application.
📖 Usage
Basic Implementation
import { generateChallenge, solveChallenge, verifySolution } from 'mayavi';
// Generate a challenge
const challenge = generateChallenge(4); // difficulty = 4
// Solve the challenge (client-side)
const solution = await solveChallenge(challenge, (nonce, hash) => {
console.log(`Progress: ${nonce} attempts, current hash: ${hash}`);
});
// Verify the solution (server-side)
const isValid = verifySolution(challenge, solution);
React Component
import { ProofOfWorkChallenge } from 'mayavi';
function MyPage() {
const handleSuccess = (challenge, solution) => {
console.log('Challenge completed!', { challenge, solution });
};
return (
<ProofOfWorkChallenge
difficulty={4}
onSuccess={handleSuccess}
onError={(error) => console.error(error)}
/>
);
}
Next.js API Route
// app/api/verify/route.ts
import { createVerificationEndpoint } from 'mayavi';
export const { POST } = createVerificationEndpoint();
API Verification
// POST /api/verify
const response = await fetch('/api/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ challenge, solution }),
});
const result = await response.json();
⚙️ Configuration
Difficulty Levels
Difficulty | Leading Zeros | Avg. Time | Description |
---|---|---|---|
2 | 00 | ~25ms | Very Easy |
3 | 000 | ~50ms | Easy |
4 | 0000 | ~200ms | Medium |
5 | 00000 | ~800ms | Hard |
6 | 000000 | ~3.2s | Very Hard |
Environment Variables
# Optional: Configure challenge expiration time (default: 5 minutes)
CHALLENGE_EXPIRY_MS=300000
# Optional: Default difficulty level
DEFAULT_DIFFICULTY=4
🏗️ Project Structure
src/
├── app/
│ ├── api/verify/ # Server-side verification endpoint
│ ├── layout.tsx # Root layout with metadata
│ └── page.tsx # Main demo page
├── components/
│ └── proof-of-work-challenge.tsx # React challenge component
└── lib/
└── proof-of-work.ts # Core proof-of-work logic
🔧 API Reference
Core Functions
generateChallenge(difficulty: number): Challenge
Generates a new proof-of-work challenge.
solveChallenge(challenge: Challenge, onProgress?: Function): Promise<Solution>
Solves a challenge by finding a valid nonce.
verifySolution(challenge: Challenge, solution: Solution): boolean
Verifies that a solution is valid for the given challenge.
isValidHash(hash: string, difficulty: number): boolean
Checks if a hash meets the difficulty requirement.
Types
interface Challenge {
data: string;
difficulty: number;
timestamp: number;
}
interface Solution {
nonce: number;
hash: string;
timestamp: number;
}
🚀 Deployment
Build for Production
npm run build
npm start
🛡️ Security Considerations
- Challenge Expiration: Challenges expire after 5 minutes to prevent replay attacks
- Server Verification: Always verify solutions on the server side
- Rate Limiting: Consider implementing rate limiting for challenge generation
- HTTPS: Use HTTPS in production to prevent man-in-the-middle attacks
🎯 Use Cases
- Bot Protection: Block automated scrapers and crawlers
- Rate Limiting: Slow down high-frequency requests
- Spam Prevention: Reduce automated form submissions
- Resource Protection: Protect expensive API endpoints
- Content Gating: Require proof-of-work before accessing premium content
🤝 Contributing
- Fork the repository at https://github.com/intincrab/mayavi
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
For detailed usage examples and integration guides, see USAGE.md.
📦 NPM Package
This project is available as an npm package for easy integration into your projects:
npm install mayavi
Package Information:
- Package Name:
mayavi
- Version: 1.0.0
- Bundle Size: Lightweight with minimal dependencies
- TypeScript: Full TypeScript support included
- Frameworks: Compatible with React, Next.js, Express, Fastify, and more
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Links
- NPM Package: https://www.npmjs.com/package/mayavi
- GitHub Repository: https://github.com/intincrab/mayavi
- Issues: https://github.com/intincrab/mayavi/issues
- Documentation: USAGE.md
🙏 Acknowledgments
- Original Anubis project by TecharoHQ
- js-sha256 for SHA-256 implementation
- Next.js for the React framework
- Tailwind CSS for styling