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:
46
changelog.md
46
changelog.md
@@ -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
|
||||
|
||||
17
index.html
17
index.html
@@ -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>
|
||||
|
||||
@@ -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
593
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
16
src/App.tsx
16
src/App.tsx
@@ -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 */}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
160
src/pages/docs/CLI.tsx
Normal 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;
|
||||
@@ -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
198
src/pages/docs/Detector.tsx
Normal 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;
|
||||
@@ -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;
|
||||
@@ -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"
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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
197
src/pages/docs/Widgets.tsx
Normal 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;
|
||||
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user