diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index e45b55a9..90dd08fc 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -22,6 +22,7 @@
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.11",
"globals": "^15.9.0",
+ "ky": "^1.7.1",
"lunr": "^2.3.9",
"openapi-typescript": "^5.4.2",
"postcss": "^8.4.44",
@@ -3576,6 +3577,18 @@
"json-buffer": "3.0.1"
}
},
+ "node_modules/ky": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/ky/-/ky-1.7.1.tgz",
+ "integrity": "sha512-KJ/IXXkFhTDqxcN8wKqMXk1/UoOpc0UnOB6H7QcqlPInh/M2B5Mlj+i9exez1w4RSwJhNFmHiUDPriAYFwb5VA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/ky?sponsor=1"
+ }
+ },
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 69f79fdb..ced0cdcc 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -27,6 +27,7 @@
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.11",
"globals": "^15.9.0",
+ "ky": "^1.7.1",
"lunr": "^2.3.9",
"openapi-typescript": "^5.4.2",
"postcss": "^8.4.44",
diff --git a/frontend/src/q.ts b/frontend/src/q.ts
index ee96ad85..b957548e 100644
--- a/frontend/src/q.ts
+++ b/frontend/src/q.ts
@@ -1,16 +1,13 @@
import { queryOptions } from "@tanstack/react-query";
import lunr from "lunr";
+import { api } from "./query";
export const getSearchIndexQuery = () =>
queryOptions({
queryKey: ["search-index"],
queryFn: async () => {
- const response = await fetch(
- `${import.meta.env.VITE_DATA_API_URL}/search.json`,
- );
+ const data = await api(`search.json`).json();
- const res = await response.json();
-
- return lunr.Index.load(res);
+ return lunr.Index.load(data);
},
});
diff --git a/frontend/src/query.ts b/frontend/src/query.ts
index 9513ade6..d2cf541a 100644
--- a/frontend/src/query.ts
+++ b/frontend/src/query.ts
@@ -1,4 +1,5 @@
import { QueryClient } from "@tanstack/react-query";
+import ky from "ky";
export const queryClient = new QueryClient({
defaultOptions: {
@@ -7,3 +8,5 @@ export const queryClient = new QueryClient({
},
},
});
+
+export const api = ky.create({ prefixUrl: import.meta.env.VITE_DATA_API_URL });
diff --git a/frontend/src/router.tsx b/frontend/src/router.tsx
index 702b2764..7b0fd58f 100644
--- a/frontend/src/router.tsx
+++ b/frontend/src/router.tsx
@@ -48,163 +48,212 @@ import { ProviderDocsError } from "./routes/Provider/Docs/error";
export const router = createBrowserRouter(
[
{
- id: "home",
- index: true,
- element: ,
- errorElement: ,
- },
- {
- id: "providers",
- path: "/providers",
- element: ,
- errorElement: ,
- loader: providersLoader,
- handle: {
- crumb: () => createCrumb("/providers", "Providers"),
- },
- },
- {
- id: "modules",
- path: "/modules",
- element: ,
- errorElement: ,
- loader: modulesLoader,
- handle: {
- crumb: () => createCrumb("/modules", "Modules"),
- },
- },
- {
- id: "module",
- path: "module",
- handle: {
- crumb: () => createCrumb("/modules", "Modules"),
- },
errorElement: ,
children: [
{
- path: ":namespace",
+ id: "home",
+ index: true,
+ element: ,
+ },
+ {
+ id: "providers",
+ path: "/providers",
+ element: ,
+ loader: providersLoader,
+ handle: {
+ crumb: () => createCrumb("/providers", "Providers"),
+ },
+ },
+ {
+ id: "modules",
+ path: "/modules",
+ element: ,
+ loader: modulesLoader,
+ handle: {
+ crumb: () => createCrumb("/modules", "Modules"),
+ },
+ },
+ {
+ id: "module",
+ path: "module",
+ handle: {
+ crumb: () => createCrumb("/modules", "Modules"),
+ },
children: [
{
- index: true,
- element: ,
- },
- {
- id: "module-version",
- path: ":name/:target/:version?",
- loader: moduleLoader,
- handle: {
- middleware: moduleMiddleware,
- crumb: ({
- namespace,
- name,
- target,
- rawVersion,
- }: ModuleRouteContext) =>
- createCrumb(
- `/module/${namespace}/${name}/${target}/${rawVersion}`,
- `${namespace}/${name}`,
- ),
- },
+ path: ":namespace",
children: [
{
- element: ,
- children: [
- {
- index: true,
- element: ,
- loader: moduleReadmeLoader,
- },
- {
- path: "inputs",
- element: ,
- },
- {
- path: "outputs",
- element: ,
- },
- {
- path: "dependencies",
- element: ,
- },
- {
- path: "resources",
- element: ,
- },
- ],
+ index: true,
+ element: ,
},
{
- path: "example/:example",
- element: ,
- loader: moduleExampleLoader,
+ id: "module-version",
+ path: ":name/:target/:version?",
+ loader: moduleLoader,
handle: {
- middleware: moduleExampleMiddleware,
+ middleware: moduleMiddleware,
crumb: ({
namespace,
name,
target,
- example,
rawVersion,
- }: ModuleRouteContext & ModuleExampleRouteContext) =>
+ }: ModuleRouteContext) =>
createCrumb(
- `/module/${namespace}/${name}/${target}/${rawVersion}/example/${example}`,
- example,
+ `/module/${namespace}/${name}/${target}/${rawVersion}`,
+ `${namespace}/${name}`,
),
},
children: [
{
- index: true,
- element: ,
- loader: moduleExampleReadmeLoader,
+ element: ,
+ children: [
+ {
+ index: true,
+ element: ,
+ loader: moduleReadmeLoader,
+ },
+ {
+ path: "inputs",
+ element: ,
+ },
+ {
+ path: "outputs",
+ element: ,
+ },
+ {
+ path: "dependencies",
+ element: ,
+ },
+ {
+ path: "resources",
+ element: ,
+ },
+ ],
},
{
- path: "inputs",
- element: ,
+ path: "example/:example",
+ element: ,
+ loader: moduleExampleLoader,
+ handle: {
+ middleware: moduleExampleMiddleware,
+ crumb: ({
+ namespace,
+ name,
+ target,
+ example,
+ rawVersion,
+ }: ModuleRouteContext & ModuleExampleRouteContext) =>
+ createCrumb(
+ `/module/${namespace}/${name}/${target}/${rawVersion}/example/${example}`,
+ example,
+ ),
+ },
+ children: [
+ {
+ index: true,
+ element: ,
+ loader: moduleExampleReadmeLoader,
+ },
+ {
+ path: "inputs",
+ element: ,
+ },
+ {
+ path: "outputs",
+ element: ,
+ },
+ ],
},
{
- path: "outputs",
- element: ,
+ path: "submodule/:submodule",
+ element: ,
+ loader: moduleSubmoduleLoader,
+ handle: {
+ middleware: moduleSubmoduleMiddleware,
+ crumb: ({
+ namespace,
+ name,
+ target,
+ submodule,
+ rawVersion,
+ }: ModuleRouteContext & ModuleSubmoduleRouteContext) =>
+ createCrumb(
+ `/module/${namespace}/${name}/${target}/${rawVersion}/submodule/${submodule}`,
+ submodule,
+ ),
+ },
+ children: [
+ {
+ index: true,
+ element: ,
+ loader: moduleSubmoduleReadmeLoader,
+ },
+ {
+ path: "inputs",
+ element: ,
+ },
+ {
+ path: "outputs",
+ element: ,
+ },
+ {
+ path: "dependencies",
+ element: ,
+ },
+ {
+ path: "resources",
+ element: ,
+ },
+ ],
},
],
},
+ ],
+ },
+ ],
+ },
+ {
+ id: "provider",
+ path: "/provider",
+ handle: {
+ crumb: () => createCrumb("/providers", "Providers"),
+ },
+ children: [
+ {
+ path: ":namespace",
+ children: [
+ {
+ index: true,
+ element: ,
+ },
{
- path: "submodule/:submodule",
- element: ,
- loader: moduleSubmoduleLoader,
+ path: ":provider/:version?",
+ element: ,
+ loader: providerLoader,
handle: {
- middleware: moduleSubmoduleMiddleware,
+ middleware: providerMiddleware,
crumb: ({
namespace,
- name,
- target,
- submodule,
- rawVersion,
- }: ModuleRouteContext & ModuleSubmoduleRouteContext) =>
+ provider,
+ version,
+ }: ProviderRouteContext) =>
createCrumb(
- `/module/${namespace}/${name}/${target}/${rawVersion}/submodule/${submodule}`,
- submodule,
+ `/provider/${namespace}/${provider}/${version}`,
+ `${namespace}/${provider}`,
),
},
children: [
{
index: true,
- element: ,
- loader: moduleSubmoduleReadmeLoader,
- },
- {
- path: "inputs",
- element: ,
- },
- {
- path: "outputs",
- element: ,
+ element: ,
+ loader: providerOverviewLoader,
},
{
- path: "dependencies",
- element: ,
- },
- {
- path: "resources",
- element: ,
+ path: "docs/:type/:doc",
+ element: ,
+ loader: providerDocsLoader,
+ errorElement: ,
},
],
},
@@ -214,55 +263,6 @@ export const router = createBrowserRouter(
},
],
},
- {
- id: "provider",
- path: "/provider",
- handle: {
- crumb: () => createCrumb("/providers", "Providers"),
- },
- errorElement: ,
- children: [
- {
- path: ":namespace",
- children: [
- {
- index: true,
- element: ,
- },
- {
- path: ":provider/:version?",
- element: ,
- loader: providerLoader,
- handle: {
- middleware: providerMiddleware,
- crumb: ({
- namespace,
- provider,
- version,
- }: ProviderRouteContext) =>
- createCrumb(
- `/provider/${namespace}/${provider}/${version}`,
- `${namespace}/${provider}`,
- ),
- },
- children: [
- {
- index: true,
- element: ,
- loader: providerOverviewLoader,
- },
- {
- path: "docs/:type/:doc",
- element: ,
- loader: providerDocsLoader,
- errorElement: ,
- },
- ],
- },
- ],
- },
- ],
- },
],
{
async unstable_dataStrategy({ request, params, matches }) {
diff --git a/frontend/src/routes/Error/index.tsx b/frontend/src/routes/Error/index.tsx
index 42f22b0e..8bd13019 100644
--- a/frontend/src/routes/Error/index.tsx
+++ b/frontend/src/routes/Error/index.tsx
@@ -1,21 +1,19 @@
import { useRouteError } from "react-router-dom";
-import { Header } from "../../components/Header";
-import { Paragraph } from "../../components/Paragraph";
-import PatternBg from "../../components/PatternBg";
-import { NotFoundPageError } from "@/utils/errors";
+import { Header } from "@/components/Header";
+import { Paragraph } from "@/components/Paragraph";
+import PatternBg from "@/components/PatternBg";
+import { is404Error } from "@/utils/errors";
export function Error() {
const routeError = useRouteError() as Error;
- const title =
- routeError instanceof NotFoundPageError
- ? "Page Not Found"
- : "An Error Occurred";
+ const is404 = is404Error(routeError);
- const message =
- routeError instanceof NotFoundPageError
- ? "The page you are looking for does not exist."
- : "We're sorry, but an unexpected error occurred. Please try again later.";
+ const title = is404 ? "Page Not Found" : "An Error Occurred";
+
+ const message = is404
+ ? "The page you are looking for does not exist."
+ : "We're sorry, but an unexpected error occurred. Please try again later.";
return (
<>
@@ -24,7 +22,7 @@ export function Error() {
{title}
{message}
- {!!routeError.message && (
+ {import.meta.env.DEV && !!routeError.message && (
{routeError.message}
)}
diff --git a/frontend/src/routes/Module/query.ts b/frontend/src/routes/Module/query.ts
index f806d264..0bd7726e 100644
--- a/frontend/src/routes/Module/query.ts
+++ b/frontend/src/routes/Module/query.ts
@@ -1,4 +1,5 @@
import { definitions } from "@/api";
+import { api } from "@/query";
import { queryOptions } from "@tanstack/react-query";
export const getModuleVersionDataQuery = (
@@ -10,13 +11,11 @@ export const getModuleVersionDataQuery = (
return queryOptions({
queryKey: ["module-version", namespace, name, target, version],
queryFn: async () => {
- const response = await fetch(
- `${import.meta.env.VITE_DATA_API_URL}/modules/${namespace}/${name}/${target}/${version}/index.json`,
- );
+ const data = await api(
+ `modules/${namespace}/${name}/${target}/${version}/index.json`,
+ ).json();
- const data = await response.json();
-
- return data as definitions["ModuleVersion"];
+ return data;
},
});
};
@@ -29,13 +28,11 @@ export const getModuleDataQuery = (
return queryOptions({
queryKey: ["module", namespace, name, target],
queryFn: async () => {
- const response = await fetch(
- `${import.meta.env.VITE_DATA_API_URL}/modules/${namespace}/${name}/${target}/index.json`,
- );
-
- const data = await response.json();
+ const data = await api(
+ `modules/${namespace}/${name}/${target}/index.json`,
+ ).json();
- return data as definitions["Module"];
+ return data;
},
});
};
@@ -49,11 +46,11 @@ export const getModuleReadmeQuery = (
return queryOptions({
queryKey: ["module-readme", namespace, name, target, version],
queryFn: async () => {
- const response = await fetch(
- `${import.meta.env.VITE_DATA_API_URL}/modules/${namespace}/${name}/${target}/${version}/README.md`,
- );
+ const data = await api(
+ `modules/${namespace}/${name}/${target}/${version}/README.md`,
+ ).text();
- return response.text();
+ return data;
},
});
};
diff --git a/frontend/src/routes/ModuleExample/query.ts b/frontend/src/routes/ModuleExample/query.ts
index c6597ce2..d0ef72cc 100644
--- a/frontend/src/routes/ModuleExample/query.ts
+++ b/frontend/src/routes/ModuleExample/query.ts
@@ -1,4 +1,4 @@
-import { queryClient } from "@/query";
+import { api, queryClient } from "@/query";
import { queryOptions } from "@tanstack/react-query";
import { getModuleVersionDataQuery } from "../Module/query";
import { NotFoundPageError } from "@/utils/errors";
@@ -20,11 +20,11 @@ export const getModuleExampleReadmeQuery = (
example,
],
queryFn: async () => {
- const response = await fetch(
- `${import.meta.env.VITE_DATA_API_URL}/modules/${namespace}/${name}/${target}/${version}/examples/${example}/README.md`,
- );
+ const data = await api(
+ `modules/${namespace}/${name}/${target}/${version}/examples/${example}/README.md`,
+ ).text();
- return response.text();
+ return data;
},
});
};
diff --git a/frontend/src/routes/ModuleSubmodule/query.ts b/frontend/src/routes/ModuleSubmodule/query.ts
index 3418effe..e51cd116 100644
--- a/frontend/src/routes/ModuleSubmodule/query.ts
+++ b/frontend/src/routes/ModuleSubmodule/query.ts
@@ -1,4 +1,4 @@
-import { queryClient } from "@/query";
+import { api, queryClient } from "@/query";
import { queryOptions } from "@tanstack/react-query";
import { getModuleVersionDataQuery } from "../Module/query";
import { NotFoundPageError } from "@/utils/errors";
@@ -20,11 +20,11 @@ export const getModuleSubmoduleReadmeQuery = (
submodule,
],
queryFn: async () => {
- const response = await fetch(
- `${import.meta.env.VITE_DATA_API_URL}/modules/${namespace}/${name}/${target}/${version}/modules/${submodule}/README.md`,
- );
+ const data = await api(
+ `modules/${namespace}/${name}/${target}/${version}/modules/${submodule}/README.md`,
+ ).text();
- return response.text();
+ return data;
},
});
};
diff --git a/frontend/src/routes/Modules/query.ts b/frontend/src/routes/Modules/query.ts
index 6fce1acf..43de0374 100644
--- a/frontend/src/routes/Modules/query.ts
+++ b/frontend/src/routes/Modules/query.ts
@@ -1,16 +1,14 @@
import { queryOptions } from "@tanstack/react-query";
import { definitions } from "@/api";
+import { api } from "@/query";
export const getModulesQuery = () =>
queryOptions({
queryKey: ["modules"],
queryFn: async () => {
- const response = await fetch(
- `${import.meta.env.VITE_DATA_API_URL}/modules/index.json`,
- );
+ const data =
+ await api(`modules/index.json`).json();
- const res = await response.json();
-
- return res.modules as definitions["ModuleList"]["modules"];
+ return data.modules;
},
});
diff --git a/frontend/src/routes/Provider/query.ts b/frontend/src/routes/Provider/query.ts
index 0191a6bd..5c37feba 100644
--- a/frontend/src/routes/Provider/query.ts
+++ b/frontend/src/routes/Provider/query.ts
@@ -1,5 +1,5 @@
import { definitions } from "@/api";
-import { NotFoundPageError } from "@/utils/errors";
+import { api } from "@/query";
import { queryOptions } from "@tanstack/react-query";
export const getProviderVersionDataQuery = (
@@ -10,13 +10,11 @@ export const getProviderVersionDataQuery = (
return queryOptions({
queryKey: ["provider-version", namespace, provider, version],
queryFn: async () => {
- const response = await fetch(
- `${import.meta.env.VITE_DATA_API_URL}/providers/${namespace}/${provider}/${version}/index.json`,
- );
+ const data = await api(
+ `providers/${namespace}/${provider}/${version}/index.json`,
+ ).json();
- const data = await response.json();
-
- return data as definitions["ProviderVersion"];
+ return data;
},
});
};
@@ -32,19 +30,14 @@ export const getProviderDocsQuery = (
return queryOptions({
queryKey: ["provider-doc", namespace, provider, type, name, lang, version],
queryFn: async () => {
- const urlBase = `${import.meta.env.VITE_DATA_API_URL}/providers/${namespace}/${provider}/${version}`;
+ const urlBase = `providers/${namespace}/${provider}/${version}`;
const requestURL =
type === undefined && name === undefined
? `${urlBase}/index.md`
: `${urlBase}/${lang ? `cdktf/${lang}/` : ""}${type}/${name}.md`;
- const response = await fetch(requestURL);
-
- if (!response.ok) {
- throw new NotFoundPageError();
- }
-
- return response.text();
+ const data = await api(requestURL).text();
+ return data;
},
});
};
@@ -56,13 +49,11 @@ export const getProviderDataQuery = (
return queryOptions({
queryKey: ["provider", namespace, provider],
queryFn: async () => {
- const response = await fetch(
- `${import.meta.env.VITE_DATA_API_URL}/providers/${namespace}/${provider}/index.json`,
- );
-
- const data = await response.json();
+ const data = await api(
+ `providers/${namespace}/${provider}/index.json`,
+ ).json();
- return data as definitions["Provider"];
+ return data;
},
});
};
diff --git a/frontend/src/routes/Providers/query.ts b/frontend/src/routes/Providers/query.ts
index e4c3fa48..cb38bdb3 100644
--- a/frontend/src/routes/Providers/query.ts
+++ b/frontend/src/routes/Providers/query.ts
@@ -1,16 +1,14 @@
import { queryOptions } from "@tanstack/react-query";
import { definitions } from "@/api";
+import { api } from "@/query";
export const getProvidersQuery = () =>
queryOptions({
queryKey: ["providers"],
queryFn: async () => {
- const response = await fetch(
- `${import.meta.env.VITE_DATA_API_URL}/providers/index.json`,
- );
+ const data =
+ await api(`providers/index.json`).json();
- const res = await response.json();
-
- return res.providers as definitions["ProviderList"]["providers"];
+ return data.providers;
},
});
diff --git a/frontend/src/utils/errors.tsx b/frontend/src/utils/errors.tsx
index f8eca856..60d9fd2b 100644
--- a/frontend/src/utils/errors.tsx
+++ b/frontend/src/utils/errors.tsx
@@ -1 +1,10 @@
+import { HTTPError } from "ky";
+
export class NotFoundPageError extends Error {}
+
+export function is404Error(error: unknown) {
+ return (
+ error instanceof NotFoundPageError ||
+ (error instanceof HTTPError && error.response.status === 404)
+ );
+}