zudoku 0.37.1 → 0.39.0
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.
- package/dist/app/main.js +2 -0
- package/dist/app/main.js.map +1 -1
- package/dist/app/tailwind.js +14 -0
- package/dist/app/tailwind.js.map +1 -1
- package/dist/config/validators/common.d.ts +287 -18
- package/dist/config/validators/common.js +2 -0
- package/dist/config/validators/common.js.map +1 -1
- package/dist/config/validators/validate.d.ts +107 -7
- package/dist/lib/authentication/authentication.d.ts +1 -0
- package/dist/lib/authentication/providers/clerk.js +19 -0
- package/dist/lib/authentication/providers/clerk.js.map +1 -1
- package/dist/lib/authentication/providers/openid.d.ts +1 -0
- package/dist/lib/authentication/providers/openid.js +5 -0
- package/dist/lib/authentication/providers/openid.js.map +1 -1
- package/dist/lib/authentication/providers/supabase.js +5 -0
- package/dist/lib/authentication/providers/supabase.js.map +1 -1
- package/dist/lib/authentication/state.d.ts +0 -26
- package/dist/lib/authentication/state.js +1 -16
- package/dist/lib/authentication/state.js.map +1 -1
- package/dist/lib/components/Heading.d.ts +1 -1
- package/dist/lib/components/Layout.js +5 -10
- package/dist/lib/components/Layout.js.map +1 -1
- package/dist/lib/components/Main.js +3 -1
- package/dist/lib/components/Main.js.map +1 -1
- package/dist/lib/components/Pagination.d.ts +10 -0
- package/dist/lib/components/Pagination.js +10 -0
- package/dist/lib/components/Pagination.js.map +1 -0
- package/dist/lib/components/TopNavigation.js +18 -2
- package/dist/lib/components/TopNavigation.js.map +1 -1
- package/dist/lib/components/navigation/SidebarItem.d.ts +1 -0
- package/dist/lib/components/navigation/SidebarItem.js +7 -3
- package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
- package/dist/lib/{plugins/markdown → components/navigation}/Toc.js +5 -7
- package/dist/lib/components/navigation/Toc.js.map +1 -0
- package/dist/lib/core/ZudokuContext.d.ts +7 -0
- package/dist/lib/core/ZudokuContext.js +8 -3
- package/dist/lib/core/ZudokuContext.js.map +1 -1
- package/dist/lib/core/plugins.d.ts +1 -1
- package/dist/lib/oas/graphql/index.d.ts +2 -1
- package/dist/lib/oas/graphql/index.js +74 -14
- package/dist/lib/oas/graphql/index.js.map +1 -1
- package/dist/lib/oas/parser/dereference/index.js +2 -0
- package/dist/lib/oas/parser/dereference/index.js.map +1 -1
- package/dist/lib/oas/parser/index.d.ts +5 -3
- package/dist/lib/oas/parser/index.js +0 -22
- package/dist/lib/oas/parser/index.js.map +1 -1
- package/dist/lib/plugins/api-catalog/index.js +19 -17
- package/dist/lib/plugins/api-catalog/index.js.map +1 -1
- package/dist/lib/plugins/markdown/MdxPage.js +3 -9
- package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
- package/dist/lib/plugins/openapi/ColorizedParam.js +1 -1
- package/dist/lib/plugins/openapi/ColorizedParam.js.map +1 -1
- package/dist/lib/plugins/openapi/Endpoint.js +1 -1
- package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.d.ts +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +29 -9
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/ParameterListItem.js +2 -1
- package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/SchemaList.d.ts +1 -0
- package/dist/lib/plugins/openapi/SchemaList.js +52 -0
- package/dist/lib/plugins/openapi/SchemaList.js.map +1 -0
- package/dist/lib/plugins/openapi/Sidecar.js +29 -5
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/client/GraphQLClient.d.ts +1 -1
- package/dist/lib/plugins/openapi/client/GraphQLClient.js +1 -1
- package/dist/lib/plugins/openapi/client/GraphQLClient.js.map +1 -1
- package/dist/lib/plugins/openapi/client/useCreateQuery.d.ts +6 -2
- package/dist/lib/plugins/openapi/client/useCreateQuery.js +5 -5
- package/dist/lib/plugins/openapi/client/useCreateQuery.js.map +1 -1
- package/dist/lib/plugins/openapi/components/EnumValues.js +1 -1
- package/dist/lib/plugins/openapi/components/EnumValues.js.map +1 -1
- package/dist/lib/plugins/openapi/graphql/gql.d.ts +6 -2
- package/dist/lib/plugins/openapi/graphql/gql.js +3 -2
- package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
- package/dist/lib/plugins/openapi/graphql/graphql.d.ts +67 -11
- package/dist/lib/plugins/openapi/graphql/graphql.js +34 -5
- package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
- package/dist/lib/plugins/openapi/index.js +12 -0
- package/dist/lib/plugins/openapi/index.js.map +1 -1
- package/dist/lib/plugins/openapi/interfaces.d.ts +26 -0
- package/dist/lib/plugins/openapi/playground/Playground.js +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js +2 -2
- package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.d.ts +1 -2
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.js +2 -2
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.d.ts +0 -1
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.js +1 -1
- package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/SchemaExampleAndDefault.d.ts +4 -0
- package/dist/lib/plugins/openapi/schema/SchemaExampleAndDefault.js +12 -0
- package/dist/lib/plugins/openapi/schema/SchemaExampleAndDefault.js.map +1 -0
- package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.d.ts +2 -4
- package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js +12 -9
- package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/SchemaView.d.ts +1 -2
- package/dist/lib/plugins/openapi/schema/SchemaView.js +30 -52
- package/dist/lib/plugins/openapi/schema/SchemaView.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/utils.d.ts +1 -0
- package/dist/lib/plugins/openapi/schema/utils.js +3 -1
- package/dist/lib/plugins/openapi/schema/utils.js.map +1 -1
- package/dist/lib/plugins/openapi/state.d.ts +25 -0
- package/dist/lib/plugins/openapi/state.js +18 -0
- package/dist/lib/plugins/openapi/state.js.map +1 -0
- package/dist/lib/plugins/openapi/util/getRoutes.js +9 -3
- package/dist/lib/plugins/openapi/util/getRoutes.js.map +1 -1
- package/dist/lib/plugins/search-pagefind/PagefindSearch.js +13 -4
- package/dist/lib/plugins/search-pagefind/PagefindSearch.js.map +1 -1
- package/dist/lib/plugins/search-pagefind/ResultList.js +19 -12
- package/dist/lib/plugins/search-pagefind/ResultList.js.map +1 -1
- package/dist/lib/plugins/search-pagefind/get-results.d.ts +8 -1
- package/dist/lib/plugins/search-pagefind/get-results.js +9 -4
- package/dist/lib/plugins/search-pagefind/get-results.js.map +1 -1
- package/dist/lib/util/traverse.d.ts +2 -8
- package/dist/lib/util/traverse.js.map +1 -1
- package/dist/lib/util/types.d.ts +7 -0
- package/dist/lib/util/types.js +2 -0
- package/dist/lib/util/types.js.map +1 -0
- package/dist/lib/util/useOnScreen.d.ts +3 -2
- package/dist/lib/util/useOnScreen.js +3 -3
- package/dist/lib/util/useOnScreen.js.map +1 -1
- package/dist/lib/util/useScrollToAnchor.js +18 -12
- package/dist/lib/util/useScrollToAnchor.js.map +1 -1
- package/dist/vite/api/schema-codegen.js +2 -2
- package/dist/vite/api/schema-codegen.js.map +1 -1
- package/dist/vite/api/schema-codegen.test.js +5 -0
- package/dist/vite/api/schema-codegen.test.js.map +1 -1
- package/dist/vite/plugin-api.js +12 -8
- package/dist/vite/plugin-api.js.map +1 -1
- package/lib/{AuthenticationPlugin-Cij2tPWa.js → AuthenticationPlugin-foqdvvkf.js} +3 -3
- package/lib/{AuthenticationPlugin-Cij2tPWa.js.map → AuthenticationPlugin-foqdvvkf.js.map} +1 -1
- package/lib/{Callout-B2vsR09t.js → Callout-D5frCCJ0.js} +2 -2
- package/lib/{Callout-B2vsR09t.js.map → Callout-D5frCCJ0.js.map} +1 -1
- package/lib/{Dialog-sbgekbjb.js → Dialog-Dv6WG8RN.js} +5 -5
- package/lib/{Dialog-sbgekbjb.js.map → Dialog-Dv6WG8RN.js.map} +1 -1
- package/lib/{Markdown-DT5Rrq8_.js → Markdown-aF5FdsNi.js} +1945 -1937
- package/lib/{Markdown-DT5Rrq8_.js.map → Markdown-aF5FdsNi.js.map} +1 -1
- package/lib/MdxPage-ZW1StNhp.js +83 -0
- package/lib/MdxPage-ZW1StNhp.js.map +1 -0
- package/lib/{OasProvider-DdEBf2qS.js → OasProvider-Cld9RAMQ.js} +4 -4
- package/lib/{OasProvider-DdEBf2qS.js.map → OasProvider-Cld9RAMQ.js.map} +1 -1
- package/lib/OperationList-D-OfzJm6.js +5065 -0
- package/lib/OperationList-D-OfzJm6.js.map +1 -0
- package/lib/Pagination-CYB3nVYx.js +46 -0
- package/lib/Pagination-CYB3nVYx.js.map +1 -0
- package/lib/SchemaList-Ci1WxRh0.js +148 -0
- package/lib/SchemaList-Ci1WxRh0.js.map +1 -0
- package/lib/SchemaView-Brn-YxHY.js +345 -0
- package/lib/SchemaView-Brn-YxHY.js.map +1 -0
- package/lib/{Select-z1Lwl0-J.js → Select-DVFRKf1R.js} +8 -8
- package/lib/{Select-z1Lwl0-J.js.map → Select-DVFRKf1R.js.map} +1 -1
- package/lib/{SlotletProvider-D8OBnr77.js → SlotletProvider-DXvc0aY6.js} +4 -4
- package/lib/{SlotletProvider-D8OBnr77.js.map → SlotletProvider-DXvc0aY6.js.map} +1 -1
- package/lib/Toc-YBsgI72s.js +92 -0
- package/lib/Toc-YBsgI72s.js.map +1 -0
- package/lib/{chunk-HA7DTUK3-ZGg2W6yV.js → chunk-HA7DTUK3-C4gP41vD.js} +5 -5
- package/lib/{chunk-HA7DTUK3-ZGg2W6yV.js.map → chunk-HA7DTUK3-C4gP41vD.js.map} +1 -1
- package/lib/{createServer-DjgKDpGV.js → createServer-mMau3eV_.js} +1732 -1664
- package/lib/{createServer-DjgKDpGV.js.map → createServer-mMau3eV_.js.map} +1 -1
- package/lib/hook-CqpVYDqN.js +1483 -0
- package/lib/hook-CqpVYDqN.js.map +1 -0
- package/lib/index-Bt7MKhZq.js +2514 -0
- package/lib/index-Bt7MKhZq.js.map +1 -0
- package/lib/{index-DdQSV2RF.js → index-CjPMxpOV.js} +809 -750
- package/lib/index-CjPMxpOV.js.map +1 -0
- package/lib/{mutation-_Z5C2wFZ.js → mutation-8LjrN7uz.js} +2 -2
- package/lib/{mutation-_Z5C2wFZ.js.map → mutation-8LjrN7uz.js.map} +1 -1
- package/lib/post-processors/traverse.js.map +1 -1
- package/lib/ui/Command.js +1 -1
- package/lib/{useExposedProps-BslIn-FE.js → useExposedProps-B9qXJedG.js} +2 -2
- package/lib/{useExposedProps-BslIn-FE.js.map → useExposedProps-B9qXJedG.js.map} +1 -1
- package/lib/zudoku.auth-auth0.js +1 -1
- package/lib/zudoku.auth-clerk.js +59 -41
- package/lib/zudoku.auth-clerk.js.map +1 -1
- package/lib/zudoku.auth-openid.js +76 -73
- package/lib/zudoku.auth-openid.js.map +1 -1
- package/lib/zudoku.components.js +31 -1440
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.hooks.js +1 -1
- package/lib/zudoku.plugin-api-catalog.js +81 -79
- package/lib/zudoku.plugin-api-catalog.js.map +1 -1
- package/lib/zudoku.plugin-api-keys.js +15 -16
- package/lib/zudoku.plugin-api-keys.js.map +1 -1
- package/lib/zudoku.plugin-custom-pages.js +2 -2
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +5 -6
- package/lib/zudoku.plugin-openapi.js.map +1 -1
- package/lib/zudoku.plugin-redirect.js +1 -1
- package/lib/zudoku.plugin-search-pagefind.js +133 -98
- package/lib/zudoku.plugin-search-pagefind.js.map +1 -1
- package/lib/zudoku.plugins.js.map +1 -1
- package/package.json +4 -3
- package/src/app/main.tsx +2 -0
- package/src/app/tailwind.ts +14 -0
- package/src/lib/authentication/authentication.ts +2 -0
- package/src/lib/authentication/providers/clerk.tsx +20 -0
- package/src/lib/authentication/providers/openid.tsx +6 -0
- package/src/lib/authentication/providers/supabase.tsx +6 -0
- package/src/lib/authentication/state.ts +1 -35
- package/src/lib/components/Layout.tsx +17 -17
- package/src/lib/components/Main.tsx +3 -1
- package/src/lib/components/Pagination.tsx +47 -0
- package/src/lib/components/TopNavigation.tsx +29 -2
- package/src/lib/components/navigation/SidebarItem.tsx +10 -4
- package/src/lib/{plugins/markdown → components/navigation}/Toc.tsx +5 -14
- package/src/lib/core/ZudokuContext.ts +13 -6
- package/src/lib/core/plugins.ts +1 -1
- package/src/lib/oas/graphql/index.ts +118 -45
- package/src/lib/oas/parser/dereference/index.ts +2 -0
- package/src/lib/oas/parser/index.ts +7 -29
- package/src/lib/plugins/api-catalog/index.tsx +40 -35
- package/src/lib/plugins/markdown/MdxPage.tsx +6 -43
- package/src/lib/plugins/openapi/ColorizedParam.tsx +1 -1
- package/src/lib/plugins/openapi/Endpoint.tsx +1 -1
- package/src/lib/plugins/openapi/OperationList.tsx +37 -16
- package/src/lib/plugins/openapi/OperationListItem.tsx +7 -2
- package/src/lib/plugins/openapi/ParameterListItem.tsx +2 -0
- package/src/lib/plugins/openapi/SchemaList.tsx +151 -0
- package/src/lib/plugins/openapi/Sidecar.tsx +36 -7
- package/src/lib/plugins/openapi/client/GraphQLClient.tsx +1 -1
- package/src/lib/plugins/openapi/client/useCreateQuery.ts +12 -5
- package/src/lib/plugins/openapi/components/EnumValues.tsx +1 -1
- package/src/lib/plugins/openapi/graphql/gql.ts +15 -6
- package/src/lib/plugins/openapi/graphql/graphql.ts +104 -15
- package/src/lib/plugins/openapi/index.tsx +13 -0
- package/src/lib/plugins/openapi/interfaces.ts +29 -0
- package/src/lib/plugins/openapi/playground/Playground.tsx +1 -1
- package/src/lib/plugins/openapi/playground/result-panel/ResultPanel.tsx +2 -1
- package/src/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.tsx +1 -8
- package/src/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.tsx +1 -2
- package/src/lib/plugins/openapi/schema/SchemaExampleAndDefault.tsx +36 -0
- package/src/lib/plugins/openapi/schema/SchemaPropertyItem.tsx +20 -21
- package/src/lib/plugins/openapi/schema/SchemaView.tsx +69 -141
- package/src/lib/plugins/openapi/schema/utils.ts +7 -1
- package/src/lib/plugins/openapi/state.ts +36 -0
- package/src/lib/plugins/openapi/util/getRoutes.tsx +9 -6
- package/src/lib/plugins/search-pagefind/PagefindSearch.tsx +26 -4
- package/src/lib/plugins/search-pagefind/ResultList.tsx +59 -47
- package/src/lib/plugins/search-pagefind/get-results.tsx +31 -10
- package/src/lib/util/traverse.ts +2 -6
- package/src/lib/util/types.ts +7 -0
- package/src/lib/util/useOnScreen.ts +6 -4
- package/src/lib/util/useScrollToAnchor.ts +20 -12
- package/dist/lib/plugins/markdown/Toc.js.map +0 -1
- package/lib/MdxPage-D2rD1vC4.js +0 -200
- package/lib/MdxPage-D2rD1vC4.js.map +0 -1
- package/lib/OperationList-DT4-gm_S.js +0 -5363
- package/lib/OperationList-DT4-gm_S.js.map +0 -1
- package/lib/hook-DzQC8PzJ.js +0 -355
- package/lib/hook-DzQC8PzJ.js.map +0 -1
- package/lib/index-DdQSV2RF.js.map +0 -1
- package/lib/index.esm-CltAN0Tf.js +0 -711
- package/lib/index.esm-CltAN0Tf.js.map +0 -1
- package/lib/joinUrl-BjDooT-T.js +0 -1154
- package/lib/joinUrl-BjDooT-T.js.map +0 -1
- /package/dist/lib/{plugins/markdown → components/navigation}/Toc.d.ts +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useMemo } from "react";
|
|
2
1
|
import { create, type Mutate, type StoreApi } from "zustand";
|
|
3
2
|
import { createJSONStorage, persist } from "zustand/middleware";
|
|
4
3
|
|
|
@@ -20,7 +19,7 @@ export type StoreWithPersist<T> = Mutate<
|
|
|
20
19
|
[["zustand/persist", unknown]]
|
|
21
20
|
>;
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
const withStorageDOMEvents = <T>(store: StoreWithPersist<T>) => {
|
|
24
23
|
const storageEventCallback = (e: StorageEvent) => {
|
|
25
24
|
if (e.key === store.persist.getOptions().name && e.newValue) {
|
|
26
25
|
void store.persist.rehydrate();
|
|
@@ -68,36 +67,3 @@ export interface UserProfile {
|
|
|
68
67
|
pictureUrl: string | undefined;
|
|
69
68
|
[key: string]: string | boolean | undefined;
|
|
70
69
|
}
|
|
71
|
-
|
|
72
|
-
interface SelectedServerState {
|
|
73
|
-
selectedServer?: string;
|
|
74
|
-
setSelectedServer: (newServer: string) => void;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export const useSelectedServerStore = create<SelectedServerState>()(
|
|
78
|
-
persist(
|
|
79
|
-
(set) => ({
|
|
80
|
-
selectedServer: undefined,
|
|
81
|
-
setSelectedServer: (newServer: string) =>
|
|
82
|
-
set({ selectedServer: newServer }),
|
|
83
|
-
}),
|
|
84
|
-
{ name: "zudoku-selected-server" },
|
|
85
|
-
),
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Simple wrapper for `useSelectedServerStore` to fall back to first of the provided servers
|
|
90
|
-
*/
|
|
91
|
-
export const useSelectedServer = (servers: Array<{ url: string }>) => {
|
|
92
|
-
const { selectedServer, setSelectedServer } = useSelectedServerStore();
|
|
93
|
-
|
|
94
|
-
const finalSelectedServer = useMemo(
|
|
95
|
-
() =>
|
|
96
|
-
selectedServer && servers.some((s) => s.url === selectedServer)
|
|
97
|
-
? selectedServer
|
|
98
|
-
: (servers.at(0)?.url ?? ""),
|
|
99
|
-
[selectedServer, servers],
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
return { selectedServer: finalSelectedServer, setSelectedServer };
|
|
103
|
-
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Helmet } from "@zudoku/react-helmet-async";
|
|
2
2
|
import { Suspense, useEffect, type ReactNode } from "react";
|
|
3
|
-
import { Outlet,
|
|
4
|
-
import {
|
|
3
|
+
import { Outlet, useLocation } from "react-router";
|
|
4
|
+
import { joinUrl } from "../util/joinUrl.js";
|
|
5
5
|
import { useScrollToAnchor } from "../util/useScrollToAnchor.js";
|
|
6
6
|
import { useScrollToTop } from "../util/useScrollToTop.js";
|
|
7
7
|
import { useZudoku } from "./context/ZudokuContext.js";
|
|
@@ -17,7 +17,8 @@ const LoadingFallback = () => (
|
|
|
17
17
|
);
|
|
18
18
|
|
|
19
19
|
export const Layout = ({ children }: { children?: ReactNode }) => {
|
|
20
|
-
const { meta, authentication } = useZudoku();
|
|
20
|
+
const { meta, authentication, options } = useZudoku();
|
|
21
|
+
const location = useLocation();
|
|
21
22
|
|
|
22
23
|
useScrollToAnchor();
|
|
23
24
|
useScrollToTop();
|
|
@@ -27,19 +28,22 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
|
|
|
27
28
|
authentication?.onPageLoad?.();
|
|
28
29
|
}, [authentication]);
|
|
29
30
|
|
|
30
|
-
// Page transition is happening: https://reactrouter.com/start/framework/pending-navigation
|
|
31
|
-
const isNavigating = Boolean(useNavigation().location);
|
|
32
|
-
const showSpinner = useSpinDelay(isNavigating, {
|
|
33
|
-
delay: 300,
|
|
34
|
-
minDuration: 500,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
31
|
return (
|
|
38
32
|
<>
|
|
39
33
|
{import.meta.env.MODE === "standalone" && (
|
|
40
34
|
<style>{`:root { --top-nav-height: 0px; }`}</style>
|
|
41
35
|
)}
|
|
42
36
|
<Helmet titleTemplate={meta?.title}>
|
|
37
|
+
{options.canonicalUrlOrigin && (
|
|
38
|
+
<link
|
|
39
|
+
rel="canonical"
|
|
40
|
+
href={joinUrl(
|
|
41
|
+
options.canonicalUrlOrigin,
|
|
42
|
+
options.basePath,
|
|
43
|
+
location.pathname,
|
|
44
|
+
)}
|
|
45
|
+
/>
|
|
46
|
+
)}
|
|
43
47
|
{meta?.description && (
|
|
44
48
|
<meta name="description" content={meta.description} />
|
|
45
49
|
)}
|
|
@@ -50,13 +54,9 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
|
|
|
50
54
|
<Slotlet name="layout-after-head" />
|
|
51
55
|
|
|
52
56
|
<div className="grid grid-cols-1 grid-rows-[min-content_1fr] lg:grid-cols-[var(--side-nav-width)_1fr] max-w-screen-2xl w-full lg:mx-auto px-4 lg:px-8 2xl:border-x">
|
|
53
|
-
{
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
<Suspense fallback={<LoadingFallback />}>
|
|
57
|
-
<Main>{children ?? <Outlet />}</Main>
|
|
58
|
-
</Suspense>
|
|
59
|
-
)}
|
|
57
|
+
<Suspense fallback={<LoadingFallback />}>
|
|
58
|
+
<Main>{children ?? <Outlet />}</Main>
|
|
59
|
+
</Suspense>
|
|
60
60
|
</div>
|
|
61
61
|
</>
|
|
62
62
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PanelLeftIcon } from "lucide-react";
|
|
2
2
|
import { type PropsWithChildren, useState } from "react";
|
|
3
|
+
import { useNavigation } from "react-router";
|
|
3
4
|
import { Drawer, DrawerTrigger } from "zudoku/ui/Drawer.js";
|
|
4
5
|
import { cn } from "../util/cn.js";
|
|
5
6
|
import { useCurrentNavigation } from "./context/ZudokuContext.js";
|
|
@@ -10,6 +11,7 @@ export const Main = ({ children }: PropsWithChildren) => {
|
|
|
10
11
|
const [isDrawerOpen, setDrawerOpen] = useState(false);
|
|
11
12
|
const { sidebar } = useCurrentNavigation();
|
|
12
13
|
const hasSidebar = sidebar.length > 0;
|
|
14
|
+
const isNavigating = useNavigation().state === "loading";
|
|
13
15
|
|
|
14
16
|
return (
|
|
15
17
|
<Drawer
|
|
@@ -34,8 +36,8 @@ export const Main = ({ children }: PropsWithChildren) => {
|
|
|
34
36
|
<main
|
|
35
37
|
data-pagefind-body
|
|
36
38
|
className={cn(
|
|
37
|
-
"h-auto dark:border-white/10 translate-x-0",
|
|
38
39
|
hasSidebar ? "lg:pl-12" : "col-span-full",
|
|
40
|
+
isNavigating && "animate-pulse",
|
|
39
41
|
)}
|
|
40
42
|
>
|
|
41
43
|
<Slotlet name="zudoku-before-content" />
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";
|
|
2
|
+
import { Link } from "react-router";
|
|
3
|
+
import { cn } from "../util/cn.js";
|
|
4
|
+
import { Button } from "./index.js";
|
|
5
|
+
|
|
6
|
+
export const Pagination = ({
|
|
7
|
+
prev,
|
|
8
|
+
next,
|
|
9
|
+
}: {
|
|
10
|
+
prev: { to: string; label: string } | undefined;
|
|
11
|
+
next: { to: string; label: string } | undefined;
|
|
12
|
+
}) => {
|
|
13
|
+
const linkClass =
|
|
14
|
+
"group transition-all p-5 space-x-1 transition-all hover:text-foreground";
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
className={cn(
|
|
19
|
+
"flex my-8 -mx-4 text-muted-foreground font-semibold",
|
|
20
|
+
prev ? "justify-between" : "justify-end",
|
|
21
|
+
)}
|
|
22
|
+
>
|
|
23
|
+
{prev && (
|
|
24
|
+
<Button variant="ghost" asChild>
|
|
25
|
+
<Link to={prev.to} relative="path" className={linkClass}>
|
|
26
|
+
<ArrowLeftIcon
|
|
27
|
+
className="group-hover:motion-safe:animate-bounce-x-start"
|
|
28
|
+
size={12}
|
|
29
|
+
/>
|
|
30
|
+
<span className="truncate">{prev.label}</span>
|
|
31
|
+
</Link>
|
|
32
|
+
</Button>
|
|
33
|
+
)}
|
|
34
|
+
{next && (
|
|
35
|
+
<Button variant="ghost" asChild>
|
|
36
|
+
<Link to={next.to} relative="path" className={linkClass}>
|
|
37
|
+
<span className="truncate ">{next.label}</span>
|
|
38
|
+
<ArrowRightIcon
|
|
39
|
+
className="group-hover:motion-safe:animate-bounce-x-end"
|
|
40
|
+
size={12}
|
|
41
|
+
/>
|
|
42
|
+
</Link>
|
|
43
|
+
</Button>
|
|
44
|
+
)}
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { useNProgress } from "@tanem/react-nprogress";
|
|
1
2
|
import { cx } from "class-variance-authority";
|
|
2
|
-
import { Suspense } from "react";
|
|
3
|
+
import { Suspense, useEffect, useState } from "react";
|
|
3
4
|
import { NavLink, useNavigation } from "react-router";
|
|
4
5
|
import type { TopNavigationItem } from "../../config/validators/common.js";
|
|
5
6
|
import { useAuth } from "../authentication/hook.js";
|
|
@@ -20,6 +21,31 @@ export const isHiddenItem =
|
|
|
20
21
|
);
|
|
21
22
|
};
|
|
22
23
|
|
|
24
|
+
const Progress = () => {
|
|
25
|
+
const navigation = useNavigation();
|
|
26
|
+
const isNavigating = navigation.state === "loading";
|
|
27
|
+
// delay the animation to avoid flickering
|
|
28
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const timer = setTimeout(() => setIsAnimating(isNavigating), 100);
|
|
32
|
+
|
|
33
|
+
return () => clearTimeout(timer);
|
|
34
|
+
}, [isNavigating]);
|
|
35
|
+
|
|
36
|
+
const { isFinished, progress } = useNProgress({ isAnimating });
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
className="absolute w-0 left-0 right-0 bottom-[-1px] h-[2px] bg-primary transition-all duration-300 ease-in-out"
|
|
41
|
+
style={{
|
|
42
|
+
opacity: isFinished ? 0 : 1,
|
|
43
|
+
width: isFinished ? 0 : `${progress * 100}%`,
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
23
49
|
export const TopNavigation = () => {
|
|
24
50
|
const { topNavigation } = useZudoku();
|
|
25
51
|
const { isAuthenticated } = useAuth();
|
|
@@ -32,7 +58,7 @@ export const TopNavigation = () => {
|
|
|
32
58
|
|
|
33
59
|
return (
|
|
34
60
|
<Suspense>
|
|
35
|
-
<div className="items-center justify-between px-8 h-[--top-nav-height] hidden lg:flex text-sm">
|
|
61
|
+
<div className="items-center justify-between px-8 h-[--top-nav-height] hidden lg:flex text-sm relative">
|
|
36
62
|
<nav className="text-sm">
|
|
37
63
|
<ul className="flex flex-row items-center gap-8">
|
|
38
64
|
{filteredItems.map((item) => (
|
|
@@ -43,6 +69,7 @@ export const TopNavigation = () => {
|
|
|
43
69
|
</ul>
|
|
44
70
|
</nav>
|
|
45
71
|
<Slotlet name="top-navigation-side" />
|
|
72
|
+
<Progress />
|
|
46
73
|
</div>
|
|
47
74
|
</Suspense>
|
|
48
75
|
);
|
|
@@ -3,14 +3,14 @@ import { ExternalLinkIcon } from "lucide-react";
|
|
|
3
3
|
import { NavLink, useLocation, useSearchParams } from "react-router";
|
|
4
4
|
|
|
5
5
|
import type { SidebarItem as SidebarItemType } from "../../../config/validators/SidebarSchema.js";
|
|
6
|
-
import {
|
|
6
|
+
import { joinUrl } from "../../util/joinUrl.js";
|
|
7
7
|
import { AnchorLink } from "../AnchorLink.js";
|
|
8
8
|
import { useViewportAnchor } from "../context/ViewportAnchorContext.js";
|
|
9
9
|
import { SidebarBadge } from "./SidebarBadge.js";
|
|
10
10
|
import { SidebarCategory } from "./SidebarCategory.js";
|
|
11
11
|
|
|
12
12
|
export const navigationListItem = cva(
|
|
13
|
-
"flex items-center gap-2 px-[--padding-nav-item] my-0.5 py-1.5 rounded-lg hover:bg-accent",
|
|
13
|
+
"flex items-center gap-2 px-[--padding-nav-item] my-0.5 py-1.5 rounded-lg hover:bg-accent tabular-nums",
|
|
14
14
|
{
|
|
15
15
|
variants: {
|
|
16
16
|
isActive: {
|
|
@@ -21,6 +21,10 @@ export const navigationListItem = cva(
|
|
|
21
21
|
true: "text-foreground/30",
|
|
22
22
|
false: "",
|
|
23
23
|
},
|
|
24
|
+
isPending: {
|
|
25
|
+
true: "bg-accent animate-pulse",
|
|
26
|
+
false: "",
|
|
27
|
+
},
|
|
24
28
|
},
|
|
25
29
|
defaultVariants: {
|
|
26
30
|
isActive: false,
|
|
@@ -49,8 +53,10 @@ export const SidebarItem = ({
|
|
|
49
53
|
case "doc":
|
|
50
54
|
return (
|
|
51
55
|
<NavLink
|
|
52
|
-
className={({ isActive }) =>
|
|
53
|
-
|
|
56
|
+
className={({ isActive, isPending }) =>
|
|
57
|
+
navigationListItem({ isActive, isPending })
|
|
58
|
+
}
|
|
59
|
+
to={joinUrl(item.id)}
|
|
54
60
|
onClick={onRequestClose}
|
|
55
61
|
end
|
|
56
62
|
>
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
type CSSProperties,
|
|
8
8
|
type PropsWithChildren,
|
|
9
9
|
} from "react";
|
|
10
|
-
import { AnchorLink } from "../../components/AnchorLink.js";
|
|
11
|
-
import { useViewportAnchor } from "../../components/context/ViewportAnchorContext.js";
|
|
12
10
|
import { cn } from "../../util/cn.js";
|
|
11
|
+
import { AnchorLink } from "../AnchorLink.js";
|
|
12
|
+
import { useViewportAnchor } from "../context/ViewportAnchorContext.js";
|
|
13
13
|
|
|
14
14
|
const DATA_ANCHOR_ATTR = "data-active";
|
|
15
15
|
|
|
@@ -24,23 +24,14 @@ const TocItem = ({
|
|
|
24
24
|
className?: string;
|
|
25
25
|
}>) => {
|
|
26
26
|
return (
|
|
27
|
-
<li
|
|
28
|
-
className={cn(
|
|
29
|
-
"truncate",
|
|
30
|
-
isActive
|
|
31
|
-
? "text-primary"
|
|
32
|
-
: "text-foreground/65 dark:text-foreground/75",
|
|
33
|
-
className,
|
|
34
|
-
)}
|
|
35
|
-
title={item.value}
|
|
36
|
-
>
|
|
27
|
+
<li className={cn("truncate", className)} title={item.value}>
|
|
37
28
|
<AnchorLink
|
|
38
29
|
to={`#${item.id}`}
|
|
39
30
|
{...{ [DATA_ANCHOR_ATTR]: item.id }}
|
|
40
31
|
className={cn(
|
|
41
32
|
isActive
|
|
42
33
|
? "text-primary"
|
|
43
|
-
: "
|
|
34
|
+
: "hover:text-accent-foreground text-muted-foreground",
|
|
44
35
|
)}
|
|
45
36
|
>
|
|
46
37
|
{item.value}
|
|
@@ -89,7 +80,7 @@ export const Toc = ({ entries }: { entries: TocEntry[] }) => {
|
|
|
89
80
|
}, [activeAnchor]);
|
|
90
81
|
|
|
91
82
|
return (
|
|
92
|
-
<aside className="sticky scrollbar top-[--header-height] h-[calc(100vh-var(--header-height))] pt-[--padding-content-top] pb-[--padding-content-bottom] overflow-y-auto ps-1 text-sm">
|
|
83
|
+
<aside className="sticky scrollbar top-8 lg:top-[--header-height] h-[calc(100vh-var(--header-height))] pt-[--padding-content-top] pb-[--padding-content-bottom] overflow-y-auto ps-1 text-sm">
|
|
93
84
|
<div className="flex items-center gap-2 font-medium mb-2">
|
|
94
85
|
<ListTreeIcon size={16} />
|
|
95
86
|
On this page
|
|
@@ -5,6 +5,7 @@ import type { Location } from "react-router";
|
|
|
5
5
|
import type { TopNavigationItem } from "../../config/validators/common.js";
|
|
6
6
|
import type { SidebarConfig } from "../../config/validators/SidebarSchema.js";
|
|
7
7
|
import type { AuthenticationProvider } from "../authentication/authentication.js";
|
|
8
|
+
import { type AuthState, useAuthState } from "../authentication/state.js";
|
|
8
9
|
import type { ComponentsContextType } from "../components/context/ComponentsContext.js";
|
|
9
10
|
import type { Slotlets } from "../components/SlotletProvider.js";
|
|
10
11
|
import { joinPath } from "../util/joinPath.js";
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
|
|
22
23
|
export interface ZudokuEvents {
|
|
23
24
|
location: (event: { from?: Location; to: Location }) => void;
|
|
25
|
+
auth: (auth: { prev: AuthState; next: AuthState }) => void;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export interface ApiIdentity {
|
|
@@ -67,6 +69,8 @@ type Page = Partial<{
|
|
|
67
69
|
}>;
|
|
68
70
|
|
|
69
71
|
export type ZudokuContextOptions = {
|
|
72
|
+
basePath?: string;
|
|
73
|
+
canonicalUrlOrigin?: string;
|
|
70
74
|
metadata?: Metadata;
|
|
71
75
|
page?: Page;
|
|
72
76
|
authentication?: AuthenticationProvider;
|
|
@@ -106,7 +110,14 @@ export class ZudokuContext {
|
|
|
106
110
|
if (!isEventConsumerPlugin(plugin)) return;
|
|
107
111
|
|
|
108
112
|
objectEntries(plugin.events).forEach(([event, handler]) => {
|
|
109
|
-
this.emitter.on(event, handler);
|
|
113
|
+
this.emitter.on(event, handler!);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
useAuthState.subscribe((state, prevState) => {
|
|
118
|
+
this.emitEvent("auth", {
|
|
119
|
+
prev: prevState,
|
|
120
|
+
next: state,
|
|
110
121
|
});
|
|
111
122
|
});
|
|
112
123
|
}
|
|
@@ -158,10 +169,6 @@ export class ZudokuContext {
|
|
|
158
169
|
throw new Error("No authentication provider configured");
|
|
159
170
|
}
|
|
160
171
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
request.headers.set("Authorization", `Bearer ${accessToken}`);
|
|
164
|
-
|
|
165
|
-
return request;
|
|
172
|
+
return await this.authentication.signRequest(request);
|
|
166
173
|
};
|
|
167
174
|
}
|
package/src/lib/core/plugins.ts
CHANGED
|
@@ -65,7 +65,7 @@ export interface CommonPlugin {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
export type EventConsumerPlugin<Event extends ZudokuEvents = ZudokuEvents> = {
|
|
68
|
-
events: { [K in keyof Event]
|
|
68
|
+
events: { [K in keyof Event]?: Event[K] };
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
export const isEventConsumerPlugin = (
|
|
@@ -97,7 +97,7 @@ const resolveExtensions = (obj: Record<string, any>) =>
|
|
|
97
97
|
export const getAllTags = (
|
|
98
98
|
schema: OpenAPIDocument,
|
|
99
99
|
slugs: ReturnType<typeof getAllSlugs>["tags"],
|
|
100
|
-
): Array<TagObject & { slug?: string }> => {
|
|
100
|
+
): Array<Omit<TagObject, "name"> & { name?: string; slug?: string }> => {
|
|
101
101
|
const rootTags = schema.tags ?? [];
|
|
102
102
|
const operationTags = new Set(
|
|
103
103
|
Object.values(schema.paths ?? {})
|
|
@@ -105,6 +105,12 @@ export const getAllTags = (
|
|
|
105
105
|
.flatMap((op) => (op as OperationObject).tags ?? []),
|
|
106
106
|
);
|
|
107
107
|
|
|
108
|
+
const hasUntaggedOperations = Object.values(schema.paths ?? {}).some((path) =>
|
|
109
|
+
Object.values(path ?? {}).some(
|
|
110
|
+
(op) => !(op as OperationObject).tags?.length,
|
|
111
|
+
),
|
|
112
|
+
);
|
|
113
|
+
|
|
108
114
|
return [
|
|
109
115
|
// Keep root tags that are actually used in operations
|
|
110
116
|
...rootTags
|
|
@@ -114,6 +120,8 @@ export const getAllTags = (
|
|
|
114
120
|
...[...operationTags]
|
|
115
121
|
.filter((tag) => !rootTags.some((rt) => rt.name === tag))
|
|
116
122
|
.map((tag) => ({ name: tag, slug: slugs[tag] })),
|
|
123
|
+
// Add untagged operations if there are any
|
|
124
|
+
...(hasUntaggedOperations ? [{ name: undefined, slug: undefined }] : []),
|
|
117
125
|
];
|
|
118
126
|
};
|
|
119
127
|
|
|
@@ -181,38 +189,55 @@ export const getAllOperations = (
|
|
|
181
189
|
return operations;
|
|
182
190
|
};
|
|
183
191
|
|
|
184
|
-
const SchemaTag = builder
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
extensions: t.field({
|
|
210
|
-
type: JSONObjectScalar,
|
|
211
|
-
resolve: (parent) => resolveExtensions(parent),
|
|
212
|
-
nullable: true,
|
|
213
|
-
}),
|
|
192
|
+
const SchemaTag = builder.objectRef<
|
|
193
|
+
Omit<TagObject, "name"> & { name?: string; slug?: string }
|
|
194
|
+
>("SchemaTag");
|
|
195
|
+
|
|
196
|
+
SchemaTag.implement({
|
|
197
|
+
fields: (t) => ({
|
|
198
|
+
name: t.exposeString("name", { nullable: true }),
|
|
199
|
+
slug: t.exposeString("slug", { nullable: true }),
|
|
200
|
+
isUntagged: t.field({ type: "Boolean", resolve: (parent) => !parent.name }),
|
|
201
|
+
description: t.exposeString("description", { nullable: true }),
|
|
202
|
+
operations: t.field({
|
|
203
|
+
type: [OperationItem],
|
|
204
|
+
resolve: (parent, _args, ctx) => {
|
|
205
|
+
const rootTags = ctx.tags.map((tag) => tag.name);
|
|
206
|
+
|
|
207
|
+
return ctx.operations
|
|
208
|
+
.filter((item) =>
|
|
209
|
+
parent.name
|
|
210
|
+
? item.tags?.includes(parent.name)
|
|
211
|
+
: item.tags?.length === 0 ||
|
|
212
|
+
// If none of the tags are present in the root tags, then show them here
|
|
213
|
+
item.tags?.every((tag) => !rootTags.includes(tag)),
|
|
214
|
+
)
|
|
215
|
+
.map((item) => ({ ...item, parentTag: parent.name }));
|
|
216
|
+
},
|
|
214
217
|
}),
|
|
215
|
-
|
|
218
|
+
prev: t.field({
|
|
219
|
+
type: SchemaTag,
|
|
220
|
+
nullable: true,
|
|
221
|
+
resolve: (parent, _args, ctx) => {
|
|
222
|
+
const index = ctx.tags.findIndex((tag) => tag.slug === parent.slug);
|
|
223
|
+
return ctx.tags[index - 1];
|
|
224
|
+
},
|
|
225
|
+
}),
|
|
226
|
+
next: t.field({
|
|
227
|
+
type: SchemaTag,
|
|
228
|
+
nullable: true,
|
|
229
|
+
resolve: (parent, _args, ctx) => {
|
|
230
|
+
const index = ctx.tags.findIndex((tag) => tag.slug === parent.slug);
|
|
231
|
+
return ctx.tags[index + 1];
|
|
232
|
+
},
|
|
233
|
+
}),
|
|
234
|
+
extensions: t.field({
|
|
235
|
+
type: JSONObjectScalar,
|
|
236
|
+
resolve: (parent) => resolveExtensions(parent),
|
|
237
|
+
nullable: true,
|
|
238
|
+
}),
|
|
239
|
+
}),
|
|
240
|
+
});
|
|
216
241
|
|
|
217
242
|
const ServerItem = builder.objectRef<ServerObject>("Server").implement({
|
|
218
243
|
fields: (t) => ({
|
|
@@ -466,6 +491,43 @@ const OperationItem = builder
|
|
|
466
491
|
}),
|
|
467
492
|
});
|
|
468
493
|
|
|
494
|
+
const SchemaItem = builder
|
|
495
|
+
.objectRef<{
|
|
496
|
+
name: string;
|
|
497
|
+
schema: SchemaObject;
|
|
498
|
+
extensions?: Record<string, any>;
|
|
499
|
+
}>("SchemaItem")
|
|
500
|
+
.implement({
|
|
501
|
+
fields: (t) => ({
|
|
502
|
+
name: t.exposeString("name"),
|
|
503
|
+
schema: t.expose("schema", { type: JSONSchemaScalar }),
|
|
504
|
+
extensions: t.expose("extensions", {
|
|
505
|
+
type: JSONObjectScalar,
|
|
506
|
+
nullable: true,
|
|
507
|
+
}),
|
|
508
|
+
}),
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
const Components = builder.objectRef<{
|
|
512
|
+
schemas?: Record<string, SchemaObject>;
|
|
513
|
+
}>("Components");
|
|
514
|
+
|
|
515
|
+
Components.implement({
|
|
516
|
+
fields: (t) => ({
|
|
517
|
+
schemas: t.field({
|
|
518
|
+
type: [SchemaItem],
|
|
519
|
+
resolve: (parent) => {
|
|
520
|
+
return Object.entries(parent.schemas ?? {}).map(([name, schema]) => ({
|
|
521
|
+
name,
|
|
522
|
+
schema,
|
|
523
|
+
extensions: resolveExtensions(schema),
|
|
524
|
+
}));
|
|
525
|
+
},
|
|
526
|
+
nullable: true,
|
|
527
|
+
}),
|
|
528
|
+
}),
|
|
529
|
+
});
|
|
530
|
+
|
|
469
531
|
const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
|
|
470
532
|
fields: (t) => ({
|
|
471
533
|
openapi: t.string({ resolve: (root) => root.openapi }),
|
|
@@ -495,24 +557,30 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
|
|
|
495
557
|
methods: Object.keys(value!) as typeof HttpMethods,
|
|
496
558
|
})),
|
|
497
559
|
}),
|
|
498
|
-
|
|
560
|
+
tag: t.field({
|
|
561
|
+
type: SchemaTag,
|
|
499
562
|
args: {
|
|
563
|
+
slug: t.arg.string(),
|
|
500
564
|
name: t.arg.string(),
|
|
565
|
+
untagged: t.arg.boolean(),
|
|
501
566
|
},
|
|
502
|
-
|
|
503
|
-
resolve: (
|
|
504
|
-
if (args.
|
|
505
|
-
return ctx.tags.
|
|
567
|
+
nullable: true,
|
|
568
|
+
resolve: (_, args, ctx) => {
|
|
569
|
+
if (args.untagged) {
|
|
570
|
+
return ctx.tags.find((tag) => tag.name === undefined);
|
|
506
571
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
572
|
+
if (args.slug) {
|
|
573
|
+
return ctx.tags.find((tag) => tag.slug === args.slug);
|
|
574
|
+
}
|
|
575
|
+
if (args.name) {
|
|
576
|
+
return ctx.tags.find((tag) => tag.name === args.name);
|
|
511
577
|
}
|
|
512
|
-
|
|
513
|
-
return ctx.tags;
|
|
514
578
|
},
|
|
515
579
|
}),
|
|
580
|
+
tags: t.field({
|
|
581
|
+
type: [SchemaTag],
|
|
582
|
+
resolve: (_root, _args, ctx) => ctx.tags,
|
|
583
|
+
}),
|
|
516
584
|
operations: t.field({
|
|
517
585
|
type: [OperationItem],
|
|
518
586
|
args: {
|
|
@@ -522,7 +590,7 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
|
|
|
522
590
|
tag: t.arg.string(),
|
|
523
591
|
untagged: t.arg.boolean(),
|
|
524
592
|
},
|
|
525
|
-
resolve: (
|
|
593
|
+
resolve: (_parent, args, ctx) =>
|
|
526
594
|
ctx.operations.filter((op) => {
|
|
527
595
|
return (
|
|
528
596
|
(!args.operationId || op.operationId === args.operationId) &&
|
|
@@ -533,6 +601,11 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
|
|
|
533
601
|
);
|
|
534
602
|
}),
|
|
535
603
|
}),
|
|
604
|
+
components: t.field({
|
|
605
|
+
type: Components,
|
|
606
|
+
resolve: (root) => root.components,
|
|
607
|
+
nullable: true,
|
|
608
|
+
}),
|
|
536
609
|
extensions: t.field({
|
|
537
610
|
type: JSONObjectScalar,
|
|
538
611
|
resolve: (root) => resolveExtensions(root),
|
|
@@ -553,7 +626,7 @@ builder.queryType({
|
|
|
553
626
|
type: t.arg({ type: SchemaSource, required: true }),
|
|
554
627
|
input: t.arg({ type: JSONScalar, required: true }),
|
|
555
628
|
},
|
|
556
|
-
resolve: async (
|
|
629
|
+
resolve: async (_parent, args, ctx) => {
|
|
557
630
|
if (args.type === "file" && typeof args.input === "string") {
|
|
558
631
|
const loadSchema = ctx.schemaImports?.[args.input];
|
|
559
632
|
|
|
@@ -38,6 +38,8 @@ export const dereference = async (
|
|
|
38
38
|
}
|
|
39
39
|
} else {
|
|
40
40
|
if ("$ref" in current && typeof current.$ref === "string") {
|
|
41
|
+
// Store the ref path before resolving
|
|
42
|
+
current.__$ref = current.$ref;
|
|
41
43
|
for (const resolver of resolvers) {
|
|
42
44
|
const resolved = await resolver(current.$ref);
|
|
43
45
|
if (resolved) return await resolve(resolved, path);
|