@upsnap/strapi 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,7 @@ const SideNav = () => {
13
13
  const CustomSubNavLink = SubNavLink;
14
14
  return /* @__PURE__ */ jsxs(SubNav, { "aria-label": "Upsnap navigation", children: [
15
15
  /* @__PURE__ */ jsx(SubNavHeader, { label: "Upsnap" }),
16
- /* @__PURE__ */ jsxs(SubNavSection, { label: "Upsnap", children: [
16
+ /* @__PURE__ */ jsxs(SubNavSection, { label: "", children: [
17
17
  /* @__PURE__ */ jsx(
18
18
  CustomSubNavLink,
19
19
  {
@@ -125,6 +125,7 @@ const PLAN_LIMITS = {
125
125
  }
126
126
  };
127
127
  const DASHBOARD_URL = "https://upsnap.ai";
128
+ const STATS_PAGE_URL = "https://stats.upsnap.ai";
128
129
  const DEFAULT_REGION = {
129
130
  id: "default",
130
131
  name: "Default (Server Region)"
@@ -7843,7 +7844,7 @@ const HealthCards = ({ monitorData, isLoading }) => {
7843
7844
  }
7844
7845
  };
7845
7846
  const RenderHealthCard = ({ data, name }) => /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardBody, { children: /* @__PURE__ */ jsx(CardContent, { paddingLeft: 1, width: "100%", children: loading === name ? /* @__PURE__ */ jsx(Loader, { small: true }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7846
- /* @__PURE__ */ jsx(CardHeader, { fontSize: 3, children: formatTitleToUppercase(name) }),
7847
+ /* @__PURE__ */ jsx(CardHeader, { fontSize: 3, children: /* @__PURE__ */ jsx(Flex, { justifyContent: "start", width: "100%", children: formatTitleToUppercase(name) }) }),
7847
7848
  data && (data?.status === "error" || data?.status === "warning" ? /* @__PURE__ */ jsx(CardTitle, { marginTop: 3, fontSize: 3, children: /* @__PURE__ */ jsxs(Flex, { direction: "row", alignItems: "center", gap: 1, children: [
7848
7849
  /* @__PURE__ */ jsxs(Box, { width: "20px", children: [
7849
7850
  /* @__PURE__ */ jsx(
@@ -8155,7 +8156,7 @@ const IncidentsTable = ({
8155
8156
  /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Message" }) }),
8156
8157
  /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Occurred At" }) })
8157
8158
  ] }) }),
8158
- /* @__PURE__ */ jsx(Tbody, { children: isLoading ? /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: 6, children: /* @__PURE__ */ jsx(Typography, { children: "Loading..." }) }) }) : incidentsData?.incidents && incidentsData?.incidents?.length === 0 ? /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: 6, children: /* @__PURE__ */ jsxs(
8159
+ /* @__PURE__ */ jsx(Tbody, { children: isLoading ? /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: 6, children: /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { children: "Loading..." }) }) }) }) : incidentsData?.incidents && incidentsData?.incidents?.length === 0 ? /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: 6, children: /* @__PURE__ */ jsxs(
8159
8160
  Flex,
8160
8161
  {
8161
8162
  width: "100%",
@@ -8743,20 +8744,23 @@ const RegionResponseTimeChart = ({
8743
8744
  }
8744
8745
  };
8745
8746
  return /* @__PURE__ */ jsxs(Card, { children: [
8746
- /* @__PURE__ */ jsxs(CardHeader, { display: "flex", style: { justifyContent: "space-between" }, children: [
8747
- /* @__PURE__ */ jsx(Typography, { variant: "delta", marginLeft: 2, padding: 3, children: "Response Time" }),
8748
- /* @__PURE__ */ jsx(Box, { padding: 3, style: { minWidth: 200 }, children: /* @__PURE__ */ jsx(
8749
- SingleSelect,
8750
- {
8751
- value: timeRange,
8752
- onChange: onTimeRangeChange,
8753
- disabled: monitor?.is_enabled === false,
8754
- children: timeRanges.map((tr) => /* @__PURE__ */ jsx(SingleSelectOption, { value: tr.value, children: tr.label }, tr.value))
8755
- }
8756
- ) })
8747
+ /* @__PURE__ */ jsxs(CardHeader, { display: "flex", direction: "column", gap: 1, children: [
8748
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", width: "100%", children: [
8749
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", marginLeft: 2, padding: 3, children: "Response Time" }),
8750
+ /* @__PURE__ */ jsx(Box, { padding: 3, style: { minWidth: 200 }, children: /* @__PURE__ */ jsx(
8751
+ SingleSelect,
8752
+ {
8753
+ value: timeRange,
8754
+ onChange: onTimeRangeChange,
8755
+ disabled: monitor?.is_enabled === false,
8756
+ children: timeRanges.map((tr) => /* @__PURE__ */ jsx(SingleSelectOption, { value: tr.value, children: tr.label }, tr.value))
8757
+ }
8758
+ ) })
8759
+ ] }),
8760
+ visibleSeries.size === 0 && /* @__PURE__ */ jsx(Box, { padding: 4, background: "neutral100", marginTop: 1, width: "100%", marginBottom: 2, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: "No regions selected. Please select at least one region to view response time results." }) })
8757
8761
  ] }),
8758
8762
  /* @__PURE__ */ jsx(CardBody, { children: /* @__PURE__ */ jsxs(CardContent, { style: { width: "100%" }, children: [
8759
- monitor?.is_enabled === false ? /* @__PURE__ */ jsx(Box, { padding: 4, background: "neutral100", children: /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: "Monitoring is Paused. Enable monitoring to see response time results." }) }) : visibleSeries.size === 0 ? /* @__PURE__ */ jsx(Box, { padding: 4, background: "neutral100", children: /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: "No regions selected. Please select at least one region to view response time results." }) }) : /* @__PURE__ */ jsx(Chart, { type: "area", height: 350, series, options: chartOptions }),
8763
+ monitor?.is_enabled === false ? /* @__PURE__ */ jsx(Box, { padding: 4, background: "neutral100", children: /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: "Monitoring is Paused. Enable monitoring to see response time results." }) }) : /* @__PURE__ */ jsx(Chart, { type: "area", height: 350, series, options: chartOptions }),
8760
8764
  /* @__PURE__ */ jsxs(
8761
8765
  Flex,
8762
8766
  {
@@ -9719,6 +9723,7 @@ function Lighthouse() {
9719
9723
  data: { monitorUrl: url, strategy: selectedStrategy, force_fetch: forceFetch }
9720
9724
  });
9721
9725
  setData(res?.lighthouseHealthCheckData || null);
9726
+ return;
9722
9727
  } catch (err) {
9723
9728
  setData(null);
9724
9729
  } finally {
@@ -9731,10 +9736,13 @@ function Lighthouse() {
9731
9736
  }
9732
9737
  }, [monitorUrl, strategy]);
9733
9738
  const handleRefresh = async () => {
9739
+ let url = monitorUrl || selectedMonitor?.monitor?.config?.meta?.url || "";
9734
9740
  if (monitorUrl) {
9735
9741
  setRefreshing(true);
9736
- await getLighthouseData(strategy, monitorUrl, true);
9742
+ await getLighthouseData(strategy, url, true);
9737
9743
  setRefreshing(false);
9744
+ } else if (!monitorUrl) {
9745
+ toast.error("Something went wrong. Please try again or refresh the page.");
9738
9746
  }
9739
9747
  };
9740
9748
  if (loading) return /* @__PURE__ */ jsx(LoadingCard, {});
@@ -10271,7 +10279,7 @@ function ListStatusPages() {
10271
10279
  onClick: () => {
10272
10280
  if (!page.is_published || !page.shareable_id) return;
10273
10281
  window.open(
10274
- `${DASHBOARD_URL}/shared/${page.shareable_id}`,
10282
+ `${STATS_PAGE_URL}/shared/${page.shareable_id}`,
10275
10283
  "_blank",
10276
10284
  "noopener,noreferrer"
10277
10285
  );
@@ -20,7 +20,7 @@ const SideNav = () => {
20
20
  const CustomSubNavLink = designSystem.SubNavLink;
21
21
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SubNav, { "aria-label": "Upsnap navigation", children: [
22
22
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.SubNavHeader, { label: "Upsnap" }),
23
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SubNavSection, { label: "Upsnap", children: [
23
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SubNavSection, { label: "", children: [
24
24
  /* @__PURE__ */ jsxRuntime.jsx(
25
25
  CustomSubNavLink,
26
26
  {
@@ -132,6 +132,7 @@ const PLAN_LIMITS = {
132
132
  }
133
133
  };
134
134
  const DASHBOARD_URL = "https://upsnap.ai";
135
+ const STATS_PAGE_URL = "https://stats.upsnap.ai";
135
136
  const DEFAULT_REGION = {
136
137
  id: "default",
137
138
  name: "Default (Server Region)"
@@ -7850,7 +7851,7 @@ const HealthCards = ({ monitorData, isLoading }) => {
7850
7851
  }
7851
7852
  };
7852
7853
  const RenderHealthCard = ({ data, name }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Card, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardBody, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardContent, { paddingLeft: 1, width: "100%", children: loading === name ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { small: true }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7853
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardHeader, { fontSize: 3, children: formatTitleToUppercase(name) }),
7854
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardHeader, { fontSize: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "start", width: "100%", children: formatTitleToUppercase(name) }) }),
7854
7855
  data && (data?.status === "error" || data?.status === "warning" ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardTitle, { marginTop: 3, fontSize: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "row", alignItems: "center", gap: 1, children: [
7855
7856
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { width: "20px", children: [
7856
7857
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -8162,7 +8163,7 @@ const IncidentsTable = ({
8162
8163
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Message" }) }),
8163
8164
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Occurred At" }) })
8164
8165
  ] }) }),
8165
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { colSpan: 6, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: "Loading..." }) }) }) : incidentsData?.incidents && incidentsData?.incidents?.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { colSpan: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
8166
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { colSpan: 6, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: "Loading..." }) }) }) }) : incidentsData?.incidents && incidentsData?.incidents?.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { colSpan: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
8166
8167
  designSystem.Flex,
8167
8168
  {
8168
8169
  width: "100%",
@@ -8750,20 +8751,23 @@ const RegionResponseTimeChart = ({
8750
8751
  }
8751
8752
  };
8752
8753
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Card, { children: [
8753
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.CardHeader, { display: "flex", style: { justifyContent: "space-between" }, children: [
8754
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", marginLeft: 2, padding: 3, children: "Response Time" }),
8755
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, style: { minWidth: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx(
8756
- designSystem.SingleSelect,
8757
- {
8758
- value: timeRange,
8759
- onChange: onTimeRangeChange,
8760
- disabled: monitor?.is_enabled === false,
8761
- children: timeRanges.map((tr) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: tr.value, children: tr.label }, tr.value))
8762
- }
8763
- ) })
8754
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.CardHeader, { display: "flex", direction: "column", gap: 1, children: [
8755
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", width: "100%", children: [
8756
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", marginLeft: 2, padding: 3, children: "Response Time" }),
8757
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, style: { minWidth: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx(
8758
+ designSystem.SingleSelect,
8759
+ {
8760
+ value: timeRange,
8761
+ onChange: onTimeRangeChange,
8762
+ disabled: monitor?.is_enabled === false,
8763
+ children: timeRanges.map((tr) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: tr.value, children: tr.label }, tr.value))
8764
+ }
8765
+ ) })
8766
+ ] }),
8767
+ visibleSeries.size === 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "neutral100", marginTop: 1, width: "100%", marginBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "No regions selected. Please select at least one region to view response time results." }) })
8764
8768
  ] }),
8765
8769
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardBody, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.CardContent, { style: { width: "100%" }, children: [
8766
- monitor?.is_enabled === false ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "neutral100", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "Monitoring is Paused. Enable monitoring to see response time results." }) }) : visibleSeries.size === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "neutral100", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "No regions selected. Please select at least one region to view response time results." }) }) : /* @__PURE__ */ jsxRuntime.jsx(Chart__default.default, { type: "area", height: 350, series, options: chartOptions }),
8770
+ monitor?.is_enabled === false ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "neutral100", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "Monitoring is Paused. Enable monitoring to see response time results." }) }) : /* @__PURE__ */ jsxRuntime.jsx(Chart__default.default, { type: "area", height: 350, series, options: chartOptions }),
8767
8771
  /* @__PURE__ */ jsxRuntime.jsxs(
8768
8772
  designSystem.Flex,
8769
8773
  {
@@ -9726,6 +9730,7 @@ function Lighthouse() {
9726
9730
  data: { monitorUrl: url, strategy: selectedStrategy, force_fetch: forceFetch }
9727
9731
  });
9728
9732
  setData(res?.lighthouseHealthCheckData || null);
9733
+ return;
9729
9734
  } catch (err) {
9730
9735
  setData(null);
9731
9736
  } finally {
@@ -9738,10 +9743,13 @@ function Lighthouse() {
9738
9743
  }
9739
9744
  }, [monitorUrl, strategy]);
9740
9745
  const handleRefresh = async () => {
9746
+ let url = monitorUrl || selectedMonitor?.monitor?.config?.meta?.url || "";
9741
9747
  if (monitorUrl) {
9742
9748
  setRefreshing(true);
9743
- await getLighthouseData(strategy, monitorUrl, true);
9749
+ await getLighthouseData(strategy, url, true);
9744
9750
  setRefreshing(false);
9751
+ } else if (!monitorUrl) {
9752
+ reactToastify.toast.error("Something went wrong. Please try again or refresh the page.");
9745
9753
  }
9746
9754
  };
9747
9755
  if (loading) return /* @__PURE__ */ jsxRuntime.jsx(LoadingCard, {});
@@ -10278,7 +10286,7 @@ function ListStatusPages() {
10278
10286
  onClick: () => {
10279
10287
  if (!page.is_published || !page.shareable_id) return;
10280
10288
  window.open(
10281
- `${DASHBOARD_URL}/shared/${page.shareable_id}`,
10289
+ `${STATS_PAGE_URL}/shared/${page.shareable_id}`,
10282
10290
  "_blank",
10283
10291
  "noopener,noreferrer"
10284
10292
  );
@@ -35,10 +35,10 @@ const index = {
35
35
  icon: PluginIcon,
36
36
  intlLabel: {
37
37
  id: `${PLUGIN_ID}.plugin.name`,
38
- defaultMessage: PLUGIN_ID
38
+ defaultMessage: PLUGIN_ID.slice(0, 1).toUpperCase() + PLUGIN_ID.slice(1)
39
39
  },
40
40
  Component: async () => {
41
- const { App } = await Promise.resolve().then(() => require("./App-CWtrva1J.js"));
41
+ const { App } = await Promise.resolve().then(() => require("./App-wfO4MA3Z.js"));
42
42
  return App;
43
43
  }
44
44
  });
@@ -33,10 +33,10 @@ const index = {
33
33
  icon: PluginIcon,
34
34
  intlLabel: {
35
35
  id: `${PLUGIN_ID}.plugin.name`,
36
- defaultMessage: PLUGIN_ID
36
+ defaultMessage: PLUGIN_ID.slice(0, 1).toUpperCase() + PLUGIN_ID.slice(1)
37
37
  },
38
38
  Component: async () => {
39
- const { App } = await import("./App-gQQDdsJk.mjs");
39
+ const { App } = await import("./App-B9MprOch.mjs");
40
40
  return App;
41
41
  }
42
42
  });
@@ -32,9 +32,9 @@ const service = ({ strapi }) => ({
32
32
  const settings2 = await this.settingsStore.get();
33
33
  return settings2?.token || null;
34
34
  },
35
- async makeBackendRequest(endpoint, options) {
35
+ async makeBackendRequest(endpoint, options, forValidation = false) {
36
36
  const token = await this.getToken();
37
- if (!token) {
37
+ if (!token && !forValidation) {
38
38
  return { error: "No token found in settings" };
39
39
  }
40
40
  const response = await fetch(`${BACKEND_URL}${endpoint}`, {
@@ -61,7 +61,7 @@ const settings = ({ strapi }) => ({
61
61
  const isValidData = await service({ strapi }).makeBackendRequest("/tokens/validate", {
62
62
  method: "POST",
63
63
  body: JSON.stringify({ token })
64
- });
64
+ }, true);
65
65
  if (!isValidData?.data?.valid) {
66
66
  ctx.body = { ok: false, error: "Invalid token" };
67
67
  return;
@@ -30,9 +30,9 @@ const service = ({ strapi }) => ({
30
30
  const settings2 = await this.settingsStore.get();
31
31
  return settings2?.token || null;
32
32
  },
33
- async makeBackendRequest(endpoint, options) {
33
+ async makeBackendRequest(endpoint, options, forValidation = false) {
34
34
  const token = await this.getToken();
35
- if (!token) {
35
+ if (!token && !forValidation) {
36
36
  return { error: "No token found in settings" };
37
37
  }
38
38
  const response = await fetch(`${BACKEND_URL}${endpoint}`, {
@@ -59,7 +59,7 @@ const settings = ({ strapi }) => ({
59
59
  const isValidData = await service({ strapi }).makeBackendRequest("/tokens/validate", {
60
60
  method: "POST",
61
61
  body: JSON.stringify({ token })
62
- });
62
+ }, true);
63
63
  if (!isValidData?.data?.valid) {
64
64
  ctx.body = { ok: false, error: "Invalid token" };
65
65
  return;
@@ -123,7 +123,7 @@ declare const _default: {
123
123
  }>): Promise<void>;
124
124
  };
125
125
  getToken(): Promise<string>;
126
- makeBackendRequest(endpoint: string, options: RequestInit): Promise<unknown>;
126
+ makeBackendRequest(endpoint: string, options: RequestInit, forValidation?: boolean): Promise<unknown>;
127
127
  };
128
128
  };
129
129
  contentTypes: {};
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.2",
2
+ "version": "1.0.4",
3
3
  "repository": {
4
4
  "type": "git",
5
5
  "url": "https://github.com/Appfoster/upsnap-strapi"
@@ -67,7 +67,7 @@
67
67
  "kind": "plugin",
68
68
  "name": "upsnap",
69
69
  "displayName": "Upsnap",
70
- "description": "Monitoring"
70
+ "description": "Complete website health monitoring for Strapi, including uptime, SSL certificates, broken links, performance metrics, domain health, and mixed content issues."
71
71
  },
72
72
  "name": "@upsnap/strapi",
73
73
  "description": "Complete website health monitoring for Strapi, including uptime, SSL certificates, broken links, performance metrics, domain health, and mixed content issues.",