diff --git a/.gitignore b/.gitignore index 43e7680..01f257a 100644 --- a/.gitignore +++ b/.gitignore @@ -168,3 +168,4 @@ dist .wrangler/ .vscode .git +test-results/ \ No newline at end of file diff --git a/README.md b/README.md index 631e7b3..afc1062 100644 --- a/README.md +++ b/README.md @@ -2,249 +2,159 @@
-Nooxy Logo +Nooxy Logo -**A free, zero dependency Notion Reverse Proxy with advanced customization features** +### **Turn Notion into a website. Free. Forever.** + +**The only Notion reverse proxy with full SEO, zero dependencies, and complete customization.** [![npm version](https://img.shields.io/npm/v/nooxy?style=flat-square)](https://www.npmjs.com/package/nooxy) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/) [![Cloudflare Workers](https://img.shields.io/badge/Cloudflare%20Workers-F38020?style=flat-square&logo=cloudflare&logoColor=white)](https://workers.cloudflare.com/) -
- -## ๐Ÿš€ What is Nooxy? - -Nooxy is a modern, open-source, zero dependency Notion reverse proxy that allows you to host your Notion pages on your own custom domain with complete control over customization. Built with TypeScript and designed for Cloudflare Workers and modern Node.js runtimes, Nooxy provides a powerful alternative to Notion's expensive custom domain feature. - -### Why Nooxy? +[Quick Start](#-quick-start) ยท [Why Nooxy](#-why-nooxy) ยท [Features](#-features) ยท [Configuration](#-configuration-reference) ยท [Examples](./examples) -Notion's custom domain feature is expensive and offers limited customization control. Nooxy solves this by providing: - -- **๐Ÿ’ฐ Completely Free** - No monthly fees or usage limits -- **๐Ÿ“ฆ Zero Dependencies** - No external dependencies, lightweight and fast -- **๐ŸŽจ Full Customization** - Inject custom CSS, JavaScript, and HTML with metadata customization -- **๐Ÿ”ง Local Development** - Test your site locally before deployment -- **โšก High Performance** - Specially Built for Cloudflare Workers edge computing and modern Node.js runtimes -- **๐Ÿ› ๏ธ Developer Friendly** - CLI tools, TypeScript support, and extensive configuration options -- **๐Ÿ”— Seamless Navigation** - Proper URL rewriting and internal link handling -- **๐Ÿ“Š SEO & Metadata** - Advanced metadata customization for better search engine optimization - -## โœจ Key Features - -### ๐Ÿ  **Local Development Support** + -Nooxy supports local development with automatic localhost detection: +--- -```typescript -// Automatically detects localhost and adjusts domain -const proxy = initializeNooxy({ - domain: 'your-domain.com', // Will be overridden to localhost:port in dev - // ... other config -}); -``` +## The Problem -- Test your Notion site locally before deployment -- Hot reloading and instant feedback -- Debug and iterate quickly +You built something great in Notion. Now you want to share it with the world on your own domain. -### ๐Ÿ“ **Multiple Configuration Instances** +**Your options today:** -Supported via `initializeNooxy({ configKey, config })` and a cached `ConfigManager` keyed by `configKey`. This lets you run multiple isolated proxies (e.g., different domains) in the same runtime with independent caches. +| Solution | Cost | SEO | Customization | Interactivity | +|----------|------|-----|---------------|---------------| +| **Notion Sites** | $10-22/mo | Limited, noindex issues | Minimal | Full | +| **Super.so** | $12-28/mo | Good, but subdomain-only hurts rankings | Good | Lost (static) | +| **Fruition** | Free | Poor, outdated | Limited | Full | +| **Nooxy** | **Free** | **Full SEO suite** | **Complete** | **Full** | -```typescript -// Production config -const prodProxy = initializeNooxy({ - configKey: 'production', - config: productionConfig, -}); +Notion Sites charges [$10/month per domain](https://www.notion.com/help/notion-sites-availability-and-pricing) with [limited SEO and customization](https://super.so/blog/notion-sites-pricing). Super.so costs [$12-28/month](https://super.so/pricing) and converts your pages to static HTMLโ€”you lose Notion's live databases, filtering, and real-time updates. Fruition is [no longer maintained](https://github.com/stephenou/fruitionsite) and lacks modern SEO features. -// Development config -const devProxy = initializeNooxy({ - configKey: 'development', - config: developmentConfig, -}); +**Nooxy gives you everything. For free.** -// Usage example in a multi-tenant Worker -export default { - async fetch(request) { - const host = new URL(request.url).hostname; - const proxy = host.endsWith('example.com') ? prodProxy : devProxy; - return proxy(request); - }, -}; +--- -Why it's useful: -- Run multiple domains/sites with a single deployment -- Separate caches for each site via `ConfigManager.getInstance(config, configKey)` -- Easier staging/production side-by-side in one process -``` +## Why Nooxy? -### ๐Ÿ”— **Advanced URL Rewriting** + + + + + +
-Nooxy provides sophisticated URL rewriting that handles: +### What you get -- **Internal Links**: All Notion internal links are rewritten to your domain -- **Navigation**: Seamless internal navigation within your custom domain and Browser back/forward buttons work correctly -- **Deep Linking**: Direct links to specific pages work seamlessly -- **Slug Mapping**: Proper slug-to-page mapping with 301 redirects i.e Clean URLs like `/about` map to Notion page IDs +- **$0/month** โ€” No subscriptions, no limits +- **Full SEO** โ€” Canonical URLs, structured data, proper indexing +- **Complete control** โ€” Inject any CSS, JavaScript, HTML +- **Live Notion** โ€” Real-time databases, filtering, collaboration +- **Your domain** โ€” Professional URLs like `yourdomain.com/about` -### ๐ŸŽ›๏ธ **CLI Tooling** + -- `npx nooxy init` - Initialize configuration files in a `nooxy/` folder at project root -- `npx nooxy generate [--path=/absolute/or/relative/path] [--no-minify]` - Generate minified string files from a custom path (defaults to current working directory). The configuration folder name must be `nooxy`. +### What you avoid -### ๐ŸŽจ **Custom Header Support** +- ~~$120-336/year~~ on hosting fees +- ~~Subdomain SEO penalties~~ from free tiers +- ~~Static pages~~ that lose Notion's power +- ~~Vendor lock-in~~ from closed platforms +- ~~Outdated tools~~ that break with Notion updates -- Inject custom HTML, CSS, and JavaScript into the header -- Complete control over the top navigation bar -- Responsive design with mobile optimization +
-### โšก **Optimized Caching & Performance** +--- -- Smart configuration caching for better performance -- Multiple instance support for different environments -- Efficient memory usage -- **Zero dependencies** for minimal bundle size and fast loading -- **Automatic minification** of custom CSS, JavaScript, and HTML files -- **Advanced minification** that preserves functionality while reducing file sizes +## Features -### ๐Ÿ”ง **Advanced Customization** +### SEO That Actually Works -- **Required custom files**: CSS, JavaScript, and HTML injection for complete control -- Custom CSS injection for styling -- JavaScript injection for functionality (both head and body) -- HTML header customization -- **Metadata customization**: Page-specific SEO metadata, Open Graph tags, Twitter cards, and JSON-LD structured data -- Optional Google Fonts integration -- Optional Google Analytics support +Nooxy rewrites Notion's HTML to give search engines exactly what they need: -### ๐Ÿ›ก๏ธ **Enhanced Security** +- **Removes `noindex` tags** โ€” Your pages get indexed by Google +- **Canonical URLs** โ€” `https://yourdomain.com/about` not `/About-abc123def` +- **Structured data** โ€” JSON-LD schema for rich search results +- **Open Graph & Twitter Cards** โ€” Beautiful social media previews +- **Custom meta tags** โ€” Title, description, keywords, author per page +- **AI attribution** โ€” Proper source credits for ChatGPT, Claude, Perplexity +- **XML sitemap** โ€” Auto-generated at `/sitemap.xml` +- **Robots.txt** โ€” Proper crawler directives at `/robots.txt` -- Proper XMLHttpRequest handling -- Blocked problematic Notion requests -- Content Security Policy management +### Complete Customization -### ๐Ÿ“Š **Advanced Metadata Customization** +- **Custom CSS** โ€” Override any Notion style, add your brand +- **JavaScript injection** โ€” Analytics, interactions, custom functionality +- **HTML headers** โ€” Navigation bars, announcements, CTAs +- **Google Fonts** โ€” Apply any font family site-wide +- **Google Analytics** โ€” Built-in GA4 support -- **Page-specific SEO**: Customize title, description, and Open Graph tags for each page -- **Social Media Optimization**: Twitter cards and Facebook Open Graph metadata -- **JSON-LD Structured Data**: Automatic generation of structured data for better search visibility -- **SEO Optimization**: Enhanced search engine optimization with customizable meta tags +### Production Ready -### ๐Ÿ“ฆ **Zero Dependencies** +- **Zero dependencies** โ€” Nothing to break, nothing to update +- **Edge computing** โ€” Runs on Cloudflare Workers' global network +- **Node.js support** โ€” Works with any modern Node.js runtime (18.17+) +- **Multi-tenant** โ€” Host multiple sites from one deployment +- **Local development** โ€” Test locally before deploying -- **No External Dependencies**: Zero runtime dependencies for maximum compatibility -- **Minimal Bundle Size**: Ultra-lightweight package for fast loading -- **Security**: No third-party dependencies means fewer security vulnerabilities -- **Reliability**: No dependency conflicts or version mismatches -- **Performance**: Faster cold starts and reduced memory usage -- **Deployment**: Easy deployment to any environment without dependency management +### Developer Experience -## ๐Ÿ“ฆ Installation +- **TypeScript** โ€” Full type safety and IntelliSense +- **CLI tools** โ€” `npx nooxy init` and `npx nooxy generate` +- **Auto-minification** โ€” CSS, JS, HTML optimized automatically +- **Clean URLs** โ€” `/about` instead of `/About-Page-abc123def456` -### Prerequisites +--- -- Node.js 18.17.0 or higher -- A Cloudflare account (for deployment) -- A custom domain (optional, for production) +## Quick Start -### Install Nooxy +### 1. Install ```bash npm install nooxy -# or -pnpm add nooxy -# or -yarn add nooxy ``` -**Zero Dependencies**: Nooxy has no runtime dependencies, making it lightweight and fast to install. - -## ๐Ÿš€ Quick Start - -### 1. Initialize Your Project +### 2. Initialize ```bash npx nooxy init ``` -This creates a `nooxy` directory with all necessary configuration files: +This creates a `nooxy/` folder with all configuration files. -``` -nooxy/ -โ”œโ”€โ”€ config.js # Main configuration file -โ”œโ”€โ”€ head.js # Custom JavaScript for -โ”œโ”€โ”€ body.js # Custom JavaScript for -โ”œโ”€โ”€ head.css # Custom CSS styles -โ”œโ”€โ”€ header.html # Custom HTML header -โ””โ”€โ”€ generated/ # Auto-generated files (created after running generate) - โ”œโ”€โ”€ _head-js-string.js - โ”œโ”€โ”€ _body-js-string.js - โ”œโ”€โ”€ _head-css-string.js - โ””โ”€โ”€ _header-html-string.js -``` - -### 2. Configure Your Site +### 3. Configure Edit `nooxy/config.js`: ```javascript -import { HEAD_JS_STRING } from './generated/_head-js-string.js'; -import { BODY_JS_STRING } from './generated/_body-js-string.js'; -import { HEAD_CSS_STRING } from './generated/_head-css-string.js'; -import { HEADER_HTML_STRING } from './generated/_header-html-string.js'; - -/** @type {import('nooxy').NooxySiteConfig} */ export const SITE_CONFIG = { - // Site domain, example.com - domain: 'your-domain.com', + // Your custom domain + domain: 'yourdomain.com', + + // Your Notion workspace (e.g., yourname.notion.site) + notionDomain: 'yourname.notion.site', - // Map slugs (short page names) to Notion page IDs - // '/' slug is your root page + // Site name for SEO + siteName: 'Your Site Name', + + // Map URLs to Notion page IDs slugToPage: { - '/': 'NOTION_HOME_PAGE_ID', - // '/contact': 'NOTION_PAGE_ID', - // '/about': 'NOTION_PAGE_ID', - // Hint: you can use '/' in slug name to create subpages - // '/about/people': 'NOTION_PAGE_ID', + '/': 'YOUR_HOME_PAGE_ID', // yourdomain.com/ + '/about': 'YOUR_ABOUT_PAGE_ID', // yourdomain.com/about + '/blog': 'YOUR_BLOG_PAGE_ID', // yourdomain.com/blog }, - // SEO metadata - siteName: 'Your Site Name', + // SEO configuration (optional but recommended) + seo: { + indexing: true, // Enable search engine indexing + keywords: 'your, keywords, here', + defaultAuthor: 'Your Name', + }, - // Additional safety: avoid serving extraneous Notion content from your website - // Use the value from your Notion like example.notion.site - notionDomain: 'example.notion.site', - - // Optional: Page-specific metadata customization for SEO - // pageMetadata: { - // 'NOTION_PAGE_ID': { - // title: 'My Custom Page Title', - // description: 'My custom page description', - // image: 'https://imagehosting.com/images/page_preview.jpg', - // author: 'My Name', - // }, - // }, - - // Optional: 404 page configuration - // fof: { - // page: "NOTION_PAGE_ID", - // slug: "/404", // default - // }, - - // Optional: Subdomain redirects - // subDomains: { - // www: { - // redirect: 'https://your-domain.com', - // }, - // }, - - // Optional: Google Font and Analytics - // googleFont: 'Roboto', - // googleTagID: 'GOOGLE_TAG_ID', - - // Required: Custom JS, CSS, HTML for head and body of a Notion page + // Required: Generated files (don't modify) customHeadCSS: HEAD_CSS_STRING, customHeadJS: HEAD_JS_STRING, customBodyJS: BODY_JS_STRING, @@ -252,24 +162,15 @@ export const SITE_CONFIG = { }; ``` -### 3. Generate Required Files +### 4. Generate ```bash -# Run from project root (where the `nooxy/` folder exists) npx nooxy generate - -# Or specify a custom path that contains the `nooxy/` folder -npx nooxy generate --path=./examples/cloudflare - -# Disable minification (optional) -npx nooxy generate --no-minify ``` -This reads files from `/nooxy/{head.js,body.js,head.css,header.html}` and converts them into minified string constants under `/nooxy/generated/`. The generated files are automatically minified for optimal performance. +### 5. Deploy -### 4. Deploy to Cloudflare Workers or run in Node.js - -Create a Cloudflare Worker and use the following code (Edge runtime): +**Cloudflare Workers** (recommended): ```typescript import { initializeNooxy } from 'nooxy'; @@ -279,437 +180,288 @@ const proxy = initializeNooxy(SITE_CONFIG); export default { async fetch(request: Request): Promise { - return await proxy(request); + return proxy(request); }, -} satisfies ExportedHandler; +}; ``` -Or use in a modern Node.js runtime (e.g., express-like frameworks that support `Request`/`Response` or via polyfills): +**Node.js**: -```ts +```typescript import { initializeNooxy } from 'nooxy'; import { SITE_CONFIG } from './nooxy/config'; import http from 'node:http'; const proxy = initializeNooxy(SITE_CONFIG); -const server = http.createServer(async (req, res) => { - const url = `http://${req.headers.host}${req.url}`; - const request = new Request(url, { method: req.method }); +http.createServer(async (req, res) => { + const request = new Request(`http://${req.headers.host}${req.url}`); const response = await proxy(request); res.statusCode = response.status; response.headers.forEach((v, k) => res.setHeader(k, v)); - const body = await response.arrayBuffer(); - res.end(Buffer.from(body)); -}); - -server.listen(8787, () => - console.log('Nooxy Node server on http://localhost:8787') -); + res.end(Buffer.from(await response.arrayBuffer())); +}).listen(8787); ``` -## ๐Ÿ“š Configuration Reference +--- -### Core Configuration +## Configuration Reference -| Field | Type | Required | Description | -| -------------- | ------------------------ | -------- | ---------------------------------------- | -| `domain` | `string` | โœ… | Your custom domain (e.g., `example.com`) | -| `siteName` | `string` | โœ… | Site name for SEO and social sharing | -| `slugToPage` | `Record` | โœ… | Mapping of URL slugs to Notion page IDs | -| `notionDomain` | `string` | โœ… | Your Notion workspace domain | +### Required -### Required Customization +| Field | Description | +|-------|-------------| +| `domain` | Your custom domain (e.g., `example.com`) | +| `notionDomain` | Your Notion workspace domain (e.g., `yourname.notion.site`) | +| `siteName` | Site name for SEO and social sharing | +| `slugToPage` | URL path to Notion page ID mapping | +| `customHeadCSS` | Generated CSS string | +| `customHeadJS` | Generated head JavaScript string | +| `customBodyJS` | Generated body JavaScript string | +| `customHeader` | Generated header HTML string | -| Field | Type | Required | Description | -| --------------- | -------- | -------- | ------------------------------ | -| `customHeadCSS` | `string` | โœ… | Custom CSS for `` | -| `customHeadJS` | `string` | โœ… | Custom JavaScript for `` | -| `customBodyJS` | `string` | โœ… | Custom JavaScript for `` | -| `customHeader` | `string` | โœ… | Custom HTML header content | +### SEO Configuration -### Optional Configuration +```javascript +seo: { + // Enable search engine indexing (default: true) + indexing: true, + + // Canonical domain (if different from domain) + // Useful when nooxy runs on subdomain but SEO points to main domain + canonicalDomain: 'example.com', + + // Path mapping for canonical URLs + // Maps nooxy paths to canonical domain paths + canonicalPathMap: { + '/': '/home', // os.example.com/ โ†’ example.com/home + '/docs': '/documentation', + }, -| Field | Type | Required | Description | -| --------------- | ----------------------------------- | -------- | ---------------------------------------------- | -| `pageMetadata` | `Record` | โŒ | Page-specific metadata customization for SEO | -| `siteIcon` | `string` | โŒ | Custom favicon URL | -| `twitterHandle` | `string` | โŒ | X (formerly Twitter) handle for social sharing | -| `subDomains` | `Record` | โŒ | Subdomain redirect configuration | -| `fof` | `FofConfig` | โŒ | 404 page configuration | -| `googleFont` | `string` | โŒ | Google Font family name | -| `googleTagID` | `string` | โŒ | Google Analytics measurement ID | + // Meta keywords for SEO + keywords: 'notion, website, custom domain', -### Page Metadata Interface + // Default author for pages + defaultAuthor: 'Your Name', -```typescript -interface PageMetadata { - title?: string; // Page title customization for SEO - description?: string; // Page description customization for SEO - image?: string; // Page-specific Open Graph image customization - author?: string; // Page author metadata customization + // Replace "Notion" branding with custom text + brandReplacement: 'Your Brand', + + // AI crawler attribution (ChatGPT, Claude, etc.) + aiAttribution: 'Your Name - yourdomain.com', +} +``` + +### Page-Specific Metadata + +```javascript +pageMetadata: { + 'NOTION_PAGE_ID': { + title: 'Custom Page Title', + description: 'Custom meta description for this page', + image: 'https://yourdomain.com/og-image.jpg', + author: 'Page Author Name', + }, } ``` -## ๐Ÿ› ๏ธ CLI Commands +### Optional Features -### Initialize Configuration +| Field | Description | +|-------|-------------| +| `twitterHandle` | Twitter/X handle for social cards (e.g., `@yourusername`) | +| `siteIcon` | Custom favicon URL | +| `googleFont` | Google Font family name (e.g., `Inter`) | +| `googleTagID` | Google Analytics measurement ID | +| `fof` | Custom 404 page configuration | +| `subDomains` | Subdomain redirect rules | + +--- + +## CLI Commands + +### Initialize Project ```bash npx nooxy init ``` -Creates the initial configuration files in a `nooxy` directory at the project root. The folder name is fixed to `nooxy`. +Creates the `nooxy/` directory with all configuration templates. -### Generate String Files +### Generate Files ```bash -npx nooxy generate [--path=/custom/path] [--no-minify] -``` +# Standard generation (with minification) +npx nooxy generate -Converts your custom files (`head.js`, `body.js`, `head.css`, `header.html`) into minified importable string constants under `/nooxy/generated/`. +# Custom path +npx nooxy generate --path=./my-project -**Options:** +# Without minification (for debugging) +npx nooxy generate --no-minify +``` -- `--path`: Specify a custom directory path that contains a `nooxy/` folder -- `--no-minify`: Disable automatic minification of generated files +Converts your custom files to optimized, importable strings. -## ๐ŸŽจ Customization Guide +--- -### Custom CSS Styling +## Customization -Edit `nooxy/head.css` to add custom styles: +### Custom CSS (`nooxy/head.css`) ```css -/* Hide Notion's default top bar */ -.notion-topbar { - display: none !important; -} +/* Hide Notion's default elements */ +.notion-topbar { display: none !important; } -/* Custom header styling */ -.nooxyBadge_4f7c2b1a-demo-topbar { - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - padding: 20px; - color: white; -} - -/* Custom page styling */ +/* Custom styling */ .notion-page-content { - max-width: 1200px; + max-width: 900px; margin: 0 auto; - padding: 20px; + font-family: 'Inter', sans-serif; } -``` - -### Custom JavaScript (body.js) -Edit `nooxy/body.js` for page functionality: - -```javascript -// Custom page interactions -document.addEventListener('DOMContentLoaded', function () { - // Add custom functionality here - console.log('Nooxy page loaded!'); - - // Example: Add smooth scrolling - document.querySelectorAll('a[href^="#"]').forEach((anchor) => { - anchor.addEventListener('click', function (e) { - e.preventDefault(); - const target = document.querySelector(this.getAttribute('href')); - if (target) { - target.scrollIntoView({ behavior: 'smooth' }); - } - }); - }); -}); +/* Dark mode support */ +.dark .notion-page-content { + background: #1a1a1a; +} ``` -### Custom Head JavaScript (head.js) - -Use `nooxy/head.js` to inject scripts that must load early in the `` (e.g., analytics, tag managers, A/B testing beacons). These run before body scripts: +### Custom JavaScript (`nooxy/body.js`) ```javascript -// Example: preload analytics or feature flags -// Runs in -(function () { - console.log('Head script loaded'); - // e.g., initialize a feature flag SDK -})(); -``` +// Analytics, interactions, custom functionality +document.addEventListener('DOMContentLoaded', () => { + console.log('Site loaded with Nooxy!'); -### Custom Header HTML + // Track page views, add smooth scrolling, etc. +}); +``` -Edit `nooxy/header.html` for custom header content: +### Custom Header (`nooxy/header.html`) ```html - -