Openstatus www.openstatus.dev
at main 243 lines 7.3 kB view raw
1import type { MDXData } from "@/content/utils"; 2import { allPlans } from "@openstatus/db/src/schema/plan/config"; 3import type { Metadata } from "next"; 4import type { 5 BlogPosting, 6 BreadcrumbList, 7 FAQPage, 8 Organization, 9 Product, 10 WebPage, 11 WithContext, 12} from "schema-dts"; 13 14export const TITLE = "openstatus"; 15export const HOMEPAGE_TITLE = 16 "OpenStatus - Open-Source Status Page & Uptime Monitoring"; 17export const DESCRIPTION = 18 "Monitor your services globally and showcase your uptime with a status page. Get started for free with our open-source status page with uptime monitoring solution."; 19 20export const OG_DESCRIPTION = 21 "Open-source status page and uptime monitoring system"; 22 23export const BASE_URL = 24 process.env.NODE_ENV === "production" 25 ? "https://www.openstatus.dev" 26 : "http://localhost:3000"; 27 28export const twitterMetadata: Metadata["twitter"] = { 29 title: TITLE, 30 description: DESCRIPTION, 31 card: "summary_large_image", 32 images: ["/api/og"], 33}; 34 35export const ogMetadata: Metadata["openGraph"] = { 36 title: TITLE, 37 description: DESCRIPTION, 38 type: "website", 39 images: ["/api/og"], 40}; 41 42export const defaultMetadata: Metadata = { 43 title: { 44 template: `%s | ${TITLE}`, 45 default: HOMEPAGE_TITLE, 46 }, 47 description: DESCRIPTION, 48 metadataBase: new URL(BASE_URL), 49 alternates: { 50 canonical: "/", 51 }, 52 twitter: twitterMetadata, 53 openGraph: ogMetadata, 54}; 55 56export const getPageMetadata = (page: MDXData, basePath?: string): Metadata => { 57 const { slug, metadata } = page; 58 const { title, description, category, publishedAt } = metadata; 59 60 const ogImage = `${BASE_URL}/api/og?title=${encodeURIComponent( 61 title, 62 )}&description=${encodeURIComponent( 63 description, 64 )}&category=${encodeURIComponent(category)}`; 65 66 const url = basePath 67 ? `${BASE_URL}/${basePath}/${slug}` 68 : `${BASE_URL}/${slug}`; 69 70 return { 71 title, 72 description, 73 alternates: { 74 canonical: url, 75 }, 76 openGraph: { 77 title, 78 description, 79 type: "article", 80 publishedTime: publishedAt.toISOString(), 81 url, 82 images: [ 83 { 84 url: ogImage, 85 }, 86 ], 87 }, 88 twitter: { 89 card: "summary_large_image", 90 title, 91 description, 92 images: [ogImage], 93 }, 94 }; 95}; 96 97export const getJsonLDWebPage = (page: MDXData): WithContext<WebPage> => { 98 return { 99 "@context": "https://schema.org", 100 "@type": "WebPage", 101 name: `${page.metadata.title} | openstatus`, 102 headline: page.metadata.description, 103 mainEntityOfPage: { 104 "@type": "WebPage", 105 "@id": "https://www.openstatus.dev", 106 }, 107 }; 108}; 109 110export const getJsonLDBlogPosting = ( 111 post: MDXData, 112 basePath: string, 113): WithContext<BlogPosting> => { 114 return { 115 "@context": "https://schema.org", 116 "@type": "BlogPosting", 117 headline: post.metadata.title, 118 datePublished: post.metadata.publishedAt.toISOString(), 119 dateModified: post.metadata.publishedAt.toISOString(), 120 description: post.metadata.description, 121 image: post.metadata.image 122 ? `${BASE_URL}${post.metadata.image}` 123 : `/api/og?title=${encodeURIComponent( 124 post.metadata.title, 125 )}&description=${encodeURIComponent( 126 post.metadata.description, 127 )}&category=${encodeURIComponent(post.metadata.category)}`, 128 url: `${BASE_URL}/${basePath}/${post.slug}`, 129 author: { 130 "@type": "Person", 131 name: post.metadata.author, 132 }, 133 }; 134}; 135 136export const getJsonLDOrganization = (): WithContext<Organization> => { 137 return { 138 "@context": "https://schema.org", 139 "@type": "Organization", 140 name: "openstatus", 141 url: "https://openstatus.dev", 142 logo: "https://openstatus.dev/assets/logos/OpenStatus-Logo.svg", 143 sameAs: [ 144 "https://github.com/openstatushq", 145 "https://linkedin.com/company/openstatus", 146 "https://bsky.app/profile/openstatus.dev", 147 "https://x.com/openstatushq", 148 ], 149 contactPoint: [ 150 { 151 "@type": "ContactPoint", 152 contactType: "Support", 153 email: "ping@openstatus.dev", 154 }, 155 ], 156 }; 157}; 158 159export const getJsonLDProduct = (): WithContext<Product> => { 160 return { 161 "@context": "https://schema.org", 162 "@type": "Product", 163 name: "openstatus", 164 description: 165 "Open-source uptime and synthetic monitoring with status pages.", 166 brand: { 167 "@type": "Brand", 168 name: "openstatus", 169 logo: "https://openstatus.dev/assets/logos/OpenStatus-Logo.svg", 170 }, 171 offers: Object.entries(allPlans).map(([_, value]) => ({ 172 "@type": "Offer", 173 price: value.price.USD, 174 name: value.title, 175 priceCurrency: "USD", 176 availability: "https://schema.org/InStock", 177 })), 178 }; 179}; 180 181export const getJsonLDBreadcrumbList = ( 182 items: { name: string; url: string }[], 183): WithContext<BreadcrumbList> => { 184 return { 185 "@context": "https://schema.org", 186 "@type": "BreadcrumbList", 187 itemListElement: items.map((item, index) => ({ 188 "@type": "ListItem", 189 position: index + 1, 190 name: item.name, 191 item: item.url, 192 })), 193 }; 194}; 195 196export const getJsonLDFAQPage = (): WithContext<FAQPage> => { 197 return { 198 "@context": "https://schema.org", 199 "@type": "FAQPage", 200 mainEntity: [ 201 { 202 "@type": "Question", 203 name: "What are the free limits?", 204 acceptedAnswer: { 205 "@type": "Answer", 206 text: "As free user you will start with a total of one monitor and one status page (incl. three page components) as well as cron jobs of min. 10m. You can upgrade to a paid plan at any time. No credit card is required to sign up and you can cancel at any time.", 207 }, 208 }, 209 { 210 "@type": "Question", 211 name: "Who are we?", 212 acceptedAnswer: { 213 "@type": "Answer", 214 text: "We are Thibault and Max and we take you with us on our journey. Read more on our about page at https://www.openstatus.dev/about.", 215 }, 216 }, 217 { 218 "@type": "Question", 219 name: "How does it work?", 220 acceptedAnswer: { 221 "@type": "Answer", 222 text: "We ping your endpoints from multiple regions to calculate uptime and display the current status on your status page. We also collect response time data like headers and timing phases and display it on your dashboard.", 223 }, 224 }, 225 { 226 "@type": "Question", 227 name: "What regions do we support?", 228 acceptedAnswer: { 229 "@type": "Answer", 230 text: "We support monitoring from 28 regions worldwide across all continents: Europe (Amsterdam, Stockholm, Paris, Frankfurt, London), North America (Dallas, New Jersey, Los Angeles, San Jose, Chicago, Toronto), South America (São Paulo), Asia (Mumbai, Tokyo, Singapore), Africa (Johannesburg), and Oceania (Sydney).", 231 }, 232 }, 233 { 234 "@type": "Question", 235 name: "How can I help?", 236 acceptedAnswer: { 237 "@type": "Answer", 238 text: "There are many ways you can help us: Spread the word by telling your friends and colleagues about OpenStatus, report bugs if you find them, suggest new features, contribute to the project if you are a developer, become a paid user if you are a business, or star our project on GitHub.", 239 }, 240 }, 241 ], 242 }; 243};