Openstatus
www.openstatus.dev
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 Organization,
7 Product,
8 WebPage,
9 WithContext,
10} from "schema-dts";
11
12export const TITLE = "openstatus";
13export const DESCRIPTION =
14 "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.";
15
16export const OG_DESCRIPTION =
17 "Open-source status page and uptime monitoring system";
18
19export const BASE_URL =
20 process.env.NODE_ENV === "production"
21 ? "https://www.openstatus.dev"
22 : "http://localhost:3000";
23
24export const twitterMetadata: Metadata["twitter"] = {
25 title: TITLE,
26 description: DESCRIPTION,
27 card: "summary_large_image",
28 images: ["/api/og"],
29};
30
31export const ogMetadata: Metadata["openGraph"] = {
32 title: TITLE,
33 description: DESCRIPTION,
34 type: "website",
35 images: ["/api/og"],
36};
37
38export const defaultMetadata: Metadata = {
39 title: {
40 template: `%s | ${TITLE}`,
41 default: TITLE,
42 },
43 description: DESCRIPTION,
44 metadataBase: new URL(BASE_URL),
45 twitter: twitterMetadata,
46 openGraph: ogMetadata,
47};
48
49export const getPageMetadata = (page: MDXData): Metadata => {
50 const { slug, metadata } = page;
51 const { title, description, category, publishedAt } = metadata;
52
53 const ogImage = `${BASE_URL}/api/og?title=${encodeURIComponent(
54 title,
55 )}&description=${encodeURIComponent(
56 description,
57 )}&category=${encodeURIComponent(category)}`;
58
59 return {
60 title,
61 description,
62 openGraph: {
63 title,
64 description,
65 type: "article",
66 publishedTime: publishedAt.toISOString(),
67 url: `${BASE_URL}/changelog/${slug}`,
68 images: [
69 {
70 url: ogImage,
71 },
72 ],
73 },
74 twitter: {
75 card: "summary_large_image",
76 title,
77 description,
78 images: [ogImage],
79 },
80 };
81};
82
83export const getJsonLDWebPage = (page: MDXData): WithContext<WebPage> => {
84 return {
85 "@context": "https://schema.org",
86 "@type": "WebPage",
87 name: `${page.metadata.title} | openstatus`,
88 headline: page.metadata.description,
89 mainEntityOfPage: {
90 "@type": "WebPage",
91 "@id": "https://www.openstatus.dev",
92 },
93 };
94};
95
96export const getJsonLDBlogPosting = (
97 post: MDXData,
98): WithContext<BlogPosting> => {
99 return {
100 "@context": "https://schema.org",
101 "@type": "BlogPosting",
102 headline: post.metadata.title,
103 datePublished: post.metadata.publishedAt.toISOString(),
104 dateModified: post.metadata.publishedAt.toISOString(),
105 description: post.metadata.description,
106 image: post.metadata.image
107 ? `${BASE_URL}${post.metadata.image}`
108 : `/api/og?title=${encodeURIComponent(
109 post.metadata.title,
110 )}&description=${encodeURIComponent(
111 post.metadata.description,
112 )}&category=${encodeURIComponent(post.metadata.category)}`,
113 url: `${BASE_URL}/blog/${post.slug}`,
114 author: {
115 "@type": "Person",
116 name: post.metadata.author,
117 },
118 };
119};
120
121export const getJsonLDOrganization = (): WithContext<Organization> => {
122 return {
123 "@context": "https://schema.org",
124 "@type": "Organization",
125 name: "openstatus",
126 url: "https://openstatus.dev",
127 logo: "https://openstatus.dev/assets/logos/OpenStatus-Logo.svg",
128 sameAs: [
129 "https://github.com/openstatushq",
130 "https://linkedin.com/company/openstatus",
131 "https://bsky.app/profile/openstatus.dev",
132 "https://x.com/openstatushq",
133 ],
134 contactPoint: [
135 {
136 "@type": "ContactPoint",
137 contactType: "Support",
138 email: "ping@openstatus.dev",
139 },
140 ],
141 };
142};
143
144export const getJsonLDProduct = (): WithContext<Product> => {
145 return {
146 "@context": "https://schema.org",
147 "@type": "Product",
148 name: "openstatus",
149 description:
150 "Open-source uptime and synthetic monitoring with status pages.",
151 brand: {
152 "@type": "Brand",
153 name: "openstatus",
154 logo: "https://openstatus.dev/assets/logos/OpenStatus-Logo.svg",
155 },
156 offers: Object.entries(allPlans).map(([_, value]) => ({
157 "@type": "Offer",
158 price: value.price.USD,
159 name: value.title,
160 priceCurrency: "USD",
161 availability: "https://schema.org/InStock",
162 })),
163 };
164};