first commit

This commit is contained in:
Raven Scott
2025-11-24 05:45:28 -05:00
commit d877724a81
49 changed files with 10767 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
{
"extends": "next/core-web-vitals"
}
+36
View File
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
.env
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
+40
View File
@@ -0,0 +1,40 @@
FROM node:20-alpine AS base
# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
+84
View File
@@ -0,0 +1,84 @@
# P2NS Website
Modern, professional public-facing website for P2NS (Peer-to-Peer Decentralized DNS System).
## Features
- **Modern Design**: Built with Next.js 14+, TypeScript, and Tailwind CSS
- **Responsive**: Mobile-first design that works on all devices
- **Dark Mode**: Automatic dark mode support
- **Interactive Diagrams**: Animated visualizations of P2P concepts
- **Comprehensive Documentation**: Complete guides and API references
- **SEO Optimized**: Proper metadata, structured data, and semantic HTML
- **Accessible**: WCAG AA compliant with proper ARIA labels
## Getting Started
### Prerequisites
- Node.js 18 or higher
- npm or yarn
### Installation
```bash
# Install dependencies
npm install
# Run development server
npm run dev
# Build for production
npm run build
# Start production server
npm start
```
The website will be available at [http://localhost:3000](http://localhost:3000).
## Project Structure
```
p2ns-website/
├── app/ # Next.js App Router pages
│ ├── about/ # About P2NS page
│ ├── learn/ # P2P education pages
│ ├── features/ # Features page
│ ├── docs/ # Documentation pages
│ └── community/ # Community page
├── components/ # React components
│ ├── layout/ # Layout components (Navigation, Footer)
│ ├── sections/ # Page sections (Hero, Features, etc.)
│ ├── diagrams/ # Interactive diagrams
│ └── ui/ # Reusable UI components
├── public/ # Static assets
└── styles/ # Global styles
```
## Deployment
### Self-Hosted
The website is designed to be self-hostable. You can deploy it using:
- **Docker**: See `Dockerfile` and `docker-compose.yml`
- **Node.js**: Run `npm run build && npm start`
- **Static Export**: Configure Next.js for static export if needed
### Environment Variables
No environment variables are required for basic operation. All configuration is handled through Next.js.
## Technologies Used
- **Next.js 14+**: React framework with App Router
- **TypeScript**: Type-safe development
- **Tailwind CSS**: Utility-first CSS framework
- **Framer Motion**: Animation library
- **Lucide React**: Icon library
- **Shiki**: Syntax highlighting
## Contributing
Contributions are welcome! Please follow the same contribution guidelines as the main P2NS repository.
+232
View File
@@ -0,0 +1,232 @@
import type { Metadata } from "next";
import ArchitectureDiagram from "@/components/diagrams/ArchitectureDiagram";
export const metadata: Metadata = {
title: "About P2NS - Peer-to-Peer Decentralized DNS System",
description:
"Learn about P2NS, a robust, firewall-resistant peer-to-peer DNS resolution system.",
};
export default function AboutPage() {
return (
<div className="min-h-screen">
{/* Hero Section */}
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div>
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
What is P2NS?
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300 leading-relaxed">
P2NS (Peer-to-Peer Name System) is a robust, firewall-resistant
peer-to-peer DNS resolution system designed to operate
independently of centralized DNS infrastructure. Utilizing UDP
hole-punching via the Holesail library, P2NS enables seamless
connectivity across challenging network environments.
</p>
</div>
</div>
</section>
{/* Problem Statement */}
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6">
The Problem with Centralized DNS
</h2>
<div className="prose prose-lg dark:prose-invert max-w-none">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Traditional DNS systems rely on centralized infrastructure
controlled by ICANN and major DNS providers. This creates several
critical issues:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>
<strong>Single Points of Failure:</strong> Centralized servers
can be targeted by DDoS attacks or taken offline, disrupting
service for millions of users.
</li>
<li>
<strong>Censorship:</strong> Governments and ISPs can block or
redirect DNS queries, limiting access to information.
</li>
<li>
<strong>Privacy Concerns:</strong> DNS queries reveal browsing
habits and can be logged, sold, or surveilled.
</li>
<li>
<strong>Network Restrictions:</strong> Firewalls, NAT, and CGNAT
make it difficult to establish direct peer-to-peer connections.
</li>
<li>
<strong>Dependency:</strong> Users are dependent on third-party
services that may change policies or go offline.
</li>
</ul>
</div>
</div>
</section>
{/* Solution */}
<section className="py-20 bg-gray-50 dark:bg-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6">
How P2NS Solves These Problems
</h2>
<div className="prose prose-lg dark:prose-invert max-w-none">
<p className="text-gray-600 dark:text-gray-300 mb-6">
P2NS addresses these fundamental issues through a decentralized,
peer-to-peer architecture:
</p>
<div className="grid md:grid-cols-2 gap-6">
<div className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">
Decentralized Resolution
</h3>
<p className="text-gray-600 dark:text-gray-300">
Domains claims are automatically synced with all peers via corestore, and all P2P queries are local to your device. No central authority controls the system.
</p>
</div>
<div className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">
Firewall Traversal
</h3>
<p className="text-gray-600 dark:text-gray-300">
UDP hole-punching technology enables connections across
firewalls, NAT, CGNAT, and restricted networks like 4G/5G or
satellite internet.
</p>
</div>
<div className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">
Privacy & Security
</h3>
<p className="text-gray-600 dark:text-gray-300">
The stack uses ibsodium for end-to-end encryption and also employs noise encryption for further security. Web connections are safeguarded via TLS and custom CA.
</p>
</div>
<div className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">
Resilience
</h3>
<p className="text-gray-600 dark:text-gray-300">
The network continues to function even if individual peers go
offline. Consensus mechanisms ensure data integrity and
prevent tampering.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Architecture */}
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 text-center">
System Architecture
</h2>
<p className="text-center text-gray-600 dark:text-gray-300 mb-12 max-w-2xl mx-auto">
P2NS is built on a modular architecture using proven P2P
technologies
</p>
<ArchitectureDiagram />
</div>
</section>
{/* Comparison Table */}
<section className="py-20 bg-gray-50 dark:bg-gray-800">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 text-center">
P2NS vs Traditional DNS
</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse bg-white dark:bg-gray-900 rounded-lg overflow-hidden">
<thead>
<tr className="bg-gray-100 dark:bg-gray-800">
<th className="px-6 py-4 text-left text-sm font-semibold text-gray-900 dark:text-white">
Feature
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-gray-900 dark:text-white">
Traditional DNS
</th>
<th className="px-6 py-4 text-left text-sm font-semibold text-gray-900 dark:text-white">
P2NS
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">
Infrastructure
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Centralized servers
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Decentralized P2P network
</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">
Firewall Traversal
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Limited
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
UDP hole-punching
</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">
Censorship Resistance
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Vulnerable
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Highly resistant
</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">
Privacy
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Queries can be logged
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Distributed queries
</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">
Resilience
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Single points of failure
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
No single point of failure
</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">
Control
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Third-party controlled
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
User-controlled
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</div>
);
}
+128
View File
@@ -0,0 +1,128 @@
import type { Metadata } from 'next';
import { Github, ExternalLink, Code, Heart, MessageCircle } from 'lucide-react';
export const metadata: Metadata = {
title: 'Community - P2NS',
description: 'Contribute to P2NS, get support, and learn about the roadmap.',
};
export default function CommunityPage() {
return (
<div className="min-h-screen">
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
Community
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300">
Join the P2NS community and help build the future of decentralized DNS
</p>
</div>
</section>
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="space-y-12">
<div>
<div className="flex items-center space-x-3 mb-4">
<Github className="h-8 w-8 text-gray-900 dark:text-white" />
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">Repository</h2>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">
P2NS is open source and available on Git. Check out the code, report issues, and contribute.
</p>
<a
href="https://git.ssh.surf/snxraven/p2ns"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center space-x-2 px-6 py-3 bg-gray-900 dark:bg-gray-100 text-white dark:text-gray-900 rounded-lg hover:bg-gray-800 dark:hover:bg-gray-200 transition-colors"
>
<Github className="h-5 w-5" />
<span>View Repository</span>
<ExternalLink className="h-4 w-4" />
</a>
</div>
<div>
<div className="flex items-center space-x-3 mb-4">
<MessageCircle className="h-8 w-8 text-gray-900 dark:text-white" />
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">Holesail Discord</h2>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Join the Holesail Discord server to connect with the community, get help, share ideas, and stay updated on the latest developments.
</p>
<a
href="https://discord.gg/3gFegYtNbN"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center space-x-2 px-6 py-3 bg-indigo-600 dark:bg-indigo-500 text-white rounded-lg hover:bg-indigo-700 dark:hover:bg-indigo-600 transition-colors"
>
<MessageCircle className="h-5 w-5" />
<span>Join Discord Server</span>
<ExternalLink className="h-4 w-4" />
</a>
</div>
<div>
<div className="flex items-center space-x-3 mb-4">
<Code className="h-8 w-8 text-gray-900 dark:text-white" />
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">Contributing</h2>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Contributions are welcome! Here's how you can help:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li>Report bugs and issues</li>
<li>Suggest new features</li>
<li>Submit pull requests</li>
<li>Improve documentation</li>
<li>Test on different platforms</li>
</ul>
<div className="bg-gray-50 dark:bg-gray-800 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">Contribution Guidelines</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>Fork the repository</li>
<li>Create a branch for your changes</li>
<li>Make your changes and test thoroughly</li>
<li>Submit a pull request with a clear description</li>
<li>Focus on stability and cross-platform compatibility</li>
</ol>
</div>
</div>
<div>
<div className="flex items-center space-x-3 mb-4">
<Heart className="h-8 w-8 text-gray-900 dark:text-white" />
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">Support</h2>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Need help? Here are some resources:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>Check the <a href="/docs/troubleshooting" className="text-blue-600 dark:text-blue-400 hover:underline">Troubleshooting</a> guide</li>
<li>Review the <a href="/docs" className="text-blue-600 dark:text-blue-400 hover:underline">Documentation</a></li>
<li>Open an issue on the repository</li>
</ul>
</div>
<div>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">Roadmap</h2>
<p className="text-gray-600 dark:text-gray-300 mb-6">
Future enhancements planned for P2NS:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li><strong>Encrypted Corestore storage:</strong> Enhanced security for stored data</li>
<li><strong>Enhanced consensus:</strong> Blockchain-style consensus mechanisms</li>
<li><strong>Mobile app integration:</strong> Native mobile applications</li>
<li><strong>Decentralized invite system:</strong> Remove master dependency</li>
<li><strong>Performance optimizations:</strong> Faster resolution and lower latency</li>
<li><strong>Additional platforms:</strong> Expanded platform support</li>
</ul>
</div>
</div>
</div>
</section>
</div>
);
}
+347
View File
@@ -0,0 +1,347 @@
import type { Metadata } from 'next';
import CodeBlock from '@/components/ui/CodeBlock';
export const metadata: Metadata = {
title: 'Admin Panel - P2NS Documentation',
description: 'Complete guide to the P2NS web-based admin interface, features, and usage instructions',
};
export default function AdminPanelPage() {
return (
<div className="min-h-screen">
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
Admin Panel
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300">
Complete guide to the web-based admin interface
</p>
</div>
</section>
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6">Introduction</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The P2NS Admin Panel is a comprehensive web-based management interface that provides real-time control
over all aspects of your P2NS node. It offers an intuitive interface for managing domains, Holesail servers
and clients, DNS records, certificates, and system settings.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-6">
The admin panel is accessible at <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">https://p2ns.admin</code> and uses WebSocket connections
for real-time updates, ensuring you always have the latest information about your system.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Getting Started</h2>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">Accessing the Admin Panel</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Once your P2NS node is running, access the admin panel by navigating to:
</p>
<CodeBlock code="https://p2ns.admin" />
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Certificate Trust</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The admin panel uses HTTPS with automatically generated certificates. On first access, you'll need to trust
the root CA certificate. The system will attempt to install it automatically, but you may need to:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li>Accept the security warning in your browser</li>
<li>Manually install the root CA certificate if automatic installation fails</li>
<li>Trust the certificate in your system's certificate store</li>
</ul>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Features Overview</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The admin panel is organized into several tabs, each providing specific functionality:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li><strong className="text-gray-900 dark:text-white">Domains</strong> - Manage P2P domain registrations</li>
<li><strong className="text-gray-900 dark:text-white">Host</strong> - Manage Holesail servers and clients</li>
<li><strong className="text-gray-900 dark:text-white">Local DNS</strong> - Custom DNS records and conflict resolution</li>
<li><strong className="text-gray-900 dark:text-white">Entries</strong> - View Autopass ledger entries</li>
<li><strong className="text-gray-900 dark:text-white">Peers</strong> - Monitor connected peers</li>
<li><strong className="text-gray-900 dark:text-white">Certificates</strong> - Manage TLS certificates</li>
<li><strong className="text-gray-900 dark:text-white">Interfaces</strong> - View virtual network interfaces</li>
<li><strong className="text-gray-900 dark:text-white">Logs</strong> - Real-time system logs</li>
<li><strong className="text-gray-900 dark:text-white">Stats</strong> - System statistics and metrics</li>
<li><strong className="text-gray-900 dark:text-white">Settings</strong> - Configure environment variables</li>
</ul>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Detailed Feature Descriptions</h2>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">Domains</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Domains tab provides comprehensive management of P2P domain registrations:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">View all domains:</strong> See all registered domains in the network with their associated hashes</li>
<li><strong className="text-gray-900 dark:text-white">Search functionality:</strong> Quickly find domains using the search bar</li>
<li><strong className="text-gray-900 dark:text-white">Local indicator:</strong> Domains claimed locally are marked with a 🏠 icon</li>
<li><strong className="text-gray-900 dark:text-white">Add domains:</strong> Register new domains by providing a domain name and Holesail hash</li>
<li><strong className="text-gray-900 dark:text-white">Remove domains:</strong> Delete locally claimed domains (only local domains can be removed)</li>
<li><strong className="text-gray-900 dark:text-white">Pagination:</strong> Navigate through large domain lists efficiently</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
All changes are synchronized in real-time via WebSocket, so you'll see updates immediately as they occur.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Host</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Host tab manages Holesail servers and clients for network tunneling:
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Holesail Servers</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Create servers:</strong> Set up new Holesail servers with custom ports, hosts, and keys</li>
<li><strong className="text-gray-900 dark:text-white">Configure options:</strong> Set name, port, host (default 0.0.0.0), key, secure/UDP flags, and log level</li>
<li><strong className="text-gray-900 dark:text-white">Domain assignment:</strong> Optionally assign servers to specific domains</li>
<li><strong className="text-gray-900 dark:text-white">Restart servers:</strong> Restart running servers without deleting them</li>
<li><strong className="text-gray-900 dark:text-white">View logs:</strong> Access real-time logs for each server in a terminal interface</li>
<li><strong className="text-gray-900 dark:text-white">Delete servers:</strong> Remove servers and clean up resources</li>
<li><strong className="text-gray-900 dark:text-white">Status monitoring:</strong> See server status (running/stopped) at a glance</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Server configurations are persisted in <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">holesail_servers.json</code> and survive restarts.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Holesail Clients</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li><strong className="text-gray-900 dark:text-white">Create clients:</strong> Set up Holesail clients to connect to remote servers</li>
<li><strong className="text-gray-900 dark:text-white">Domain selection:</strong> Choose which domain the client should connect for</li>
<li><strong className="text-gray-900 dark:text-white">Key and port:</strong> Configure connection key and local port</li>
<li><strong className="text-gray-900 dark:text-white">Restart clients:</strong> Restart clients without deleting configuration</li>
<li><strong className="text-gray-900 dark:text-white">View logs:</strong> Monitor client connection logs in real-time</li>
<li><strong className="text-gray-900 dark:text-white">Delete clients:</strong> Remove client configurations</li>
<li><strong className="text-gray-900 dark:text-white">Status tracking:</strong> Monitor client connection status</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
Client configurations are persisted in <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">holesail_clients.json</code>.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Local DNS</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Local DNS tab allows you to manage custom DNS records and resolve conflicts between P2P and public DNS:
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Custom DNS Records</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Create and manage custom DNS records for any domain. Supported record types include:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">A</strong> - IPv4 address records</li>
<li><strong className="text-gray-900 dark:text-white">AAAA</strong> - IPv6 address records</li>
<li><strong className="text-gray-900 dark:text-white">CNAME</strong> - Canonical name records</li>
<li><strong className="text-gray-900 dark:text-white">MX</strong> - Mail exchange records</li>
<li><strong className="text-gray-900 dark:text-white">TXT</strong> - Text records</li>
<li><strong className="text-gray-900 dark:text-white">SRV</strong> - Service records</li>
<li><strong className="text-gray-900 dark:text-white">SOA</strong> - Start of authority records</li>
<li><strong className="text-gray-900 dark:text-white">CAA</strong> - Certificate authority authorization</li>
<li><strong className="text-gray-900 dark:text-white">NS</strong> - Name server records</li>
<li><strong className="text-gray-900 dark:text-white">PTR</strong> - Pointer records</li>
<li><strong className="text-gray-900 dark:text-white">OTHER</strong> - Other record types</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Each record can be edited or deleted, and all changes are persisted to <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">local_dns.json</code>.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">DNS Conflict Selector</h4>
<p className="text-gray-600 dark:text-gray-300 mb-6">
When a domain exists in both the P2P network and public DNS, the DNS Conflict Selector allows you to choose
which version to use. You can set preferences for each conflicting domain, and your choices are saved in
<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">selector_cache.json</code> for persistence across restarts.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Entries</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Entries tab displays all Autopass ledger entries, which represent domain claims and votes in the P2P network:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li><strong className="text-gray-900 dark:text-white">View all entries:</strong> Browse all claims and votes in the distributed ledger</li>
<li><strong className="text-gray-900 dark:text-white">Search functionality:</strong> Search entries by key or value</li>
<li><strong className="text-gray-900 dark:text-white">Pagination:</strong> Navigate through large entry lists</li>
<li><strong className="text-gray-900 dark:text-white">Real-time updates:</strong> See new entries as they're added to the network</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
This view helps you understand the consensus state of the network and see how domain claims are being voted on.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Peers</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Peers tab shows all currently connected peers in the P2P network:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li><strong className="text-gray-900 dark:text-white">Peer list:</strong> View all connected peers with their public keys</li>
<li><strong className="text-gray-900 dark:text-white">Peer count:</strong> See the total number of connected peers</li>
<li><strong className="text-gray-900 dark:text-white">Search:</strong> Find specific peers by public key</li>
<li><strong className="text-gray-900 dark:text-white">Pagination:</strong> Navigate through peer lists</li>
<li><strong className="text-gray-900 dark:text-white">Real-time updates:</strong> See peers connect and disconnect in real-time</li>
</ul>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Certificates</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Certificates tab manages TLS certificates for secure HTTPS connections:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Generate certificates:</strong> Create new certificates for any domain</li>
<li><strong className="text-gray-900 dark:text-white">View certificate details:</strong> Inspect certificate information including SANs and expiration</li>
<li><strong className="text-gray-900 dark:text-white">Regenerate certificates:</strong> Create new certificates for existing domains</li>
<li><strong className="text-gray-900 dark:text-white">Delete certificates:</strong> Remove certificates for domains</li>
<li><strong className="text-gray-900 dark:text-white">Search functionality:</strong> Find certificates by domain name</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">CA Management</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li><strong className="text-gray-900 dark:text-white">Regenerate Root CA:</strong> Create a new root certificate authority</li>
<li><strong className="text-gray-900 dark:text-white">Install Root CA:</strong> Install the root CA certificate in your system's trust store</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
The root CA is used to sign all domain certificates, ensuring secure connections to P2P domains.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Interfaces</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Interfaces tab displays virtual network interface mappings:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Domain-to-IP mappings:</strong> See which domains are assigned to which local IP addresses</li>
<li><strong className="text-gray-900 dark:text-white">Search functionality:</strong> Find interfaces by domain or IP</li>
<li><strong className="text-gray-900 dark:text-white">Cleanup:</strong> Remove unused virtual interfaces to free up IP addresses</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
Virtual interfaces are automatically created when domains are added and are used for local routing.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Logs</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Logs tab provides a real-time terminal view of system logs:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li><strong className="text-gray-900 dark:text-white">Real-time streaming:</strong> See logs as they're generated</li>
<li><strong className="text-gray-900 dark:text-white">Log levels:</strong> View DEBUG, INFO, WARN, and ERROR messages</li>
<li><strong className="text-gray-900 dark:text-white">Terminal interface:</strong> Full-featured terminal with scrollback and search</li>
<li><strong className="text-gray-900 dark:text-white">Auto-scroll:</strong> Automatically scroll to show latest logs</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
This is invaluable for debugging issues and monitoring system behavior in real-time.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Stats</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Stats tab provides comprehensive statistics and metrics about your P2NS node:
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">System Overview</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">System uptime:</strong> How long the node has been running</li>
<li><strong className="text-gray-900 dark:text-white">Node type:</strong> Master or joiner node status</li>
<li><strong className="text-gray-900 dark:text-white">Connected peers:</strong> Current number of connected peers</li>
<li><strong className="text-gray-900 dark:text-white">Total domains:</strong> Number of registered domains</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">DNS Statistics</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>Total DNS queries and success rate</li>
<li>Average response time</li>
<li>P2P resolution rate</li>
<li>Query type distribution</li>
<li>Top queried domains</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Network & Peers</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>Peer connection events over time</li>
<li>Total connections and average duration</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Holesail Statistics</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>Active connections</li>
<li>Servers and clients started</li>
<li>Average connection duration</li>
<li>Protocol usage (TCP/UDP)</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">API & Requests</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>Total API requests and success rate</li>
<li>Average response time</li>
<li>Failed requests</li>
<li>Endpoint usage patterns</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Resource Usage</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li>Active sockets, servers, and connections</li>
<li>Memory usage (heap, RSS, external)</li>
<li>CPU usage and load average</li>
<li>Event loop performance</li>
</ul>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Domain Management</h4>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-6">
<li>Domains added and removed</li>
<li>Net change over time</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
All statistics include interactive charts and can be exported for analysis. You can adjust the refresh interval
and time range to focus on specific periods.
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Settings</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Settings tab allows you to view and edit environment variables:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">View all settings:</strong> See all current environment variable values</li>
<li><strong className="text-gray-900 dark:text-white">Edit values:</strong> Modify settings like <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">LOG_LEVEL</code>, <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">SUBNET_BASE</code>, etc.</li>
<li><strong className="text-gray-900 dark:text-white">Search functionality:</strong> Quickly find specific settings</li>
<li><strong className="text-gray-900 dark:text-white">Save changes:</strong> Persist modifications to <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">.env</code> file</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
Changes take effect after saving, though some settings may require a restart to apply fully.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Real-time Updates</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The admin panel uses WebSocket connections to provide real-time updates across all tabs:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Automatic refresh:</strong> Data updates automatically when changes occur</li>
<li><strong className="text-gray-900 dark:text-white">Live logs:</strong> System logs stream in real-time</li>
<li><strong className="text-gray-900 dark:text-white">Peer updates:</strong> See peers connect and disconnect immediately</li>
<li><strong className="text-gray-900 dark:text-white">Domain changes:</strong> New domain registrations appear instantly</li>
<li><strong className="text-gray-900 dark:text-white">Status indicators:</strong> Connection status shown in the top-right corner</li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mb-6">
The WebSocket connection automatically reconnects if interrupted, ensuring you always have the latest information.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Tips and Best Practices</h2>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300 mb-4">
<li><strong className="text-gray-900 dark:text-white">Monitor logs regularly:</strong> Check the Logs tab to catch issues early</li>
<li><strong className="text-gray-900 dark:text-white">Use Stats for optimization:</strong> Review statistics to identify performance bottlenecks</li>
<li><strong className="text-gray-900 dark:text-white">Clean up interfaces:</strong> Periodically clean unused virtual interfaces to free resources</li>
<li><strong className="text-gray-900 dark:text-white">Manage certificates:</strong> Regenerate certificates if you encounter SSL errors</li>
<li><strong className="text-gray-900 dark:text-white">Backup configurations:</strong> The JSON files (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">domains.json</code>, <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">local_dns.json</code>, etc.) can be backed up for disaster recovery</li>
<li><strong className="text-gray-900 dark:text-white">Use search effectively:</strong> Most tabs have search functionality to quickly find specific items</li>
<li><strong className="text-gray-900 dark:text-white">Check peer connections:</strong> Monitor the Peers tab to ensure network connectivity</li>
<li><strong className="text-gray-900 dark:text-white">Review DNS conflicts:</strong> Use the DNS Conflict Selector to manage domains that exist in both P2P and public DNS</li>
</ul>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">API Integration</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
While the admin panel provides a user-friendly interface, all functionality is also available via the REST API
for programmatic access. See the <a href="/docs/api" className="text-blue-600 dark:text-blue-400 hover:underline">API Reference</a> documentation
for complete endpoint documentation.
</p>
<p className="text-gray-600 dark:text-gray-300 mb-6">
The admin panel itself uses these API endpoints, so you can build custom tools or integrate P2NS management
into your own applications.
</p>
</div>
</section>
</div>
);
}
+91
View File
@@ -0,0 +1,91 @@
import type { Metadata } from 'next';
import CodeBlock from '@/components/ui/CodeBlock';
export const metadata: Metadata = {
title: 'API Reference - P2NS Documentation',
description: 'Complete REST API and WebSocket documentation for P2NS.',
};
export default function APIPage() {
return (
<div className="min-h-screen">
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
API Reference
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300">
Complete REST API and WebSocket documentation
</p>
</div>
</section>
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<p className="text-gray-600 dark:text-gray-300 mb-8">
The P2NS Admin API provides comprehensive endpoints for managing the decentralized DNS system.
All endpoints are accessible at <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">https://p2ns.admin</code>.
</p>
<div className="bg-blue-50 dark:bg-blue-900 border-l-4 border-blue-500 p-4 rounded mb-8">
<p className="text-blue-800 dark:text-blue-200">
<strong>Note:</strong> For complete API documentation including all endpoints, request/response formats,
and WebSocket events, please refer to the{' '}
<a
href="https://git.ssh.surf/snxraven/p2ns/src/branch/main/docs/RESTAPI.md"
target="_blank"
rel="noopener noreferrer"
className="underline"
>
REST API documentation
</a>{' '}
in the main repository.
</p>
</div>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6">Base URL</h2>
<CodeBlock code="https://p2ns.admin" />
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">WebSocket Endpoint</h2>
<CodeBlock code="wss://p2ns.admin/ws" />
<p className="text-gray-600 dark:text-gray-300 mt-4">
The WebSocket connection provides real-time updates including logs, database changes, peer updates,
and system events.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Key Endpoints</h2>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">GET /api/resolved-domains</code> - List all resolved domains</li>
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">POST /api/add-domain</code> - Add a new domain</li>
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">POST /api/remove-domain</code> - Remove a domain</li>
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">GET /api/peers</code> - List connected peers</li>
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">GET /api/status</code> - Get system status</li>
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">GET /api/local-dns</code> - Get local DNS records</li>
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">GET /api/holesail-servers</code> - List Holesail servers</li>
<li><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">GET /api/holesail-clients</code> - List Holesail clients</li>
</ul>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Authentication</h2>
<p className="text-gray-600 dark:text-gray-300">
The API does not require authentication since it's designed for local use. In production environments,
you should restrict access to trusted networks or implement authentication.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Response Format</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Most endpoints return JSON responses. Success responses typically return <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">200</code>
with the requested data or <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">"OK"</code> for successful operations.
Errors return appropriate HTTP status codes with error messages.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">More Information</h2>
<p className="text-gray-600 dark:text-gray-300">
For detailed API documentation including all endpoints, parameters, response formats, and WebSocket message types,
see the <a href="https://git.ssh.surf/snxraven/p2ns/src/branch/main/docs/RESTAPI.md" target="_blank" rel="noopener noreferrer" className="text-blue-600 dark:text-blue-400 hover:underline">full API documentation</a>.
</p>
</div>
</section>
</div>
);
}
+134
View File
@@ -0,0 +1,134 @@
import type { Metadata } from 'next';
import ArchitectureDiagram from '@/components/diagrams/ArchitectureDiagram';
export const metadata: Metadata = {
title: 'Architecture - P2NS Documentation',
description: 'Deep dive into P2NS system architecture and components.',
};
export default function ArchitecturePage() {
return (
<div className="min-h-screen">
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
System Architecture
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300">
Deep dive into P2NS components and design
</p>
</div>
</section>
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<ArchitectureDiagram />
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Core Components</h2>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">Corestore & Autopass</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Corestore provides decentralized, append-only storage for domain claims and votes. Autopass manages
secure writer additions through an invitation system, ensuring only authorized peers can write to the ledger.
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>Stores claims as <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">claim:domain:claimant</code></li>
<li>Stores votes as <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">vote:domain:claimant:voter</code></li>
<li>Master nodes initialize the core and issue invites</li>
<li>Joiners request invites to become writers</li>
</ul>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Hyperswarm</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Hyperswarm handles peer discovery using a fixed topic derived from <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">sha256('p2ns-dns')</code>.
All peers interested in P2NS join this topic and can discover each other through the DHT.
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>Automatic peer discovery</li>
<li>Handles peer churn (peers joining/leaving)</li>
<li>No central directory server required</li>
<li>Resilient to network partitions</li>
</ul>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">DNS Handler</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The DNS handler runs a UDP server on port 53 (configurable) that resolves domains through multiple mechanisms:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li><strong>P2P Resolution:</strong> Queries the Corestore for domain claims</li>
<li><strong>Local DNS:</strong> Checks local_dns.json for custom records</li>
<li><strong>Public DNS Fallback:</strong> Forwards to public DNS servers for non-P2P domains</li>
<li><strong>Conflict Resolution:</strong> Uses selector_cache.json preferences when domains exist in both P2P and public DNS</li>
</ul>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Proxy Server</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The proxy server handles HTTP/HTTPS traffic routing:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li><strong>HTTPS (port 443):</strong> Routes to local IPs via Holesail or public IPs based on DNS preferences</li>
<li><strong>HTTP (port 80):</strong> Redirects to HTTPS per domain</li>
<li><strong>TLS Termination:</strong> Per-domain TLS servers with SNI support</li>
<li><strong>WebSocket Support:</strong> Handles WebSocket upgrades for real-time applications</li>
</ul>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Holesail Integration</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Holesail provides UDP hole-punching for P2P tunneling:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li><strong>Servers:</strong> Persistent servers that can be assigned to domains</li>
<li><strong>Clients:</strong> Created lazily when domains are accessed, timeout after inactivity</li>
<li><strong>Configuration:</strong> Stored in holesail_servers.json and holesail_clients.json</li>
<li><strong>Management:</strong> Full control through admin interface with log viewing</li>
</ul>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Data Flow</h2>
<ol className="list-decimal pl-6 space-y-3 text-gray-600 dark:text-gray-300">
<li>User queries a domain via DNS (e.g., <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">dig @127.0.0.1 example.tld</code>)</li>
<li>DNS handler checks local_dns.json, then Corestore for P2P claims, then public DNS</li>
<li>If P2P domain, assigns local IP and creates Holesail client if needed</li>
<li>User accesses domain via HTTPS proxy</li>
<li>Proxy routes to local IP, which tunnels through Holesail to the peer</li>
<li>Response is returned through the tunnel and back to the user</li>
</ol>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Consensus Mechanism</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
P2NS uses a simple voting system for domain claims:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>When a domain is claimed, peers vote on the claim</li>
<li>Local claims are automatically voted for by the claiming peer</li>
<li>Consensus is reached when a claim has the most votes</li>
<li>Ties are broken lexically (alphabetically)</li>
<li>This prevents domain hijacking and ensures network integrity</li>
</ul>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Master vs Joiner Modes</h2>
<div className="grid md:grid-cols-2 gap-6">
<div className="bg-gray-50 dark:bg-gray-800 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Master Node</h3>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>Initializes the Corestore</li>
<li>Loads domains from domains.json</li>
<li>Issues invites to joiners</li>
<li>Can add domains directly</li>
</ul>
</div>
<div className="bg-gray-50 dark:bg-gray-800 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Joiner Node</h3>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>Connects to existing network</li>
<li>Requests invites from master</li>
<li>Syncs domain data from peers</li>
<li>Can vote on domain claims</li>
</ul>
</div>
</div>
</div>
</section>
</div>
);
}
+174
View File
@@ -0,0 +1,174 @@
import type { Metadata } from 'next';
import CodeBlock from '@/components/ui/CodeBlock';
export const metadata: Metadata = {
title: 'Configuration - P2NS Documentation',
description: 'Environment variables and configuration options for P2NS.',
};
export default function ConfigurationPage() {
return (
<div className="min-h-screen">
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
Configuration
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300">
Customize P2NS to fit your needs
</p>
</div>
</section>
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6">Environment Variables</h2>
<p className="text-gray-600 dark:text-gray-300 mb-6">
Configure P2NS via a <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">.env</code> file (copy from <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">default.env</code>):
</p>
<div className="space-y-8">
<div>
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">Storage & Files</h3>
<table className="w-full border-collapse bg-white dark:bg-gray-900">
<thead>
<tr className="bg-gray-100 dark:bg-gray-800">
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Variable</th>
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Default</th>
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">STORAGE_DIR</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">./my-storage</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Corestore data directory</td>
</tr>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">DOMAINS_FILE</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">domains.json</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Domains JSON file</td>
</tr>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">LOCAL_DNS_FILE</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">local_dns.json</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Local DNS records file</td>
</tr>
</tbody>
</table>
</div>
<div>
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">Network Configuration</h3>
<table className="w-full border-collapse bg-white dark:bg-gray-900">
<thead>
<tr className="bg-gray-100 dark:bg-gray-800">
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Variable</th>
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Default</th>
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">DNS_PORT</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">53</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">DNS server port</td>
</tr>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">HTTPS_PORT</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">443</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">HTTPS proxy port</td>
</tr>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">HTTP_PORT</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">80</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">HTTP redirect port</td>
</tr>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">PUBLIC_DNS_SERVER</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">1.1.1.1</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Public DNS fallback</td>
</tr>
</tbody>
</table>
</div>
<div>
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">Virtual Interfaces</h3>
<table className="w-full border-collapse bg-white dark:bg-gray-900">
<thead>
<tr className="bg-gray-100 dark:bg-gray-800">
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Variable</th>
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Default</th>
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">SUBNET_BASE</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">192.168.3</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Virtual interface IP base</td>
</tr>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">INITIAL_IP_INDEX</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">2</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Starting IP index</td>
</tr>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">SUBNET_NAME</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">lo0</code> (macOS), <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">lo</code> (Linux)</td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Interface for virtual IPs</td>
</tr>
</tbody>
</table>
</div>
<div>
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">Other Settings</h3>
<table className="w-full border-collapse bg-white dark:bg-gray-900">
<thead>
<tr className="bg-gray-100 dark:bg-gray-800">
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Variable</th>
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Default</th>
<th className="px-4 py-2 text-left border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-white font-semibold">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">LOG_LEVEL</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">0</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Logging level (0-3: DEBUG, INFO, WARN, ERROR)</td>
</tr>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">HOLESAIL_TIMEOUT</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">300000</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Holesail client timeout (ms)</td>
</tr>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">DISABLE_DNS_SERVER</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">false</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Disable DNS server</td>
</tr>
<tr>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">DISABLE_PROXY_SERVER</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-900 dark:text-gray-200"><code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">false</code></td>
<td className="px-4 py-2 border border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-300">Disable proxy servers</td>
</tr>
</tbody>
</table>
</div>
</div>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Example Configuration</h2>
<CodeBlock code={`LOG_LEVEL=1
STORAGE_DIR=./my-storage
INTERNAL_DOMAINS=peer.directory,peer.dir,p2ns.admin
SUBNET_BASE=192.168.3
SELECTOR_CACHE_FILE=selector_cache.json
PUBLIC_DNS_SERVER=1.1.1.1`} />
</div>
</section>
</div>
);
}
+115
View File
@@ -0,0 +1,115 @@
import type { Metadata } from 'next';
import CodeBlock from '@/components/ui/CodeBlock';
export const metadata: Metadata = {
title: 'Getting Started - P2NS Documentation',
description: 'Installation and quick start guide for P2NS.',
};
export default function GettingStartedPage() {
return (
<div className="min-h-screen">
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
Getting Started
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300">
Get P2NS up and running in minutes
</p>
</div>
</section>
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6">Prerequisites</h2>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li><strong>Node.js:</strong> Version 18 or higher (tested up to 20.x)</li>
<li><strong>Holesail CLI:</strong> For generating connection hashes (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">npm install -g holesail</code>)</li>
<li><strong>Platform:</strong> macOS or Linux (sudo required for ports &lt;1024 and interfaces). Windows support planned.</li>
<li><strong>Dependencies:</strong> All dependencies are installed via npm</li>
</ul>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Installation</h2>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">1. Clone the Repository</h3>
<CodeBlock code={`git clone https://git.ssh.surf/snxraven/p2ns.git
cd p2ns`} />
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">2. Install Dependencies</h3>
<CodeBlock code="npm install" />
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">3. Configure Environment (Optional)</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Copy the default environment file and customize as needed:
</p>
<CodeBlock code={`cp default.env .env
# Edit .env with your preferred settings`} />
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Running the System</h2>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">Master Node</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The master node initializes the network and loads domains from <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">domains.json</code>:
</p>
<CodeBlock code="sudo node p2ns.js --master" />
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Joiner Node</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Joiner nodes connect to the network via invites:
</p>
<CodeBlock code="sudo node p2ns.js" />
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">Clean Storage</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
To start fresh, remove the storage directory:
</p>
<CodeBlock code="sudo node p2ns.js --clean [--master]" />
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Adding Your First Domain</h2>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">1. Generate a Holesail Hash</h3>
<CodeBlock code="holesail --live 80 --public" />
<p className="text-gray-600 dark:text-gray-300 mb-4 mt-4">
This will output a connection hash like: <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">hs://s00084bf87dfa89a3048fb081c0e6207eb5a</code>
</p>
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4 mt-8">2. Add the Domain</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
You can add domains in several ways:
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Via Admin Interface</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Access <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">https://p2ns.admin</code> and use the Domains tab to add domains interactively.
</p>
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Via domains.json</h4>
<CodeBlock code={`[
{
"domain": "example.tld",
"hash": "hs://s00084bf87dfa89a3048fb081c0e6207eb5a"
}
]`} language="json" />
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Accessing the Interfaces</h2>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li><strong>Admin Interface:</strong> <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">https://p2ns.admin</code></li>
<li><strong>Peer Directory:</strong> <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">https://peer.directory</code></li>
</ul>
<p className="text-gray-600 dark:text-gray-300 mt-4">
<strong>Note:</strong> You'll need to trust the root CA certificate in your browser. The system will attempt to install it automatically.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Next Steps</h2>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>Read the <a href="/docs/configuration" className="text-blue-600 dark:text-blue-400 hover:underline">Configuration</a> guide</li>
<li>Check out the <a href="/docs/api" className="text-blue-600 dark:text-blue-400 hover:underline">API Reference</a></li>
<li>Learn about <a href="/learn/p2p" className="text-blue-600 dark:text-blue-400 hover:underline">How P2P Works</a></li>
</ul>
</div>
</section>
</div>
);
}
+94
View File
@@ -0,0 +1,94 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import { Book, Settings, Code, Wrench, Network, FileText, LayoutDashboard } from 'lucide-react';
export const metadata: Metadata = {
title: 'Documentation - P2NS',
description: 'Complete documentation for P2NS including installation, configuration, API reference, and troubleshooting.',
};
const docSections = [
{
title: 'Getting Started',
description: 'Installation guide, prerequisites, and quick start instructions',
icon: Book,
href: '/docs/getting-started',
},
{
title: 'Configuration',
description: 'Environment variables, setup files, and configuration options',
icon: Settings,
href: '/docs/configuration',
},
{
title: 'Admin Panel',
description: 'Complete guide to the web-based admin interface and its features',
icon: LayoutDashboard,
href: '/docs/admin-panel',
},
{
title: 'API Reference',
description: 'Complete REST API documentation and WebSocket events',
icon: FileText,
href: '/docs/api',
},
{
title: 'Troubleshooting',
description: 'Common issues, solutions, and debugging tips',
icon: Wrench,
href: '/docs/troubleshooting',
},
{
title: 'Architecture',
description: 'Deep dive into system components and technical details',
icon: Network,
href: '/docs/architecture',
},
];
export default function DocsPage() {
return (
<div className="min-h-screen">
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
Documentation
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300">
Complete guides and references for using and understanding P2NS
</p>
</div>
</section>
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{docSections.map((section) => {
const Icon = section.icon;
return (
<Link
key={section.href}
href={section.href}
className="group bg-white dark:bg-gray-800 p-6 rounded-lg border border-gray-200 dark:border-gray-700 hover:border-blue-500 dark:hover:border-blue-500 transition-all hover:shadow-lg"
>
<div className="flex items-center space-x-3 mb-4">
<div className="p-2 bg-blue-100 dark:bg-blue-900 rounded-lg group-hover:bg-blue-200 dark:group-hover:bg-blue-800 transition-colors">
<Icon className="h-6 w-6 text-blue-600 dark:text-blue-400" />
</div>
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
{section.title}
</h2>
</div>
<p className="text-gray-600 dark:text-gray-400">
{section.description}
</p>
</Link>
);
})}
</div>
</div>
</section>
</div>
);
}
+147
View File
@@ -0,0 +1,147 @@
import type { Metadata } from 'next';
import CodeBlock from '@/components/ui/CodeBlock';
export const metadata: Metadata = {
title: 'Troubleshooting - P2NS Documentation',
description: 'Common issues and solutions for P2NS.',
};
export default function TroubleshootingPage() {
return (
<div className="min-h-screen">
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
Troubleshooting
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300">
Common issues and their solutions
</p>
</div>
</section>
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6">Port Conflicts</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
If you encounter port conflicts, check which processes are using the ports:
</p>
<CodeBlock code={`# Check ports 53, 80, 443
netstat -an | grep LISTEN | grep -E ':(53|80|443)'
# Or on Linux
lsof -i :53
lsof -i :80
lsof -i :443`} />
<p className="text-gray-600 dark:text-gray-300 mt-4">
<strong>Solution:</strong> Stop conflicting services or set <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">DISABLE_DNS_SERVER=true</code> or <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">DISABLE_PROXY_SERVER=true</code> in your <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">.env</code> file.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Certificate Authority Issues</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
If the root CA isn't trusted, you may see certificate errors in your browser. Verify installation:
</p>
<CodeBlock code={`# macOS - Check Keychain
security find-certificate -c "P2NS Root CA"
# Linux - Check certificates directory
ls /usr/local/share/ca-certificates/p2ns*
# Windows - Check certificate store
certutil -store -user ROOT | findstr P2NS`} />
<p className="text-gray-600 dark:text-gray-300 mt-4">
<strong>Solution:</strong> Manually install the CA from <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">./certs/ca.cert.pem</code> or use the admin interface to regenerate and install.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Holesail Connection Failures</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
If Holesail connections fail, verify the hash is correct:
</p>
<CodeBlock code={`# Test hash generation
holesail --live 80 --public
# Check Holesail CLI is installed
which holesail
npm list -g holesail`} />
<p className="text-gray-600 dark:text-gray-300 mt-4">
<strong>Solution:</strong> Ensure Holesail CLI is installed globally (<code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">npm install -g holesail</code>) and the hash is valid.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">DNS Resolution Issues</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
If domains aren't resolving, check several things:
</p>
<CodeBlock code={`# Test DNS resolution
dig @127.0.0.1 example.tld
# Check if DNS server is running
curl -k https://p2ns.admin/api/status
# Verify peer connections
curl -k https://p2ns.admin/api/peers`} />
<p className="text-gray-600 dark:text-gray-300 mt-4">
<strong>Common causes:</strong>
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>No peers connected - check swarm logs</li>
<li>Domain not claimed - verify in domains.json or admin interface</li>
<li>DNS conflict - check selector_cache.json preferences</li>
<li>Local DNS override - check local_dns.json</li>
</ul>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Interface Issues</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Virtual interface creation requires sudo privileges:
</p>
<CodeBlock code={`# macOS - Check interfaces
ifconfig lo0
# Linux - Check interfaces
ip addr show lo
# Verify IP assignments
curl -k https://p2ns.admin/api/interfaces`} />
<p className="text-gray-600 dark:text-gray-300 mt-4">
<strong>Solution:</strong> Ensure you're running with sudo and the interface name is correct for your platform.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Admin Interface Not Loading</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
If the admin interface doesn't load:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>Verify <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">p2ns.admin</code> resolves to 127.0.0.1</li>
<li>Check WebSocket connection at <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">wss://p2ns.admin/ws</code></li>
<li>Verify certificate is trusted</li>
<li>Check browser console for errors</li>
</ul>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Sync Issues</h2>
<p className="text-gray-600 dark:text-gray-300 mb-4">
If domains aren't syncing across peers:
</p>
<CodeBlock code={`# Reset storage (WARNING: deletes all data)
sudo node p2ns.js --clean --master
# Check swarm logs for peer events
# Look for [Swarm] connection/disconnection messages`} />
<p className="text-gray-600 dark:text-gray-300 mt-4">
<strong>Solution:</strong> Monitor swarm logs, ensure peers are connected, and verify Autopass invites are working.
</p>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 mt-12">Getting Help</h2>
<p className="text-gray-600 dark:text-gray-300">
If you're still experiencing issues:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-600 dark:text-gray-300">
<li>Check the logs in the admin interface</li>
<li>Review the <a href="/docs/architecture" className="text-blue-600 dark:text-blue-400 hover:underline">Architecture</a> documentation</li>
<li>Check the <a href="https://git.ssh.surf/snxraven/p2ns" target="_blank" rel="noopener noreferrer" className="text-blue-600 dark:text-blue-400 hover:underline">repository</a> for known issues</li>
<li>Enable debug logging by setting <code className="bg-gray-800 dark:bg-gray-700 text-gray-100 dark:text-gray-200 px-1.5 py-0.5 rounded">LOG_LEVEL=0</code> in your .env</li>
</ul>
</div>
</section>
</div>
);
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

+225
View File
@@ -0,0 +1,225 @@
// app/features/page.tsx
import type { Metadata } from 'next';
import { MotionDiv } from '@/components/ui/MotionDiv';
import {
Network,
Shield,
Zap,
Globe,
Lock,
Settings,
Server,
Users,
Check,
Code,
Database,
type LucideIcon,
} from 'lucide-react';
export const metadata: Metadata = {
title: 'Features - P2NS Peer-to-Peer DNS System',
description:
'Comprehensive features of P2NS including decentralized DNS, firewall traversal, proxy servers, and more.',
};
type Feature = {
name: string;
icon: LucideIcon;
description: string;
benefits: string[];
example: string;
};
const features: Feature[] = [
{
name: 'Decentralized DNS Resolution',
icon: Network,
description: 'Resolve domains to hashes via a P2P core, independent of ICANN or central DNS servers.',
benefits: [
'No single point of failure',
'Censorship-resistant',
'User-controlled resolution',
'Consensus-based domain claims',
],
example:
'Domains are stored in a distributed ledger accessible by all peers, ensuring resilience and transparency.',
},
{
name: 'Firewall and NAT Traversal',
icon: Shield,
description: 'Uses Holesail for UDP hole-punching to connect across restrictive networks.',
benefits: [
'Works behind firewalls',
'Traverses NAT and CGNAT',
'Supports 4G/5G networks',
'Compatible with satellite internet',
],
example:
'Even devices behind multiple layers of NAT can establish direct P2P connections using advanced hole-punching techniques.',
},
{
name: 'Dynamic Local IP Assignment',
icon: Zap,
description: 'Assigns unique local IPs to domains via virtual network interfaces.',
benefits: ['Automatic IP management', 'Seamless routing', 'No manual configuration', 'Clean interface cleanup'],
example:
'Each domain gets a unique IP from the 192.168.3.x subnet, automatically assigned and managed by the system.',
},
{
name: 'Hybrid DNS Resolution',
icon: Globe,
description: 'Falls back to public DNS for non-P2P domains with custom local DNS record support.',
benefits: ['Best of both worlds', 'Custom DNS records', 'Public DNS fallback', 'Flexible configuration'],
example:
'P2P domains resolve through the network, while traditional domains use public DNS servers like 1.1.1.1.',
},
{
name: 'DNS Conflict Selector',
icon: Check,
description: 'Choose between P2P and public DNS records for domains with both, managed via admin interface.',
benefits: ['User choice', 'Persistent preferences', 'Easy management', 'Per-domain control'],
example:
'If myspace.com exists in both P2P and public DNS, you can choose which version to use and save your preference.',
},
{
name: 'Integrated Proxy Servers',
icon: Server,
description: 'HTTP/HTTPS proxies with automatic HTTP-to-HTTPS redirection and WebSocket support.',
benefits: ['Automatic HTTPS', 'WebSocket support', 'TLS termination', 'Per-domain routing'],
example:
'Access P2P domains through standard HTTP/HTTPS protocols, with automatic certificate management and secure connections.',
},
{
name: 'Holesail Server and Client Management',
icon: Settings,
description: 'Persistent Holesail servers and clients for tunneling, manageable via the admin interface.',
benefits: ['Persistent tunnels', 'Easy management', 'Log viewing', 'Restart capabilities'],
example:
'Create and manage Holesail servers that persist across restarts, with full control through the web interface.',
},
{
name: 'Automatic Certificate Management',
icon: Lock,
description: 'Generates and installs a root CA and per-domain certificates with SANs for secure TLS connections.',
benefits: ['Automatic generation', 'Root CA installation', 'SAN support', 'IP inclusion'],
example:
'The system automatically generates and installs certificates for all domains, including the root CA in your system trust store.',
},
{
name: 'Peer Directory Interface',
icon: Users,
description: 'Web-based directory at peer.directory for browsing and searching domains.',
benefits: ['Easy discovery', 'Search functionality', 'Real-time updates', 'User-friendly interface'],
example: 'Browse all available domains in the P2P network through a clean, searchable web interface.',
},
{
name: 'Web-Based Admin Interface',
icon: Code,
description:
'Comprehensive management panel for domains, Holesail servers/clients, local DNS, certificates, and more.',
benefits: ['Full system control', 'Real-time updates', 'WebSocket integration', 'Intuitive UI'],
example:
'Manage all aspects of your P2NS node through a modern web interface with real-time updates and comprehensive controls.',
},
{
name: 'Stateful Persistence',
icon: Database,
description: 'Stores data in Corestore, domains in JSON files, and configurations persist across restarts.',
benefits: ['Data durability', 'Automatic backups', 'Easy migration', 'Version control'],
example:
'All domain claims, votes, and configurations are persisted to disk, ensuring your network survives restarts.',
},
];
const CheckIcon = Check;
export default function FeaturesPage() {
return (
<div className="min-h-screen">
{/* Hero */}
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
Comprehensive Features
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300">
P2NS provides everything you need to build and manage a decentralized DNS network
</p>
</div>
</section>
{/* Features List */}
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="space-y-24">
{features.map((feature, index) => {
const Icon = feature.icon;
return (
<MotionDiv
key={feature.name}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="grid md:grid-cols-3 gap-8 items-start"
>
<div className="md:col-span-1">
<div className="inline-flex p-4 rounded-lg bg-gradient-to-r from-blue-500 to-purple-500 mb-4">
<Icon className="h-8 w-8 text-white" />
</div>
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-3">
{feature.name}
</h2>
<p className="text-gray-600 dark:text-gray-300">{feature.description}</p>
</div>
<div className="md:col-span-2 space-y-6">
<div>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">
Key Benefits
</h3>
<ul className="grid sm:grid-cols-2 gap-3">
{feature.benefits.map((benefit) => (
<li key={benefit} className="flex items-center gap-3">
<CheckIcon className="h-5 w-5 text-green-500 flex-shrink-0" />
<span className="text-gray-600 dark:text-gray-300">{benefit}</span>
</li>
))}
</ul>
</div>
<div className="bg-gray-50 dark:bg-gray-800 p-5 rounded-lg border border-gray-200 dark:border-gray-700">
<p className="text-sm text-gray-600 dark:text-gray-400">
<strong className="text-gray-900 dark:text-white">Example:</strong>{' '}
{feature.example}
</p>
</div>
</div>
</MotionDiv>
);
})}
</div>
</div>
</section>
{/* CTA */}
<section className="py-20 bg-gradient-to-r from-blue-600 to-purple-600">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 className="text-3xl font-bold text-white mb-4">Ready to Get Started?</h2>
<p className="text-xl text-blue-100 mb-8">
Explore the documentation and start building with P2NS today
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<a
href="/docs"
className="px-8 py-3 border-2 border-white rounded-md text-white hover:bg-white hover:text-blue-600 transition-colors font-medium"
>
View Documentation
</a>
</div>
</div>
</section>
</div>
);
}
+76
View File
@@ -0,0 +1,76 @@
@import "tailwindcss";
:root {
--background: #000000;
--foreground: #171717;
--font-inter: 'Inter', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
}
.dark {
--background: #0a0a0a;
--foreground: #ededed;
}
html {
background: var(--background);
}
body {
color: var(--foreground);
background: var(--background);
font-family: var(--font-inter);
transition: background-color 0.2s ease, color 0.2s ease;
min-height: 100vh;
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
/* Smooth scrolling */
html {
scroll-behavior: smooth;
}
/* Focus styles for accessibility */
*:focus-visible {
outline: 2px solid rgb(59 130 246);
outline-offset: 2px;
}
/* Code block styling */
pre {
border-radius: 0.5rem;
overflow-x: auto;
}
code {
font-family: var(--font-mono);
font-size: 0.875rem;
}
/* Prose adjustments */
.prose code {
background-color: rgb(243 244 246);
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-size: 0.875rem;
}
.dark .prose code {
background-color: rgb(31 41 55);
}
.prose pre {
background-color: rgb(17 24 39);
color: rgb(243 244 246);
}
.prose pre code {
background-color: transparent;
padding: 0;
color: rgb(243 244 246);
}
}
+73
View File
@@ -0,0 +1,73 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import Navigation from "@/components/layout/Navigation";
import Footer from "@/components/layout/Footer";
const inter = Inter({
subsets: ["latin"],
variable: '--font-inter',
});
export const metadata: Metadata = {
title: "P2NS - Peer-to-Peer Decentralized DNS System",
description: "A robust, firewall-resistant peer-to-peer DNS resolution system that operates independently of centralized DNS infrastructure.",
keywords: ["P2P", "DNS", "decentralized", "peer-to-peer", "NAT traversal", "firewall", "Holesail", "Hyperswarm", "Corestore"],
authors: [{ name: "Raven Scott" }],
creator: "Raven Scott",
publisher: "P2NS",
openGraph: {
title: "P2NS - Peer-to-Peer Decentralized DNS System",
description: "A robust, firewall-resistant peer-to-peer DNS resolution system",
type: "website",
siteName: "P2NS",
},
twitter: {
card: "summary_large_image",
title: "P2NS - Peer-to-Peer Decentralized DNS System",
description: "A robust, firewall-resistant peer-to-peer DNS resolution system",
},
robots: {
index: true,
follow: true,
},
alternates: {
canonical: "/",
},
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'P2NS',
applicationCategory: 'NetworkApplication',
operatingSystem: 'macOS, Linux',
description: 'A robust, firewall-resistant peer-to-peer DNS resolution system',
url: 'https://git.ssh.surf/snxraven/p2ns',
author: {
'@type': 'Person',
name: 'Raven Scott',
},
};
return (
<html lang="en" className="scroll-smooth bg-black dark:bg-gray-900">
<body className={`${inter.variable} antialiased min-h-screen flex flex-col bg-black dark:bg-gray-900`}>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<Navigation />
<main className="flex-1" id="main-content">
{children}
</main>
<Footer />
</body>
</html>
);
}
+222
View File
@@ -0,0 +1,222 @@
import type { Metadata } from 'next';
import UDPHolePunchingDiagram from '@/components/diagrams/UDPHolePunchingDiagram';
import NATTraversalDiagram from '@/components/diagrams/NATTraversalDiagram';
import PeerDiscoveryDiagram from '@/components/diagrams/PeerDiscoveryDiagram';
export const metadata: Metadata = {
title: 'How P2P Works - Understanding Peer-to-Peer Networking',
description: 'Learn about peer-to-peer networking, UDP hole-punching, NAT traversal, and how P2NS uses these technologies.',
};
export default function P2PPage() {
return (
<div className="min-h-screen">
{/* Introduction */}
<section className="py-20 bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 dark:text-white mb-6">
Understanding Peer-to-Peer Networking
</h1>
<p className="text-xl text-gray-600 dark:text-gray-300 leading-relaxed mb-8">
Peer-to-peer (P2P) networking is a distributed architecture where participants (peers) share resources
and communicate directly without relying on a central server. P2NS leverages P2P technology to create
a resilient, decentralized DNS system.
</p>
<div className="bg-blue-100 dark:bg-blue-900 border-l-4 border-blue-500 p-4 rounded">
<p className="text-sm text-blue-800 dark:text-blue-200">
<strong>Key Concept:</strong> In a P2P network, each node can act as both a client and a server,
enabling direct communication and resource sharing between peers.
</p>
</div>
</div>
</section>
{/* UDP Hole Punching */}
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
UDP Hole Punching
</h2>
<p className="text-lg text-gray-600 dark:text-gray-300 mb-8">
UDP hole-punching is a technique that allows two peers behind NAT (Network Address Translation)
devices to establish a direct connection. This is essential for P2P networking in environments
with firewalls or NAT.
</p>
<UDPHolePunchingDiagram />
<div className="mt-8 prose prose-lg dark:prose-invert max-w-none">
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">How It Works</h3>
<ol className="list-decimal pl-6 space-y-3 text-gray-600 dark:text-gray-300">
<li>
<strong>Both peers contact a rendezvous server:</strong> Each peer sends a UDP packet to a
publicly accessible server, which records their public IP addresses and ports.
</li>
<li>
<strong>Exchange connection information:</strong> The server shares each peer's public endpoint
with the other peer.
</li>
<li>
<strong>Simultaneous connection attempts:</strong> Both peers attempt to send UDP packets to
each other's public endpoints at the same time.
</li>
<li>
<strong>NAT creates a "hole":</strong> The NAT device sees an outgoing packet and creates a
temporary mapping, allowing incoming packets from that destination.
</li>
<li>
<strong>Direct connection established:</strong> Once the hole is punched, peers can communicate
directly without the rendezvous server.
</li>
</ol>
</div>
</div>
</section>
{/* NAT Traversal */}
<section className="py-20 bg-gray-50 dark:bg-gray-800">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
NAT Traversal
</h2>
<p className="text-lg text-gray-600 dark:text-gray-300 mb-8">
Network Address Translation (NAT) is used by routers to share a single public IP address among multiple
devices. NAT traversal techniques allow P2P connections to work through these devices.
</p>
<NATTraversalDiagram />
<div className="mt-8 grid md:grid-cols-2 gap-6">
<div className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Types of NAT</h3>
<ul className="space-y-2 text-gray-600 dark:text-gray-300">
<li><strong>Full Cone NAT:</strong> Allows any external host to send packets to the mapped port.</li>
<li><strong>Restricted Cone NAT:</strong> Only allows packets from previously contacted hosts.</li>
<li><strong>Port Restricted Cone NAT:</strong> Similar to restricted, but also checks the port.</li>
<li><strong>Symmetric NAT:</strong> Different external ports for different destinations (most challenging).</li>
</ul>
</div>
<div className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">CGNAT Challenges</h3>
<p className="text-gray-600 dark:text-gray-300 mb-3">
Carrier-Grade NAT (CGNAT) adds an additional layer of NAT, making traversal even more complex.
P2NS uses Holesail, which is specifically designed to handle these challenging scenarios.
</p>
<p className="text-gray-600 dark:text-gray-300">
Holesail implements advanced techniques including:
</p>
<ul className="list-disc pl-6 mt-2 text-gray-600 dark:text-gray-300">
<li>Multiple simultaneous connection attempts</li>
<li>Protocol-specific optimizations</li>
</ul>
</div>
</div>
</div>
</section>
{/* Peer Discovery */}
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
Peer Discovery with Hyperswarm
</h2>
<p className="text-lg text-gray-600 dark:text-gray-300 mb-8">
Hyperswarm is a distributed hash table (DHT) based peer discovery system. It allows peers to find
each other without a central directory server.
</p>
<PeerDiscoveryDiagram />
<div className="mt-8 prose prose-lg dark:prose-invert max-w-none">
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">How Hyperswarm Works</h3>
<div className="space-y-4 text-gray-600 dark:text-gray-300">
<p>
<strong>Topic-based Discovery:</strong> P2NS uses a fixed topic (derived from 'p2ns-dns') to create
a discovery channel. All peers interested in P2NS join this topic.
</p>
<p>
<strong>DHT Lookup:</strong> When a peer wants to find others, it queries the DHT for the topic.
The DHT returns a list of peers that have announced themselves for that topic.
</p>
<p>
<strong>Connection Establishment:</strong> Once peers discover each other, they use the UDP
hole-punching techniques described above to establish direct connections.
</p>
<p>
<strong>Automatic Reconnection:</strong> Hyperswarm automatically handles peer churn, reconnecting
when peers go offline and come back online.
</p>
</div>
</div>
</div>
</section>
{/* Corestore & Autopass */}
<section className="py-20 bg-gray-50 dark:bg-gray-800">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
Decentralized Storage & Security
</h2>
<div className="grid md:grid-cols-2 gap-8">
<div className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Corestore</h3>
<p className="text-gray-600 dark:text-gray-300 mb-3">
Corestore provides decentralized, append-only storage for P2NS. Domain claims and votes are stored
in a distributed ledger that all peers can access and verify.
</p>
<ul className="list-disc pl-6 space-y-1 text-gray-600 dark:text-gray-300">
<li>Append-only structure prevents tampering</li>
<li>Cryptographically signed entries</li>
<li>Automatic replication across peers</li>
<li>Conflict resolution through voting</li>
</ul>
</div>
<div className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-3">Autopass</h3>
<p className="text-gray-600 dark:text-gray-300 mb-3">
Autopass manages secure writer additions to the Corestore. It ensures only authorized peers can
write to the ledger, preventing spam and attacks.
</p>
<ul className="list-disc pl-6 space-y-1 text-gray-600 dark:text-gray-300">
<li>Invitation-based access control</li>
<li>Master nodes issue invites</li>
<li>Cryptographic verification</li>
<li>Prevents unauthorized writes</li>
</ul>
</div>
</div>
</div>
</section>
{/* Glossary */}
<section className="py-20 bg-white dark:bg-gray-900">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-8">
Glossary
</h2>
<dl className="space-y-6">
{[
{ term: 'NAT (Network Address Translation)', definition: 'A method of remapping IP addresses, allowing multiple devices to share a single public IP address.' },
{ term: 'CGNAT (Carrier-Grade NAT)', definition: 'A large-scale NAT implementation used by ISPs to conserve IPv4 addresses, adding complexity to P2P connections.' },
{ term: 'UDP Hole Punching', definition: 'A technique that allows two peers behind NAT devices to establish a direct connection by coordinating packet timing.' },
{ term: 'DHT (Distributed Hash Table)', definition: 'A decentralized key-value store that allows peers to find each other without a central directory.' },
{ term: 'Rendezvous Server', definition: 'A publicly accessible server that helps peers behind NAT discover each other\'s public endpoints.' },
{ term: 'Peer Discovery', definition: 'The process of finding other peers in a P2P network, typically using DHT or similar mechanisms.' },
{ term: 'Consensus', definition: 'A mechanism for agreeing on the state of distributed data, in P2NS achieved through voting on domain claims.' },
].map((item) => (
<div key={item.term} className="border-l-4 border-blue-500 pl-4">
<dt className="text-lg font-semibold text-gray-900 dark:text-white mb-1">
{item.term}
</dt>
<dd className="text-gray-600 dark:text-gray-300">
{item.definition}
</dd>
</div>
))}
</dl>
</div>
</section>
</div>
);
}
+17
View File
@@ -0,0 +1,17 @@
import Hero from '@/components/sections/Hero';
import FeaturesGrid from '@/components/sections/FeaturesGrid';
import HowItWorks from '@/components/sections/HowItWorks';
import TechnologyStack from '@/components/sections/TechnologyStack';
import QuickStart from '@/components/sections/QuickStart';
export default function Home() {
return (
<>
<Hero />
<FeaturesGrid />
<HowItWorks />
<TechnologyStack />
<QuickStart />
</>
);
}
+13
View File
@@ -0,0 +1,13 @@
import { MetadataRoute } from 'next';
export default async function robots(): Promise<MetadataRoute.Robots> {
return {
rules: {
userAgent: '*',
allow: '/',
disallow: ['/api/'],
},
sitemap: 'https://p2ns.example.com/sitemap.xml', // Update with your actual domain
};
}
+87
View File
@@ -0,0 +1,87 @@
import { MetadataRoute } from 'next';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = 'https://p2ns.example.com'; // Update with your actual domain
return [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 1,
},
{
url: `${baseUrl}/about`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/learn/p2p`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/features`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/docs`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.9,
},
{
url: `${baseUrl}/docs/getting-started`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.9,
},
{
url: `${baseUrl}/docs/configuration`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.8,
},
{
url: `${baseUrl}/docs/examples`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.8,
},
{
url: `${baseUrl}/docs/api`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.8,
},
{
url: `${baseUrl}/docs/troubleshooting`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.7,
},
{
url: `${baseUrl}/docs/architecture`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.7,
},
{
url: `${baseUrl}/examples`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.7,
},
{
url: `${baseUrl}/community`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.6,
},
];
}
@@ -0,0 +1,87 @@
'use client';
import { motion } from 'framer-motion';
import { Network, Database, Shield, Server, Globe, Lock } from 'lucide-react';
const components = [
{
name: 'Corestore & Autopass',
description: 'Decentralized storage and secure writer additions',
icon: Database,
position: 'top-left',
},
{
name: 'Hyperswarm',
description: 'Peer discovery using fixed topic',
icon: Network,
position: 'top-center',
},
{
name: 'DNS Handler',
description: 'UDP server for P2P and public DNS resolution',
icon: Globe,
position: 'top-right',
},
{
name: 'Proxy Server',
description: 'HTTPS/HTTP with WebSocket support',
icon: Server,
position: 'bottom-left',
},
{
name: 'Holesail',
description: 'Secure UDP Holepunched Tunnels',
icon: Shield,
position: 'bottom-right',
},
{
name: 'Certificate Authority',
description: 'Automatic TLS certificate generation and management',
icon: Lock,
position: 'bottom-center',
},
];
export default function ArchitectureDiagram() {
return (
<div className="relative bg-gray-50 dark:bg-gray-800 rounded-lg p-8 border border-gray-200 dark:border-gray-700">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{components.map((component, index) => {
const Icon = component.icon;
return (
<motion.div
key={component.name}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700 hover:border-blue-500 dark:hover:border-blue-500 transition-colors"
>
<div className="flex items-center space-x-3 mb-3">
<div className="p-2 bg-blue-100 dark:bg-blue-900 rounded-lg">
<Icon className="h-6 w-6 text-blue-600 dark:text-blue-400" />
</div>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
{component.name}
</h3>
</div>
<p className="text-sm text-gray-600 dark:text-gray-400">
{component.description}
</p>
</motion.div>
);
})}
</div>
<div className="mt-8 text-center">
<div className="inline-flex items-center space-x-2 px-4 py-2 bg-blue-100 dark:bg-blue-900 rounded-lg">
<Network className="h-5 w-5 text-blue-600 dark:text-blue-400" />
<span className="text-sm font-medium text-gray-900 dark:text-white">
All components work together to create a resilient P2P DNS system
</span>
</div>
</div>
</div>
);
}
@@ -0,0 +1,83 @@
'use client';
import { motion } from 'framer-motion';
import { Router, Globe, Shield } from 'lucide-react';
export default function NATTraversalDiagram() {
return (
<div className="bg-gray-50 dark:bg-gray-800 rounded-lg p-8 border border-gray-200 dark:border-gray-700">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{/* Local Network */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700"
>
<div className="flex items-center space-x-2 mb-4">
<Router className="h-6 w-6 text-blue-600 dark:text-blue-400" />
<h3 className="font-semibold text-gray-900 dark:text-white">Local Network</h3>
</div>
<ul className="space-y-2 text-sm text-gray-600 dark:text-gray-400">
<li> Device 1: 192.168.1.10</li>
<li> Device 2: 192.168.1.11</li>
<li> Device 3: 192.168.1.12</li>
</ul>
</motion.div>
{/* NAT Device */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.2 }}
className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700"
>
<div className="flex items-center space-x-2 mb-4">
<Shield className="h-6 w-6 text-purple-600 dark:text-purple-400" />
<h3 className="font-semibold text-gray-900 dark:text-white">NAT Router</h3>
</div>
<div className="text-sm text-gray-600 dark:text-gray-400 space-y-2">
<p><strong>Public IP:</strong> 203.0.113.1</p>
<p><strong>Function:</strong></p>
<ul className="list-disc pl-4 space-y-1">
<li>Maps private IPs to public ports</li>
<li>Maintains connection state</li>
<li>Blocks unsolicited incoming traffic</li>
</ul>
</div>
</motion.div>
{/* Internet */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.4 }}
className="bg-white dark:bg-gray-900 p-6 rounded-lg border border-gray-200 dark:border-gray-700"
>
<div className="flex items-center space-x-2 mb-4">
<Globe className="h-6 w-6 text-green-600 dark:text-green-400" />
<h3 className="font-semibold text-gray-900 dark:text-white">Internet</h3>
</div>
<div className="text-sm text-gray-600 dark:text-gray-400 space-y-2">
<p><strong>Challenge:</strong></p>
<ul className="list-disc pl-4 space-y-1">
<li>Devices behind NAT can't receive direct connections</li>
<li>UDP hole-punching creates temporary openings</li>
<li>CGNAT adds additional complexity</li>
</ul>
</div>
</motion.div>
</div>
<div className="mt-6 p-4 bg-blue-50 dark:bg-blue-900 rounded-lg border border-blue-200 dark:border-blue-700">
<p className="text-sm text-blue-800 dark:text-blue-200">
<strong>P2NS Solution:</strong> Holesail uses advanced UDP hole-punching techniques and relay servers
to establish connections even through multiple layers of NAT and CGNAT.
</p>
</div>
</div>
);
}
@@ -0,0 +1,77 @@
'use client';
import { motion } from 'framer-motion';
import { Network, Search, Users } from 'lucide-react';
export default function PeerDiscoveryDiagram() {
return (
<div className="bg-gray-50 dark:bg-gray-800 rounded-lg p-8 border border-gray-200 dark:border-gray-700">
<div className="text-center mb-8">
<div className="inline-flex items-center space-x-2 px-4 py-2 bg-purple-100 dark:bg-purple-900 rounded-lg mb-4">
<Search className="h-5 w-5 text-purple-600 dark:text-purple-400" />
<span className="text-sm font-medium text-gray-900 dark:text-white">
Topic: sha256('p2ns-dns')
</span>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
{[
{ name: 'Peer 1', status: 'Online' },
{ name: 'Peer 2', status: 'Online' },
{ name: 'Peer 3', status: 'Online' },
{ name: 'Peer 4', status: 'Online' },
].map((peer, index) => (
<motion.div
key={peer.name}
initial={{ opacity: 0, scale: 0.9 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: index * 0.1 }}
className="bg-white dark:bg-gray-900 p-4 rounded-lg border border-gray-200 dark:border-gray-700 text-center"
>
<Network className="h-8 w-8 text-blue-600 dark:text-blue-400 mx-auto mb-2" />
<h4 className="font-semibold text-gray-900 dark:text-white text-sm mb-1">
{peer.name}
</h4>
<span className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200">
{peer.status}
</span>
</motion.div>
))}
</div>
<div className="mt-8 grid md:grid-cols-3 gap-6">
<div className="bg-white dark:bg-gray-900 p-4 rounded-lg border border-gray-200 dark:border-gray-700">
<h4 className="font-semibold text-gray-900 dark:text-white mb-2 text-sm">1. Join Topic</h4>
<p className="text-xs text-gray-600 dark:text-gray-400">
Peers announce themselves to the DHT using the P2NS topic
</p>
</div>
<div className="bg-white dark:bg-gray-900 p-4 rounded-lg border border-gray-200 dark:border-gray-700">
<h4 className="font-semibold text-gray-900 dark:text-white mb-2 text-sm">2. Discover Peers</h4>
<p className="text-xs text-gray-600 dark:text-gray-400">
Query the DHT to find other peers interested in the same topic
</p>
</div>
<div className="bg-white dark:bg-gray-900 p-4 rounded-lg border border-gray-200 dark:border-gray-700">
<h4 className="font-semibold text-gray-900 dark:text-white mb-2 text-sm">3. Connect</h4>
<p className="text-xs text-gray-600 dark:text-gray-400">
Establish direct connections using UDP hole-punching
</p>
</div>
</div>
<div className="mt-6 p-4 bg-purple-50 dark:bg-purple-900 rounded-lg border border-purple-200 dark:border-purple-700">
<div className="flex items-center space-x-2">
<Users className="h-5 w-5 text-purple-600 dark:text-purple-400" />
<p className="text-sm text-purple-800 dark:text-purple-200">
<strong>Hyperswarm</strong> automatically handles peer churn and reconnection, ensuring the network
remains connected even as peers join and leave.
</p>
</div>
</div>
</div>
);
}
@@ -0,0 +1,92 @@
'use client';
import { motion } from 'framer-motion';
import { Network, Server, ArrowRight, ArrowLeft } from 'lucide-react';
export default function UDPHolePunchingDiagram() {
return (
<div className="bg-gray-50 dark:bg-gray-800 rounded-lg p-8 border border-gray-200 dark:border-gray-700">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 items-center">
{/* Peer A */}
<motion.div
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
className="text-center"
>
<div className="bg-blue-100 dark:bg-blue-900 p-6 rounded-lg mb-4">
<Network className="h-12 w-12 text-blue-600 dark:text-blue-400 mx-auto mb-2" />
<h3 className="font-semibold text-gray-900 dark:text-white">Peer A</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">Behind NAT</p>
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">
<p>Private IP: 192.168.1.10</p>
<p>Public: 203.0.113.1:5000</p>
</div>
</motion.div>
{/* Rendezvous Server */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.2 }}
className="text-center"
>
<div className="bg-purple-100 dark:bg-purple-900 p-6 rounded-lg mb-4">
<Server className="h-12 w-12 text-purple-600 dark:text-purple-400 mx-auto mb-2" />
<h3 className="font-semibold text-gray-900 dark:text-white">Rendezvous</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">Server</p>
</div>
<div className="space-y-2">
<div className="flex items-center justify-center space-x-2 text-sm">
<ArrowRight className="h-4 w-4 text-green-500" />
<span className="text-gray-600 dark:text-gray-400">Exchange info</span>
</div>
<div className="flex items-center justify-center space-x-2 text-sm">
<ArrowLeft className="h-4 w-4 text-green-500" />
<span className="text-gray-600 dark:text-gray-400">Coordinate</span>
</div>
</div>
</motion.div>
{/* Peer B */}
<motion.div
initial={{ opacity: 0, x: 20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.4 }}
className="text-center"
>
<div className="bg-green-100 dark:bg-green-900 p-6 rounded-lg mb-4">
<Network className="h-12 w-12 text-green-600 dark:text-green-400 mx-auto mb-2" />
<h3 className="font-semibold text-gray-900 dark:text-white">Peer B</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">Behind NAT</p>
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">
<p>Private IP: 10.0.0.5</p>
<p>Public: 198.51.100.2:6000</p>
</div>
</motion.div>
</div>
<div className="mt-8 pt-8 border-t border-gray-200 dark:border-gray-700">
<div className="text-center">
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.6 }}
className="inline-flex items-center space-x-2 px-4 py-2 bg-green-100 dark:bg-green-900 rounded-lg"
>
<ArrowRight className="h-5 w-5 text-green-600 dark:text-green-400" />
<span className="text-sm font-medium text-gray-900 dark:text-white">
After hole-punching, peers connect directly
</span>
</motion.div>
</div>
</div>
</div>
);
}
+75
View File
@@ -0,0 +1,75 @@
import Link from 'next/link';
import { Github, ExternalLink } from 'lucide-react';
export default function Footer() {
return (
<footer className="border-t border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<div className="grid grid-cols-1 md:grid-cols-4 gap-8">
<div className="col-span-1 md:col-span-2">
<h3 className="text-lg font-bold mb-4 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
P2NS
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
A robust, firewall-resistant peer-to-peer DNS resolution system that operates independently of centralized DNS infrastructure.
</p>
<a
href="https://git.ssh.surf/snxraven/p2ns"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center space-x-2 text-sm text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
>
<Github size={16} />
<span>View on Git</span>
<ExternalLink size={14} />
</a>
</div>
<div>
<h4 className="text-sm font-semibold mb-4 text-gray-900 dark:text-gray-100">Documentation</h4>
<ul className="space-y-2">
<li>
<Link href="/docs" className="text-sm text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
Getting Started
</Link>
</li>
<li>
<Link href="/learn/p2p" className="text-sm text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
Learn P2P
</Link>
</li>
<li>
<Link href="/features" className="text-sm text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
Features
</Link>
</li>
</ul>
</div>
<div>
<h4 className="text-sm font-semibold mb-4 text-gray-900 dark:text-gray-100">Community</h4>
<ul className="space-y-2">
<li>
<Link href="/community" className="text-sm text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
Contributing
</Link>
</li>
<li>
<Link href="/about" className="text-sm text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
About
</Link>
</li>
</ul>
</div>
</div>
<div className="mt-8 pt-8 border-t border-gray-200 dark:border-gray-800">
<p className="text-sm text-center text-gray-600 dark:text-gray-400">
© {new Date().getFullYear()} P2NS.
</p>
</div>
</div>
</footer>
);
}
+118
View File
@@ -0,0 +1,118 @@
'use client';
import Link from 'next/link';
import { useState } from 'react';
import { Menu, X, Ship } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import PearsIcon from '@/components/ui/PearsIcon';
const navItems = [
{ name: 'Home', href: '/' },
{ name: 'About', href: '/about' },
{ name: 'Learn P2P', href: '/learn/p2p' },
{ name: 'Features', href: '/features' },
{ name: 'Docs', href: '/docs' },
{ name: 'Community', href: '/community' },
];
const externalNavItems = [
{ name: 'Holesail.io', href: 'https://holesail.io', icon: Ship },
{ name: 'Built with Pears', href: 'https://pears.com', icon: PearsIcon },
];
export default function Navigation() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
return (
<nav className="sticky top-0 z-50 w-full border-b border-gray-200 dark:border-gray-800 bg-white/80 dark:bg-gray-900/80 backdrop-blur-sm">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<Link href="/" className="flex items-center space-x-2">
<span className="text-2xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
P2NS
</span>
</Link>
{/* Desktop Navigation */}
<div className="hidden md:flex items-center space-x-8">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className="text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
>
{item.name}
</Link>
))}
{externalNavItems.map((item) => {
const Icon = item.icon;
return (
<a
key={item.href}
href={item.href}
target="_blank"
rel="noopener noreferrer"
className="text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors flex items-center space-x-1.5"
>
<Icon className="h-4 w-4" />
<span>{item.name}</span>
</a>
);
})}
</div>
{/* Mobile Menu Button */}
<button
className="md:hidden p-2 rounded-md text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
aria-label="Toggle menu"
>
{mobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
</div>
{/* Mobile Menu */}
<AnimatePresence>
{mobileMenuOpen && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
className="md:hidden border-t border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900"
>
<div className="px-4 pt-2 pb-4 space-y-1">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className="block px-3 py-2 rounded-md text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
{item.name}
</Link>
))}
{externalNavItems.map((item) => {
const Icon = item.icon;
return (
<a
key={item.href}
href={item.href}
target="_blank"
rel="noopener noreferrer"
className="flex items-center space-x-2 px-3 py-2 rounded-md text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
<Icon className="h-4 w-4" />
<span>{item.name}</span>
</a>
);
})}
</div>
</motion.div>
)}
</AnimatePresence>
</nav>
);
}
+110
View File
@@ -0,0 +1,110 @@
'use client';
import { motion } from 'framer-motion';
import {
Network,
Shield,
Zap,
Globe,
Lock,
Settings,
Server,
Users,
} from 'lucide-react';
const features = [
{
name: 'Decentralized DNS',
description: 'Resolve domains to hashes via P2P core, independent of ICANN or central DNS servers.',
icon: Network,
color: 'from-blue-500 to-blue-600',
},
{
name: 'Firewall Traversal',
description: 'Uses Holesail for UDP hole-punching to connect across restrictive networks, NAT, and CGNAT.',
icon: Shield,
color: 'from-green-500 to-green-600',
},
{
name: 'Dynamic IP Assignment',
description: 'Assigns unique local IPs to domains via virtual network interfaces for seamless routing.',
icon: Zap,
color: 'from-yellow-500 to-yellow-600',
},
{
name: 'Hybrid DNS Resolution',
description: 'Falls back to public DNS for non-P2P domains with custom local DNS record support.',
icon: Globe,
color: 'from-purple-500 to-purple-600',
},
{
name: 'Integrated Proxy',
description: 'HTTP/HTTPS proxies with automatic redirection, WebSocket support, and TLS management.',
icon: Server,
color: 'from-red-500 to-red-600',
},
{
name: 'Certificate Authority',
description: 'Automatic certificate generation and installation with root CA and per-domain certificates.',
icon: Lock,
color: 'from-indigo-500 to-indigo-600',
},
{
name: 'Admin Interface',
description: 'Comprehensive web-based management panel for domains, servers, DNS, and certificates.',
icon: Settings,
color: 'from-pink-500 to-pink-600',
},
{
name: 'Peer Directory',
description: 'Web-based directory for browsing and searching domains across the P2P network.',
icon: Users,
color: 'from-cyan-500 to-cyan-600',
},
];
export default function FeaturesGrid() {
return (
<section className="py-24 bg-white dark:bg-gray-900">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-16">
<h2 className="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4">
Powerful Features
</h2>
<p className="text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
Everything you need to build and manage a decentralized DNS network
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
{features.map((feature, index) => {
const Icon = feature.icon;
return (
<motion.div
key={feature.name}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="relative group"
>
<div className="bg-white dark:bg-gray-800 rounded-lg p-6 border border-gray-200 dark:border-gray-700 hover:border-blue-500 dark:hover:border-blue-500 transition-all hover:shadow-lg h-full">
<div className={`inline-flex p-3 rounded-lg bg-gradient-to-r ${feature.color} mb-4`}>
<Icon className="h-6 w-6 text-white" />
</div>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
{feature.name}
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
{feature.description}
</p>
</div>
</motion.div>
);
})}
</div>
</div>
</section>
);
}
+63
View File
@@ -0,0 +1,63 @@
'use client';
import Link from 'next/link';
import { ArrowRight, Zap } from 'lucide-react';
import { motion } from 'framer-motion';
export default function Hero() {
return (
<section className="relative overflow-hidden bg-gradient-to-b from-blue-50 via-white to-white dark:from-gray-900 dark:via-gray-900 dark:to-gray-900 py-20 sm:py-32">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<h1 className="text-4xl sm:text-5xl md:text-6xl font-bold tracking-tight text-gray-900 dark:text-white mb-6">
Decentralized DNS for the
<span className="block bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
Modern Internet
</span>
</h1>
<p className="mt-6 text-lg sm:text-xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
P2NS is a robust, firewall-resistant peer-to-peer DNS resolution system that operates independently of centralized DNS infrastructure.
Connect across firewalls, NAT, CGNAT, and restricted networks with ease.
</p>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.2 }}
className="mt-10 flex flex-col sm:flex-row gap-4 justify-center"
>
<Link
href="/docs"
className="inline-flex items-center justify-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 transition-all shadow-lg hover:shadow-xl"
>
Get Started
<ArrowRight className="ml-2 h-5 w-5" />
</Link>
<Link
href="/learn/p2p"
className="inline-flex items-center justify-center px-6 py-3 border border-gray-300 dark:border-gray-700 text-base font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
Learn How P2P Works
<Zap className="ml-2 h-5 w-5" />
</Link>
</motion.div>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.4 }}
className="mt-16"
>
</motion.div>
</div>
</div>
</section>
);
}
+82
View File
@@ -0,0 +1,82 @@
'use client';
import { motion } from 'framer-motion';
import { Search, Network, Lock, CheckCircle } from 'lucide-react';
const steps = [
{
number: '01',
title: 'Discover Peers',
description: 'Hyperswarm discovers peers using a fixed topic, enabling automatic peer discovery across the network.',
icon: Search,
},
{
number: '02',
title: 'Establish Connection',
description: 'UDP hole-punching via Holesail creates connections across firewalls, NAT, and CGNAT.',
icon: Network,
},
{
number: '03',
title: 'Resolve Domains',
description: 'Domains are resolved to Holesail hashes through the decentralized P2P network with consensus voting.',
icon: Lock,
},
{
number: '04',
title: 'Route Traffic',
description: 'Virtual interfaces assign local IPs, and integrated proxies route traffic through secure tunnels.',
icon: CheckCircle,
},
];
export default function HowItWorks() {
return (
<section className="py-24 bg-gray-50 dark:bg-gray-800">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-16">
<h2 className="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4">
How It Works
</h2>
<p className="text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
P2NS uses cutting-edge P2P technology to create a resilient, decentralized DNS system
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
{steps.map((step, index) => (
<motion.div
key={step.number}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="relative"
>
<div className="bg-white dark:bg-gray-900 rounded-lg p-6 border border-gray-200 dark:border-gray-700 h-full">
<div className="flex items-center justify-between mb-4">
<span className="text-4xl font-bold text-gray-200 dark:text-gray-700">
{step.number}
</span>
<div className="p-3 rounded-lg bg-blue-100 dark:bg-blue-900">
<step.icon className="h-6 w-6 text-blue-600 dark:text-blue-400" />
</div>
</div>
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">
{step.title}
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
{step.description}
</p>
</div>
{index < steps.length - 1 && (
<div className="hidden lg:block absolute top-1/2 -right-4 w-8 h-0.5 bg-gray-300 dark:bg-gray-600 transform -translate-y-1/2" />
)}
</motion.div>
))}
</div>
</div>
</section>
);
}
+85
View File
@@ -0,0 +1,85 @@
'use client';
import { motion } from 'framer-motion';
import { Terminal, Copy, Check } from 'lucide-react';
import { useState } from 'react';
const commands = [
{ label: 'Clone repository', command: 'git clone https://git.ssh.surf/snxraven/p2ns.git' },
{ label: 'Install dependencies', command: 'npm install' },
{ label: 'Run as master node', command: 'sudo node p2ns.js' },
];
export default function QuickStart() {
const [copiedIndex, setCopiedIndex] = useState<number | null>(null);
const copyToClipboard = (text: string, index: number) => {
navigator.clipboard.writeText(text);
setCopiedIndex(index);
setTimeout(() => setCopiedIndex(null), 2000);
};
return (
<section className="py-24 bg-gradient-to-b from-gray-50 to-white dark:from-gray-800 dark:to-gray-900">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4">
Quick Start
</h2>
<p className="text-lg text-gray-600 dark:text-gray-300">
Get P2NS running in minutes
</p>
</div>
<div className="space-y-4">
{commands.map((item, index) => (
<motion.div
key={index}
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: index * 0.1 }}
className="bg-gray-900 dark:bg-black rounded-lg p-4 border border-gray-800"
>
<div className="flex items-center justify-between mb-2">
<span className="text-sm text-gray-400">{item.label}</span>
<button
onClick={() => copyToClipboard(item.command, index)}
className="p-1 text-gray-400 hover:text-white transition-colors"
aria-label="Copy command"
>
{copiedIndex === index ? (
<Check className="h-4 w-4 text-green-500" />
) : (
<Copy className="h-4 w-4" />
)}
</button>
</div>
<div className="flex items-center space-x-2">
<Terminal className="h-4 w-4 text-green-400" />
<code className="text-sm text-gray-300 font-mono">{item.command}</code>
</div>
</motion.div>
))}
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.4 }}
className="mt-8 text-center"
>
<a
href="/docs"
className="inline-flex items-center text-blue-600 dark:text-blue-400 hover:underline font-medium"
>
View full documentation
<span className="ml-1"></span>
</a>
</motion.div>
</div>
</section>
);
}
+50
View File
@@ -0,0 +1,50 @@
'use client';
import { motion } from 'framer-motion';
const technologies = [
{ name: 'Corestore', description: 'Decentralized storage' },
{ name: 'Hyperswarm', description: 'Peer discovery' },
{ name: 'Holesail', description: 'UDP hole-punching' },
{ name: 'Autopass', description: 'Secure invitations' },
{ name: 'Node.js', description: 'Runtime environment' },
{ name: 'Protomux', description: 'Channel multiplexing' },
];
export default function TechnologyStack() {
return (
<section className="py-24 bg-white dark:bg-gray-900">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-16">
<h2 className="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4">
Built on Modern Technology
</h2>
<p className="text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
P2NS leverages proven P2P technologies to create a robust, scalable DNS system
</p>
</div>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-6">
{technologies.map((tech, index) => (
<motion.div
key={tech.name}
initial={{ opacity: 0, scale: 0.9 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: index * 0.1 }}
className="text-center p-6 bg-gray-50 dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 hover:border-blue-500 dark:hover:border-blue-500 transition-colors"
>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-1">
{tech.name}
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
{tech.description}
</p>
</motion.div>
))}
</div>
</div>
</section>
);
}
+41
View File
@@ -0,0 +1,41 @@
'use client';
import { useState } from 'react';
import { Copy, Check } from 'lucide-react';
interface CodeBlockProps {
code: string;
language?: string;
}
export default function CodeBlock({ code, language = 'bash' }: CodeBlockProps) {
const [copied, setCopied] = useState(false);
const copyToClipboard = () => {
navigator.clipboard.writeText(code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<div className="relative group">
<div className="absolute top-2 right-2">
<button
onClick={copyToClipboard}
className="p-2 bg-gray-700 hover:bg-gray-600 rounded text-gray-300 hover:text-white transition-colors opacity-0 group-hover:opacity-100"
aria-label="Copy code"
>
{copied ? (
<Check className="h-4 w-4 text-green-400" />
) : (
<Copy className="h-4 w-4" />
)}
</button>
</div>
<pre className="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto">
<code className={`language-${language}`}>{code}</code>
</pre>
</div>
);
}
+13
View File
@@ -0,0 +1,13 @@
'use client';
import { motion } from 'framer-motion';
import type { MotionProps } from 'framer-motion';
import { forwardRef } from 'react';
interface Props extends MotionProps {
className?: string;
}
export const MotionDiv = forwardRef<HTMLDivElement, Props>(
(props, ref) => <motion.div ref={ref} {...props} />
);
+20
View File
@@ -0,0 +1,20 @@
export default function PearsIcon({ className }: { className?: string }) {
return (
<svg width="22" height="22" viewBox="0 0 127 182" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
<path d="M58.9658 0H68.0374V17.9736H58.9658V0Z" fill="#B0D944"></path>
<path d="M54.4299 23.6604V27.3005H45.3583V31.8506H81.6449V27.3005H72.5732V20.2471H63.5016V23.6604H54.4299Z" fill="#B0D944"></path>
<path d="M90.7166 34.124H63.5016V37.5374H36.2866V45.7275H90.7166V34.124Z" fill="#B0D944"></path>
<path d="M99.7882 48.0041H63.5016V51.4175H27.215V59.6076H99.7882V48.0041Z" fill="#B0D944"></path>
<path d="M99.7882 61.8811H63.5016V65.2944H27.215V73.4846H99.7882V61.8811Z" fill="#B0D944"></path>
<path d="M108.86 75.758H63.5016V79.1714H18.1433V87.3615H108.86V75.758Z" fill="#B0D944"></path>
<path d="M108.86 89.635H63.5016V93.0483H18.1433V101.238H108.86V89.635Z" fill="#B0D944"></path>
<path d="M63.4984 103.512V106.925H9.07166V115.115H117.932V103.512H63.4984Z" fill="#B0D944"></path>
<path d="M127 117.392H63.4984V120.805H0V128.996H127V117.392Z" fill="#B0D944"></path>
<path d="M127 131.269H63.4984V134.682H0V142.873H127V131.269Z" fill="#B0D944"></path>
<path d="M127 145.146H63.4984V148.559H0V156.749H127V145.146Z" fill="#B0D944"></path>
<path d="M108.86 159.023H63.5016V162.436H18.1433V170.626H108.86V159.023Z" fill="#B0D944"></path>
<path d="M90.7166 172.9H63.5016V176.313H36.2866V182H90.7166V172.9Z" fill="#B0D944"></path>
</svg>
);
}
+13
View File
@@ -0,0 +1,13 @@
version: '3.8'
services:
website:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
restart: unless-stopped
+18
View File
@@ -0,0 +1,18 @@
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
]),
]);
export default eslintConfig;
+10
View File
@@ -0,0 +1,10 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
formats: ['image/avif', 'image/webp'],
},
}
module.exports = nextConfig
+7
View File
@@ -0,0 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;
+7275
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
{
"name": "p2ns-website",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"framer-motion": "^11.0.0",
"lucide-react": "^0.554.0",
"shiki": "^1.0.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.17",
"@types/node": "^20.19.25",
"@types/react": "^19.2.6",
"@types/react-dom": "^19.2.3",
"autoprefixer": "^10.4.22",
"eslint": "^9.39.1",
"eslint-config-next": "^16.0.3",
"next": "^16.0.3",
"postcss": "^8.5.6",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"tailwindcss": "^4.1.17",
"typescript": "^5.9.3"
}
}
+7
View File
@@ -0,0 +1,7 @@
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;
+1
View File
@@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 391 B

+1
View File
@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+1
View File
@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 128 B

+1
View File
@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

After

Width:  |  Height:  |  Size: 385 B

+25
View File
@@ -0,0 +1,25 @@
import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
colors: {
background: "var(--background)",
foreground: "var(--foreground)",
},
fontFamily: {
sans: ['var(--font-inter)', 'system-ui', 'sans-serif'],
mono: ['var(--font-mono)', 'monospace'],
},
},
},
plugins: [],
darkMode: 'class',
};
export default config;
+41
View File
@@ -0,0 +1,41 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./*"
]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}