feat(site): initial about.uptime.link website

- Rebrand from idp.global to uptime.link
- Add JetBrains Mono as primary font
- Update Hero with port detection, network scanning, status widgets
- Update Features for uptime monitoring capabilities
- Update HowItWorks for CLI-based workflow
- Create new docs: CLI, Widgets, Detector
- Remove idp.global specific pages (FairUsage, Docker, OIDC, Organizations, Users)
- Use emerald green color scheme throughout
This commit is contained in:
2025-12-23 00:37:37 +00:00
parent 59f64a1291
commit 4eb89bd330
24 changed files with 1434 additions and 2148 deletions

View File

@@ -1,40 +1,12 @@
# Changelog
## 2025-12-22 - 0.2.0 - feat(docs)
add in-app documentation pages and Fair Usage Policy
## 2025-12-23 - 0.0.1 - feat(site)
Initial about.uptime.link website
- Add FairUsagePolicy page and route (/fair-usage) with full policy content and a sticky header/footer
- Introduce a docs section with a DocsLayout and nested routes: Introduction, Quick Start, Docker, Configuration, SDK, OIDC, Organizations, Users
- Update App.tsx to register docs routes and the Fair Usage route
- Update UI components (Navbar, Footer, Hero, HowItWorks) to use internal docs routes and add a Fair Usage link
- Refactor DocsLayout to provide independent scrolling for the sidebar and main content and tweak header/sidebar layout
- Include code examples and navigation between docs pages to improve developer onboarding
## 2025-12-22 - 0.1.0 - feat(site)
revamp landing pages and add documentation layout
- Add new DocsLayout component with sidebar navigation, header, sign-in CTA and documentation links
- Revise Hero, Features, HowItWorks, Navbar and Footer copy to emphasize organization management, OIDC provider, RBAC, 2FA, deploy/self-host options and TypeScript SDK
- Introduce new feature cards and icons; restructure feature list and feature preview UI
- Update CTAs and links to point to docs, repository, community and sign-in endpoints; wrap buttons with asChild anchors for proper navigation
- Minor UI tweak: reduce feature card animation delay from 150ms to 100ms
## 2025-04-03 - 0.0.0 - Site UI, theming, content and infra updates
Large update adding dark theme support, UI refactors, content/footer updates, and initial site creation.
- Add dark theme support across the app (complete dark theme implementation).
- Add a dark theme toggle (using next-themes) and enable dark mode support for UI components.
- Fix dark mode styling specifically for the HowItWorks section.
- Refactor UI for an improved modern look and feel; improve Hero preview to resemble a passport.
- Remove the CTA component and restructure the CTA section for improved layout.
- Add sample passport data (John Doe) and fix the hero passport link to the correct URL.
- Add identity URL mapping: map idp://user.global/identity to https://passport.idp.global/john.doe.
- Add legal and company links to the footer (note: one revert related to this change was recorded and then re-applied).
- Fix a syntax error in HowItWorks.tsx (missing comma).
- Create the about.idp.global website (initial implementation).
- Standardize project tech stack setup: use vite_react_shadcn_ts.
## 2025-11-30 - 0.0.0 - Miscellaneous housekeeping
Several small/undocumented updates and housekeeping commits were made on this date; no detailed changelog messages were provided.
- Multiple minor updates / maintenance changes (details not specified in commit messages).
- Create uptime.link landing page with uptime monitoring focus
- Add Hero section with port detection, local network scanning, status widgets features
- Add Features section: Port Detection, Network Scanning, Status Widgets, Alerts, Service Discovery, Self-Host, SDK, Open Source
- Add HowItWorks section: Install CLI, Scan Network, Configure Monitors, Track & Alert
- Add documentation pages: Introduction, Quick Start, CLI, Configuration, SDK, Widgets, Detector
- Configure JetBrains Mono as the primary font
- Use emerald green color scheme for uptime monitoring branding

View File

@@ -3,16 +3,21 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>idp.global - Free Open Source Identity Platform</title>
<meta name="description" content="idp.global is an OpenID like platform that provides an Open Source, free identity to everyone who wants one." />
<meta name="author" content="idp.global" />
<title>uptime.link - Open Source Uptime Monitoring</title>
<meta name="description" content="uptime.link is an Open Source uptime monitoring platform with local network detection, service discovery, and embeddable status widgets." />
<meta name="author" content="uptime.link" />
<meta property="og:title" content="idp.global - Free Open Source Identity Platform" />
<meta property="og:description" content="idp.global is an OpenID like platform that provides an Open Source, free identity to everyone who wants one." />
<meta property="og:title" content="uptime.link - Open Source Uptime Monitoring" />
<meta property="og:description" content="uptime.link is an Open Source uptime monitoring platform with local network detection, service discovery, and embeddable status widgets." />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@idp_global" />
<meta name="twitter:site" content="@uptime_link" />
<!-- JetBrains Mono Font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&display=swap" rel="stylesheet">
</head>
<body>

View File

@@ -1,7 +1,7 @@
{
"name": "vite_react_shadcn_ts",
"name": "about.uptime.link",
"private": true,
"version": "0.2.0",
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",

593
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,18 +7,16 @@ import { BrowserRouter, Routes, Route } from "react-router-dom";
import { ThemeProvider } from "@/components/ThemeProvider";
import Index from "./pages/Index";
import NotFound from "./pages/NotFound";
import FairUsagePolicy from "./pages/FairUsagePolicy";
// Docs pages
import DocsLayout from "./pages/docs/DocsLayout";
import Introduction from "./pages/docs/Introduction";
import QuickStart from "./pages/docs/QuickStart";
import Docker from "./pages/docs/Docker";
import CLI from "./pages/docs/CLI";
import Configuration from "./pages/docs/Configuration";
import SDK from "./pages/docs/SDK";
import OIDC from "./pages/docs/OIDC";
import Organizations from "./pages/docs/Organizations";
import Users from "./pages/docs/Users";
import Widgets from "./pages/docs/Widgets";
import Detector from "./pages/docs/Detector";
const queryClient = new QueryClient();
@@ -31,18 +29,16 @@ const App = () => (
<BrowserRouter>
<Routes>
<Route path="/" element={<Index />} />
<Route path="/fair-usage" element={<FairUsagePolicy />} />
{/* Documentation routes */}
<Route path="/docs" element={<DocsLayout />}>
<Route index element={<Introduction />} />
<Route path="quick-start" element={<QuickStart />} />
<Route path="docker" element={<Docker />} />
<Route path="cli" element={<CLI />} />
<Route path="configuration" element={<Configuration />} />
<Route path="sdk" element={<SDK />} />
<Route path="oidc" element={<OIDC />} />
<Route path="organizations" element={<Organizations />} />
<Route path="users" element={<Users />} />
<Route path="widgets" element={<Widgets />} />
<Route path="detector" element={<Detector />} />
</Route>
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}

View File

@@ -1,48 +1,48 @@
import React from 'react';
import { Building2, Key, Users, Shield, Fingerprint, Container, Code2, Zap } from 'lucide-react';
import { Activity, Wifi, Globe, Bell, Server, Code2, Container, Zap } from 'lucide-react';
import { cn } from '@/lib/utils';
const features = [
{
icon: Building2,
title: 'Organization Management',
description: 'Multi-tenant architecture with full organization lifecycle management. Invite members, assign roles, and transfer ownership.'
icon: Activity,
title: 'Port Detection',
description: 'Automatically detect and monitor open ports. Support for HTTP, HTTPS, SSH, FTP, SMTP, MySQL, PostgreSQL, MongoDB, and Redis.'
},
{
icon: Key,
title: 'OpenID Connect Provider',
description: 'Full OIDC compliance for third-party app integration. Authorization code flow with PKCE, token refresh, and revocation.'
icon: Wifi,
title: 'Local Network Scanning',
description: 'Scan your local network to discover services. Identify service types automatically based on port signatures and responses.'
},
{
icon: Users,
title: 'User Management',
description: 'Complete user lifecycle from registration to profile management. Support for email/password, magic links, and API tokens.'
icon: Globe,
title: 'Status Widgets',
description: 'Embeddable web components for your status page. Display real-time uptime status anywhere with a simple script tag.'
},
{
icon: Shield,
title: 'Role-Based Access Control',
description: 'Fine-grained permissions with admin, member, and custom roles. Control access at organization and application level.'
icon: Bell,
title: 'Instant Alerts',
description: 'Get notified immediately when services go down. Configure alert thresholds and notification channels for your team.'
},
{
icon: Fingerprint,
title: 'Two-Factor Authentication',
description: 'Enhanced security with 2FA support. JWT-based sessions with automatic refresh and device management.'
icon: Server,
title: 'Service Discovery',
description: 'Automatic service type identification. Detect HTTP servers, databases, mail servers, and more with intelligent probing.'
},
{
icon: Container,
title: 'Deploy Anywhere',
description: 'Self-host with our Docker image or use idp.global for free. Your digital identity, your choice of infrastructure.'
title: 'Self-Host Ready',
description: 'Deploy with Docker or run the CLI locally. Full control over your monitoring infrastructure with zero dependencies.'
},
{
icon: Code2,
title: 'TypeScript SDK',
description: 'Type-safe client libraries for browser and Node.js. Real-time updates via WebSocket with typed API requests.'
description: 'Type-safe client libraries for Node.js and browser. Programmatic access to all monitoring features and status data.'
},
{
icon: Zap,
title: 'Open Source',
description: 'MIT licensed and fully transparent. Community-driven development hosted on code.foss.global with no vendor lock-in.'
description: 'MIT licensed and fully transparent. Community-driven development with no vendor lock-in or hidden fees.'
}
];
@@ -52,12 +52,12 @@ const Features = () => {
<div className="container">
{/* Section Header */}
<div className="text-center max-w-2xl mx-auto mb-16">
<div className="label-pill mb-4">Platform Capabilities</div>
<div className="label-pill mb-4">Monitoring Capabilities</div>
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
Enterprise Identity, Open Source Freedom
Complete Uptime Visibility
</h2>
<p className="text-lg text-muted-foreground">
Everything you need to manage authentication, users, and organizations for your applications.
Everything you need to monitor your infrastructure and keep your services running.
</p>
</div>
@@ -72,14 +72,14 @@ const Features = () => {
"group p-6 rounded-xl border border-border/50 bg-card",
"transition-all duration-300 ease-out",
"hover:border-border hover:shadow-lg hover:-translate-y-1",
"dark:hover:shadow-[0_0_30px_rgba(59,130,246,0.1)]",
"dark:hover:shadow-[0_0_30px_rgba(16,185,129,0.1)]",
"animate-fade-in-up"
)}
style={{ animationDelay: `${index * 100}ms` }}
>
{/* Icon Container */}
<div className="mb-4 w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center group-hover:bg-primary/20 transition-colors">
<Icon className="h-5 w-5 text-primary" />
<div className="mb-4 w-10 h-10 rounded-lg bg-emerald-500/10 flex items-center justify-center group-hover:bg-emerald-500/20 transition-colors">
<Icon className="h-5 w-5 text-emerald-500" />
</div>
<h3 className="text-lg font-semibold text-foreground mb-2">{feature.title}</h3>
<p className="text-sm text-muted-foreground leading-relaxed">{feature.description}</p>

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Globe, Github, Twitter, Linkedin } from 'lucide-react';
import { Activity, Github, Twitter, Linkedin } from 'lucide-react';
const Footer = () => {
return (
@@ -11,15 +11,15 @@ const Footer = () => {
{/* Brand Column */}
<div className="col-span-2 md:col-span-4 lg:col-span-1">
<Link to="/" className="flex items-center gap-2 mb-4 group">
<Globe className="h-5 w-5 text-muted-foreground group-hover:text-foreground transition-colors" />
<span className="text-base font-semibold text-foreground">idp.global</span>
<Activity className="h-5 w-5 text-emerald-500 group-hover:text-emerald-400 transition-colors" />
<span className="text-base font-semibold text-foreground">uptime.link</span>
</Link>
<p className="text-sm text-muted-foreground mb-4 max-w-xs">
Open Source Identity Provider for SMEs and enterprises. MIT Licensed.
Open Source uptime monitoring with local network detection. MIT Licensed.
</p>
<div className="flex space-x-3">
<a
href="https://code.foss.global/idp.global/idp.global"
href="https://code.foss.global/uptime.link/uptime.link"
className="text-muted-foreground hover:text-foreground transition-colors"
aria-label="Source Code"
>
@@ -59,8 +59,8 @@ const Footer = () => {
</Link>
</li>
<li>
<a href="https://idp.global" className="text-sm text-muted-foreground hover:text-foreground transition-colors">
Sign In
<a href="https://uptime.link" className="text-sm text-muted-foreground hover:text-foreground transition-colors">
Dashboard
</a>
</li>
</ul>
@@ -88,7 +88,7 @@ const Footer = () => {
</a>
</li>
<li>
<a href="https://code.foss.global/idp.global/idp.global" className="text-sm text-muted-foreground hover:text-foreground transition-colors">
<a href="https://code.foss.global/uptime.link/uptime.link" className="text-sm text-muted-foreground hover:text-foreground transition-colors">
Source Code
</a>
</li>

View File

@@ -3,14 +3,14 @@ import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import { Building2, Users, Key, Shield, CheckCircle2 } from 'lucide-react';
import { Activity, Wifi, Globe, Bell, CheckCircle2 } from 'lucide-react';
const Hero = () => {
return (
<section className="relative pt-24 pb-20 md:pt-32 md:pb-28 bg-background overflow-hidden">
{/* Subtle background glow */}
<div className="absolute inset-0 -z-10">
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-primary/5 rounded-full blur-3xl" />
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-emerald-500/5 rounded-full blur-3xl" />
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-accent/5 rounded-full blur-3xl" />
</div>
@@ -19,21 +19,18 @@ const Hero = () => {
{/* Content */}
<div className="space-y-8 animate-fade-in-up">
<div className="space-y-4">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 text-primary text-sm font-medium">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 text-sm font-medium">
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-primary"></span>
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-500 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
</span>
Open Source Identity Provider
Open Source Uptime Monitoring
</div>
<h1 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold tracking-tight text-foreground text-balance">
Your Digital Identity, Forever Free
Monitor Everything, Miss Nothing
</h1>
<p className="text-lg md:text-xl text-muted-foreground max-w-lg leading-relaxed">
Get your free digital passport on idp.global. An Open Source Identity Provider with OIDC, organization management, and RBAC. Self-host or use our free SaaS.*
</p>
<p className="text-xs text-muted-foreground/70">
* <Link to="/fair-usage" className="hover:text-foreground underline underline-offset-2 transition-colors">Fair Usage Policy</Link> applies
Open Source uptime monitoring with local network detection, automatic service discovery, and embeddable status widgets. Self-host or use our free platform.
</p>
</div>
<div className="flex flex-wrap gap-4 pt-2">
@@ -42,7 +39,7 @@ const Hero = () => {
className="h-12 px-6 bg-foreground text-background hover:bg-foreground/90 font-medium rounded-lg transition-all duration-200 hover:-translate-y-0.5"
asChild
>
<a href="https://idp.global">Get Your Free Identity</a>
<a href="https://uptime.link">Start Monitoring</a>
</Button>
<Button
variant="outline"
@@ -50,57 +47,68 @@ const Hero = () => {
className="h-12 px-6 border-border text-foreground hover:bg-accent/10 font-medium rounded-lg transition-all duration-200"
asChild
>
<a href="https://code.foss.global/idp.global/idp.global">Self-Host</a>
<a href="https://code.foss.global/uptime.link/uptime.link">View Source</a>
</Button>
</div>
</div>
{/* Feature Preview Card */}
{/* Status Preview Card */}
<div className="hidden lg:block relative animate-fade-in-up stagger-2">
{/* Glow effect behind card */}
<div className="absolute inset-0 -z-10 bg-primary/10 dark:bg-primary/5 rounded-3xl blur-2xl scale-95" />
<div className="absolute inset-0 -z-10 bg-emerald-500/10 dark:bg-emerald-500/5 rounded-3xl blur-2xl scale-95" />
<Card className="relative border border-border/50 bg-card shadow-2xl dark:shadow-glow-blue rounded-xl overflow-hidden">
<div className="p-6 space-y-5">
{/* Header */}
<div className="flex items-center justify-between">
<span className="text-[10px] font-medium uppercase tracking-widest text-muted-foreground">
Identity Provider
Status Dashboard
</span>
<span className="text-xs font-semibold text-primary">idp.global</span>
<span className="text-xs font-semibold text-emerald-500">uptime.link</span>
</div>
{/* Features Grid */}
{/* Status Grid */}
<div className="grid grid-cols-2 gap-4">
<div className="p-3 rounded-lg bg-muted/50 border border-border/50">
<Building2 className="h-5 w-5 text-primary mb-2" />
<div className="text-xs font-medium text-foreground">Organizations</div>
<div className="text-[10px] text-muted-foreground">Multi-tenant support</div>
<Activity className="h-5 w-5 text-emerald-500 mb-2" />
<div className="text-xs font-medium text-foreground">Port Detection</div>
<div className="text-[10px] text-muted-foreground">HTTP, SSH, DB ports</div>
</div>
<div className="p-3 rounded-lg bg-muted/50 border border-border/50">
<Users className="h-5 w-5 text-primary mb-2" />
<div className="text-xs font-medium text-foreground">User Management</div>
<div className="text-[10px] text-muted-foreground">RBAC & invitations</div>
<Wifi className="h-5 w-5 text-emerald-500 mb-2" />
<div className="text-xs font-medium text-foreground">Local Network</div>
<div className="text-[10px] text-muted-foreground">Scan & discover</div>
</div>
<div className="p-3 rounded-lg bg-muted/50 border border-border/50">
<Key className="h-5 w-5 text-primary mb-2" />
<div className="text-xs font-medium text-foreground">OIDC Provider</div>
<div className="text-[10px] text-muted-foreground">SSO for your apps</div>
<Globe className="h-5 w-5 text-emerald-500 mb-2" />
<div className="text-xs font-medium text-foreground">Status Widgets</div>
<div className="text-[10px] text-muted-foreground">Embed anywhere</div>
</div>
<div className="p-3 rounded-lg bg-muted/50 border border-border/50">
<Shield className="h-5 w-5 text-primary mb-2" />
<div className="text-xs font-medium text-foreground">2FA & Security</div>
<div className="text-[10px] text-muted-foreground">JWT-based auth</div>
<Bell className="h-5 w-5 text-emerald-500 mb-2" />
<div className="text-xs font-medium text-foreground">Alerts</div>
<div className="text-[10px] text-muted-foreground">Instant notifications</div>
</div>
</div>
{/* Code snippet */}
<div className="pt-4 border-t border-border/50 space-y-2">
<div className="text-[10px] font-medium uppercase tracking-widest text-muted-foreground">Quick Integration</div>
<div className="bg-muted/50 rounded-md p-3">
<code className="text-xs font-mono text-muted-foreground">
<span className="text-primary">import</span> {'{ IdpClient }'} <span className="text-primary">from</span> <span className="text-accent">'@idp.global/idpclient'</span>
</code>
{/* Service Status */}
<div className="pt-4 border-t border-border/50 space-y-3">
<div className="text-[10px] font-medium uppercase tracking-widest text-muted-foreground">Live Status</div>
<div className="space-y-2">
<div className="flex items-center justify-between text-xs">
<span className="text-muted-foreground">api.example.com</span>
<span className="flex items-center gap-1 text-emerald-500">
<span className="h-1.5 w-1.5 rounded-full bg-emerald-500"></span>
Operational
</span>
</div>
<div className="flex items-center justify-between text-xs">
<span className="text-muted-foreground">db.internal:5432</span>
<span className="flex items-center gap-1 text-emerald-500">
<span className="h-1.5 w-1.5 rounded-full bg-emerald-500"></span>
Operational
</span>
</div>
</div>
</div>
@@ -110,7 +118,7 @@ const Hero = () => {
<CheckCircle2 className="h-4 w-4 text-accent" />
<span className="text-xs font-medium text-muted-foreground">MIT Licensed</span>
</div>
<code className="text-xs font-mono text-muted-foreground">Self-host or Free SaaS</code>
<code className="text-xs text-muted-foreground">99.9% uptime</code>
</div>
</div>
</Card>

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { ArrowRight, Container, Building2, Key, Rocket } from 'lucide-react';
import { ArrowRight, Download, Wifi, Settings, BarChart3 } from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
@@ -9,27 +9,27 @@ import { cn } from '@/lib/utils';
const steps = [
{
number: '01',
title: 'Deploy Your Instance',
description: "Pull our Docker image and deploy in minutes. Configure with environment variables for MongoDB and your domain.",
icon: Container
title: 'Install the CLI',
description: "Install the uptime.link CLI via npm or run our Docker container. Get up and running in under a minute.",
icon: Download
},
{
number: '02',
title: 'Set Up Organizations',
description: "Create organizations for your teams or clients. Invite members and assign roles with granular permissions.",
icon: Building2
title: 'Scan Your Network',
description: "Run the detector to scan your local network. Automatically discover running services and open ports.",
icon: Wifi
},
{
number: '03',
title: 'Register Your Apps',
description: 'Add your applications as OIDC clients. Get client IDs and secrets for secure OAuth 2.0 authentication.',
icon: Key
title: 'Configure Monitors',
description: 'Set up monitoring for your endpoints. Define check intervals, timeout thresholds, and alert rules.',
icon: Settings
},
{
number: '04',
title: 'Integrate & Launch',
description: 'Use our TypeScript SDK or standard OIDC endpoints. Your users can now authenticate across all your services.',
icon: Rocket
title: 'Track & Alert',
description: 'View real-time status dashboards. Embed status widgets on your site and get instant downtime alerts.',
icon: BarChart3
}
];
@@ -41,10 +41,10 @@ const HowItWorks = () => {
<div className="text-center max-w-2xl mx-auto mb-16">
<div className="label-pill mb-4">Getting Started</div>
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
From Zero to SSO in Minutes
Start Monitoring in Minutes
</h2>
<p className="text-lg text-muted-foreground">
Deploy your own identity provider and integrate with your applications seamlessly
From installation to full uptime visibility in four simple steps
</p>
</div>
@@ -64,8 +64,8 @@ const HowItWorks = () => {
<CardContent className="p-6 flex flex-col h-full">
{/* Header with icon and step number */}
<div className="mb-6 flex items-center justify-between">
<div className="w-10 h-10 flex items-center justify-center rounded-md bg-primary/10 group-hover:bg-primary transition-colors duration-300">
<Icon className="w-5 h-5 text-primary group-hover:text-primary-foreground transition-colors duration-300" />
<div className="w-10 h-10 flex items-center justify-center rounded-md bg-emerald-500/10 group-hover:bg-emerald-500 transition-colors duration-300">
<Icon className="w-5 h-5 text-emerald-500 group-hover:text-white transition-colors duration-300" />
</div>
<span className="text-5xl font-bold tabular-nums text-muted/30 select-none">
{step.number}
@@ -73,7 +73,7 @@ const HowItWorks = () => {
</div>
{/* Content */}
<h3 className="text-lg font-semibold text-foreground mb-2 group-hover:text-primary transition-colors duration-300">
<h3 className="text-lg font-semibold text-foreground mb-2 group-hover:text-emerald-500 transition-colors duration-300">
{step.title}
</h3>
<p className="text-sm text-muted-foreground leading-relaxed mb-4 flex-grow">
@@ -82,7 +82,7 @@ const HowItWorks = () => {
{/* Progress bar */}
<div className="mt-auto overflow-hidden">
<div className="h-0.5 w-8 bg-primary/30 group-hover:w-full group-hover:bg-primary transition-all duration-500 rounded-full" />
<div className="h-0.5 w-8 bg-emerald-500/30 group-hover:w-full group-hover:bg-emerald-500 transition-all duration-500 rounded-full" />
</div>
</CardContent>
</Card>

View File

@@ -3,7 +3,7 @@ import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Globe, Menu } from 'lucide-react';
import { Activity, Menu } from 'lucide-react';
import { ThemeToggle } from '@/components/ThemeToggle';
interface NavbarProps extends React.HTMLAttributes<HTMLElement> {}
@@ -31,8 +31,8 @@ const Navbar = ({ className, ...props }: NavbarProps) => {
<div className="container flex h-14 items-center justify-between">
{/* Logo */}
<Link to="/" className="flex items-center gap-2 group">
<Globe className="h-5 w-5 text-foreground/80 group-hover:text-primary transition-colors" />
<span className="text-base font-semibold tracking-tight text-foreground">idp.global</span>
<Activity className="h-5 w-5 text-emerald-500 group-hover:text-emerald-400 transition-colors" />
<span className="text-base font-semibold tracking-tight text-foreground">uptime.link</span>
</Link>
{/* Desktop Navigation */}
@@ -71,7 +71,7 @@ const Navbar = ({ className, ...props }: NavbarProps) => {
className="h-8 px-4 bg-foreground text-background hover:bg-foreground/90 dark:bg-foreground dark:text-background dark:hover:bg-foreground/90 font-medium"
asChild
>
<a href="https://idp.global">Sign In</a>
<a href="https://uptime.link">Dashboard</a>
</Button>
</div>

View File

@@ -1,231 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Globe, ArrowLeft } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { ThemeToggle } from '@/components/ThemeToggle';
const FairUsagePolicy = () => {
return (
<div className="min-h-screen bg-background">
{/* Header */}
<header className="sticky top-0 z-50 w-full border-b border-border bg-background/95 backdrop-blur">
<div className="container flex h-14 items-center">
<Link to="/" className="flex items-center gap-2 mr-6 group">
<Globe className="h-5 w-5 text-foreground/80 group-hover:text-primary transition-colors" />
<span className="text-base font-semibold tracking-tight text-foreground">idp.global</span>
</Link>
<div className="ml-auto flex items-center gap-3">
<ThemeToggle />
<Button size="sm" className="h-8" asChild>
<a href="https://idp.global">Sign In</a>
</Button>
</div>
</div>
</header>
{/* Content */}
<main className="container max-w-3xl py-12 md:py-16">
<Button variant="ghost" size="sm" className="mb-8" asChild>
<Link to="/">
<ArrowLeft className="mr-2 h-4 w-4" />
Back to Home
</Link>
</Button>
<article className="prose prose-neutral dark:prose-invert max-w-none">
<h1 className="text-4xl font-bold tracking-tight text-foreground mb-4">
Fair Usage Policy
</h1>
<p className="text-lg text-muted-foreground mb-8">
Last updated: December 2024
</p>
<section className="space-y-6">
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Overview</h2>
<p className="text-muted-foreground leading-relaxed">
idp.global provides a free, Open Source Identity Provider platform for individuals,
developers, and organizations. To ensure the service remains available, performant,
and secure for all users, we have established this Fair Usage Policy. By using
idp.global, you agree to comply with these guidelines.
</p>
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Acceptable Use</h2>
<p className="text-muted-foreground leading-relaxed mb-4">
You may use idp.global for:
</p>
<ul className="list-disc list-inside text-muted-foreground space-y-2 ml-4">
<li>Personal digital identity management</li>
<li>Authentication for your applications and services</li>
<li>Organization and team management</li>
<li>Development, testing, and production workloads</li>
<li>Integration via our OIDC/OAuth 2.0 endpoints</li>
</ul>
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Prohibited Activities</h2>
<p className="text-muted-foreground leading-relaxed mb-4">
The following activities are strictly prohibited:
</p>
<h3 className="text-lg font-medium text-foreground mt-6 mb-3">Illegal Activities</h3>
<ul className="list-disc list-inside text-muted-foreground space-y-2 ml-4">
<li>Using the service for any unlawful purpose or in violation of any applicable laws</li>
<li>Identity theft, fraud, or impersonation of others</li>
<li>Distribution of malware, phishing, or other malicious content</li>
<li>Money laundering or financing of illegal activities</li>
<li>Violation of intellectual property rights</li>
</ul>
<h3 className="text-lg font-medium text-foreground mt-6 mb-3">Service Abuse</h3>
<ul className="list-disc list-inside text-muted-foreground space-y-2 ml-4">
<li>Denial of Service (DoS) or Distributed Denial of Service (DDoS) attacks</li>
<li>Excessive API requests designed to overload or disrupt the service</li>
<li>Automated account creation (bot registrations), other than explicitly designed for by the platform</li>
<li>Circumventing rate limits or security measures</li>
<li>Scraping, crawling, or harvesting user data</li>
<li>Attempting to gain unauthorized access to other users' accounts or data</li>
</ul>
<h3 className="text-lg font-medium text-foreground mt-6 mb-3">Harmful Content & Behavior</h3>
<ul className="list-disc list-inside text-muted-foreground space-y-2 ml-4">
<li>Harassment, abuse, or threats against other users</li>
<li>Spam or unsolicited bulk communications</li>
<li>Distribution of harmful, offensive, or illegal content</li>
<li>Creating accounts for the purpose of abusing invitations or referrals</li>
</ul>
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Rate Limits</h2>
<p className="text-muted-foreground leading-relaxed mb-4">
To ensure fair access for all users, the following rate limits apply:
</p>
<ul className="list-disc list-inside text-muted-foreground space-y-2 ml-4">
<li>API requests are subject to reasonable rate limiting</li>
<li>Authentication attempts are limited to prevent brute-force attacks</li>
<li>Bulk operations (invitations, exports) may be throttled</li>
</ul>
<p className="text-muted-foreground leading-relaxed mt-4">
If you require higher limits for legitimate use cases, please contact us to discuss
enterprise options or self-hosting.
</p>
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Resource Limits</h2>
<p className="text-muted-foreground leading-relaxed mb-4">
Free accounts on the hosted platform are subject to reasonable resource limits:
</p>
<ul className="list-disc list-inside text-muted-foreground space-y-2 ml-4">
<li>Organizations per user: Fair use, no hard limit for legitimate purposes</li>
<li>Members per organization: Fair use, contact us for large teams</li>
<li>API tokens per user: Reasonable limits apply</li>
<li>Storage: Profile data and authentication records only</li>
</ul>
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Our Commitment</h2>
<p className="text-muted-foreground leading-relaxed mb-4">
We believe that digital identity is a fundamental right. We will always try, to the best
of our conscience, to not lock anyone out of the platform. We strive to tolerate different
viewpoints and will not discriminate based on personal beliefs, political opinions, or
other lawful expressions.
</p>
<p className="text-muted-foreground leading-relaxed mb-4">
That said, in the end, all decisions regarding this platform come down to our own judgment.
We are human, and while we aim to be fair and consistent, we cannot guarantee that our
decisions will align with everyone's expectations.
</p>
<p className="text-muted-foreground leading-relaxed">
If you have any concerns about relying on our judgment, or if you simply prefer complete
autonomy over your identity infrastructure, we strongly encourage you to{' '}
<Link to="/docs/docker" className="text-primary hover:underline">
self-host your own instance
</Link>.
The software is fully Open Source under the MIT License, and self-hosted instances
operate entirely under your own control with no dependency on our decisions.
</p>
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Enforcement</h2>
<p className="text-muted-foreground leading-relaxed mb-4">
Violations of this Fair Usage Policy may result in:
</p>
<ul className="list-disc list-inside text-muted-foreground space-y-2 ml-4">
<li>Warning notifications</li>
<li>Temporary rate limiting or service restrictions</li>
<li>Suspension of account access</li>
<li>Permanent termination of accounts</li>
<li>Reporting to appropriate authorities for illegal activities</li>
</ul>
<p className="text-muted-foreground leading-relaxed mt-4">
We reserve the right to take action at our discretion to protect the service and its users.
</p>
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Self-Hosting Alternative</h2>
<p className="text-muted-foreground leading-relaxed">
idp.global is Open Source (MIT License). If your use case exceeds the fair usage
guidelines of our hosted platform, you are welcome to{' '}
<Link to="/docs/docker" className="text-primary hover:underline">
self-host your own instance
</Link>{' '}
without any restrictions. Self-hosted instances are not subject to this policy.
</p>
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Reporting Violations</h2>
<p className="text-muted-foreground leading-relaxed">
If you become aware of any violations of this policy, please report them to{' '}
<a href="mailto:abuse@idp.global" className="text-primary hover:underline">
abuse@idp.global
</a>{' '}
or through our{' '}
<a href="https://community.foss.global" className="text-primary hover:underline">
community forum
</a>.
</p>
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Changes to This Policy</h2>
<p className="text-muted-foreground leading-relaxed">
We may update this Fair Usage Policy from time to time. Continued use of the service
after changes constitutes acceptance of the updated policy. Significant changes will
be announced through our usual communication channels.
</p>
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground mt-8 mb-4">Contact</h2>
<p className="text-muted-foreground leading-relaxed">
For questions about this policy or to discuss your specific use case, please contact
us at{' '}
<a href="mailto:hello@task.vc" className="text-primary hover:underline">
hello@task.vc
</a>.
</p>
</div>
</section>
</article>
{/* Footer */}
<div className="mt-16 pt-8 border-t border-border">
<p className="text-sm text-muted-foreground">
© {new Date().getFullYear()} Task Venture Capital GmbH. All rights reserved.
</p>
</div>
</main>
</div>
);
};
export default FairUsagePolicy;

160
src/pages/docs/CLI.tsx Normal file
View File

@@ -0,0 +1,160 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { ArrowRight } from 'lucide-react';
const CLI = () => {
return (
<div className="space-y-8">
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">CLI</h1>
<p className="text-xl text-muted-foreground">
The uptime.link command-line interface for managing monitors and scanning networks.
</p>
</div>
{/* Installation */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Installation</h2>
<p className="text-muted-foreground">
Install the CLI globally:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<code className="text-sm text-foreground">npm install -g @uptime.link/cli</code>
</div>
<p className="text-sm text-muted-foreground">
Verify the installation:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<code className="text-sm text-foreground">uptime --version</code>
</div>
</div>
{/* Commands */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Commands</h2>
<div className="space-y-6">
{/* scan */}
<div className="space-y-2">
<h3 className="text-lg font-medium text-foreground">uptime scan</h3>
<p className="text-muted-foreground text-sm">
Scan the local network to discover running services.
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`uptime scan [options]
Options:
--range <cidr> IP range to scan (default: local subnet)
--ports <list> Comma-separated list of ports to check
--timeout <ms> Connection timeout in milliseconds
--json Output results as JSON`}</pre>
</div>
</div>
{/* add */}
<div className="space-y-2">
<h3 className="text-lg font-medium text-foreground">uptime add</h3>
<p className="text-muted-foreground text-sm">
Add an endpoint to monitor.
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`uptime add <url> [options]
Options:
--interval <sec> Check interval in seconds (default: 60)
--timeout <ms> Request timeout in milliseconds
--name <string> Friendly name for the endpoint
--alert <webhook> Webhook URL for alerts`}</pre>
</div>
</div>
{/* remove */}
<div className="space-y-2">
<h3 className="text-lg font-medium text-foreground">uptime remove</h3>
<p className="text-muted-foreground text-sm">
Remove an endpoint from monitoring.
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`uptime remove <url|name>`}</pre>
</div>
</div>
{/* status */}
<div className="space-y-2">
<h3 className="text-lg font-medium text-foreground">uptime status</h3>
<p className="text-muted-foreground text-sm">
Show status of all monitored endpoints.
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`uptime status [options]
Options:
--json Output results as JSON
--watch Continuously update status`}</pre>
</div>
</div>
{/* check */}
<div className="space-y-2">
<h3 className="text-lg font-medium text-foreground">uptime check</h3>
<p className="text-muted-foreground text-sm">
Perform a one-time check on an endpoint.
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`uptime check <url> [options]
Options:
--timeout <ms> Request timeout in milliseconds
--verbose Show detailed response info`}</pre>
</div>
</div>
</div>
</div>
{/* Configuration */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Configuration File</h2>
<p className="text-muted-foreground">
The CLI stores configuration in <code className="text-emerald-500">~/.uptime.link/config.json</code>:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`{
"endpoints": [
{
"url": "https://api.example.com",
"name": "API Server",
"interval": 60,
"timeout": 5000
}
],
"alerts": {
"webhook": "https://hooks.slack.com/..."
}
}`}</pre>
</div>
</div>
{/* Next steps */}
<div className="space-y-4 pt-4 border-t border-border">
<h2 className="text-xl font-semibold text-foreground">Next Steps</h2>
<div className="flex flex-wrap gap-3">
<Button variant="outline" asChild>
<Link to="/docs/configuration">
Configuration
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button variant="outline" asChild>
<Link to="/docs/detector">
Network Detector
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
</div>
);
};
export default CLI;

View File

@@ -1,173 +1,195 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { ArrowRight, ArrowLeft } from 'lucide-react';
const CodeBlock = ({ children, title }: { children: string; title?: string }) => (
<div className="rounded-lg border border-border overflow-hidden">
{title && (
<div className="px-4 py-2 bg-muted/50 border-b border-border text-xs font-medium text-muted-foreground">
{title}
</div>
)}
<pre className="p-4 overflow-x-auto bg-muted/30">
<code className="text-sm font-mono text-foreground">{children}</code>
</pre>
</div>
);
import { ArrowRight } from 'lucide-react';
const Configuration = () => {
return (
<div className="space-y-8">
{/* Header */}
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">
Configuration
</h1>
<p className="text-xl text-muted-foreground leading-relaxed">
Configure your idp.global instance for production use.
<h1 className="text-4xl font-bold tracking-tight text-foreground">Configuration</h1>
<p className="text-xl text-muted-foreground">
Configure uptime.link for your monitoring needs.
</p>
</div>
{/* Core Configuration */}
{/* Environment Variables */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Core Configuration</h2>
<h2 className="text-2xl font-semibold text-foreground">Environment Variables</h2>
<p className="text-muted-foreground">
idp.global is configured via environment variables. These are the essential settings:
</p>
<h3 className="text-lg font-medium text-foreground">Database</h3>
<CodeBlock title="Environment">
{`# MongoDB connection string
# Supports replica sets and authentication
MONGODB_URL=mongodb://user:pass@host:27017/idp?authSource=admin
# For MongoDB Atlas
MONGODB_URL=mongodb+srv://user:pass@cluster.mongodb.net/idp`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Server</h3>
<CodeBlock title="Environment">
{`# Public URL of your instance (required for OAuth redirects)
IDP_BASEURL=https://idp.yourdomain.com
# Instance name shown in UI
INSTANCE_NAME=My Company IDP`}
</CodeBlock>
</div>
{/* JWT Configuration */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">JWT & Security</h2>
<p className="text-muted-foreground">
idp.global uses RS256 (RSA) for JWT signing. Keys are automatically generated and rotated.
</p>
<div className="p-4 rounded-lg border border-border bg-muted/30">
<h4 className="font-medium text-foreground mb-2">Key Management</h4>
<ul className="list-disc list-inside text-sm text-muted-foreground space-y-1">
<li>RSA key pairs are auto-generated on first startup</li>
<li>Public keys are available at <code className="text-primary">/.well-known/jwks.json</code></li>
<li>Keys are stored in MongoDB for persistence across restarts</li>
<li>Automatic key rotation can be configured</li>
</ul>
</div>
</div>
{/* OIDC Configuration */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">OIDC Endpoints</h2>
<p className="text-muted-foreground">
The following OIDC endpoints are automatically configured based on your <code className="text-primary">IDP_BASEURL</code>:
Configure the CLI and SDK using environment variables:
</p>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left py-2 px-3 font-medium text-foreground">Endpoint</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Path</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Variable</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Description</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Default</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="py-2 px-3 text-muted-foreground">Discovery</td>
<td className="py-2 px-3"><code className="text-primary">/.well-known/openid-configuration</code></td>
<td className="py-2 px-3"><code className="text-emerald-500">UPTIME_API_URL</code></td>
<td className="py-2 px-3 text-muted-foreground">API server URL</td>
<td className="py-2 px-3 text-muted-foreground">https://api.uptime.link</td>
</tr>
<tr>
<td className="py-2 px-3 text-muted-foreground">JWKS</td>
<td className="py-2 px-3"><code className="text-primary">/.well-known/jwks.json</code></td>
<td className="py-2 px-3"><code className="text-emerald-500">UPTIME_API_KEY</code></td>
<td className="py-2 px-3 text-muted-foreground">API authentication key</td>
<td className="py-2 px-3 text-muted-foreground">-</td>
</tr>
<tr>
<td className="py-2 px-3 text-muted-foreground">Authorization</td>
<td className="py-2 px-3"><code className="text-primary">/oauth/authorize</code></td>
<td className="py-2 px-3"><code className="text-emerald-500">UPTIME_CHECK_INTERVAL</code></td>
<td className="py-2 px-3 text-muted-foreground">Default check interval (seconds)</td>
<td className="py-2 px-3 text-muted-foreground">60</td>
</tr>
<tr>
<td className="py-2 px-3 text-muted-foreground">Token</td>
<td className="py-2 px-3"><code className="text-primary">/oauth/token</code></td>
<td className="py-2 px-3"><code className="text-emerald-500">UPTIME_TIMEOUT</code></td>
<td className="py-2 px-3 text-muted-foreground">Request timeout (ms)</td>
<td className="py-2 px-3 text-muted-foreground">5000</td>
</tr>
<tr>
<td className="py-2 px-3 text-muted-foreground">UserInfo</td>
<td className="py-2 px-3"><code className="text-primary">/oauth/userinfo</code></td>
</tr>
<tr>
<td className="py-2 px-3 text-muted-foreground">Revocation</td>
<td className="py-2 px-3"><code className="text-primary">/oauth/revoke</code></td>
<td className="py-2 px-3"><code className="text-emerald-500">UPTIME_ALERT_WEBHOOK</code></td>
<td className="py-2 px-3 text-muted-foreground">Webhook URL for alerts</td>
<td className="py-2 px-3 text-muted-foreground">-</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Supported Scopes */}
{/* Config File */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Supported OAuth Scopes</h2>
<h2 className="text-2xl font-semibold text-foreground">Configuration File</h2>
<p className="text-muted-foreground">
Create a <code className="text-emerald-500">uptime.config.json</code> file in your project root:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`{
"endpoints": [
{
"url": "https://api.example.com/health",
"name": "API Health",
"interval": 30,
"timeout": 5000,
"expectedStatus": 200
},
{
"url": "https://db.internal:5432",
"name": "Database",
"type": "tcp",
"interval": 60
}
],
"alerts": {
"webhook": "https://hooks.slack.com/services/...",
"email": "ops@example.com",
"threshold": 3
},
"detector": {
"ports": [80, 443, 22, 3306, 5432, 27017, 6379],
"timeout": 2000
}
}`}</pre>
</div>
</div>
{/* Endpoint Configuration */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Endpoint Options</h2>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left py-2 px-3 font-medium text-foreground">Scope</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Option</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Type</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="py-2 px-3"><code className="text-primary">openid</code></td>
<td className="py-2 px-3 text-muted-foreground">Required for OIDC. Returns sub claim.</td>
<td className="py-2 px-3"><code className="text-emerald-500">url</code></td>
<td className="py-2 px-3 text-muted-foreground">string</td>
<td className="py-2 px-3 text-muted-foreground">Endpoint URL (required)</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-primary">profile</code></td>
<td className="py-2 px-3 text-muted-foreground">User's name and profile information</td>
<td className="py-2 px-3"><code className="text-emerald-500">name</code></td>
<td className="py-2 px-3 text-muted-foreground">string</td>
<td className="py-2 px-3 text-muted-foreground">Friendly display name</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-primary">email</code></td>
<td className="py-2 px-3 text-muted-foreground">User's email address and verification status</td>
<td className="py-2 px-3"><code className="text-emerald-500">type</code></td>
<td className="py-2 px-3 text-muted-foreground">"http" | "tcp"</td>
<td className="py-2 px-3 text-muted-foreground">Check type (default: http)</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-primary">organizations</code></td>
<td className="py-2 px-3 text-muted-foreground">User's organization memberships</td>
<td className="py-2 px-3"><code className="text-emerald-500">interval</code></td>
<td className="py-2 px-3 text-muted-foreground">number</td>
<td className="py-2 px-3 text-muted-foreground">Check interval in seconds</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-primary">roles</code></td>
<td className="py-2 px-3 text-muted-foreground">User's roles within organizations</td>
<td className="py-2 px-3"><code className="text-emerald-500">timeout</code></td>
<td className="py-2 px-3 text-muted-foreground">number</td>
<td className="py-2 px-3 text-muted-foreground">Request timeout in milliseconds</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">expectedStatus</code></td>
<td className="py-2 px-3 text-muted-foreground">number</td>
<td className="py-2 px-3 text-muted-foreground">Expected HTTP status code</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">headers</code></td>
<td className="py-2 px-3 text-muted-foreground">object</td>
<td className="py-2 px-3 text-muted-foreground">Custom HTTP headers</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Navigation */}
<div className="flex justify-between pt-8 border-t border-border">
<Button variant="ghost" asChild>
<Link to="/docs/docker">
<ArrowLeft className="mr-2 h-4 w-4" />
Docker Deployment
</Link>
</Button>
<Button variant="ghost" asChild>
<Link to="/docs/sdk">
TypeScript SDK
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
{/* Alert Configuration */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Alert Configuration</h2>
<p className="text-muted-foreground">
Configure how you receive downtime notifications:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`{
"alerts": {
// Webhook URL (Slack, Discord, etc.)
"webhook": "https://hooks.slack.com/services/...",
// Email notifications
"email": "ops@example.com",
// Number of failures before alerting
"threshold": 3,
// Minimum time between alerts (seconds)
"cooldown": 300
}
}`}</pre>
</div>
</div>
{/* Next steps */}
<div className="space-y-4 pt-4 border-t border-border">
<h2 className="text-xl font-semibold text-foreground">Next Steps</h2>
<div className="flex flex-wrap gap-3">
<Button variant="outline" asChild>
<Link to="/docs/sdk">
TypeScript SDK
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button variant="outline" asChild>
<Link to="/docs/widgets">
Status Widgets
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
</div>
);

198
src/pages/docs/Detector.tsx Normal file
View File

@@ -0,0 +1,198 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { ArrowRight } from 'lucide-react';
const Detector = () => {
return (
<div className="space-y-8">
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">Network Detector</h1>
<p className="text-xl text-muted-foreground">
Scan your local network to discover services and open ports automatically.
</p>
</div>
{/* Overview */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Overview</h2>
<p className="text-muted-foreground">
The detector module scans network ranges and identifies running services based on open ports
and protocol responses. It supports automatic identification of common service types.
</p>
</div>
{/* Supported Services */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Supported Services</h2>
<p className="text-muted-foreground">
The detector can automatically identify these service types:
</p>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left py-2 px-3 font-medium text-foreground">Service</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Default Port</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Detection Method</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="py-2 px-3 text-emerald-500">HTTP</td>
<td className="py-2 px-3 text-muted-foreground">80</td>
<td className="py-2 px-3 text-muted-foreground">HTTP response headers</td>
</tr>
<tr>
<td className="py-2 px-3 text-emerald-500">HTTPS</td>
<td className="py-2 px-3 text-muted-foreground">443</td>
<td className="py-2 px-3 text-muted-foreground">TLS handshake + HTTP</td>
</tr>
<tr>
<td className="py-2 px-3 text-emerald-500">SSH</td>
<td className="py-2 px-3 text-muted-foreground">22</td>
<td className="py-2 px-3 text-muted-foreground">SSH banner</td>
</tr>
<tr>
<td className="py-2 px-3 text-emerald-500">FTP</td>
<td className="py-2 px-3 text-muted-foreground">21</td>
<td className="py-2 px-3 text-muted-foreground">FTP banner</td>
</tr>
<tr>
<td className="py-2 px-3 text-emerald-500">SMTP</td>
<td className="py-2 px-3 text-muted-foreground">25, 587</td>
<td className="py-2 px-3 text-muted-foreground">SMTP greeting</td>
</tr>
<tr>
<td className="py-2 px-3 text-emerald-500">MySQL</td>
<td className="py-2 px-3 text-muted-foreground">3306</td>
<td className="py-2 px-3 text-muted-foreground">MySQL handshake packet</td>
</tr>
<tr>
<td className="py-2 px-3 text-emerald-500">PostgreSQL</td>
<td className="py-2 px-3 text-muted-foreground">5432</td>
<td className="py-2 px-3 text-muted-foreground">PostgreSQL protocol</td>
</tr>
<tr>
<td className="py-2 px-3 text-emerald-500">MongoDB</td>
<td className="py-2 px-3 text-muted-foreground">27017</td>
<td className="py-2 px-3 text-muted-foreground">MongoDB wire protocol</td>
</tr>
<tr>
<td className="py-2 px-3 text-emerald-500">Redis</td>
<td className="py-2 px-3 text-muted-foreground">6379</td>
<td className="py-2 px-3 text-muted-foreground">Redis PING response</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* CLI Usage */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">CLI Usage</h2>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`# Scan local network
uptime scan
# Scan specific IP range
uptime scan --range 192.168.1.0/24
# Scan specific ports
uptime scan --ports 80,443,22,3306,5432
# Output as JSON
uptime scan --json
# With custom timeout
uptime scan --timeout 3000`}</pre>
</div>
</div>
{/* SDK Usage */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">SDK Usage</h2>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`import { Detector } from '@uptime.link/sdk';
const detector = new Detector();
// Scan network
const services = await detector.scan({
range: '192.168.1.0/24',
ports: [80, 443, 22, 3306, 5432, 27017, 6379],
timeout: 2000,
concurrent: 100 // Max concurrent connections
});
// Process results
for (const service of services) {
console.log(\`Found \${service.type} at \${service.host}:\${service.port}\`);
}
// Check a single port
const isOpen = await detector.checkPort('192.168.1.1', 22);
// Identify service type
const type = await detector.identifyService('192.168.1.1', 22);
// Returns: 'ssh' | 'http' | 'mysql' | etc.`}</pre>
</div>
</div>
{/* Service Detection */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Service Detection Logic</h2>
<p className="text-muted-foreground">
The detector uses multiple methods to identify services:
</p>
<ol className="list-decimal list-inside space-y-2 text-muted-foreground ml-4">
<li><strong className="text-foreground">Port matching:</strong> Common ports are checked first (e.g., 22 = SSH, 80 = HTTP)</li>
<li><strong className="text-foreground">Banner grabbing:</strong> Reads the initial response from the service</li>
<li><strong className="text-foreground">Protocol probing:</strong> Sends protocol-specific requests to confirm service type</li>
<li><strong className="text-foreground">TLS detection:</strong> Attempts TLS handshake for encrypted services</li>
</ol>
</div>
{/* Output Format */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Output Format</h2>
<p className="text-muted-foreground">
Each discovered service includes:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`{
"host": "192.168.1.10",
"port": 3306,
"open": true,
"type": "mysql",
"version": "8.0.32",
"banner": "5.7.42-log",
"responseTime": 12,
"tls": false
}`}</pre>
</div>
</div>
{/* Next steps */}
<div className="space-y-4 pt-4 border-t border-border">
<h2 className="text-xl font-semibold text-foreground">Next Steps</h2>
<div className="flex flex-wrap gap-3">
<Button variant="outline" asChild>
<Link to="/docs/cli">
CLI Reference
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button variant="outline" asChild>
<Link to="/docs/sdk">
TypeScript SDK
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
</div>
);
};
export default Detector;

View File

@@ -1,227 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { ArrowRight, ArrowLeft } from 'lucide-react';
const CodeBlock = ({ children, title }: { children: string; title?: string }) => (
<div className="rounded-lg border border-border overflow-hidden">
{title && (
<div className="px-4 py-2 bg-muted/50 border-b border-border text-xs font-medium text-muted-foreground">
{title}
</div>
)}
<pre className="p-4 overflow-x-auto bg-muted/30">
<code className="text-sm font-mono text-foreground">{children}</code>
</pre>
</div>
);
const Docker = () => {
return (
<div className="space-y-8">
{/* Header */}
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">
Docker Deployment
</h1>
<p className="text-xl text-muted-foreground leading-relaxed">
Deploy idp.global on your own infrastructure using Docker. Full control over your
data with the same features as the hosted platform.
</p>
</div>
{/* Prerequisites */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Prerequisites</h2>
<ul className="list-disc list-inside text-muted-foreground space-y-2 ml-2">
<li>Docker 20.10 or later</li>
<li>MongoDB 5.0 or later (local or cloud-hosted like MongoDB Atlas)</li>
<li>A domain name with SSL certificate (for production)</li>
<li>Minimum 1GB RAM, 10GB storage</li>
</ul>
</div>
{/* Quick Start */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Quick Start</h2>
<p className="text-muted-foreground">
Pull and run the official Docker image:
</p>
<CodeBlock title="Terminal">
{`# Pull the latest image
docker pull code.foss.global/idp.global/idp.global
# Run with required environment variables
docker run -d \\
--name idp-global \\
-p 2999:2999 \\
-e MONGODB_URL=mongodb://localhost:27017/idp \\
-e IDP_BASEURL=https://idp.yourdomain.com \\
-e INSTANCE_NAME=my-idp \\
code.foss.global/idp.global/idp.global`}
</CodeBlock>
</div>
{/* Docker Compose */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Docker Compose</h2>
<p className="text-muted-foreground">
For a complete setup including MongoDB, use Docker Compose:
</p>
<CodeBlock title="docker-compose.yml">
{`version: '3.8'
services:
idp:
image: code.foss.global/idp.global/idp.global
container_name: idp-global
restart: unless-stopped
ports:
- "2999:2999"
environment:
MONGODB_URL: mongodb://mongo:27017/idp
IDP_BASEURL: https://idp.yourdomain.com
INSTANCE_NAME: my-idp
depends_on:
- mongo
networks:
- idp-network
mongo:
image: mongo:7
container_name: idp-mongo
restart: unless-stopped
volumes:
- mongo-data:/data/db
networks:
- idp-network
networks:
idp-network:
driver: bridge
volumes:
mongo-data:`}
</CodeBlock>
<CodeBlock title="Terminal">
{`# Start all services
docker-compose up -d
# View logs
docker-compose logs -f idp
# Stop services
docker-compose down`}
</CodeBlock>
</div>
{/* Environment Variables */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Environment Variables</h2>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left py-2 px-3 font-medium text-foreground">Variable</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Required</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="py-2 px-3">
<code className="text-primary">MONGODB_URL</code>
</td>
<td className="py-2 px-3 text-green-600 dark:text-green-400">Yes</td>
<td className="py-2 px-3 text-muted-foreground">MongoDB connection string</td>
</tr>
<tr>
<td className="py-2 px-3">
<code className="text-primary">IDP_BASEURL</code>
</td>
<td className="py-2 px-3 text-green-600 dark:text-green-400">Yes</td>
<td className="py-2 px-3 text-muted-foreground">Public URL of your instance (with https://)</td>
</tr>
<tr>
<td className="py-2 px-3">
<code className="text-primary">INSTANCE_NAME</code>
</td>
<td className="py-2 px-3 text-muted-foreground">No</td>
<td className="py-2 px-3 text-muted-foreground">Display name for this instance (default: idp.global)</td>
</tr>
<tr>
<td className="py-2 px-3">
<code className="text-primary">SERVEZONE_PLATFORM_AUTHORIZATION</code>
</td>
<td className="py-2 px-3 text-muted-foreground">No</td>
<td className="py-2 px-3 text-muted-foreground">ServeZone platform auth token (optional)</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Reverse Proxy */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Reverse Proxy Setup</h2>
<p className="text-muted-foreground">
For production, configure a reverse proxy with SSL. Here's an example nginx configuration:
</p>
<CodeBlock title="nginx.conf">
{`server {
listen 443 ssl http2;
server_name idp.yourdomain.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
proxy_pass http://localhost:2999;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}`}
</CodeBlock>
</div>
{/* Health Check */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Health Check</h2>
<p className="text-muted-foreground">
Verify your instance is running correctly:
</p>
<CodeBlock title="Terminal">
{`# Check if the server is responding
curl https://idp.yourdomain.com
# Check OIDC discovery endpoint
curl https://idp.yourdomain.com/.well-known/openid-configuration`}
</CodeBlock>
</div>
{/* Navigation */}
<div className="flex justify-between pt-8 border-t border-border">
<Button variant="ghost" asChild>
<Link to="/docs/quick-start">
<ArrowLeft className="mr-2 h-4 w-4" />
Quick Start
</Link>
</Button>
<Button variant="ghost" asChild>
<Link to="/docs/configuration">
Configuration
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
);
};
export default Docker;

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Link, Outlet, useLocation } from 'react-router-dom';
import { cn } from '@/lib/utils';
import { Globe, BookOpen, Rocket, Container, Code2, Key, Building2, Terminal, Users, ExternalLink } from 'lucide-react';
import { Activity, BookOpen, Rocket, Terminal, Code2, Globe, Wifi, Settings, ExternalLink } from 'lucide-react';
import { ThemeToggle } from '@/components/ThemeToggle';
import { Button } from '@/components/ui/button';
@@ -14,24 +14,23 @@ const navigation = [
]
},
{
title: 'Deployment',
title: 'Installation',
items: [
{ title: 'Docker', href: '/docs/docker', icon: Container },
{ title: 'Configuration', href: '/docs/configuration', icon: Terminal },
{ title: 'CLI', href: '/docs/cli', icon: Terminal },
{ title: 'Configuration', href: '/docs/configuration', icon: Settings },
]
},
{
title: 'Integration',
items: [
{ title: 'TypeScript SDK', href: '/docs/sdk', icon: Code2 },
{ title: 'OIDC / OAuth 2.0', href: '/docs/oidc', icon: Key },
{ title: 'Status Widgets', href: '/docs/widgets', icon: Globe },
]
},
{
title: 'Features',
items: [
{ title: 'Organizations', href: '/docs/organizations', icon: Building2 },
{ title: 'User Management', href: '/docs/users', icon: Users },
{ title: 'Network Detector', href: '/docs/detector', icon: Wifi },
]
},
];
@@ -45,8 +44,8 @@ const DocsLayout = () => {
<header className="shrink-0 z-50 w-full border-b border-border bg-background">
<div className="flex h-14 items-center px-4 md:px-6">
<Link to="/" className="flex items-center gap-2 mr-6 group">
<Globe className="h-5 w-5 text-foreground/80 group-hover:text-primary transition-colors" />
<span className="text-base font-semibold tracking-tight text-foreground">idp.global</span>
<Activity className="h-5 w-5 text-emerald-500 group-hover:text-emerald-400 transition-colors" />
<span className="text-base font-semibold tracking-tight text-foreground">uptime.link</span>
</Link>
<div className="flex items-center gap-1 text-sm text-muted-foreground">
<span>/</span>
@@ -61,7 +60,7 @@ const DocsLayout = () => {
<ExternalLink className="h-3 w-3" />
</a>
<a
href="https://code.foss.global/idp.global/idp.global"
href="https://code.foss.global/uptime.link/uptime.link"
className="text-sm text-muted-foreground hover:text-foreground transition-colors hidden md:flex items-center gap-1"
>
Source
@@ -69,7 +68,7 @@ const DocsLayout = () => {
</a>
<ThemeToggle />
<Button size="sm" className="h-8" asChild>
<a href="https://idp.global">Sign In</a>
<a href="https://uptime.link">Dashboard</a>
</Button>
</div>
</div>
@@ -97,7 +96,7 @@ const DocsLayout = () => {
className={cn(
"flex items-center gap-2 px-2 py-1.5 text-sm rounded-md transition-colors",
isActive
? "bg-primary/10 text-primary font-medium"
? "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 font-medium"
: "text-muted-foreground hover:text-foreground hover:bg-muted"
)}
>

View File

@@ -2,7 +2,7 @@ import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import { ArrowRight, Building2, Key, Users, Shield, Container, Code2 } from 'lucide-react';
import { ArrowRight, Activity, Wifi, Globe, Bell, Server, Code2 } from 'lucide-react';
const Introduction = () => {
return (
@@ -10,35 +10,35 @@ const Introduction = () => {
{/* Header */}
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">
idp.global Documentation
uptime.link Documentation
</h1>
<p className="text-xl text-muted-foreground leading-relaxed">
A modern, Open Source Identity Provider (IdP) for managing user authentication,
organizations, and role-based access control. Built with TypeScript for SMEs and enterprises.
Open Source uptime monitoring with local network detection, automatic service discovery,
and embeddable status widgets. Built with TypeScript.
</p>
</div>
{/* Quick links */}
<div className="grid sm:grid-cols-2 gap-4">
<Card className="p-5 hover:border-primary/50 transition-colors">
<Card className="p-5 hover:border-emerald-500/50 transition-colors">
<Link to="/docs/quick-start" className="block space-y-2">
<div className="flex items-center justify-between">
<h3 className="font-semibold text-foreground">Quick Start</h3>
<ArrowRight className="h-4 w-4 text-muted-foreground" />
</div>
<p className="text-sm text-muted-foreground">
Get up and running with idp.global in under 5 minutes.
Get up and running with uptime.link in under 5 minutes.
</p>
</Link>
</Card>
<Card className="p-5 hover:border-primary/50 transition-colors">
<Link to="/docs/docker" className="block space-y-2">
<Card className="p-5 hover:border-emerald-500/50 transition-colors">
<Link to="/docs/cli" className="block space-y-2">
<div className="flex items-center justify-between">
<h3 className="font-semibold text-foreground">Docker Deployment</h3>
<h3 className="font-semibold text-foreground">CLI Installation</h3>
<ArrowRight className="h-4 w-4 text-muted-foreground" />
</div>
<p className="text-sm text-muted-foreground">
Deploy your own instance with Docker in minutes.
Install the command-line tool for local monitoring.
</p>
</Link>
</Card>
@@ -50,40 +50,40 @@ const Introduction = () => {
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
{[
{
icon: Users,
title: 'User Management',
description: 'Email/password, magic links, API tokens, password reset, and device management.'
icon: Activity,
title: 'Port Detection',
description: 'Detect and monitor open ports for HTTP, SSH, databases, and more.'
},
{
icon: Building2,
title: 'Organizations',
description: 'Multi-tenant architecture with member invitations and ownership transfer.'
icon: Wifi,
title: 'Network Scanning',
description: 'Scan local networks to discover running services automatically.'
},
{
icon: Shield,
title: 'Role-Based Access',
description: 'Fine-grained RBAC with admin, member, and custom roles.'
icon: Globe,
title: 'Status Widgets',
description: 'Embeddable web components for real-time status display.'
},
{
icon: Key,
title: 'OIDC Provider',
description: 'Full OpenID Connect compliance for third-party app SSO.'
icon: Bell,
title: 'Instant Alerts',
description: 'Get notified immediately when services go down.'
},
{
icon: Container,
title: 'Self-Hostable',
description: 'Deploy anywhere with Docker or use our free hosted platform.'
icon: Server,
title: 'Service Discovery',
description: 'Automatic identification of service types (HTTP, DB, SSH).'
},
{
icon: Code2,
title: 'TypeScript SDK',
description: 'Type-safe client libraries for browser and Node.js.'
description: 'Type-safe client library for programmatic access.'
},
].map((feature) => {
const Icon = feature.icon;
return (
<div key={feature.title} className="p-4 rounded-lg border border-border bg-card">
<Icon className="h-5 w-5 text-primary mb-2" />
<Icon className="h-5 w-5 text-emerald-500 mb-2" />
<h3 className="font-medium text-foreground mb-1">{feature.title}</h3>
<p className="text-sm text-muted-foreground">{feature.description}</p>
</div>
@@ -96,63 +96,42 @@ const Introduction = () => {
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Architecture</h2>
<p className="text-muted-foreground">
idp.global is built as a modular TypeScript monorepo with the following structure:
uptime.link is built as a modular TypeScript monorepo with the following packages:
</p>
<div className="bg-muted/50 rounded-lg p-4 font-mono text-sm">
<pre className="text-muted-foreground overflow-x-auto">{`├── ts/ # Server-side code (Node.js)
│ └── reception/ # Core identity management logic
├── ts_interfaces/ # Shared TypeScript interfaces
├── ts_idpclient/ # Browser/Node client library
── ts_idpcli/ # Command-line interface tool
└── ts_web/ # Web frontend components`}</pre>
<div className="bg-muted/50 rounded-lg p-4 text-sm">
<pre className="text-muted-foreground overflow-x-auto">{`├── api/ # API server package
├── cli/ # Command-line interface
├── detector/ # Network and port detection
├── interfaces/ # Shared TypeScript interfaces
── webwidget/ # Embeddable status widgets`}</pre>
</div>
</div>
{/* Published packages */}
{/* Supported Services */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">NPM Packages</h2>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left py-2 px-3 font-medium text-foreground">Package</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="py-2 px-3">
<code className="text-primary">@idp.global/interfaces</code>
</td>
<td className="py-2 px-3 text-muted-foreground">TypeScript interfaces for API contracts</td>
</tr>
<tr>
<td className="py-2 px-3">
<code className="text-primary">@idp.global/idpclient</code>
</td>
<td className="py-2 px-3 text-muted-foreground">Client library for browser and Node.js</td>
</tr>
<tr>
<td className="py-2 px-3">
<code className="text-primary">@idp.global/web</code>
</td>
<td className="py-2 px-3 text-muted-foreground">Web UI components</td>
</tr>
</tbody>
</table>
<h2 className="text-2xl font-semibold text-foreground">Supported Services</h2>
<p className="text-muted-foreground">
The detector can automatically identify and monitor these service types:
</p>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3">
{['HTTP/HTTPS', 'SSH', 'FTP', 'SMTP', 'MySQL', 'PostgreSQL', 'MongoDB', 'Redis'].map((service) => (
<div key={service} className="px-3 py-2 rounded-md bg-muted/50 border border-border text-sm text-center">
{service}
</div>
))}
</div>
</div>
{/* CTA */}
<div className="flex flex-wrap gap-4 pt-4">
<Button asChild>
<Button className="bg-emerald-600 hover:bg-emerald-700" asChild>
<Link to="/docs/quick-start">
Get Started
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button variant="outline" asChild>
<a href="https://idp.global">Try Free Platform</a>
<a href="https://uptime.link">Try Dashboard</a>
</Button>
</div>
</div>

View File

@@ -1,224 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { ArrowRight, ArrowLeft } from 'lucide-react';
const CodeBlock = ({ children, title }: { children: string; title?: string }) => (
<div className="rounded-lg border border-border overflow-hidden">
{title && (
<div className="px-4 py-2 bg-muted/50 border-b border-border text-xs font-medium text-muted-foreground">
{title}
</div>
)}
<pre className="p-4 overflow-x-auto bg-muted/30">
<code className="text-sm font-mono text-foreground">{children}</code>
</pre>
</div>
);
const OIDC = () => {
return (
<div className="space-y-8">
{/* Header */}
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">
OIDC / OAuth 2.0
</h1>
<p className="text-xl text-muted-foreground leading-relaxed">
idp.global implements a full OpenID Connect provider. Use it for SSO across
your applications with standard OAuth 2.0 flows.
</p>
</div>
{/* Discovery */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Discovery Document</h2>
<p className="text-muted-foreground">
The OIDC discovery endpoint provides all configuration information:
</p>
<CodeBlock title="Request">
{`GET https://idp.global/.well-known/openid-configuration`}
</CodeBlock>
<CodeBlock title="Response">
{`{
"issuer": "https://idp.global",
"authorization_endpoint": "https://idp.global/oauth/authorize",
"token_endpoint": "https://idp.global/oauth/token",
"userinfo_endpoint": "https://idp.global/oauth/userinfo",
"jwks_uri": "https://idp.global/.well-known/jwks.json",
"revocation_endpoint": "https://idp.global/oauth/revoke",
"scopes_supported": ["openid", "profile", "email", "organizations", "roles"],
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"code_challenge_methods_supported": ["S256"]
}`}
</CodeBlock>
</div>
{/* Register Your App */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Register Your Application</h2>
<p className="text-muted-foreground">
Before integrating, register your application in the idp.global dashboard to get:
</p>
<ul className="list-disc list-inside text-muted-foreground space-y-1 ml-2">
<li><strong>Client ID</strong> - Your application's public identifier</li>
<li><strong>Client Secret</strong> - Keep this secure, used for token exchange</li>
<li><strong>Redirect URIs</strong> - Allowed callback URLs after authentication</li>
</ul>
</div>
{/* Authorization Code Flow */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Authorization Code Flow (with PKCE)</h2>
<p className="text-muted-foreground">
The recommended flow for web and mobile applications.
</p>
<h3 className="text-lg font-medium text-foreground">Step 1: Generate PKCE Challenge</h3>
<CodeBlock title="JavaScript">
{`// Generate code verifier (random string)
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return btoa(String.fromCharCode(...array))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
// Generate code challenge from verifier
async function generateCodeChallenge(verifier) {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const hash = await crypto.subtle.digest('SHA-256', data);
return btoa(String.fromCharCode(...new Uint8Array(hash)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);
// Store codeVerifier for later use`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Step 2: Redirect to Authorization</h3>
<CodeBlock title="URL">
{`https://idp.global/oauth/authorize?
client_id=your-client-id&
redirect_uri=https://yourapp.com/callback&
response_type=code&
scope=openid profile email organizations&
state=random-state-value&
code_challenge=YOUR_CODE_CHALLENGE&
code_challenge_method=S256`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Step 3: Handle Callback</h3>
<p className="text-muted-foreground">
After user authenticates, they're redirected to your callback URL with an authorization code:
</p>
<CodeBlock title="Callback URL">
{`https://yourapp.com/callback?code=AUTHORIZATION_CODE&state=random-state-value`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Step 4: Exchange Code for Tokens</h3>
<CodeBlock title="Request">
{`POST https://idp.global/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=https://yourapp.com/callback&
client_id=your-client-id&
client_secret=your-client-secret&
code_verifier=YOUR_CODE_VERIFIER`}
</CodeBlock>
<CodeBlock title="Response">
{`{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}`}
</CodeBlock>
</div>
{/* UserInfo */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">UserInfo Endpoint</h2>
<p className="text-muted-foreground">
Retrieve user information using the access token:
</p>
<CodeBlock title="Request">
{`GET https://idp.global/oauth/userinfo
Authorization: Bearer ACCESS_TOKEN`}
</CodeBlock>
<CodeBlock title="Response">
{`{
"sub": "user-uuid-here",
"name": "John Doe",
"email": "john@example.com",
"email_verified": true,
"organizations": [
{
"id": "org-uuid",
"name": "Acme Corp",
"slug": "acme",
"roles": ["admin", "member"]
}
],
"roles": ["user"]
}`}
</CodeBlock>
</div>
{/* Token Refresh */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Refresh Tokens</h2>
<CodeBlock title="Request">
{`POST https://idp.global/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&
refresh_token=YOUR_REFRESH_TOKEN&
client_id=your-client-id&
client_secret=your-client-secret`}
</CodeBlock>
</div>
{/* Token Revocation */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Token Revocation</h2>
<CodeBlock title="Request">
{`POST https://idp.global/oauth/revoke
Content-Type: application/x-www-form-urlencoded
token=TOKEN_TO_REVOKE&
client_id=your-client-id&
client_secret=your-client-secret`}
</CodeBlock>
</div>
{/* Navigation */}
<div className="flex justify-between pt-8 border-t border-border">
<Button variant="ghost" asChild>
<Link to="/docs/sdk">
<ArrowLeft className="mr-2 h-4 w-4" />
TypeScript SDK
</Link>
</Button>
<Button variant="ghost" asChild>
<Link to="/docs/organizations">
Organizations
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
);
};
export default OIDC;

View File

@@ -1,233 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { ArrowRight, ArrowLeft } from 'lucide-react';
const CodeBlock = ({ children, title }: { children: string; title?: string }) => (
<div className="rounded-lg border border-border overflow-hidden">
{title && (
<div className="px-4 py-2 bg-muted/50 border-b border-border text-xs font-medium text-muted-foreground">
{title}
</div>
)}
<pre className="p-4 overflow-x-auto bg-muted/30">
<code className="text-sm font-mono text-foreground">{children}</code>
</pre>
</div>
);
const Organizations = () => {
return (
<div className="space-y-8">
{/* Header */}
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">
Organizations
</h1>
<p className="text-xl text-muted-foreground leading-relaxed">
idp.global supports multi-tenant architecture with organizations. Users can belong to
multiple organizations with different roles in each.
</p>
</div>
{/* Concepts */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Key Concepts</h2>
<div className="grid sm:grid-cols-2 gap-4">
<div className="p-4 rounded-lg border border-border bg-card">
<h3 className="font-medium text-foreground mb-1">Organization</h3>
<p className="text-sm text-muted-foreground">
A container for users, roles, and applications. Typically represents a company, team, or project.
</p>
</div>
<div className="p-4 rounded-lg border border-border bg-card">
<h3 className="font-medium text-foreground mb-1">Member</h3>
<p className="text-sm text-muted-foreground">
A user who belongs to an organization. Members can have one or more roles.
</p>
</div>
<div className="p-4 rounded-lg border border-border bg-card">
<h3 className="font-medium text-foreground mb-1">Role</h3>
<p className="text-sm text-muted-foreground">
Defines permissions within an organization. Built-in roles include admin and member.
</p>
</div>
<div className="p-4 rounded-lg border border-border bg-card">
<h3 className="font-medium text-foreground mb-1">Owner</h3>
<p className="text-sm text-muted-foreground">
The user who created the organization. Has full control and can transfer ownership.
</p>
</div>
</div>
</div>
{/* Creating Organizations */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Creating Organizations</h2>
<CodeBlock title="TypeScript">
{`import { IdpClient } from '@idp.global/idpclient';
const idpClient = new IdpClient('https://idp.global');
// Create a new organization
const result = await idpClient.createOrganization(
'Acme Corporation', // Display name
'acme-corp', // URL-friendly slug (must be unique)
'manifest' // Organization type
);
if (result.resultingOrganization) {
console.log('Created:', result.resultingOrganization.id);
console.log('Slug:', result.resultingOrganization.slug);
}`}
</CodeBlock>
</div>
{/* Member Management */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Member Management</h2>
<h3 className="text-lg font-medium text-foreground">Invite Members</h3>
<CodeBlock title="TypeScript">
{`// Send invitation email to new member
await idpClient.requests.createInvitation.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-uuid',
email: 'newmember@example.com',
roles: ['member'] // Roles to assign
});
// Invite as admin
await idpClient.requests.createInvitation.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-uuid',
email: 'admin@example.com',
roles: ['admin', 'member']
});`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">List Members</h3>
<CodeBlock title="TypeScript">
{`const members = await idpClient.requests.getOrgMembers.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-uuid'
});
for (const member of members.members) {
console.log(member.user.email, member.roles);
}`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Update Member Roles</h3>
<CodeBlock title="TypeScript">
{`await idpClient.requests.updateMemberRoles.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-uuid',
userId: 'user-uuid',
roles: ['admin', 'member']
});`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Remove Members</h3>
<CodeBlock title="TypeScript">
{`await idpClient.requests.removeMember.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-uuid',
userId: 'user-uuid'
});`}
</CodeBlock>
</div>
{/* Role-Based Access */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Built-in Roles</h2>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left py-2 px-3 font-medium text-foreground">Role</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Permissions</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="py-2 px-3"><code className="text-primary">admin</code></td>
<td className="py-2 px-3 text-muted-foreground">
Full organization management: invite/remove members, manage roles, update settings, register apps
</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-primary">member</code></td>
<td className="py-2 px-3 text-muted-foreground">
Basic access: view organization, access approved applications
</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Ownership Transfer */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Ownership Transfer</h2>
<p className="text-muted-foreground">
Organization owners can transfer ownership to another admin member:
</p>
<CodeBlock title="TypeScript">
{`await idpClient.requests.transferOwnership.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-uuid',
newOwnerId: 'new-owner-user-uuid'
});`}
</CodeBlock>
</div>
{/* Organizations in JWT */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Organizations in JWT Claims</h2>
<p className="text-muted-foreground">
When requesting the <code className="text-primary">organizations</code> scope, the user's organizations
are included in the ID token and userinfo response:
</p>
<CodeBlock title="JWT Payload">
{`{
"sub": "user-uuid",
"email": "user@example.com",
"organizations": [
{
"id": "org-uuid-1",
"name": "Acme Corp",
"slug": "acme",
"roles": ["admin", "member"]
},
{
"id": "org-uuid-2",
"name": "Other Org",
"slug": "other",
"roles": ["member"]
}
]
}`}
</CodeBlock>
</div>
{/* Navigation */}
<div className="flex justify-between pt-8 border-t border-border">
<Button variant="ghost" asChild>
<Link to="/docs/oidc">
<ArrowLeft className="mr-2 h-4 w-4" />
OIDC / OAuth 2.0
</Link>
</Button>
<Button variant="ghost" asChild>
<Link to="/docs/users">
User Management
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
);
};
export default Organizations;

View File

@@ -1,179 +1,137 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { ArrowRight, ArrowLeft, ExternalLink } from 'lucide-react';
const CodeBlock = ({ children, title }: { children: string; title?: string }) => (
<div className="rounded-lg border border-border overflow-hidden">
{title && (
<div className="px-4 py-2 bg-muted/50 border-b border-border text-xs font-medium text-muted-foreground">
{title}
</div>
)}
<pre className="p-4 overflow-x-auto bg-muted/30">
<code className="text-sm font-mono text-foreground">{children}</code>
</pre>
</div>
);
import { ArrowRight, CheckCircle2 } from 'lucide-react';
const QuickStart = () => {
return (
<div className="space-y-8">
{/* Header */}
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">
Quick Start
</h1>
<p className="text-xl text-muted-foreground leading-relaxed">
Get started with idp.global in under 5 minutes. Choose between using our
free hosted platform or self-hosting with Docker.
<h1 className="text-4xl font-bold tracking-tight text-foreground">Quick Start</h1>
<p className="text-xl text-muted-foreground">
Get uptime.link running and monitoring your first endpoint in under 5 minutes.
</p>
</div>
{/* Option 1: Hosted Platform */}
{/* Prerequisites */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Option 1: Use Free Hosted Platform</h2>
<p className="text-muted-foreground">
The fastest way to get started. Create your free account on idp.global and start using
it immediately. No installation required.
</p>
<div className="space-y-3">
<div className="flex items-start gap-3">
<span className="flex items-center justify-center w-6 h-6 rounded-full bg-primary text-primary-foreground text-xs font-bold shrink-0">1</span>
<div>
<p className="font-medium text-foreground">Create your account</p>
<p className="text-sm text-muted-foreground">
Visit <a href="https://idp.global" className="text-primary hover:underline">idp.global</a> and sign up for a free account.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<span className="flex items-center justify-center w-6 h-6 rounded-full bg-primary text-primary-foreground text-xs font-bold shrink-0">2</span>
<div>
<p className="font-medium text-foreground">Create an organization</p>
<p className="text-sm text-muted-foreground">
Set up your first organization and invite team members.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<span className="flex items-center justify-center w-6 h-6 rounded-full bg-primary text-primary-foreground text-xs font-bold shrink-0">3</span>
<div>
<p className="font-medium text-foreground">Register your application</p>
<p className="text-sm text-muted-foreground">
Create an OAuth/OIDC client for your app and get your credentials.
</p>
</div>
</div>
</div>
<Button asChild>
<a href="https://idp.global">
Get Started Free
<ExternalLink className="ml-2 h-4 w-4" />
</a>
</Button>
</div>
{/* Option 2: Self-Host */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Option 2: Self-Host with Docker</h2>
<p className="text-muted-foreground">
Deploy your own instance for complete control over your data and infrastructure.
</p>
<h3 className="text-lg font-medium text-foreground">Prerequisites</h3>
<ul className="list-disc list-inside text-muted-foreground space-y-1 ml-2">
<li>Docker installed on your server</li>
<li>MongoDB instance (local or cloud)</li>
<li>A domain name pointing to your server</li>
<h2 className="text-2xl font-semibold text-foreground">Prerequisites</h2>
<ul className="space-y-2">
{['Node.js 18+ or Docker', 'npm or pnpm package manager'].map((item) => (
<li key={item} className="flex items-center gap-2 text-muted-foreground">
<CheckCircle2 className="h-4 w-4 text-emerald-500" />
{item}
</li>
))}
</ul>
<h3 className="text-lg font-medium text-foreground">1. Pull the Docker image</h3>
<CodeBlock title="Terminal">
{`docker pull code.foss.global/idp.global/idp.global`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">2. Run the container</h3>
<CodeBlock title="Terminal">
{`docker run -d \\
-p 2999:2999 \\
-e MONGODB_URL=mongodb://your-mongo:27017/idp \\
-e IDP_BASEURL=https://your-domain.com \\
-e INSTANCE_NAME=my-idp \\
code.foss.global/idp.global/idp.global`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">3. Access your instance</h3>
<p className="text-muted-foreground">
Your idp.global instance is now running on port 2999. Configure your reverse proxy
(nginx, traefik, etc.) to handle HTTPS and route traffic to the container.
</p>
<Button variant="outline" asChild>
<Link to="/docs/docker">
Full Docker Guide
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
{/* Integrate with your app */}
{/* Step 1 */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Integrate with Your Application</h2>
<h2 className="text-2xl font-semibold text-foreground">1. Install the CLI</h2>
<p className="text-muted-foreground">
Once you have access to an idp.global instance, install the TypeScript client:
Install the uptime.link CLI globally using npm or pnpm:
</p>
<CodeBlock title="Terminal">
{`npm install @idp.global/idpclient`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Basic Usage</h3>
<CodeBlock title="app.ts">
{`import { IdpClient } from '@idp.global/idpclient';
// Initialize the client
const idpClient = new IdpClient('https://idp.global');
// Enable WebSocket connection for real-time updates
await idpClient.enableTypedSocket();
// Check if user is logged in
const isLoggedIn = await idpClient.determineLoginStatus();
if (isLoggedIn) {
// Get current user info
const userInfo = await idpClient.whoIs();
console.log('User:', userInfo.user);
// Get user's organizations
const orgs = await idpClient.getRolesAndOrganizations();
console.log('Organizations:', orgs.organizations);
}`}
</CodeBlock>
<Button variant="outline" asChild>
<Link to="/docs/sdk">
Full SDK Documentation
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<div className="bg-muted/50 rounded-lg p-4">
<code className="text-sm text-foreground">npm install -g @uptime.link/cli</code>
</div>
<p className="text-sm text-muted-foreground">
Or with pnpm:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<code className="text-sm text-foreground">pnpm add -g @uptime.link/cli</code>
</div>
</div>
{/* Navigation */}
<div className="flex justify-between pt-8 border-t border-border">
<Button variant="ghost" asChild>
<Link to="/docs">
<ArrowLeft className="mr-2 h-4 w-4" />
Introduction
</Link>
</Button>
<Button variant="ghost" asChild>
<Link to="/docs/docker">
Docker Deployment
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
{/* Step 2 */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">2. Scan Your Network</h2>
<p className="text-muted-foreground">
Run the detector to discover services on your local network:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<code className="text-sm text-foreground">uptime scan</code>
</div>
<p className="text-sm text-muted-foreground">
This will scan common ports and detect running services like HTTP servers, databases, and more.
</p>
</div>
{/* Step 3 */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">3. Add a Monitor</h2>
<p className="text-muted-foreground">
Add an endpoint to monitor:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`uptime add https://api.example.com --interval 60`}</pre>
</div>
<p className="text-sm text-muted-foreground">
This adds the endpoint to your monitoring list with 60-second check intervals.
</p>
</div>
{/* Step 4 */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">4. View Status</h2>
<p className="text-muted-foreground">
Check the status of all monitored endpoints:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<code className="text-sm text-foreground">uptime status</code>
</div>
<p className="text-sm text-muted-foreground">
You'll see a table with the current status, response time, and uptime percentage for each endpoint.
</p>
</div>
{/* Using the SDK */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Using the SDK</h2>
<p className="text-muted-foreground">
For programmatic access, install the TypeScript SDK:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<code className="text-sm text-foreground">npm install @uptime.link/sdk</code>
</div>
<div className="bg-muted/50 rounded-lg p-4 mt-4">
<pre className="text-sm text-foreground overflow-x-auto">{`import { UptimeClient } from '@uptime.link/sdk';
const client = new UptimeClient();
// Check a single endpoint
const result = await client.check('https://api.example.com');
console.log(result.status, result.responseTime);
// Scan local network
const services = await client.scanNetwork();
console.log('Found services:', services);`}</pre>
</div>
</div>
{/* Next steps */}
<div className="space-y-4 pt-4 border-t border-border">
<h2 className="text-xl font-semibold text-foreground">Next Steps</h2>
<div className="flex flex-wrap gap-3">
<Button variant="outline" asChild>
<Link to="/docs/cli">
CLI Reference
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button variant="outline" asChild>
<Link to="/docs/widgets">
Status Widgets
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button variant="outline" asChild>
<Link to="/docs/detector">
Network Detector
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
</div>
);

View File

@@ -1,216 +1,189 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { ArrowRight, ArrowLeft } from 'lucide-react';
const CodeBlock = ({ children, title }: { children: string; title?: string }) => (
<div className="rounded-lg border border-border overflow-hidden">
{title && (
<div className="px-4 py-2 bg-muted/50 border-b border-border text-xs font-medium text-muted-foreground">
{title}
</div>
)}
<pre className="p-4 overflow-x-auto bg-muted/30">
<code className="text-sm font-mono text-foreground">{children}</code>
</pre>
</div>
);
import { ArrowRight } from 'lucide-react';
const SDK = () => {
return (
<div className="space-y-8">
{/* Header */}
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">
TypeScript SDK
</h1>
<p className="text-xl text-muted-foreground leading-relaxed">
The official TypeScript client library for idp.global. Works in both browser and Node.js
environments with full type safety.
<h1 className="text-4xl font-bold tracking-tight text-foreground">TypeScript SDK</h1>
<p className="text-xl text-muted-foreground">
Programmatic access to uptime.link monitoring features with full TypeScript support.
</p>
</div>
{/* Installation */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Installation</h2>
<CodeBlock title="Terminal">
{`npm install @idp.global/idpclient
# or with pnpm
pnpm add @idp.global/idpclient
# or with yarn
yarn add @idp.global/idpclient`}
</CodeBlock>
<div className="bg-muted/50 rounded-lg p-4">
<code className="text-sm text-foreground">npm install @uptime.link/sdk</code>
</div>
</div>
{/* Initialization */}
{/* Basic Usage */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Initialization</h2>
<CodeBlock title="client.ts">
{`import { IdpClient } from '@idp.global/idpclient';
<h2 className="text-2xl font-semibold text-foreground">Basic Usage</h2>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`import { UptimeClient } from '@uptime.link/sdk';
// Connect to the hosted platform
const idpClient = new IdpClient('https://idp.global');
// Or connect to your self-hosted instance
const idpClient = new IdpClient('https://idp.yourdomain.com');
// Enable WebSocket for real-time updates
await idpClient.enableTypedSocket();`}
</CodeBlock>
</div>
{/* Authentication */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Authentication</h2>
<h3 className="text-lg font-medium text-foreground">Check Login Status</h3>
<CodeBlock title="auth.ts">
{`// Check if user is currently logged in
const isLoggedIn = await idpClient.determineLoginStatus();
if (isLoggedIn) {
console.log('User is authenticated');
}`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Login with Email & Password</h3>
<CodeBlock title="auth.ts">
{`const response = await idpClient.requests.loginWithUserNameAndPassword.fire({
username: 'user@example.com',
password: 'securepassword'
// Initialize the client
const client = new UptimeClient({
apiKey: process.env.UPTIME_API_KEY, // Optional for cloud sync
});
if (response.refreshToken) {
// Store the refresh token securely
await idpClient.refreshJwt(response.refreshToken);
console.log('Login successful!');
} else if (response.error) {
console.error('Login failed:', response.error);
}`}
</CodeBlock>
// Check an endpoint
const result = await client.check('https://api.example.com');
<h3 className="text-lg font-medium text-foreground">Login with Magic Link</h3>
<CodeBlock title="auth.ts">
{`// Request magic link email
await idpClient.requests.loginWithEmail.fire({
email: 'user@example.com'
console.log({
url: result.url,
status: result.status, // 'up' | 'down'
statusCode: result.statusCode, // 200
responseTime: result.responseTime, // 123 (ms)
timestamp: result.timestamp
});`}</pre>
</div>
</div>
{/* Network Scanning */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Network Scanning</h2>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`import { Detector } from '@uptime.link/sdk';
const detector = new Detector();
// Scan local network for services
const services = await detector.scan({
range: '192.168.1.0/24',
ports: [80, 443, 22, 3306, 5432],
timeout: 2000
});
// User clicks link in email, which contains a token
// Your callback page handles the token:
await idpClient.requests.verifyMagicLink.fire({
token: tokenFromUrl
});`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Get Current User</h3>
<CodeBlock title="user.ts">
{`// Get current user information
const userInfo = await idpClient.whoIs();
console.log('User ID:', userInfo.user.id);
console.log('Email:', userInfo.user.email);
console.log('Name:', userInfo.user.name);`}
</CodeBlock>
for (const service of services) {
console.log({
host: service.host,
port: service.port,
type: service.type, // 'http' | 'ssh' | 'mysql' | etc.
open: service.open
});
}`}</pre>
</div>
</div>
{/* Organizations */}
{/* Continuous Monitoring */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Organizations</h2>
<h2 className="text-2xl font-semibold text-foreground">Continuous Monitoring</h2>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`import { Monitor } from '@uptime.link/sdk';
<h3 className="text-lg font-medium text-foreground">Get User's Organizations</h3>
<CodeBlock title="organizations.ts">
{`const result = await idpClient.getRolesAndOrganizations();
const monitor = new Monitor({
endpoints: [
{ url: 'https://api.example.com', interval: 30 },
{ url: 'https://app.example.com', interval: 60 }
]
});
for (const org of result.organizations) {
console.log('Organization:', org.name);
console.log('Slug:', org.slug);
console.log('Your roles:', org.roles);
}`}
</CodeBlock>
// Listen for status changes
monitor.on('statusChange', (event) => {
console.log(\`\${event.url} is now \${event.status}\`);
<h3 className="text-lg font-medium text-foreground">Create Organization</h3>
<CodeBlock title="organizations.ts">
{`const result = await idpClient.createOrganization(
'My Company', // Display name
'my-company', // URL slug
'manifest' // Type
);
console.log('Created:', result.resultingOrganization);`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Invite Members</h3>
<CodeBlock title="organizations.ts">
{`await idpClient.requests.createInvitation.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-id',
email: 'newmember@example.com',
roles: ['member']
});`}
</CodeBlock>
</div>
{/* JWT Handling */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">JWT Handling</h2>
<CodeBlock title="jwt.ts">
{`// Get current JWT for API calls
const jwt = await idpClient.getJwt();
// Use in Authorization header
fetch('/api/protected', {
headers: {
'Authorization': \`Bearer \${jwt}\`
if (event.status === 'down') {
// Trigger alert
sendAlert(event);
}
});
// Refresh JWT with refresh token
await idpClient.refreshJwt(refreshToken);
// Start monitoring
monitor.start();
// Logout (clears tokens)
await idpClient.logout();`}
</CodeBlock>
// Stop when done
// monitor.stop();`}</pre>
</div>
</div>
{/* TypeScript Interfaces */}
{/* API Reference */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">TypeScript Interfaces</h2>
<p className="text-muted-foreground">
All API types are available from <code className="text-primary">@idp.global/interfaces</code>:
</p>
<CodeBlock title="types.ts">
{`import type {
IUser,
IOrganization,
IRole,
IJwt,
IApp
} from '@idp.global/interfaces';
<h2 className="text-2xl font-semibold text-foreground">API Reference</h2>
// Use in your application
function handleUser(user: IUser) {
console.log(user.email);
}`}
</CodeBlock>
<div className="space-y-6">
<div className="space-y-2">
<h3 className="text-lg font-medium text-foreground">UptimeClient</h3>
<p className="text-sm text-muted-foreground">Main client for endpoint checks.</p>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left py-2 px-3 font-medium text-foreground">Method</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">check(url)</code></td>
<td className="py-2 px-3 text-muted-foreground">Check a single endpoint</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">checkMany(urls)</code></td>
<td className="py-2 px-3 text-muted-foreground">Check multiple endpoints in parallel</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">getHistory(url)</code></td>
<td className="py-2 px-3 text-muted-foreground">Get check history for an endpoint</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="space-y-2">
<h3 className="text-lg font-medium text-foreground">Detector</h3>
<p className="text-sm text-muted-foreground">Network and service detection.</p>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left py-2 px-3 font-medium text-foreground">Method</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">scan(options)</code></td>
<td className="py-2 px-3 text-muted-foreground">Scan network for services</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">checkPort(host, port)</code></td>
<td className="py-2 px-3 text-muted-foreground">Check if a port is open</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">identifyService(host, port)</code></td>
<td className="py-2 px-3 text-muted-foreground">Identify service type</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* Navigation */}
<div className="flex justify-between pt-8 border-t border-border">
<Button variant="ghost" asChild>
<Link to="/docs/configuration">
<ArrowLeft className="mr-2 h-4 w-4" />
Configuration
</Link>
</Button>
<Button variant="ghost" asChild>
<Link to="/docs/oidc">
OIDC / OAuth 2.0
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
{/* Next steps */}
<div className="space-y-4 pt-4 border-t border-border">
<h2 className="text-xl font-semibold text-foreground">Next Steps</h2>
<div className="flex flex-wrap gap-3">
<Button variant="outline" asChild>
<Link to="/docs/widgets">
Status Widgets
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button variant="outline" asChild>
<Link to="/docs/detector">
Network Detector
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
</div>
);

View File

@@ -1,253 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { ArrowLeft, ExternalLink } from 'lucide-react';
const CodeBlock = ({ children, title }: { children: string; title?: string }) => (
<div className="rounded-lg border border-border overflow-hidden">
{title && (
<div className="px-4 py-2 bg-muted/50 border-b border-border text-xs font-medium text-muted-foreground">
{title}
</div>
)}
<pre className="p-4 overflow-x-auto bg-muted/30">
<code className="text-sm font-mono text-foreground">{children}</code>
</pre>
</div>
);
const Users = () => {
return (
<div className="space-y-8">
{/* Header */}
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">
User Management
</h1>
<p className="text-xl text-muted-foreground leading-relaxed">
Complete user lifecycle management from registration to profile updates,
with multiple authentication methods and security features.
</p>
</div>
{/* Authentication Methods */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Authentication Methods</h2>
<div className="grid sm:grid-cols-2 gap-4">
<div className="p-4 rounded-lg border border-border bg-card">
<h3 className="font-medium text-foreground mb-1">Email & Password</h3>
<p className="text-sm text-muted-foreground">
Traditional authentication with secure password hashing and optional 2FA.
</p>
</div>
<div className="p-4 rounded-lg border border-border bg-card">
<h3 className="font-medium text-foreground mb-1">Magic Links</h3>
<p className="text-sm text-muted-foreground">
Passwordless authentication via email. Secure, time-limited tokens.
</p>
</div>
<div className="p-4 rounded-lg border border-border bg-card">
<h3 className="font-medium text-foreground mb-1">API Tokens</h3>
<p className="text-sm text-muted-foreground">
Long-lived tokens for programmatic access and CI/CD pipelines.
</p>
</div>
<div className="p-4 rounded-lg border border-border bg-card">
<h3 className="font-medium text-foreground mb-1">OAuth / OIDC</h3>
<p className="text-sm text-muted-foreground">
SSO via third-party applications using standard protocols.
</p>
</div>
</div>
</div>
{/* Registration */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">User Registration</h2>
<CodeBlock title="TypeScript">
{`import { IdpClient } from '@idp.global/idpclient';
const idpClient = new IdpClient('https://idp.global');
// Start registration - sends verification email
const result = await idpClient.requests.firstRegistration.fire({
email: 'newuser@example.com'
});
if (result.success) {
console.log('Verification email sent');
}
// User clicks verification link, then completes registration
await idpClient.requests.finishRegistration.fire({
token: verificationTokenFromEmail,
password: 'securePassword123',
name: 'John Doe'
});`}
</CodeBlock>
</div>
{/* Profile Management */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Profile Management</h2>
<h3 className="text-lg font-medium text-foreground">Get User Data</h3>
<CodeBlock title="TypeScript">
{`const userData = await idpClient.requests.getUserData.fire({
jwt: await idpClient.getJwt()
});
console.log('Name:', userData.user.name);
console.log('Email:', userData.user.email);
console.log('Created:', userData.user.createdAt);`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Update Profile</h3>
<CodeBlock title="TypeScript">
{`await idpClient.requests.setUserData.fire({
jwt: await idpClient.getJwt(),
name: 'John Updated',
// Other profile fields as needed
});`}
</CodeBlock>
</div>
{/* Password Management */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Password Management</h2>
<h3 className="text-lg font-medium text-foreground">Change Password</h3>
<CodeBlock title="TypeScript">
{`await idpClient.requests.changePassword.fire({
jwt: await idpClient.getJwt(),
currentPassword: 'oldPassword',
newPassword: 'newSecurePassword'
});`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Password Reset Flow</h3>
<CodeBlock title="TypeScript">
{`// Request password reset email
await idpClient.requests.requestPasswordReset.fire({
email: 'user@example.com'
});
// User clicks reset link, then sets new password
await idpClient.requests.resetPassword.fire({
token: resetTokenFromEmail,
newPassword: 'newSecurePassword'
});`}
</CodeBlock>
</div>
{/* Session Management */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Session Management</h2>
<h3 className="text-lg font-medium text-foreground">List Active Sessions</h3>
<CodeBlock title="TypeScript">
{`const sessions = await idpClient.requests.getUserSessions.fire({
jwt: await idpClient.getJwt()
});
for (const session of sessions.sessions) {
console.log('Device:', session.userAgent);
console.log('Last active:', session.lastActiveAt);
console.log('IP:', session.ipAddress);
}`}
</CodeBlock>
<h3 className="text-lg font-medium text-foreground">Revoke Session</h3>
<CodeBlock title="TypeScript">
{`// Revoke a specific session
await idpClient.requests.revokeSession.fire({
jwt: await idpClient.getJwt(),
sessionId: 'session-uuid'
});
// Revoke all sessions except current
await idpClient.requests.revokeAllSessions.fire({
jwt: await idpClient.getJwt()
});`}
</CodeBlock>
</div>
{/* Two-Factor Authentication */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Two-Factor Authentication</h2>
<p className="text-muted-foreground">
Users can enable 2FA for enhanced account security:
</p>
<CodeBlock title="TypeScript">
{`// Enable 2FA - returns QR code data for authenticator app
const setup = await idpClient.requests.enable2FA.fire({
jwt: await idpClient.getJwt()
});
console.log('Scan QR code:', setup.qrCodeUrl);
console.log('Or enter manually:', setup.secret);
// Verify and activate 2FA
await idpClient.requests.verify2FA.fire({
jwt: await idpClient.getJwt(),
code: '123456' // Code from authenticator app
});
// Disable 2FA
await idpClient.requests.disable2FA.fire({
jwt: await idpClient.getJwt(),
code: '123456' // Requires valid 2FA code
});`}
</CodeBlock>
</div>
{/* User Data Model */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">User Data Model</h2>
<CodeBlock title="TypeScript Interface">
{`interface IUser {
id: string;
email: string;
emailVerified: boolean;
name: string;
createdAt: string;
updatedAt: string;
twoFactorEnabled: boolean;
// Additional fields based on configuration
}`}
</CodeBlock>
</div>
{/* Help */}
<div className="p-4 rounded-lg border border-border bg-muted/30">
<h3 className="font-medium text-foreground mb-2">Need Help?</h3>
<p className="text-sm text-muted-foreground mb-3">
Join our community for support, discussions, and feature requests.
</p>
<Button variant="outline" size="sm" asChild>
<a href="https://community.foss.global">
Visit Community
<ExternalLink className="ml-2 h-3 w-3" />
</a>
</Button>
</div>
{/* Navigation */}
<div className="flex justify-between pt-8 border-t border-border">
<Button variant="ghost" asChild>
<Link to="/docs/organizations">
<ArrowLeft className="mr-2 h-4 w-4" />
Organizations
</Link>
</Button>
<Button variant="ghost" asChild>
<Link to="/docs">
Back to Overview
</Link>
</Button>
</div>
</div>
);
};
export default Users;

197
src/pages/docs/Widgets.tsx Normal file
View File

@@ -0,0 +1,197 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { ArrowRight } from 'lucide-react';
const Widgets = () => {
return (
<div className="space-y-8">
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight text-foreground">Status Widgets</h1>
<p className="text-xl text-muted-foreground">
Embeddable web components to display real-time uptime status on your website.
</p>
</div>
{/* Quick Start */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Quick Start</h2>
<p className="text-muted-foreground">
Add the status widget to any HTML page with a single script tag:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`<script src="https://cdn.uptime.link/widget.js"></script>
<uptime-status endpoint="https://api.example.com"></uptime-status>`}</pre>
</div>
</div>
{/* Widget Types */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Widget Types</h2>
<div className="space-y-6">
{/* Status Badge */}
<div className="space-y-2">
<h3 className="text-lg font-medium text-foreground">Status Badge</h3>
<p className="text-sm text-muted-foreground">
A compact badge showing current status.
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`<uptime-badge
endpoint="https://api.example.com"
label="API Status"
></uptime-badge>`}</pre>
</div>
</div>
{/* Status Card */}
<div className="space-y-2">
<h3 className="text-lg font-medium text-foreground">Status Card</h3>
<p className="text-sm text-muted-foreground">
A card showing status, uptime percentage, and response time.
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`<uptime-card
endpoint="https://api.example.com"
name="API Server"
show-uptime="true"
show-response-time="true"
></uptime-card>`}</pre>
</div>
</div>
{/* Status Page */}
<div className="space-y-2">
<h3 className="text-lg font-medium text-foreground">Status Page</h3>
<p className="text-sm text-muted-foreground">
A full status page with multiple endpoints.
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`<uptime-page
endpoints='[
{"url": "https://api.example.com", "name": "API"},
{"url": "https://app.example.com", "name": "Web App"},
{"url": "https://db.internal:5432", "name": "Database"}
]'
title="System Status"
></uptime-page>`}</pre>
</div>
</div>
</div>
</div>
{/* Customization */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Customization</h2>
<p className="text-muted-foreground">
Customize the appearance using CSS variables:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`<style>
uptime-card {
--uptime-bg: #1a1a1a;
--uptime-text: #ffffff;
--uptime-up: #10b981;
--uptime-down: #ef4444;
--uptime-border: #333333;
--uptime-radius: 8px;
}
</style>`}</pre>
</div>
</div>
{/* Attributes */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Attributes</h2>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left py-2 px-3 font-medium text-foreground">Attribute</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Type</th>
<th className="text-left py-2 px-3 font-medium text-foreground">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">endpoint</code></td>
<td className="py-2 px-3 text-muted-foreground">string</td>
<td className="py-2 px-3 text-muted-foreground">URL to monitor</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">name</code></td>
<td className="py-2 px-3 text-muted-foreground">string</td>
<td className="py-2 px-3 text-muted-foreground">Display name for the endpoint</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">refresh</code></td>
<td className="py-2 px-3 text-muted-foreground">number</td>
<td className="py-2 px-3 text-muted-foreground">Refresh interval in seconds (default: 60)</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">show-uptime</code></td>
<td className="py-2 px-3 text-muted-foreground">boolean</td>
<td className="py-2 px-3 text-muted-foreground">Show uptime percentage</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">show-response-time</code></td>
<td className="py-2 px-3 text-muted-foreground">boolean</td>
<td className="py-2 px-3 text-muted-foreground">Show response time</td>
</tr>
<tr>
<td className="py-2 px-3"><code className="text-emerald-500">theme</code></td>
<td className="py-2 px-3 text-muted-foreground">"light" | "dark" | "auto"</td>
<td className="py-2 px-3 text-muted-foreground">Color theme</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* React Integration */}
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">React Integration</h2>
<p className="text-muted-foreground">
Use the React wrapper for type-safe integration:
</p>
<div className="bg-muted/50 rounded-lg p-4">
<pre className="text-sm text-foreground overflow-x-auto">{`import { StatusCard, StatusPage } from '@uptime.link/react';
function MyStatusPage() {
return (
<StatusPage
endpoints={[
{ url: 'https://api.example.com', name: 'API' },
{ url: 'https://app.example.com', name: 'Web App' }
]}
title="System Status"
theme="dark"
/>
);
}`}</pre>
</div>
</div>
{/* Next steps */}
<div className="space-y-4 pt-4 border-t border-border">
<h2 className="text-xl font-semibold text-foreground">Next Steps</h2>
<div className="flex flex-wrap gap-3">
<Button variant="outline" asChild>
<Link to="/docs/sdk">
TypeScript SDK
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button variant="outline" asChild>
<Link to="/docs/detector">
Network Detector
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
</div>
);
};
export default Widgets;

View File

@@ -63,13 +63,13 @@ export default {
border: 'hsl(var(--sidebar-border))',
ring: 'hsl(var(--sidebar-ring))'
},
idp: {
blue: '#0056b3',
teal: '#33C3F0',
darkBlue: '#003366',
lightBlue: '#e6f7ff',
uptime: {
green: '#10b981',
emerald: '#34d399',
darkGreen: '#065f46',
lightGreen: '#d1fae5',
gray: '#f5f5f5',
darkGray: '#333333'
darkGray: '#1f2937'
}
},
borderRadius: {
@@ -112,7 +112,7 @@ export default {
'glow-pulse': 'glow-pulse 3s ease-in-out infinite'
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
sans: ['JetBrains Mono', 'monospace'],
mono: ['JetBrains Mono', 'SF Mono', 'Fira Code', 'monospace']
},
boxShadow: {