@umami/shiso 1.17.0 → 1.19.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/chunks/App.js +1217 -196
- package/dist/chunks/architectureDiagram-5GKGNRK7.js +1 -1
- package/dist/chunks/chunk-GMAD6QVW.js +1 -1
- package/dist/chunks/cose-bilkent-JH36ORCC.js +1 -1
- package/dist/chunks/dist.js +1 -1
- package/dist/chunks/docs.js +843 -22
- package/dist/chunks/ganttDiagram-EL5Y4UJY.js +1 -1
- package/dist/chunks/src.js +1 -1
- package/dist/components.js +1 -1
- package/dist/entry-client.js +1 -1
- package/dist/entry-server.js +1 -1
- package/docs.schema.json +1164 -1131
- package/package.json +1 -2
- package/scripts/check-content.mjs +44 -15
- package/scripts/expand-openapi-navigation.mjs +47 -21
- package/scripts/generate-openapi.mjs +36 -11
- package/scripts/generate-search-index.mjs +19 -18
- package/scripts/lib/openapi-project.mjs +197 -0
- package/scripts/lib/openapi.mjs +257 -111
- package/scripts/lib/request-samples.mjs +323 -0
- package/scripts/load-docs-config.mjs +23 -15
- package/scripts/load-shiso-config.mjs +30 -1
- package/scripts/prerender.mjs +17 -14
- package/scripts/vite-docs-config.mjs +1 -0
- package/src/App.tsx +32 -22
- package/src/components/ApiPlayground.tsx +522 -0
- package/src/components/CodeBlock.tsx +3 -1
- package/src/components/DocContent.tsx +15 -4
- package/src/components/Docs.tsx +19 -2
- package/src/components/Footer.tsx +3 -1
- package/src/components/Header.tsx +4 -3
- package/src/components/LanguageSwitcher.tsx +38 -29
- package/src/components/OpenApiOperation.tsx +73 -20
- package/src/components/OpenApiSchema.tsx +97 -0
- package/src/components/PageActions.tsx +8 -7
- package/src/components/SideNav.tsx +2 -2
- package/src/components/docs/Changelog.tsx +5 -5
- package/src/components/docs/CodeGroup.tsx +3 -1
- package/src/components/docs/Mermaid.tsx +8 -6
- package/src/components/docs/PropertiesTable.tsx +11 -6
- package/src/components/docs/Tabs.tsx +3 -1
- package/src/components/docs/Tree.tsx +3 -1
- package/src/components/docs/ZoomableImage.tsx +4 -2
- package/src/components/ui/dialog.tsx +7 -2
- package/src/components/ui/sheet.tsx +5 -2
- package/src/lib/label-context.tsx +7 -0
- package/src/lib/labels.ts +37 -0
- package/src/lib/openapi.generated.ts +2 -1
- package/src/lib/openapi.ts +123 -16
- package/src/lib/site-config.ts +66 -2
- package/src/lib/site-model.ts +14 -32
- package/src/lib/standalone-pages.ts +15 -1
- package/src/lib/translations/de.json +99 -0
- package/src/lib/translations/en.json +99 -0
- package/src/lib/translations/es.json +99 -0
- package/src/lib/translations/fr.json +99 -0
- package/src/lib/translations/ja.json +99 -0
- package/src/lib/translations/zh-Hans.json +99 -0
- package/src/lib/translations/zh-Hant.json +99 -0
- package/src/lib/types.ts +109 -37
- package/types/config.d.ts +7 -1
- package/types/labels.d.ts +101 -0
- package/vite.config.ts +3 -4
- package/CHANGELOG.md +0 -8
package/dist/chunks/App.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { $ as useFloatingNodeId, $n as
|
|
1
|
+
import { $ as useFloatingNodeId, $n as ARROW_LEFT, $t as resolveIcon, A as safePolygon, An as isValidLocale, Ar as createLucideIcon, B as attachPreventUnmountOnClose, Bn as getMinListIndex, Cr as getParentNode, D as useAnchorPositioning, Dn as resolveLabels, Dr as X$1, Dt as Collapsible, E as getDisabledMountTransitionStyles, En as englishLabels, Er as isLastTraversableNode, Et as Expandable, F as createInitialPopupStoreState, Fn as getTabbableAfterElement, Ft as useCompositeItem, G as useTriggerDataForwarding, Gn as isVirtualPointerEvent, H as useImplicitActiveTrigger, Hn as isIndexOutOfListBounds, I as popupStoreSelectors, In as getTabbableBeforeElement, Ir as Routes, J as useDismiss, Jn as isTypeableCombobox, K as useSyncedFloatingRootContext, Kn as stopEvent, L as PopupTriggerMap, Ln as isOutsideEvent, Lr as useLocation, M as useHoverFloatingInteraction, Mn as addEventListener, Mr as Link, Mt as CodeGroup, N as useFocus, Nn as useDirection, Nr as Navigate, Nt as COMPOSITE_KEYS, O as popupTransitionStateMapping, On as getLanguageName, Or as ChevronRight, Ot as CollapsibleContent, P as usePopupHandleStore, Pn as getNextTabbable, Pr as Route, Pt as inertValue, Q as FloatingTree, Qn as ARROW_DOWN, R as FOCUSABLE_POPUP_PROPS, Rn as findNonDisabledListIndex, Rr as useNavigate, Sn as Mermaid, Sr as useRefWithInit, T as usePositioner, Tn as useLabels, Tr as isHTMLElement, Tt as renderInlineMarkdown, U as useOpenStateTransitions, Un as isListIndexDisabled, V as setPopupOpenState, Vn as isElementVisible, W as usePopupInteractionProps, Wn as isVirtualClick, X as FloatingFocusManager, Xn as contains, Xt as Badge$1, Y as useClick, Yn as activeElement, Yt as Badge, Z as FloatingNode, Zn as getTarget, _n as triggerFocus, _r as ownerDocument, a as DialogTitle, an as useCompositeListItem, ar as useBaseUiId, at as POPUP_COLLISION_AVOIDANCE, bn as CompositeList, br as useIsoLayoutEffect, bt as usePanelContent, c as useOpenInteractionType, cn as createChangeEventDetails, cr as Button, ct as fastComponent, d as useScrollLock, dn as focusOut, dr as EMPTY_ARRAY, en as getIcon, er as ARROW_RIGHT, et as useFloatingParentNodeId, f as DialogPortal$1, fn as imperativeAction, fr as EMPTY_OBJECT, g as DialogBackdrop, gn as siblingOpen, gr as dispatchClickWithModifiers, gt as PropertiesTable, h as DialogClose, hn as outsidePress, hr as useButton, i as DialogContent$1, in as transitionStatusMapping, ir as mac, it as DROPDOWN_COLLISION_AVOIDANCE, j as useHoverReferenceInteraction, jn as resolveLocale, k as pressableTriggerOpenStateMapping, kn as getTextDirection, kr as Check, kt as CollapsibleTrigger, l as DialogTitle$1, ln as cancelOpen, lr as cn, lt as fastComponentRef, m as DialogPopup, mn as listNavigation, mr as useMergedRefs, n as ZoomableImage, nn as useAnimationsFinished, nr as jsdom, nt as FloatingTreeStore, o as DialogTrigger, on as useTransitionStatus, or as useId$2, ot as enqueueFocus, p as InternalBackdrop, pn as itemPress, pr as NOOP, q as ReactStore, qn as getFloatingFocusElement, r as Dialog$1, rn as useValueAsRef, rr as webkit, rt as FloatingPortal, s as DialogTrigger$1, sn as useAnimationFrame, sr as useTimeout, st as FocusGuard, t as docs_exports, tn as useOpenChangeComplete, tr as ARROW_UP, tt as useFloatingTree, u as DialogRoot, un as escapeKey, ur as useRenderElement, vn as triggerHover, vr as useCompositeRootContext, w as TooltipProvider, wn as LabelContext, wr as getWindow, xn as useControlled, xr as useStableCallback, yn as triggerPress, yr as mergeProps$1, yt as PanelProvider, z as PopupHandleAttachment, zn as getMaxListIndex } from "./docs.js";
|
|
2
2
|
import { n as highlightTerms } from "./search.js";
|
|
3
3
|
import { resolveSearchProvider } from "../search.js";
|
|
4
4
|
import * as React from "react";
|
|
5
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
|
+
import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
6
6
|
import "@fontsource-variable/inter/index.css";
|
|
7
7
|
import "@fontsource/jetbrains-mono/400.css";
|
|
8
8
|
import "@umami/shiso/styles.css";
|
|
@@ -12,7 +12,7 @@ import * as ReactDOM from "react-dom";
|
|
|
12
12
|
import shiso from "virtual:shiso-config";
|
|
13
13
|
import rawConfig from "virtual:shiso-docs-config";
|
|
14
14
|
import { LAST_MODIFIED } from "@/generated/last-modified";
|
|
15
|
-
import { OPENAPI_OPERATIONS } from "@/lib/openapi.generated";
|
|
15
|
+
import { OPENAPI_OPERATIONS, OPENAPI_SCHEMAS } from "@/lib/openapi.generated";
|
|
16
16
|
|
|
17
17
|
//#region ../../node_modules/.pnpm/lucide-react@1.28.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/arrow-left.mjs
|
|
18
18
|
/**
|
|
@@ -1203,6 +1203,7 @@ function copyText(pre, language) {
|
|
|
1203
1203
|
return lines.filter((line) => language === "diff" || line.dataset.diff !== "remove").map((line) => line.textContent || "").join("\n");
|
|
1204
1204
|
}
|
|
1205
1205
|
function CodeBlock({ children, className, style, ...rest }) {
|
|
1206
|
+
const labels = useLabels();
|
|
1206
1207
|
const { "data-title": title, "data-language": language, "data-line-start": lineStart, "data-line-count": lineCount, "data-placement": placement, "data-actions": actions, ...preProps } = rest;
|
|
1207
1208
|
const textInput = useRef(null);
|
|
1208
1209
|
const [copied, setCopied] = useState(false);
|
|
@@ -1253,7 +1254,7 @@ function CodeBlock({ children, className, style, ...rest }) {
|
|
|
1253
1254
|
size: "icon-sm",
|
|
1254
1255
|
className: cn("absolute right-3 inline-flex size-7 items-center justify-center rounded-sm text-muted-foreground hover:bg-accent hover:text-accent-foreground", title ? "top-1" : "top-2.5"),
|
|
1255
1256
|
onClick: handleCopy,
|
|
1256
|
-
"aria-label":
|
|
1257
|
+
"aria-label": copied ? labels.copied : labels.copyCode,
|
|
1257
1258
|
children: copied ? /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" }) : /* @__PURE__ */ jsx(Copy, { className: "size-3.5" })
|
|
1258
1259
|
})
|
|
1259
1260
|
]
|
|
@@ -2171,6 +2172,43 @@ function useMenuItem(params) {
|
|
|
2171
2172
|
}), [getItemProps, mergedRef]);
|
|
2172
2173
|
}
|
|
2173
2174
|
|
|
2175
|
+
//#endregion
|
|
2176
|
+
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menu/checkbox-item/MenuCheckboxItemDataAttributes.mjs
|
|
2177
|
+
let MenuCheckboxItemDataAttributes = /*#__PURE__*/ function(MenuCheckboxItemDataAttributes) {
|
|
2178
|
+
/**
|
|
2179
|
+
* Present when the menu checkbox item is checked.
|
|
2180
|
+
*/
|
|
2181
|
+
MenuCheckboxItemDataAttributes["checked"] = "data-checked";
|
|
2182
|
+
/**
|
|
2183
|
+
* Present when the menu checkbox item is not checked.
|
|
2184
|
+
*/
|
|
2185
|
+
MenuCheckboxItemDataAttributes["unchecked"] = "data-unchecked";
|
|
2186
|
+
/**
|
|
2187
|
+
* Present when the menu checkbox item is disabled.
|
|
2188
|
+
*/
|
|
2189
|
+
MenuCheckboxItemDataAttributes["disabled"] = "data-disabled";
|
|
2190
|
+
/**
|
|
2191
|
+
* Present when the menu checkbox item is highlighted.
|
|
2192
|
+
*/
|
|
2193
|
+
MenuCheckboxItemDataAttributes["highlighted"] = "data-highlighted";
|
|
2194
|
+
return MenuCheckboxItemDataAttributes;
|
|
2195
|
+
}({});
|
|
2196
|
+
|
|
2197
|
+
//#endregion
|
|
2198
|
+
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menu/utils/stateAttributesMapping.mjs
|
|
2199
|
+
const itemMapping = {
|
|
2200
|
+
checked(value) {
|
|
2201
|
+
if (value) return { [MenuCheckboxItemDataAttributes.checked]: "" };
|
|
2202
|
+
return { [MenuCheckboxItemDataAttributes.unchecked]: "" };
|
|
2203
|
+
},
|
|
2204
|
+
...transitionStatusMapping
|
|
2205
|
+
};
|
|
2206
|
+
|
|
2207
|
+
//#endregion
|
|
2208
|
+
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menu/group/MenuGroupContext.mjs
|
|
2209
|
+
const MenuGroupContext = /*#__PURE__*/ React.createContext(void 0);
|
|
2210
|
+
MenuGroupContext.displayName = "MenuGroupContext";
|
|
2211
|
+
|
|
2174
2212
|
//#endregion
|
|
2175
2213
|
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menu/item/MenuItem.mjs
|
|
2176
2214
|
/**
|
|
@@ -2594,6 +2632,187 @@ const MenuPositioner = /*#__PURE__*/ React.forwardRef(function MenuPositioner(co
|
|
|
2594
2632
|
});
|
|
2595
2633
|
MenuPositioner.displayName = "MenuPositioner";
|
|
2596
2634
|
|
|
2635
|
+
//#endregion
|
|
2636
|
+
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menu/radio-group/MenuRadioGroupContext.mjs
|
|
2637
|
+
const MenuRadioGroupContext = /*#__PURE__*/ React.createContext(void 0);
|
|
2638
|
+
MenuRadioGroupContext.displayName = "MenuRadioGroupContext";
|
|
2639
|
+
function useMenuRadioGroupContext() {
|
|
2640
|
+
const context = React.useContext(MenuRadioGroupContext);
|
|
2641
|
+
if (context === void 0) throw new Error("Base UI: MenuRadioGroupContext is missing. MenuRadioGroup parts must be placed within <Menu.RadioGroup>.");
|
|
2642
|
+
return context;
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2645
|
+
//#endregion
|
|
2646
|
+
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menu/radio-group/MenuRadioGroup.mjs
|
|
2647
|
+
/**
|
|
2648
|
+
* Groups related radio items.
|
|
2649
|
+
* Renders a `<div>` element.
|
|
2650
|
+
*
|
|
2651
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
2652
|
+
*/
|
|
2653
|
+
const MenuRadioGroup = /*#__PURE__*/ React.memo(/*#__PURE__*/ React.forwardRef(function MenuRadioGroup(componentProps, forwardedRef) {
|
|
2654
|
+
const { render, className, value: valueProp, defaultValue, onValueChange: onValueChangeProp, disabled = false, style, "aria-labelledby": ariaLabelledByProp, ...elementProps } = componentProps;
|
|
2655
|
+
const [labelId, setLabelId] = React.useState(void 0);
|
|
2656
|
+
const [value, setValueUnwrapped] = useControlled({
|
|
2657
|
+
controlled: valueProp,
|
|
2658
|
+
default: defaultValue,
|
|
2659
|
+
name: "MenuRadioGroup"
|
|
2660
|
+
});
|
|
2661
|
+
const setValue = useStableCallback((newValue, eventDetails) => {
|
|
2662
|
+
onValueChangeProp?.(newValue, eventDetails);
|
|
2663
|
+
if (eventDetails.isCanceled) return;
|
|
2664
|
+
setValueUnwrapped(newValue);
|
|
2665
|
+
});
|
|
2666
|
+
const element = useRenderElement("div", componentProps, {
|
|
2667
|
+
state: { disabled },
|
|
2668
|
+
ref: forwardedRef,
|
|
2669
|
+
props: {
|
|
2670
|
+
role: "group",
|
|
2671
|
+
"aria-labelledby": ariaLabelledByProp ?? labelId,
|
|
2672
|
+
"aria-disabled": disabled || void 0,
|
|
2673
|
+
...elementProps
|
|
2674
|
+
}
|
|
2675
|
+
});
|
|
2676
|
+
const context = React.useMemo(() => ({
|
|
2677
|
+
value,
|
|
2678
|
+
setValue,
|
|
2679
|
+
disabled
|
|
2680
|
+
}), [
|
|
2681
|
+
value,
|
|
2682
|
+
setValue,
|
|
2683
|
+
disabled
|
|
2684
|
+
]);
|
|
2685
|
+
return /*#__PURE__*/ jsx(MenuGroupContext.Provider, {
|
|
2686
|
+
value: setLabelId,
|
|
2687
|
+
children: /*#__PURE__*/ jsx(MenuRadioGroupContext.Provider, {
|
|
2688
|
+
value: context,
|
|
2689
|
+
children: element
|
|
2690
|
+
})
|
|
2691
|
+
});
|
|
2692
|
+
}));
|
|
2693
|
+
MenuRadioGroup.displayName = "MenuRadioGroup";
|
|
2694
|
+
|
|
2695
|
+
//#endregion
|
|
2696
|
+
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menu/radio-item/MenuRadioItemContext.mjs
|
|
2697
|
+
const MenuRadioItemContext = /*#__PURE__*/ React.createContext(void 0);
|
|
2698
|
+
MenuRadioItemContext.displayName = "MenuRadioItemContext";
|
|
2699
|
+
function useMenuRadioItemContext() {
|
|
2700
|
+
const context = React.useContext(MenuRadioItemContext);
|
|
2701
|
+
if (context === void 0) throw new Error("Base UI: MenuRadioItemContext is missing. MenuRadioItem parts must be placed within <Menu.RadioItem>.");
|
|
2702
|
+
return context;
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
//#endregion
|
|
2706
|
+
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menu/radio-item/MenuRadioItem.mjs
|
|
2707
|
+
/**
|
|
2708
|
+
* A menu item that works like a radio button in a given group.
|
|
2709
|
+
* Renders a `<div>` element.
|
|
2710
|
+
*
|
|
2711
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
2712
|
+
*/
|
|
2713
|
+
const MenuRadioItem = /*#__PURE__*/ React.forwardRef(function MenuRadioItem(componentProps, forwardedRef) {
|
|
2714
|
+
const { render, className, id: idProp, label, nativeButton = false, disabled: disabledProp = false, closeOnClick = false, value, style, ...elementProps } = componentProps;
|
|
2715
|
+
const listItem = useCompositeListItem({
|
|
2716
|
+
guess: true,
|
|
2717
|
+
label
|
|
2718
|
+
});
|
|
2719
|
+
const menuPositionerContext = useMenuPositionerContext(true);
|
|
2720
|
+
const id = useBaseUiId(idProp);
|
|
2721
|
+
const { store } = useMenuRootContext();
|
|
2722
|
+
const highlighted = store.useState("isActive", listItem.index);
|
|
2723
|
+
const itemProps = store.useState("itemProps");
|
|
2724
|
+
const { value: selectedValue, setValue: setSelectedValue, disabled: groupDisabled } = useMenuRadioGroupContext();
|
|
2725
|
+
const rootDisabled = store.useState("disabled");
|
|
2726
|
+
const disabled = disabledProp || groupDisabled || rootDisabled;
|
|
2727
|
+
const checked = selectedValue === value;
|
|
2728
|
+
const { getItemProps, itemRef } = useMenuItem({
|
|
2729
|
+
closeOnClick,
|
|
2730
|
+
disabled,
|
|
2731
|
+
highlighted,
|
|
2732
|
+
id,
|
|
2733
|
+
store,
|
|
2734
|
+
nativeButton,
|
|
2735
|
+
nodeId: menuPositionerContext?.context.nodeId,
|
|
2736
|
+
itemMetadata: REGULAR_ITEM
|
|
2737
|
+
});
|
|
2738
|
+
const state = React.useMemo(() => ({
|
|
2739
|
+
disabled,
|
|
2740
|
+
highlighted,
|
|
2741
|
+
checked
|
|
2742
|
+
}), [
|
|
2743
|
+
disabled,
|
|
2744
|
+
highlighted,
|
|
2745
|
+
checked
|
|
2746
|
+
]);
|
|
2747
|
+
function handleClick(event) {
|
|
2748
|
+
const details = createChangeEventDetails(itemPress, event.nativeEvent, void 0, { preventUnmountOnClose: NOOP });
|
|
2749
|
+
setSelectedValue(value, details);
|
|
2750
|
+
}
|
|
2751
|
+
const element = useRenderElement("div", componentProps, {
|
|
2752
|
+
state,
|
|
2753
|
+
stateAttributesMapping: itemMapping,
|
|
2754
|
+
props: [
|
|
2755
|
+
itemProps,
|
|
2756
|
+
{
|
|
2757
|
+
role: "menuitemradio",
|
|
2758
|
+
"aria-checked": checked,
|
|
2759
|
+
onClick: handleClick
|
|
2760
|
+
},
|
|
2761
|
+
elementProps,
|
|
2762
|
+
getItemProps
|
|
2763
|
+
],
|
|
2764
|
+
ref: [
|
|
2765
|
+
itemRef,
|
|
2766
|
+
forwardedRef,
|
|
2767
|
+
listItem.ref
|
|
2768
|
+
]
|
|
2769
|
+
});
|
|
2770
|
+
return /*#__PURE__*/ jsx(MenuRadioItemContext.Provider, {
|
|
2771
|
+
value: state,
|
|
2772
|
+
children: element
|
|
2773
|
+
});
|
|
2774
|
+
});
|
|
2775
|
+
MenuRadioItem.displayName = "MenuRadioItem";
|
|
2776
|
+
|
|
2777
|
+
//#endregion
|
|
2778
|
+
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menu/radio-item-indicator/MenuRadioItemIndicator.mjs
|
|
2779
|
+
/**
|
|
2780
|
+
* Indicates whether the radio item is selected.
|
|
2781
|
+
* Renders a `<span>` element.
|
|
2782
|
+
*
|
|
2783
|
+
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
|
|
2784
|
+
*/
|
|
2785
|
+
const MenuRadioItemIndicator = /*#__PURE__*/ React.forwardRef(function MenuRadioItemIndicator(componentProps, forwardedRef) {
|
|
2786
|
+
const { render, className, style, keepMounted = false, ...elementProps } = componentProps;
|
|
2787
|
+
const item = useMenuRadioItemContext();
|
|
2788
|
+
const indicatorRef = React.useRef(null);
|
|
2789
|
+
const { transitionStatus, mounted, setMounted } = useTransitionStatus(item.checked);
|
|
2790
|
+
useOpenChangeComplete({
|
|
2791
|
+
open: item.checked,
|
|
2792
|
+
ref: indicatorRef,
|
|
2793
|
+
onComplete() {
|
|
2794
|
+
if (!item.checked) setMounted(false);
|
|
2795
|
+
}
|
|
2796
|
+
});
|
|
2797
|
+
const state = {
|
|
2798
|
+
checked: item.checked,
|
|
2799
|
+
disabled: item.disabled,
|
|
2800
|
+
highlighted: item.highlighted,
|
|
2801
|
+
transitionStatus
|
|
2802
|
+
};
|
|
2803
|
+
return useRenderElement("span", componentProps, {
|
|
2804
|
+
state,
|
|
2805
|
+
stateAttributesMapping: itemMapping,
|
|
2806
|
+
ref: [forwardedRef, indicatorRef],
|
|
2807
|
+
props: {
|
|
2808
|
+
"aria-hidden": true,
|
|
2809
|
+
...elementProps
|
|
2810
|
+
},
|
|
2811
|
+
enabled: keepMounted || mounted
|
|
2812
|
+
});
|
|
2813
|
+
});
|
|
2814
|
+
MenuRadioItemIndicator.displayName = "MenuRadioItemIndicator";
|
|
2815
|
+
|
|
2597
2816
|
//#endregion
|
|
2598
2817
|
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menubar/MenubarContext.mjs
|
|
2599
2818
|
const MenubarContext = /*#__PURE__*/ React.createContext(null);
|
|
@@ -3402,6 +3621,25 @@ function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
|
|
|
3402
3621
|
...props
|
|
3403
3622
|
});
|
|
3404
3623
|
}
|
|
3624
|
+
function DropdownMenuRadioGroup({ ...props }) {
|
|
3625
|
+
return /* @__PURE__ */ jsx(MenuRadioGroup, {
|
|
3626
|
+
"data-slot": "dropdown-menu-radio-group",
|
|
3627
|
+
...props
|
|
3628
|
+
});
|
|
3629
|
+
}
|
|
3630
|
+
function DropdownMenuRadioItem({ className, children, inset, ...props }) {
|
|
3631
|
+
return /* @__PURE__ */ jsxs(MenuRadioItem, {
|
|
3632
|
+
"data-slot": "dropdown-menu-radio-item",
|
|
3633
|
+
"data-inset": inset,
|
|
3634
|
+
className: cn("relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
|
|
3635
|
+
...props,
|
|
3636
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
3637
|
+
className: "pointer-events-none absolute right-2 flex items-center justify-center",
|
|
3638
|
+
"data-slot": "dropdown-menu-radio-item-indicator",
|
|
3639
|
+
children: /* @__PURE__ */ jsx(MenuRadioItemIndicator, { children: /* @__PURE__ */ jsx(Check, {}) })
|
|
3640
|
+
}), children]
|
|
3641
|
+
});
|
|
3642
|
+
}
|
|
3405
3643
|
|
|
3406
3644
|
//#endregion
|
|
3407
3645
|
//#region src/lib/paths.ts
|
|
@@ -4076,66 +4314,6 @@ function isNodeHidden(node) {
|
|
|
4076
4314
|
return !!node.hidden || node.children.every(isNodeHidden);
|
|
4077
4315
|
}
|
|
4078
4316
|
|
|
4079
|
-
//#endregion
|
|
4080
|
-
//#region src/lib/locale.ts
|
|
4081
|
-
/** Primary language subtags written right-to-left. */
|
|
4082
|
-
const RTL_LANGUAGES = /* @__PURE__ */ new Set([
|
|
4083
|
-
"ar",
|
|
4084
|
-
"ckb",
|
|
4085
|
-
"dv",
|
|
4086
|
-
"fa",
|
|
4087
|
-
"he",
|
|
4088
|
-
"iw",
|
|
4089
|
-
"ps",
|
|
4090
|
-
"sd",
|
|
4091
|
-
"ug",
|
|
4092
|
-
"ur",
|
|
4093
|
-
"yi"
|
|
4094
|
-
]);
|
|
4095
|
-
/** BCP 47-shaped tags with a 2-3 letter primary subtag, e.g. "es" or "pt-BR". */
|
|
4096
|
-
const LOCALE_PATTERN = /^[a-z]{2,3}(-[a-z0-9]{2,8})*$/i;
|
|
4097
|
-
function isValidLocale(value) {
|
|
4098
|
-
if (!value || !LOCALE_PATTERN.test(value)) return false;
|
|
4099
|
-
try {
|
|
4100
|
-
return Intl.getCanonicalLocales(value).length > 0;
|
|
4101
|
-
} catch {
|
|
4102
|
-
return false;
|
|
4103
|
-
}
|
|
4104
|
-
}
|
|
4105
|
-
/**
|
|
4106
|
-
* Locale for a page: its scope's language code when valid, then the
|
|
4107
|
-
* site-wide shiso.config `locale`, then en-US.
|
|
4108
|
-
*/
|
|
4109
|
-
function resolveLocale(language, fallback) {
|
|
4110
|
-
if (isValidLocale(language)) return Intl.getCanonicalLocales(language)[0];
|
|
4111
|
-
if (isValidLocale(fallback)) return Intl.getCanonicalLocales(fallback)[0];
|
|
4112
|
-
return "en-US";
|
|
4113
|
-
}
|
|
4114
|
-
/** Document direction for a locale, e.g. "ar" and "he" read right-to-left. */
|
|
4115
|
-
function getTextDirection(locale) {
|
|
4116
|
-
const primary = locale.split("-")[0]?.toLowerCase() || "";
|
|
4117
|
-
return RTL_LANGUAGES.has(primary) ? "rtl" : "ltr";
|
|
4118
|
-
}
|
|
4119
|
-
/**
|
|
4120
|
-
* A language's name written in that language, for language selectors:
|
|
4121
|
-
* "ja" -> "日本語", "zh-Hant" -> "繁體中文", "es" -> "Español". Labels that
|
|
4122
|
-
* are not valid locale codes (e.g. "English") are returned unchanged.
|
|
4123
|
-
*/
|
|
4124
|
-
function getLanguageName(language) {
|
|
4125
|
-
if (!isValidLocale(language)) return language;
|
|
4126
|
-
const locale = Intl.getCanonicalLocales(language)[0];
|
|
4127
|
-
try {
|
|
4128
|
-
const name = new Intl.DisplayNames([locale], {
|
|
4129
|
-
type: "language",
|
|
4130
|
-
fallback: "none"
|
|
4131
|
-
}).of(locale);
|
|
4132
|
-
if (!name) return language;
|
|
4133
|
-
return name.charAt(0).toLocaleUpperCase(locale) + name.slice(1);
|
|
4134
|
-
} catch {
|
|
4135
|
-
return language;
|
|
4136
|
-
}
|
|
4137
|
-
}
|
|
4138
|
-
|
|
4139
4317
|
//#endregion
|
|
4140
4318
|
//#region src/lib/content.ts
|
|
4141
4319
|
/**
|
|
@@ -4243,36 +4421,6 @@ function resolveSearchConfig(config) {
|
|
|
4243
4421
|
|
|
4244
4422
|
//#endregion
|
|
4245
4423
|
//#region src/lib/site-model.ts
|
|
4246
|
-
const SHISO_THEME_LABELS = {
|
|
4247
|
-
menu: "Menu",
|
|
4248
|
-
documentationNavigation: "Documentation navigation",
|
|
4249
|
-
sections: "Sections",
|
|
4250
|
-
tableOfContents: "On this page",
|
|
4251
|
-
tableOfContentsNavigation: "Table of contents",
|
|
4252
|
-
searchTitle: "Search",
|
|
4253
|
-
searching: "Searching...",
|
|
4254
|
-
searchUnavailable: "Search unavailable",
|
|
4255
|
-
noResults: "No results",
|
|
4256
|
-
lastUpdated: "Last updated on",
|
|
4257
|
-
relatedTopics: "Related topics",
|
|
4258
|
-
previousPage: "Previous",
|
|
4259
|
-
nextPage: "Next",
|
|
4260
|
-
notFound: "Page not found",
|
|
4261
|
-
dismissBanner: "Dismiss banner",
|
|
4262
|
-
toggleTheme: "Toggle theme",
|
|
4263
|
-
moreOptions: "More options",
|
|
4264
|
-
copied: "Copied",
|
|
4265
|
-
expand: "Expand",
|
|
4266
|
-
collapse: "Collapse",
|
|
4267
|
-
copyPage: "Copy page",
|
|
4268
|
-
copyPageDescription: "Copy this page as Markdown",
|
|
4269
|
-
viewMarkdown: "View as Markdown",
|
|
4270
|
-
viewMarkdownDescription: "Open this page as plain Markdown",
|
|
4271
|
-
openInChatGPT: "Open in ChatGPT",
|
|
4272
|
-
openInClaude: "Open in Claude",
|
|
4273
|
-
openInPerplexity: "Open in Perplexity",
|
|
4274
|
-
askQuestionsAboutPage: "Ask questions about this page"
|
|
4275
|
-
};
|
|
4276
4424
|
function isInternalHref(href) {
|
|
4277
4425
|
return /^(?:#|\/|\.\.?\/)/.test(href);
|
|
4278
4426
|
}
|
|
@@ -4297,6 +4445,15 @@ function normalizeNavbar(config) {
|
|
|
4297
4445
|
primary
|
|
4298
4446
|
} : null;
|
|
4299
4447
|
}
|
|
4448
|
+
function normalizePlayground(config) {
|
|
4449
|
+
const playground = config?.playground;
|
|
4450
|
+
const display = playground?.display === "simple" || playground?.display === "none" ? playground.display : "interactive";
|
|
4451
|
+
const proxy = playground?.proxy?.trim() || void 0;
|
|
4452
|
+
return proxy ? {
|
|
4453
|
+
display,
|
|
4454
|
+
proxy
|
|
4455
|
+
} : { display };
|
|
4456
|
+
}
|
|
4300
4457
|
function normalizeFooter(config) {
|
|
4301
4458
|
const socials = (config?.socials || []).filter((link) => !!link?.href).map(normalizeLink);
|
|
4302
4459
|
const links = (config?.links || []).filter((column) => column?.items?.length).map((column) => ({
|
|
@@ -4353,14 +4510,15 @@ function resolveSiteModel(config, docs, shiso) {
|
|
|
4353
4510
|
showTimestamp: config.metadata?.timestamp === true,
|
|
4354
4511
|
drilldown: config.interaction?.drilldown,
|
|
4355
4512
|
locale: shiso?.locale || "en-US",
|
|
4356
|
-
labels:
|
|
4513
|
+
labels: resolveLabels(shiso?.locale || "en-US", shiso?.translations),
|
|
4514
|
+
api: { playground: normalizePlayground(config.api) },
|
|
4357
4515
|
docs
|
|
4358
4516
|
};
|
|
4359
4517
|
}
|
|
4360
4518
|
function aiPrompt(mdUrl) {
|
|
4361
4519
|
return `Read ${mdUrl} so I can ask questions about it.`;
|
|
4362
4520
|
}
|
|
4363
|
-
function resolveContextualOptions(options, page, labels =
|
|
4521
|
+
function resolveContextualOptions(options, page, labels = englishLabels) {
|
|
4364
4522
|
const mdHref = `${toHref(page.url)}.md`;
|
|
4365
4523
|
const absolutePageUrl = toAbsoluteUrl(page.url);
|
|
4366
4524
|
const mdUrl = absolutePageUrl ? `${absolutePageUrl}.md` : void 0;
|
|
@@ -4463,10 +4621,15 @@ function normalizeStandalonePages(config, resolvePageFile, site, options = {}) {
|
|
|
4463
4621
|
const fileSlug = normalizePageSlug(item?.page);
|
|
4464
4622
|
const filePath = resolvePageFile(fileSlug);
|
|
4465
4623
|
if (!filePath) throw new Error(`Missing standalone page file for "${fileSlug}": expected "content/pages/${fileSlug}.tsx", ".mdx", or ".md".`);
|
|
4624
|
+
const language = item?.language?.trim() || void 0;
|
|
4625
|
+
if (language && !site.scopes.some((scope) => scope.language === language)) throw invalid(`standalone page "${path}" uses language "${language}", which is not declared in navigation.languages.`);
|
|
4626
|
+
const key = language && fileSlug.startsWith(`${language}/`) ? fileSlug.slice(language.length + 1) : fileSlug;
|
|
4466
4627
|
pages.push({
|
|
4467
4628
|
path,
|
|
4468
4629
|
filePath,
|
|
4469
|
-
title: item?.title?.trim() || void 0
|
|
4630
|
+
title: item?.title?.trim() || void 0,
|
|
4631
|
+
language,
|
|
4632
|
+
key
|
|
4470
4633
|
});
|
|
4471
4634
|
}
|
|
4472
4635
|
return pages;
|
|
@@ -4499,10 +4662,38 @@ const hasRootStandalonePage = standalonePages.some((page) => page.path === "/");
|
|
|
4499
4662
|
function getStandalonePage(pathname) {
|
|
4500
4663
|
return getStandalonePageByPathname(standalonePages, stripBase(pathname));
|
|
4501
4664
|
}
|
|
4502
|
-
/**
|
|
4665
|
+
/** Landing scope of a language: its default version. */
|
|
4666
|
+
function getLanguageScope(language) {
|
|
4667
|
+
return docsSite.scopes.find((scope) => scope.language === language && scope.isLanguageDefault);
|
|
4668
|
+
}
|
|
4669
|
+
/**
|
|
4670
|
+
* Scope that owns the current pathname. A standalone page tagged with a
|
|
4671
|
+
* `language` belongs to that language's landing scope; unknown paths and
|
|
4672
|
+
* untagged standalone pages belong to the default scope.
|
|
4673
|
+
*/
|
|
4503
4674
|
function getScopeByPathname(pathname) {
|
|
4504
4675
|
const page = getPageByPathname(pathname);
|
|
4505
|
-
|
|
4676
|
+
if (page) return getScopeForPage(docsSite, page);
|
|
4677
|
+
const standalone = getStandalonePage(pathname);
|
|
4678
|
+
return (standalone?.language ? getLanguageScope(standalone.language) : void 0) || getDefaultScope(docsSite);
|
|
4679
|
+
}
|
|
4680
|
+
/**
|
|
4681
|
+
* The same standalone page in another language, matched by `key`. Untagged
|
|
4682
|
+
* pages count as the default scope's language.
|
|
4683
|
+
*/
|
|
4684
|
+
function getStandaloneCounterpart(page, language) {
|
|
4685
|
+
const defaultLanguage = getDefaultScope(docsSite).language;
|
|
4686
|
+
return standalonePages.find((candidate) => candidate.key === page.key && (candidate.language || defaultLanguage) === language) || null;
|
|
4687
|
+
}
|
|
4688
|
+
/**
|
|
4689
|
+
* Home link for the current pathname: the "/" standalone page in the current
|
|
4690
|
+
* language when one exists, else "/", else the docs home when nothing owns "/".
|
|
4691
|
+
*/
|
|
4692
|
+
function getHomeHref(pathname) {
|
|
4693
|
+
const root = standalonePages.find((page) => page.path === "/");
|
|
4694
|
+
if (!root) return docsHomeUrl;
|
|
4695
|
+
const language = getScopeByPathname(pathname).language;
|
|
4696
|
+
return language && getStandaloneCounterpart(root, language)?.path || "/";
|
|
4506
4697
|
}
|
|
4507
4698
|
/** Document language and direction for a pathname, from its scope's language. */
|
|
4508
4699
|
function getLocaleByPathname(pathname) {
|
|
@@ -4512,6 +4703,20 @@ function getLocaleByPathname(pathname) {
|
|
|
4512
4703
|
dir: getTextDirection(lang)
|
|
4513
4704
|
};
|
|
4514
4705
|
}
|
|
4706
|
+
/** Resolve UI text on every route, including standalone pages and language switches. */
|
|
4707
|
+
function getSiteModelByPathname(pathname) {
|
|
4708
|
+
const { lang } = getLocaleByPathname(pathname);
|
|
4709
|
+
const labels = resolveLabels(lang, shiso.translations);
|
|
4710
|
+
const customPrompt = typeof siteConfig.search === "object" ? siteConfig.search.prompt?.trim() : void 0;
|
|
4711
|
+
return {
|
|
4712
|
+
...siteModel,
|
|
4713
|
+
labels,
|
|
4714
|
+
search: {
|
|
4715
|
+
...siteModel.search,
|
|
4716
|
+
prompt: customPrompt || labels.searchPlaceholder
|
|
4717
|
+
}
|
|
4718
|
+
};
|
|
4719
|
+
}
|
|
4515
4720
|
const siteName = siteModel.name;
|
|
4516
4721
|
/** Trailing-slash-insensitive route key for redirect matching. */
|
|
4517
4722
|
function toRouteKey(routePath) {
|
|
@@ -4565,8 +4770,10 @@ function getPageTitle(pageTitle) {
|
|
|
4565
4770
|
//#region src/components/LanguageSwitcher.tsx
|
|
4566
4771
|
/**
|
|
4567
4772
|
* Language selector for multi-language sites. Each option is a language's
|
|
4568
|
-
* landing scope — its default version — so switching languages
|
|
4569
|
-
*
|
|
4773
|
+
* landing scope — its default version — so switching languages lands on that
|
|
4774
|
+
* language's default-version first page. On a standalone page (e.g. a home
|
|
4775
|
+
* page) it lands on the same page in the chosen language when one exists.
|
|
4776
|
+
* Hidden languages never
|
|
4570
4777
|
* appear as options. Each language is shown by its native name, e.g. "ja"
|
|
4571
4778
|
* as "日本語".
|
|
4572
4779
|
*/
|
|
@@ -4575,26 +4782,32 @@ function LanguageSwitcher() {
|
|
|
4575
4782
|
const navigate = useNavigate();
|
|
4576
4783
|
const current = getScopeByPathname(pathname);
|
|
4577
4784
|
const options = getLanguageScopes(docsSite);
|
|
4785
|
+
const standalone = getStandalonePage(pathname);
|
|
4578
4786
|
if (!current.language || options.length < 2 && !current.hidden) return null;
|
|
4579
4787
|
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
|
|
4580
|
-
render: /* @__PURE__ */ jsx(Button, {
|
|
4581
|
-
|
|
4582
|
-
className: "h-auto gap-1.5 rounded-md bg-card px-2.5 py-1.5 text-sm font-medium text-foreground"
|
|
4583
|
-
}),
|
|
4788
|
+
render: /* @__PURE__ */ jsx(Button, { variant: "outline" }),
|
|
4789
|
+
"aria-label": `Language: ${getLanguageName(current.language)}`,
|
|
4584
4790
|
children: [getLanguageName(current.language), /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 rotate-90 text-muted-foreground" })]
|
|
4585
4791
|
}), /* @__PURE__ */ jsx(DropdownMenuContent, {
|
|
4586
4792
|
align: "start",
|
|
4587
4793
|
className: "min-w-32",
|
|
4588
|
-
children:
|
|
4589
|
-
|
|
4590
|
-
|
|
4794
|
+
children: /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
|
|
4795
|
+
value: current.language,
|
|
4796
|
+
onValueChange: (language) => {
|
|
4797
|
+
const scope = options.find((option) => option.language === language);
|
|
4798
|
+
if (scope && scope.language !== current.language) {
|
|
4799
|
+
const counterpart = standalone && scope.language ? getStandaloneCounterpart(standalone, scope.language) : null;
|
|
4800
|
+
navigate(counterpart?.path || scope.firstPageUrl);
|
|
4801
|
+
}
|
|
4591
4802
|
},
|
|
4592
|
-
children:
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4803
|
+
children: options.map((scope) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, {
|
|
4804
|
+
value: scope.language,
|
|
4805
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
4806
|
+
lang: isValidLocale(scope.language) ? scope.language : void 0,
|
|
4807
|
+
children: scope.language ? getLanguageName(scope.language) : null
|
|
4808
|
+
})
|
|
4809
|
+
}, scope.id))
|
|
4810
|
+
})
|
|
4598
4811
|
})] });
|
|
4599
4812
|
}
|
|
4600
4813
|
|
|
@@ -7749,7 +7962,7 @@ function Header({ site }) {
|
|
|
7749
7962
|
const { logo, navbar, name, appearance, labels } = site;
|
|
7750
7963
|
const { pathname } = useLocation();
|
|
7751
7964
|
const docs = getScopeByPathname(pathname).docs;
|
|
7752
|
-
const brandHref = logo?.href || (
|
|
7965
|
+
const brandHref = logo?.href || getHomeHref(pathname);
|
|
7753
7966
|
const hasBrand = !!name || !!logo?.light || !!logo?.dark;
|
|
7754
7967
|
const brandClassName = "inline-flex items-center gap-2 text-xl font-bold text-foreground tracking-[-0.03em]";
|
|
7755
7968
|
const brandContent = /* @__PURE__ */ jsxs(Fragment$1, { children: [logo?.invert && logo.light ? /* @__PURE__ */ jsx("img", {
|
|
@@ -8114,8 +8327,39 @@ const METHOD_COLORS = {
|
|
|
8114
8327
|
POST: "blue",
|
|
8115
8328
|
PUT: "orange",
|
|
8116
8329
|
PATCH: "purple",
|
|
8117
|
-
DELETE: "red"
|
|
8330
|
+
DELETE: "red",
|
|
8331
|
+
WEBHOOK: "yellow"
|
|
8118
8332
|
};
|
|
8333
|
+
const HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
8334
|
+
"GET",
|
|
8335
|
+
"POST",
|
|
8336
|
+
"PUT",
|
|
8337
|
+
"PATCH",
|
|
8338
|
+
"DELETE",
|
|
8339
|
+
"HEAD",
|
|
8340
|
+
"OPTIONS",
|
|
8341
|
+
"TRACE"
|
|
8342
|
+
]);
|
|
8343
|
+
/** Short sidebar badge text for a method. */
|
|
8344
|
+
function methodBadgeText(method) {
|
|
8345
|
+
if (method === "DELETE") return "DEL";
|
|
8346
|
+
if (method === "WEBHOOK") return "HOOK";
|
|
8347
|
+
return method;
|
|
8348
|
+
}
|
|
8349
|
+
/**
|
|
8350
|
+
* Normalizes an `openapi:` frontmatter value into a lookup key. Mirrors
|
|
8351
|
+
* normalizeOperationKey in scripts/lib/openapi.mjs: the method (or "webhook")
|
|
8352
|
+
* is uppercased and an optional leading spec qualifier is kept verbatim.
|
|
8353
|
+
*/
|
|
8354
|
+
function normalizeOperationKey(value) {
|
|
8355
|
+
if (typeof value !== "string" || !value.trim()) return void 0;
|
|
8356
|
+
const [first, ...rest] = value.trim().split(/\s+/);
|
|
8357
|
+
if (!rest.length) return void 0;
|
|
8358
|
+
const upper = first.toUpperCase();
|
|
8359
|
+
if (upper === "WEBHOOK" || HTTP_METHODS.has(upper)) return `${upper} ${rest.join(" ")}`;
|
|
8360
|
+
const inner = normalizeOperationKey(rest.join(" "));
|
|
8361
|
+
return inner ? `${first} ${inner}` : void 0;
|
|
8362
|
+
}
|
|
8119
8363
|
function methodColor(method) {
|
|
8120
8364
|
return method && METHOD_COLORS[method.toUpperCase()] || "gray";
|
|
8121
8365
|
}
|
|
@@ -8125,86 +8369,764 @@ function statusColor(status) {
|
|
|
8125
8369
|
if (status.startsWith("4") || status.startsWith("5")) return "red";
|
|
8126
8370
|
return "gray";
|
|
8127
8371
|
}
|
|
8372
|
+
/**
|
|
8373
|
+
* Resolves the effective playground display for a page: the frontmatter
|
|
8374
|
+
* `playground` value wins over `api.playground.display`.
|
|
8375
|
+
*/
|
|
8376
|
+
function resolvePlaygroundDisplay(playground, frontmatter) {
|
|
8377
|
+
const override = frontmatter?.playground;
|
|
8378
|
+
if (override === "interactive" || override === "simple" || override === "none") return override;
|
|
8379
|
+
return playground.display;
|
|
8380
|
+
}
|
|
8128
8381
|
/** Looks up the operation bound by an `openapi:` frontmatter value. */
|
|
8129
8382
|
function getOperation(key) {
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8383
|
+
const normalized = normalizeOperationKey(key);
|
|
8384
|
+
return normalized ? OPENAPI_OPERATIONS[normalized] : void 0;
|
|
8385
|
+
}
|
|
8386
|
+
/** Looks up the schema bound by an `openapi-schema:` frontmatter value. */
|
|
8387
|
+
function getSchema(key) {
|
|
8388
|
+
if (typeof key !== "string" || !key.trim()) return void 0;
|
|
8389
|
+
return OPENAPI_SCHEMAS[key.trim().split(/\s+/).join(" ")];
|
|
8390
|
+
}
|
|
8391
|
+
/**
|
|
8392
|
+
* Section headings for a schema page, in render order. Mirrors schemaAnchors
|
|
8393
|
+
* in scripts/lib/openapi.mjs.
|
|
8394
|
+
*/
|
|
8395
|
+
function schemaSections(page, labels = englishLabels) {
|
|
8396
|
+
return [...page.schema.children?.length ? [{
|
|
8397
|
+
name: labels.apiSchemaProperties,
|
|
8398
|
+
id: "properties",
|
|
8399
|
+
size: 2
|
|
8400
|
+
}] : [], ...page.example ? [{
|
|
8401
|
+
name: labels.apiExample,
|
|
8402
|
+
id: "example",
|
|
8403
|
+
size: 2
|
|
8404
|
+
}] : []];
|
|
8405
|
+
}
|
|
8406
|
+
/** Where a security scheme's credential travels: a header unless it is a query or cookie API key. */
|
|
8407
|
+
function securityLocation(scheme) {
|
|
8408
|
+
return scheme.type === "apiKey" && scheme.in ? scheme.in : "header";
|
|
8409
|
+
}
|
|
8410
|
+
/** Security schemes that are sent in the given parameter location. */
|
|
8411
|
+
function securityForLocation(operation, location) {
|
|
8412
|
+
return operation.security.filter((scheme) => securityLocation(scheme) === location);
|
|
8413
|
+
}
|
|
8414
|
+
/** Display name of the header, query, or cookie entry a scheme adds. */
|
|
8415
|
+
function securityFieldName(scheme) {
|
|
8416
|
+
return scheme.type === "apiKey" ? scheme.paramName || scheme.name : "Authorization";
|
|
8133
8417
|
}
|
|
8134
8418
|
/** Parameter groups shared by the renderer and table of contents. */
|
|
8135
|
-
function operationParameterSections(operation) {
|
|
8419
|
+
function operationParameterSections(operation, labels = englishLabels) {
|
|
8136
8420
|
return [
|
|
8137
8421
|
{
|
|
8138
8422
|
location: "header",
|
|
8139
|
-
name:
|
|
8423
|
+
name: labels.apiHeaders
|
|
8140
8424
|
},
|
|
8141
8425
|
{
|
|
8142
8426
|
location: "path",
|
|
8143
|
-
name:
|
|
8427
|
+
name: labels.apiPathParameters
|
|
8144
8428
|
},
|
|
8145
8429
|
{
|
|
8146
8430
|
location: "query",
|
|
8147
|
-
name:
|
|
8431
|
+
name: labels.apiQueryParameters
|
|
8148
8432
|
},
|
|
8149
8433
|
{
|
|
8150
8434
|
location: "cookie",
|
|
8151
|
-
name:
|
|
8435
|
+
name: labels.apiCookieParameters
|
|
8152
8436
|
}
|
|
8153
|
-
].filter(({ location }) => operation.parameters[location].length > 0 || location
|
|
8437
|
+
].filter(({ location }) => operation.parameters[location].length > 0 || securityForLocation(operation, location).length > 0);
|
|
8154
8438
|
}
|
|
8155
8439
|
/**
|
|
8156
8440
|
* Section headings for an operation, in render order. The single source of
|
|
8157
8441
|
* truth for section ids: the component, the table of contents, the content
|
|
8158
8442
|
* checker, and the search indexer all derive their anchors from these labels.
|
|
8159
8443
|
*/
|
|
8160
|
-
function operationSections(operation) {
|
|
8444
|
+
function operationSections(operation, labels = englishLabels, options = {}) {
|
|
8161
8445
|
const slugger = createSlugger();
|
|
8162
|
-
|
|
8446
|
+
const playground = options.playground && !operation.webhook;
|
|
8447
|
+
const names = [
|
|
8448
|
+
playground ? "Try it" : void 0,
|
|
8163
8449
|
...operationParameterSections(operation).map((section) => section.name),
|
|
8164
|
-
operation.requestBody ? "Request body" : void 0,
|
|
8450
|
+
operation.requestBody ? operation.webhook ? "Payload" : "Request body" : void 0,
|
|
8165
8451
|
operation.responses.length ? "Responses" : void 0,
|
|
8166
8452
|
operation.samples.length ? "Code samples" : void 0
|
|
8167
|
-
].filter((name) => Boolean(name))
|
|
8168
|
-
|
|
8453
|
+
].filter((name) => Boolean(name));
|
|
8454
|
+
const translated = [
|
|
8455
|
+
...playground ? [labels.apiPlayground] : [],
|
|
8456
|
+
...operationParameterSections(operation, labels).map((section) => section.name),
|
|
8457
|
+
...operation.requestBody ? [operation.webhook ? labels.apiPayload : labels.apiRequestBody] : [],
|
|
8458
|
+
...operation.responses.length ? [labels.apiResponses] : [],
|
|
8459
|
+
...operation.samples.length ? [labels.apiCodeSamples] : []
|
|
8460
|
+
];
|
|
8461
|
+
return names.map((name, index) => ({
|
|
8462
|
+
name: translated[index],
|
|
8169
8463
|
id: slugger.slug(name),
|
|
8170
8464
|
size: 2
|
|
8171
8465
|
}));
|
|
8172
8466
|
}
|
|
8173
8467
|
|
|
8468
|
+
//#endregion
|
|
8469
|
+
//#region scripts/lib/request-samples.mjs
|
|
8470
|
+
/**
|
|
8471
|
+
* Request building shared by the build-time sample generator and the browser
|
|
8472
|
+
* API playground. This module is deliberately free of Node imports: it is
|
|
8473
|
+
* bundled into the client runtime as well as executed by the build scripts.
|
|
8474
|
+
*
|
|
8475
|
+
* `buildRequest` turns an operation plus user-supplied values into a concrete
|
|
8476
|
+
* HTTP request description; `buildCodeSamples` renders that description as
|
|
8477
|
+
* cURL, JavaScript, and Python. Values that are missing fall back to the
|
|
8478
|
+
* spec's examples or to angle-bracket placeholders such as `<token>`, so the
|
|
8479
|
+
* static samples and the live playground always agree on the request shape.
|
|
8480
|
+
*/
|
|
8481
|
+
const PLACEHOLDER = /^<[^<>]+>$/;
|
|
8482
|
+
/** Percent-encodes a value unless it is a documentation placeholder. */
|
|
8483
|
+
function encodeValue(value) {
|
|
8484
|
+
return PLACEHOLDER.test(value) ? value : encodeURIComponent(value);
|
|
8485
|
+
}
|
|
8486
|
+
function toBase64(value) {
|
|
8487
|
+
if (typeof btoa === "function") return btoa(value);
|
|
8488
|
+
return Buffer.from(value, "utf8").toString("base64");
|
|
8489
|
+
}
|
|
8490
|
+
function capitalize(value) {
|
|
8491
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
8492
|
+
}
|
|
8493
|
+
/** Placeholder credential text shown in samples when no value is supplied. */
|
|
8494
|
+
function securityPlaceholder(scheme) {
|
|
8495
|
+
if (scheme.type === "http") return scheme.scheme === "basic" ? "<credentials>" : "<token>";
|
|
8496
|
+
if (scheme.type === "apiKey") return "<api-key>";
|
|
8497
|
+
return "<access-token>";
|
|
8498
|
+
}
|
|
8499
|
+
/**
|
|
8500
|
+
* Applies one security scheme to the request. `value` is a string for token
|
|
8501
|
+
* and API key schemes, `{ username, password }` for HTTP basic, or undefined
|
|
8502
|
+
* to emit a placeholder.
|
|
8503
|
+
*/
|
|
8504
|
+
function applySecurity(scheme, value, target) {
|
|
8505
|
+
const placeholder = securityPlaceholder(scheme);
|
|
8506
|
+
if (scheme.type === "apiKey") {
|
|
8507
|
+
const credential = typeof value === "string" && value ? value : placeholder;
|
|
8508
|
+
const name = scheme.paramName || scheme.name;
|
|
8509
|
+
if (scheme.in === "query") target.query[name] = credential;
|
|
8510
|
+
else if (scheme.in === "cookie") target.cookies[name] = credential;
|
|
8511
|
+
else target.headers[name] = credential;
|
|
8512
|
+
return;
|
|
8513
|
+
}
|
|
8514
|
+
if (scheme.type === "http" && scheme.scheme === "basic") {
|
|
8515
|
+
const credential = value && typeof value === "object" && (value.username || value.password) ? toBase64(`${value.username || ""}:${value.password || ""}`) : typeof value === "string" && value ? value : placeholder;
|
|
8516
|
+
target.headers.Authorization = `Basic ${credential}`;
|
|
8517
|
+
return;
|
|
8518
|
+
}
|
|
8519
|
+
const prefix = scheme.type === "http" && scheme.scheme && scheme.scheme !== "bearer" ? capitalize(scheme.scheme) : "Bearer";
|
|
8520
|
+
const credential = typeof value === "string" && value ? value : placeholder;
|
|
8521
|
+
target.headers.Authorization = `${prefix} ${credential}`;
|
|
8522
|
+
}
|
|
8523
|
+
/** Content categories the sample renderers and playground understand. */
|
|
8524
|
+
function bodyKind(contentType) {
|
|
8525
|
+
if (!contentType) return "none";
|
|
8526
|
+
if (/[+/]json\b/i.test(contentType)) return "json";
|
|
8527
|
+
if (/x-www-form-urlencoded/i.test(contentType)) return "form";
|
|
8528
|
+
if (/multipart\/form-data/i.test(contentType)) return "multipart";
|
|
8529
|
+
return "raw";
|
|
8530
|
+
}
|
|
8531
|
+
function parseFields(body) {
|
|
8532
|
+
if (!body) return {};
|
|
8533
|
+
try {
|
|
8534
|
+
const parsed = JSON.parse(body);
|
|
8535
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
8536
|
+
return Object.fromEntries(Object.entries(parsed).map(([key, value]) => [key, typeof value === "string" ? value : JSON.stringify(value)]));
|
|
8537
|
+
} catch {
|
|
8538
|
+
return {};
|
|
8539
|
+
}
|
|
8540
|
+
}
|
|
8541
|
+
function parameterValue(node, supplied) {
|
|
8542
|
+
if (supplied !== void 0 && supplied !== null && supplied !== "") return String(supplied);
|
|
8543
|
+
return node.example;
|
|
8544
|
+
}
|
|
8545
|
+
/**
|
|
8546
|
+
* Builds a concrete request from an operation and optional user values:
|
|
8547
|
+
* `{ server, path, query, header, cookie, auth, body }`. Without values, the
|
|
8548
|
+
* spec's examples fill required parameters and credentials become
|
|
8549
|
+
* placeholders, which is the shape rendered in the static code samples.
|
|
8550
|
+
*/
|
|
8551
|
+
function buildRequest(operation, values = {}) {
|
|
8552
|
+
const live = values.live === true;
|
|
8553
|
+
const target = {
|
|
8554
|
+
headers: {},
|
|
8555
|
+
query: {},
|
|
8556
|
+
cookies: {}
|
|
8557
|
+
};
|
|
8558
|
+
for (const scheme of operation.security || []) applySecurity(scheme, values.auth?.[scheme.name], target);
|
|
8559
|
+
const params = operation.parameters;
|
|
8560
|
+
const pathValues = {};
|
|
8561
|
+
for (const node of params.path) {
|
|
8562
|
+
const value = parameterValue(node, values.path?.[node.name]);
|
|
8563
|
+
if (live && value !== void 0) pathValues[node.name] = value;
|
|
8564
|
+
}
|
|
8565
|
+
for (const node of params.query) {
|
|
8566
|
+
const value = parameterValue(node, values.query?.[node.name]);
|
|
8567
|
+
if (value !== void 0 && (live || node.required || values.query?.[node.name])) target.query[node.name] = value;
|
|
8568
|
+
}
|
|
8569
|
+
for (const node of params.header) {
|
|
8570
|
+
const value = parameterValue(node, values.header?.[node.name]);
|
|
8571
|
+
if (value !== void 0 && (live || node.required || values.header?.[node.name])) target.headers[node.name] = value;
|
|
8572
|
+
}
|
|
8573
|
+
for (const node of params.cookie) {
|
|
8574
|
+
const value = parameterValue(node, values.cookie?.[node.name]);
|
|
8575
|
+
if (value !== void 0 && (live || node.required || values.cookie?.[node.name])) target.cookies[node.name] = value;
|
|
8576
|
+
}
|
|
8577
|
+
const server = (values.server || operation.servers?.[0]?.url || operation.serverUrl || "").trim().replace(/\/+$/, "");
|
|
8578
|
+
const pathname = operation.path.replace(/\{([^}]+)\}/g, (match, name) => pathValues[name] !== void 0 ? encodeURIComponent(pathValues[name]) : match);
|
|
8579
|
+
const query = Object.entries(target.query).map(([key, value]) => `${encodeURIComponent(key)}=${encodeValue(value)}`).join("&");
|
|
8580
|
+
const url = `${server}${pathname}${query ? `?${query}` : ""}`;
|
|
8581
|
+
const cookieHeader = Object.entries(target.cookies).map(([key, value]) => `${key}=${value}`).join("; ");
|
|
8582
|
+
if (cookieHeader) target.headers.Cookie = cookieHeader;
|
|
8583
|
+
const contentType = operation.requestBody?.contentType;
|
|
8584
|
+
const kind = operation.requestBody ? bodyKind(contentType) : "none";
|
|
8585
|
+
const body = values.body !== void 0 ? values.body : operation.requestBody?.example;
|
|
8586
|
+
return {
|
|
8587
|
+
method: operation.method,
|
|
8588
|
+
url,
|
|
8589
|
+
headers: target.headers,
|
|
8590
|
+
contentType,
|
|
8591
|
+
bodyKind: kind,
|
|
8592
|
+
body: kind === "none" ? void 0 : body,
|
|
8593
|
+
fields: kind === "form" || kind === "multipart" ? parseFields(body) : void 0
|
|
8594
|
+
};
|
|
8595
|
+
}
|
|
8596
|
+
function shellQuote(value) {
|
|
8597
|
+
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
8598
|
+
}
|
|
8599
|
+
function curlSample(request) {
|
|
8600
|
+
const { method, url, headers, bodyKind: kind, body, fields, contentType } = request;
|
|
8601
|
+
const lines = [`curl -X ${method} ${shellQuote(url)}`];
|
|
8602
|
+
for (const [key, value] of Object.entries(headers)) lines.push(` -H ${shellQuote(`${key}: ${value}`)}`);
|
|
8603
|
+
if (kind === "json" && body) lines.push(` -H ${shellQuote(`Content-Type: ${contentType}`)}`, ` -d ${shellQuote(body)}`);
|
|
8604
|
+
else if (kind === "form") for (const [key, value] of Object.entries(fields || {})) lines.push(` --data-urlencode ${shellQuote(`${key}=${value}`)}`);
|
|
8605
|
+
else if (kind === "multipart") for (const [key, value] of Object.entries(fields || {})) lines.push(` -F ${shellQuote(`${key}=${value}`)}`);
|
|
8606
|
+
else if (kind === "raw" && body) lines.push(` -H ${shellQuote(`Content-Type: ${contentType}`)}`, ` -d ${shellQuote(body)}`);
|
|
8607
|
+
return lines.join(" \\\n");
|
|
8608
|
+
}
|
|
8609
|
+
|
|
8610
|
+
//#endregion
|
|
8611
|
+
//#region src/components/ApiPlayground.tsx
|
|
8612
|
+
const REQUEST_TIMEOUT_MS = 3e4;
|
|
8613
|
+
const AUTH_STORAGE_KEY = "shiso:api-auth";
|
|
8614
|
+
const BODYLESS_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
|
|
8615
|
+
const PARAMETER_LOCATIONS = [
|
|
8616
|
+
"path",
|
|
8617
|
+
"query",
|
|
8618
|
+
"header"
|
|
8619
|
+
];
|
|
8620
|
+
const inputClass = "h-8 w-full min-w-0 rounded-md border border-border bg-background px-2.5 font-mono text-foreground text-sm placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-3 focus-visible:ring-ring/50";
|
|
8621
|
+
function isBasic(scheme) {
|
|
8622
|
+
return scheme.type === "http" && scheme.scheme === "basic";
|
|
8623
|
+
}
|
|
8624
|
+
function initialParameters(operation) {
|
|
8625
|
+
const values = {
|
|
8626
|
+
path: {},
|
|
8627
|
+
query: {},
|
|
8628
|
+
header: {}
|
|
8629
|
+
};
|
|
8630
|
+
for (const location of PARAMETER_LOCATIONS) for (const node of operation.parameters[location]) if (node.name) values[location][node.name] = node.example ?? "";
|
|
8631
|
+
return values;
|
|
8632
|
+
}
|
|
8633
|
+
function readStoredAuth() {
|
|
8634
|
+
try {
|
|
8635
|
+
const raw = window.sessionStorage.getItem(AUTH_STORAGE_KEY);
|
|
8636
|
+
const parsed = raw ? JSON.parse(raw) : void 0;
|
|
8637
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
8638
|
+
} catch {
|
|
8639
|
+
return {};
|
|
8640
|
+
}
|
|
8641
|
+
}
|
|
8642
|
+
function writeStoredAuth(values) {
|
|
8643
|
+
try {
|
|
8644
|
+
window.sessionStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(values));
|
|
8645
|
+
} catch {}
|
|
8646
|
+
}
|
|
8647
|
+
/** Resolves the playground proxy template into the URL to fetch. */
|
|
8648
|
+
function proxiedUrl(url, proxy) {
|
|
8649
|
+
if (!proxy) return url;
|
|
8650
|
+
const encoded = encodeURIComponent(url);
|
|
8651
|
+
return proxy.includes("$url") ? proxy.replaceAll("$url", encoded) : `${proxy}${encoded}`;
|
|
8652
|
+
}
|
|
8653
|
+
function prettyBody(text, contentType) {
|
|
8654
|
+
if (/json/i.test(contentType || "") || /^\s*[{[]/.test(text)) try {
|
|
8655
|
+
return {
|
|
8656
|
+
body: JSON.stringify(JSON.parse(text), null, 2),
|
|
8657
|
+
json: true
|
|
8658
|
+
};
|
|
8659
|
+
} catch {}
|
|
8660
|
+
return {
|
|
8661
|
+
body: text,
|
|
8662
|
+
json: false
|
|
8663
|
+
};
|
|
8664
|
+
}
|
|
8665
|
+
function ParameterInput({ id, node, value, onChange }) {
|
|
8666
|
+
const options = node.enum ?? (node.type === "boolean" ? ["true", "false"] : void 0);
|
|
8667
|
+
if (options) return /* @__PURE__ */ jsxs("select", {
|
|
8668
|
+
id,
|
|
8669
|
+
className: inputClass,
|
|
8670
|
+
value,
|
|
8671
|
+
required: node.required,
|
|
8672
|
+
onChange: (event) => onChange(event.target.value),
|
|
8673
|
+
children: [!node.required && /* @__PURE__ */ jsx("option", {
|
|
8674
|
+
value: "",
|
|
8675
|
+
children: "—"
|
|
8676
|
+
}), options.map((option) => /* @__PURE__ */ jsx("option", {
|
|
8677
|
+
value: option,
|
|
8678
|
+
children: option
|
|
8679
|
+
}, option))]
|
|
8680
|
+
});
|
|
8681
|
+
return /* @__PURE__ */ jsx("input", {
|
|
8682
|
+
id,
|
|
8683
|
+
type: "text",
|
|
8684
|
+
className: inputClass,
|
|
8685
|
+
value,
|
|
8686
|
+
required: node.required,
|
|
8687
|
+
placeholder: node.type,
|
|
8688
|
+
autoComplete: "off",
|
|
8689
|
+
spellCheck: false,
|
|
8690
|
+
onChange: (event) => onChange(event.target.value)
|
|
8691
|
+
});
|
|
8692
|
+
}
|
|
8693
|
+
function Field({ id, label, required, hint, children }) {
|
|
8694
|
+
const labels = useLabels();
|
|
8695
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
8696
|
+
className: "grid grid-cols-[minmax(0,1fr)] gap-1 sm:grid-cols-[minmax(8rem,30%)_minmax(0,1fr)] sm:items-center sm:gap-3",
|
|
8697
|
+
children: [/* @__PURE__ */ jsxs("label", {
|
|
8698
|
+
htmlFor: id,
|
|
8699
|
+
className: "flex flex-wrap items-baseline gap-1.5 text-sm",
|
|
8700
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
8701
|
+
className: "font-mono text-foreground",
|
|
8702
|
+
children: label
|
|
8703
|
+
}), required ? /* @__PURE__ */ jsx("span", {
|
|
8704
|
+
className: "text-destructive text-xs",
|
|
8705
|
+
children: labels.fieldRequired
|
|
8706
|
+
}) : hint ? /* @__PURE__ */ jsx("span", {
|
|
8707
|
+
className: "text-muted-foreground text-xs",
|
|
8708
|
+
children: hint
|
|
8709
|
+
}) : null]
|
|
8710
|
+
}), children]
|
|
8711
|
+
});
|
|
8712
|
+
}
|
|
8713
|
+
/**
|
|
8714
|
+
* The "Try it" panel: a form built from the operation's servers, security
|
|
8715
|
+
* schemes, parameters, and request body that sends real requests from the
|
|
8716
|
+
* browser and shows the response. Credentials persist in sessionStorage so a
|
|
8717
|
+
* token entered once is reused on every endpoint page during the tab's life.
|
|
8718
|
+
*/
|
|
8719
|
+
function ApiPlayground({ operation, proxy }) {
|
|
8720
|
+
const labels = useLabels();
|
|
8721
|
+
const idPrefix = useId();
|
|
8722
|
+
const [server, setServer] = useState(operation.servers[0]?.url ?? operation.serverUrl);
|
|
8723
|
+
const [auth, setAuth] = useState({});
|
|
8724
|
+
const [parameters, setParameters] = useState(() => initialParameters(operation));
|
|
8725
|
+
const [body, setBody] = useState(operation.requestBody?.example ?? "");
|
|
8726
|
+
const [status, setStatus] = useState("idle");
|
|
8727
|
+
const [response, setResponse] = useState();
|
|
8728
|
+
const [error, setError] = useState();
|
|
8729
|
+
const controller = useRef(null);
|
|
8730
|
+
useEffect(() => {
|
|
8731
|
+
setAuth(readStoredAuth());
|
|
8732
|
+
}, []);
|
|
8733
|
+
useEffect(() => () => controller.current?.abort(), []);
|
|
8734
|
+
const hasBody = !!operation.requestBody && !BODYLESS_METHODS.has(operation.method);
|
|
8735
|
+
const requestValues = useMemo(() => ({
|
|
8736
|
+
live: true,
|
|
8737
|
+
server,
|
|
8738
|
+
auth,
|
|
8739
|
+
body: hasBody ? body : void 0,
|
|
8740
|
+
...parameters
|
|
8741
|
+
}), [
|
|
8742
|
+
server,
|
|
8743
|
+
auth,
|
|
8744
|
+
body,
|
|
8745
|
+
hasBody,
|
|
8746
|
+
parameters
|
|
8747
|
+
]);
|
|
8748
|
+
const preview = useMemo(() => curlSample(buildRequest(operation, requestValues)), [operation, requestValues]);
|
|
8749
|
+
function updateAuth(name, value) {
|
|
8750
|
+
setAuth((current) => {
|
|
8751
|
+
const next = {
|
|
8752
|
+
...current,
|
|
8753
|
+
[name]: value
|
|
8754
|
+
};
|
|
8755
|
+
writeStoredAuth(next);
|
|
8756
|
+
return next;
|
|
8757
|
+
});
|
|
8758
|
+
}
|
|
8759
|
+
function updateParameter(location, name, value) {
|
|
8760
|
+
setParameters((current) => ({
|
|
8761
|
+
...current,
|
|
8762
|
+
[location]: {
|
|
8763
|
+
...current[location],
|
|
8764
|
+
[name]: value
|
|
8765
|
+
}
|
|
8766
|
+
}));
|
|
8767
|
+
}
|
|
8768
|
+
function cancel() {
|
|
8769
|
+
controller.current?.abort();
|
|
8770
|
+
}
|
|
8771
|
+
async function send(event) {
|
|
8772
|
+
event.preventDefault();
|
|
8773
|
+
if (status === "pending") return;
|
|
8774
|
+
const request = buildRequest(operation, requestValues);
|
|
8775
|
+
const abort = new AbortController();
|
|
8776
|
+
controller.current = abort;
|
|
8777
|
+
setStatus("pending");
|
|
8778
|
+
setError(void 0);
|
|
8779
|
+
const timeout = window.setTimeout(() => abort.abort("timeout"), REQUEST_TIMEOUT_MS);
|
|
8780
|
+
const started = performance.now();
|
|
8781
|
+
try {
|
|
8782
|
+
const headers = new Headers();
|
|
8783
|
+
for (const [key, value] of Object.entries(request.headers)) if (key.toLowerCase() !== "cookie") headers.set(key, value);
|
|
8784
|
+
let payload;
|
|
8785
|
+
if (hasBody) {
|
|
8786
|
+
const fields = request.fields ?? {};
|
|
8787
|
+
if (request.bodyKind === "form") payload = new URLSearchParams(fields);
|
|
8788
|
+
else if (request.bodyKind === "multipart") {
|
|
8789
|
+
const form = new FormData();
|
|
8790
|
+
for (const [key, value] of Object.entries(fields)) form.append(key, value);
|
|
8791
|
+
payload = form;
|
|
8792
|
+
} else if (request.body) {
|
|
8793
|
+
payload = request.body;
|
|
8794
|
+
if (request.contentType) headers.set("Content-Type", request.contentType);
|
|
8795
|
+
}
|
|
8796
|
+
}
|
|
8797
|
+
const result = await fetch(proxiedUrl(request.url, proxy), {
|
|
8798
|
+
method: request.method,
|
|
8799
|
+
headers,
|
|
8800
|
+
body: payload,
|
|
8801
|
+
signal: abort.signal
|
|
8802
|
+
});
|
|
8803
|
+
const { body: pretty, json } = prettyBody(await result.text(), result.headers.get("content-type"));
|
|
8804
|
+
const responseHeaders = [];
|
|
8805
|
+
result.headers.forEach((value, key) => {
|
|
8806
|
+
responseHeaders.push([key, value]);
|
|
8807
|
+
});
|
|
8808
|
+
setResponse({
|
|
8809
|
+
status: result.status,
|
|
8810
|
+
statusText: result.statusText,
|
|
8811
|
+
headers: responseHeaders,
|
|
8812
|
+
body: pretty,
|
|
8813
|
+
json,
|
|
8814
|
+
elapsed: Math.round(performance.now() - started)
|
|
8815
|
+
});
|
|
8816
|
+
setStatus("done");
|
|
8817
|
+
} catch (caught) {
|
|
8818
|
+
if (abort.signal.aborted && abort.signal.reason === "timeout") {
|
|
8819
|
+
setError(labels.apiRequestTimedOut);
|
|
8820
|
+
setStatus("error");
|
|
8821
|
+
} else if (abort.signal.aborted) setStatus(response ? "done" : "idle");
|
|
8822
|
+
else {
|
|
8823
|
+
const detail = caught instanceof Error && caught.message ? ` (${caught.message})` : "";
|
|
8824
|
+
setError(`${labels.apiRequestFailed}${detail}`);
|
|
8825
|
+
setStatus("error");
|
|
8826
|
+
}
|
|
8827
|
+
} finally {
|
|
8828
|
+
window.clearTimeout(timeout);
|
|
8829
|
+
if (controller.current === abort) controller.current = null;
|
|
8830
|
+
}
|
|
8831
|
+
}
|
|
8832
|
+
const serverListId = `${idPrefix}-servers`;
|
|
8833
|
+
const parameterGroups = PARAMETER_LOCATIONS.map((location) => ({
|
|
8834
|
+
location,
|
|
8835
|
+
name: {
|
|
8836
|
+
path: labels.apiPathParameters,
|
|
8837
|
+
query: labels.apiQueryParameters,
|
|
8838
|
+
header: labels.apiHeaders
|
|
8839
|
+
}[location],
|
|
8840
|
+
nodes: operation.parameters[location].filter((node) => node.name)
|
|
8841
|
+
})).filter((group) => group.nodes.length > 0);
|
|
8842
|
+
return /* @__PURE__ */ jsxs("form", {
|
|
8843
|
+
onSubmit: send,
|
|
8844
|
+
className: "not-prose my-4 flex flex-col gap-5 rounded-lg border border-border bg-card p-4 text-sm",
|
|
8845
|
+
"data-slot": "api-playground",
|
|
8846
|
+
"data-pagefind-ignore": true,
|
|
8847
|
+
"aria-busy": status === "pending",
|
|
8848
|
+
children: [
|
|
8849
|
+
/* @__PURE__ */ jsxs("div", {
|
|
8850
|
+
className: "flex flex-col gap-2",
|
|
8851
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
8852
|
+
htmlFor: `${idPrefix}-server`,
|
|
8853
|
+
className: "text-muted-foreground text-xs",
|
|
8854
|
+
children: labels.apiServer
|
|
8855
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
8856
|
+
className: "flex flex-wrap items-center gap-2",
|
|
8857
|
+
children: [
|
|
8858
|
+
/* @__PURE__ */ jsx(Badge, {
|
|
8859
|
+
color: methodColor(operation.method),
|
|
8860
|
+
size: "sm",
|
|
8861
|
+
className: "font-mono",
|
|
8862
|
+
children: operation.method
|
|
8863
|
+
}),
|
|
8864
|
+
/* @__PURE__ */ jsx("input", {
|
|
8865
|
+
id: `${idPrefix}-server`,
|
|
8866
|
+
type: "text",
|
|
8867
|
+
className: cn(inputClass, "flex-1 basis-48"),
|
|
8868
|
+
value: server,
|
|
8869
|
+
list: operation.servers.length > 1 ? serverListId : void 0,
|
|
8870
|
+
autoComplete: "off",
|
|
8871
|
+
spellCheck: false,
|
|
8872
|
+
onChange: (event) => setServer(event.target.value)
|
|
8873
|
+
}),
|
|
8874
|
+
operation.servers.length > 1 && /* @__PURE__ */ jsx("datalist", {
|
|
8875
|
+
id: serverListId,
|
|
8876
|
+
children: operation.servers.map((item) => /* @__PURE__ */ jsx("option", {
|
|
8877
|
+
value: item.url,
|
|
8878
|
+
children: item.description
|
|
8879
|
+
}, item.url))
|
|
8880
|
+
}),
|
|
8881
|
+
/* @__PURE__ */ jsx("code", {
|
|
8882
|
+
className: "font-mono text-muted-foreground",
|
|
8883
|
+
children: operation.path
|
|
8884
|
+
})
|
|
8885
|
+
]
|
|
8886
|
+
})]
|
|
8887
|
+
}),
|
|
8888
|
+
operation.security.length > 0 && /* @__PURE__ */ jsxs("fieldset", {
|
|
8889
|
+
className: "flex flex-col gap-3",
|
|
8890
|
+
children: [
|
|
8891
|
+
/* @__PURE__ */ jsx("legend", {
|
|
8892
|
+
className: "mb-2 text-muted-foreground text-xs",
|
|
8893
|
+
children: labels.apiAuthorization
|
|
8894
|
+
}),
|
|
8895
|
+
operation.security.map((scheme) => {
|
|
8896
|
+
const value = auth[scheme.name];
|
|
8897
|
+
const fieldId = `${idPrefix}-auth-${scheme.name}`;
|
|
8898
|
+
if (isBasic(scheme)) {
|
|
8899
|
+
const basic = value && typeof value === "object" ? value : {
|
|
8900
|
+
username: "",
|
|
8901
|
+
password: ""
|
|
8902
|
+
};
|
|
8903
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
8904
|
+
className: "flex flex-col gap-2",
|
|
8905
|
+
children: [/* @__PURE__ */ jsx(Field, {
|
|
8906
|
+
id: `${fieldId}-user`,
|
|
8907
|
+
label: labels.apiUsername,
|
|
8908
|
+
hint: scheme.name,
|
|
8909
|
+
children: /* @__PURE__ */ jsx("input", {
|
|
8910
|
+
id: `${fieldId}-user`,
|
|
8911
|
+
type: "text",
|
|
8912
|
+
className: inputClass,
|
|
8913
|
+
value: basic.username,
|
|
8914
|
+
autoComplete: "off",
|
|
8915
|
+
onChange: (event) => updateAuth(scheme.name, {
|
|
8916
|
+
...basic,
|
|
8917
|
+
username: event.target.value
|
|
8918
|
+
})
|
|
8919
|
+
})
|
|
8920
|
+
}), /* @__PURE__ */ jsx(Field, {
|
|
8921
|
+
id: `${fieldId}-pass`,
|
|
8922
|
+
label: labels.apiPassword,
|
|
8923
|
+
children: /* @__PURE__ */ jsx("input", {
|
|
8924
|
+
id: `${fieldId}-pass`,
|
|
8925
|
+
type: "password",
|
|
8926
|
+
className: inputClass,
|
|
8927
|
+
value: basic.password,
|
|
8928
|
+
autoComplete: "off",
|
|
8929
|
+
onChange: (event) => updateAuth(scheme.name, {
|
|
8930
|
+
...basic,
|
|
8931
|
+
password: event.target.value
|
|
8932
|
+
})
|
|
8933
|
+
})
|
|
8934
|
+
})]
|
|
8935
|
+
}, scheme.name);
|
|
8936
|
+
}
|
|
8937
|
+
const label = scheme.type === "apiKey" ? scheme.paramName || labels.apiApiKey : scheme.type === "http" && scheme.scheme !== "bearer" ? "Authorization" : labels.apiToken;
|
|
8938
|
+
return /* @__PURE__ */ jsx(Field, {
|
|
8939
|
+
id: fieldId,
|
|
8940
|
+
label,
|
|
8941
|
+
hint: scheme.label,
|
|
8942
|
+
children: /* @__PURE__ */ jsx("input", {
|
|
8943
|
+
id: fieldId,
|
|
8944
|
+
type: "password",
|
|
8945
|
+
className: inputClass,
|
|
8946
|
+
value: typeof value === "string" ? value : "",
|
|
8947
|
+
autoComplete: "off",
|
|
8948
|
+
onChange: (event) => updateAuth(scheme.name, event.target.value)
|
|
8949
|
+
})
|
|
8950
|
+
}, scheme.name);
|
|
8951
|
+
}),
|
|
8952
|
+
/* @__PURE__ */ jsx("p", {
|
|
8953
|
+
className: "m-0 text-muted-foreground text-xs",
|
|
8954
|
+
children: labels.apiCredentialsStored
|
|
8955
|
+
})
|
|
8956
|
+
]
|
|
8957
|
+
}),
|
|
8958
|
+
parameterGroups.map((group) => /* @__PURE__ */ jsxs("fieldset", {
|
|
8959
|
+
className: "flex flex-col gap-3",
|
|
8960
|
+
children: [/* @__PURE__ */ jsx("legend", {
|
|
8961
|
+
className: "mb-2 text-muted-foreground text-xs",
|
|
8962
|
+
children: group.name
|
|
8963
|
+
}), group.nodes.map((node) => {
|
|
8964
|
+
const name = node.name;
|
|
8965
|
+
const fieldId = `${idPrefix}-${group.location}-${name}`;
|
|
8966
|
+
return /* @__PURE__ */ jsx(Field, {
|
|
8967
|
+
id: fieldId,
|
|
8968
|
+
label: name,
|
|
8969
|
+
required: node.required,
|
|
8970
|
+
hint: labels.apiOptional,
|
|
8971
|
+
children: /* @__PURE__ */ jsx(ParameterInput, {
|
|
8972
|
+
id: fieldId,
|
|
8973
|
+
node,
|
|
8974
|
+
value: parameters[group.location][name] ?? "",
|
|
8975
|
+
onChange: (value) => updateParameter(group.location, name, value)
|
|
8976
|
+
})
|
|
8977
|
+
}, name);
|
|
8978
|
+
})]
|
|
8979
|
+
}, group.location)),
|
|
8980
|
+
operation.parameters.cookie.length > 0 && /* @__PURE__ */ jsx("p", {
|
|
8981
|
+
className: "m-0 text-muted-foreground text-xs",
|
|
8982
|
+
children: labels.apiCookiesUnsupported
|
|
8983
|
+
}),
|
|
8984
|
+
hasBody && /* @__PURE__ */ jsxs("div", {
|
|
8985
|
+
className: "flex flex-col gap-2",
|
|
8986
|
+
children: [/* @__PURE__ */ jsxs("label", {
|
|
8987
|
+
htmlFor: `${idPrefix}-body`,
|
|
8988
|
+
className: "flex items-baseline gap-2 text-muted-foreground text-xs",
|
|
8989
|
+
children: [labels.apiBody, /* @__PURE__ */ jsx("span", {
|
|
8990
|
+
className: "font-mono",
|
|
8991
|
+
children: operation.requestBody?.contentType
|
|
8992
|
+
})]
|
|
8993
|
+
}), /* @__PURE__ */ jsx("textarea", {
|
|
8994
|
+
id: `${idPrefix}-body`,
|
|
8995
|
+
className: cn(inputClass, "h-auto min-h-32 resize-y py-2 leading-relaxed"),
|
|
8996
|
+
value: body,
|
|
8997
|
+
spellCheck: false,
|
|
8998
|
+
onChange: (event) => setBody(event.target.value)
|
|
8999
|
+
})]
|
|
9000
|
+
}),
|
|
9001
|
+
/* @__PURE__ */ jsxs("div", {
|
|
9002
|
+
className: "flex flex-wrap items-center gap-2",
|
|
9003
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
9004
|
+
type: "submit",
|
|
9005
|
+
disabled: status === "pending",
|
|
9006
|
+
children: status === "pending" ? labels.apiSending : labels.apiSend
|
|
9007
|
+
}), status === "pending" && /* @__PURE__ */ jsx(Button, {
|
|
9008
|
+
type: "button",
|
|
9009
|
+
variant: "outline",
|
|
9010
|
+
onClick: cancel,
|
|
9011
|
+
children: labels.apiCancel
|
|
9012
|
+
})]
|
|
9013
|
+
}),
|
|
9014
|
+
/* @__PURE__ */ jsx(Expandable, {
|
|
9015
|
+
title: labels.apiRequest,
|
|
9016
|
+
children: /* @__PURE__ */ jsx(CodeBlock, {
|
|
9017
|
+
"data-language": "bash",
|
|
9018
|
+
"data-line-count": String(preview.split("\n").length),
|
|
9019
|
+
className: "text-xs",
|
|
9020
|
+
children: /* @__PURE__ */ jsx("code", {
|
|
9021
|
+
className: "language-bash",
|
|
9022
|
+
children: preview
|
|
9023
|
+
})
|
|
9024
|
+
})
|
|
9025
|
+
}),
|
|
9026
|
+
/* @__PURE__ */ jsxs("div", {
|
|
9027
|
+
className: "flex flex-col gap-2",
|
|
9028
|
+
role: "status",
|
|
9029
|
+
"aria-live": "polite",
|
|
9030
|
+
children: [
|
|
9031
|
+
/* @__PURE__ */ jsx("div", {
|
|
9032
|
+
className: "text-muted-foreground text-xs",
|
|
9033
|
+
children: labels.apiResponse
|
|
9034
|
+
}),
|
|
9035
|
+
status === "error" && error && /* @__PURE__ */ jsx("p", {
|
|
9036
|
+
className: "m-0 text-destructive",
|
|
9037
|
+
children: error
|
|
9038
|
+
}),
|
|
9039
|
+
response ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
9040
|
+
/* @__PURE__ */ jsxs("div", {
|
|
9041
|
+
className: "flex flex-wrap items-center gap-2",
|
|
9042
|
+
children: [
|
|
9043
|
+
/* @__PURE__ */ jsx(Badge, {
|
|
9044
|
+
color: statusColor(String(response.status)),
|
|
9045
|
+
size: "sm",
|
|
9046
|
+
children: response.status
|
|
9047
|
+
}),
|
|
9048
|
+
response.statusText && /* @__PURE__ */ jsx("span", {
|
|
9049
|
+
className: "text-muted-foreground",
|
|
9050
|
+
children: response.statusText
|
|
9051
|
+
}),
|
|
9052
|
+
/* @__PURE__ */ jsx("span", {
|
|
9053
|
+
className: "text-muted-foreground text-xs",
|
|
9054
|
+
children: labels.apiElapsed.replace("{ms}", () => String(response.elapsed))
|
|
9055
|
+
})
|
|
9056
|
+
]
|
|
9057
|
+
}),
|
|
9058
|
+
response.headers.length > 0 && /* @__PURE__ */ jsx(Expandable, {
|
|
9059
|
+
title: labels.apiResponseHeaders,
|
|
9060
|
+
children: /* @__PURE__ */ jsx("dl", {
|
|
9061
|
+
className: "m-0 grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1 font-mono text-xs",
|
|
9062
|
+
children: response.headers.map(([key, value]) => /* @__PURE__ */ jsxs("div", {
|
|
9063
|
+
className: "contents",
|
|
9064
|
+
children: [/* @__PURE__ */ jsx("dt", {
|
|
9065
|
+
className: "text-muted-foreground",
|
|
9066
|
+
children: key
|
|
9067
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
9068
|
+
className: "m-0 break-all text-foreground",
|
|
9069
|
+
children: value
|
|
9070
|
+
})]
|
|
9071
|
+
}, key))
|
|
9072
|
+
})
|
|
9073
|
+
}),
|
|
9074
|
+
/* @__PURE__ */ jsx(CodeBlock, {
|
|
9075
|
+
"data-language": response.json ? "json" : "text",
|
|
9076
|
+
"data-title": labels.apiResponseBody,
|
|
9077
|
+
"data-line-count": String(response.body.split("\n").length),
|
|
9078
|
+
className: "text-xs",
|
|
9079
|
+
children: /* @__PURE__ */ jsx("code", {
|
|
9080
|
+
className: response.json ? "language-json" : "language-text",
|
|
9081
|
+
children: response.body || " "
|
|
9082
|
+
})
|
|
9083
|
+
})
|
|
9084
|
+
] }) : status !== "error" && /* @__PURE__ */ jsx("p", {
|
|
9085
|
+
className: "m-0 text-muted-foreground",
|
|
9086
|
+
children: labels.apiNoResponse
|
|
9087
|
+
})
|
|
9088
|
+
]
|
|
9089
|
+
})
|
|
9090
|
+
]
|
|
9091
|
+
});
|
|
9092
|
+
}
|
|
9093
|
+
|
|
8174
9094
|
//#endregion
|
|
8175
9095
|
//#region src/components/OpenApiOperation.tsx
|
|
8176
|
-
function FieldChildren({ node }) {
|
|
9096
|
+
function FieldChildren$1({ node }) {
|
|
9097
|
+
const labels = useLabels();
|
|
8177
9098
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [node.description, node.enum && node.enum.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
8178
9099
|
className: "mt-1",
|
|
8179
9100
|
children: [
|
|
8180
|
-
|
|
9101
|
+
labels.fieldOptions,
|
|
8181
9102
|
" ",
|
|
8182
9103
|
node.enum.map((value, index) => /* @__PURE__ */ jsxs("span", { children: [index > 0 && ", ", /* @__PURE__ */ jsx("code", { children: value })] }, value))
|
|
8183
9104
|
]
|
|
8184
9105
|
})] });
|
|
8185
9106
|
}
|
|
8186
|
-
function schemaDetails(node) {
|
|
9107
|
+
function schemaDetails(node, labels) {
|
|
8187
9108
|
if (!node.children?.length) return void 0;
|
|
8188
9109
|
return /* @__PURE__ */ jsx(Expandable, {
|
|
8189
|
-
title: node.type === "oneOf" || node.type === "anyOf" ?
|
|
8190
|
-
children: /* @__PURE__ */ jsx(SchemaTable, { nodes: node.children })
|
|
9110
|
+
title: node.type === "oneOf" || node.type === "anyOf" ? labels.allowedTypes : labels.properties,
|
|
9111
|
+
children: /* @__PURE__ */ jsx(SchemaTable$1, { nodes: node.children })
|
|
8191
9112
|
});
|
|
8192
9113
|
}
|
|
8193
|
-
function SchemaTable({ nodes }) {
|
|
9114
|
+
function SchemaTable$1({ nodes }) {
|
|
9115
|
+
const labels = useLabels();
|
|
8194
9116
|
return /* @__PURE__ */ jsx(PropertiesTable, { children: nodes.map((node) => /* @__PURE__ */ jsx(PropertiesTable.Row, {
|
|
8195
9117
|
name: node.name || node.type,
|
|
8196
9118
|
type: node.type,
|
|
8197
9119
|
required: node.required,
|
|
8198
9120
|
deprecated: node.deprecated,
|
|
8199
9121
|
default: node.default,
|
|
8200
|
-
details: schemaDetails(node),
|
|
8201
|
-
children: /* @__PURE__ */ jsx(FieldChildren, { node })
|
|
9122
|
+
details: schemaDetails(node, labels),
|
|
9123
|
+
children: /* @__PURE__ */ jsx(FieldChildren$1, { node })
|
|
8202
9124
|
}, node.name || node.type)) });
|
|
8203
9125
|
}
|
|
8204
9126
|
/** Renders a schema tree: a root object's properties, or the node itself. */
|
|
8205
9127
|
function SchemaFields({ node }) {
|
|
8206
9128
|
const isUnion = node.type === "oneOf" || node.type === "anyOf";
|
|
8207
|
-
return /* @__PURE__ */ jsx(SchemaTable, { nodes: !node.name && !isUnion && node.children?.length ? node.children : [node] });
|
|
9129
|
+
return /* @__PURE__ */ jsx(SchemaTable$1, { nodes: !node.name && !isUnion && node.children?.length ? node.children : [node] });
|
|
8208
9130
|
}
|
|
8209
9131
|
function HighlightedCode({ language, title, html, source, lineCount }) {
|
|
8210
9132
|
return /* @__PURE__ */ jsx(CodeBlock, {
|
|
@@ -8220,49 +9142,69 @@ function HighlightedCode({ language, title, html, source, lineCount }) {
|
|
|
8220
9142
|
})
|
|
8221
9143
|
});
|
|
8222
9144
|
}
|
|
9145
|
+
/** How a credential is sent, e.g. "Bearer <token>" or "<api-key>". */
|
|
9146
|
+
function credentialExample(scheme) {
|
|
9147
|
+
const placeholder = securityPlaceholder(scheme);
|
|
9148
|
+
if (scheme.type === "apiKey") return placeholder;
|
|
9149
|
+
return `${scheme.type === "http" && scheme.scheme && scheme.scheme !== "bearer" ? scheme.scheme.charAt(0).toUpperCase() + scheme.scheme.slice(1) : "Bearer"} ${placeholder}`;
|
|
9150
|
+
}
|
|
8223
9151
|
/** The generated reference for one API operation, rendered under the page body. */
|
|
8224
|
-
function OpenApiOperation({ operation }) {
|
|
8225
|
-
const
|
|
9152
|
+
function OpenApiOperation({ operation, playground: requested = false }) {
|
|
9153
|
+
const labels = useLabels();
|
|
9154
|
+
const playground = operation.webhook ? false : requested;
|
|
9155
|
+
const options = { playground: !!playground };
|
|
9156
|
+
const sectionEntries = operationSections(operation, labels, options);
|
|
9157
|
+
const sections = new Map(operationSections(operation, void 0, options).map((entry) => [entry.name, entry.id]));
|
|
9158
|
+
const parameterSections = operationParameterSections(operation, labels);
|
|
9159
|
+
const parameterOffset = playground ? 1 : 0;
|
|
8226
9160
|
return /* @__PURE__ */ jsxs("div", {
|
|
8227
9161
|
className: "docs-markdown",
|
|
8228
9162
|
children: [
|
|
8229
|
-
|
|
8230
|
-
id: sections.get(
|
|
9163
|
+
playground && /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx("h2", {
|
|
9164
|
+
id: sections.get("Try it"),
|
|
9165
|
+
children: labels.apiPlayground
|
|
9166
|
+
}), /* @__PURE__ */ jsx(ApiPlayground, {
|
|
9167
|
+
operation,
|
|
9168
|
+
proxy: playground.proxy
|
|
9169
|
+
})] }),
|
|
9170
|
+
parameterSections.map(({ location, name }, index) => /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx("h2", {
|
|
9171
|
+
id: sectionEntries[index + parameterOffset].id,
|
|
8231
9172
|
children: name
|
|
8232
|
-
}), /* @__PURE__ */ jsxs(PropertiesTable, { children: [location
|
|
8233
|
-
name:
|
|
9173
|
+
}), /* @__PURE__ */ jsxs(PropertiesTable, { children: [securityForLocation(operation, location).map((scheme) => /* @__PURE__ */ jsxs(PropertiesTable.Row, {
|
|
9174
|
+
name: securityFieldName(scheme),
|
|
8234
9175
|
type: "string",
|
|
8235
9176
|
required: true,
|
|
8236
9177
|
children: [
|
|
8237
|
-
|
|
8238
|
-
|
|
9178
|
+
scheme.description || labels.apiCredentials,
|
|
9179
|
+
" ",
|
|
9180
|
+
/* @__PURE__ */ jsx("code", { children: credentialExample(scheme) }),
|
|
8239
9181
|
"."
|
|
8240
9182
|
]
|
|
8241
|
-
}), operation.parameters[location].map((parameter) => /* @__PURE__ */ jsx(PropertiesTable.Row, {
|
|
9183
|
+
}, `security:${scheme.name}`)), operation.parameters[location].map((parameter) => /* @__PURE__ */ jsx(PropertiesTable.Row, {
|
|
8242
9184
|
name: parameter.name || parameter.type,
|
|
8243
9185
|
type: parameter.type,
|
|
8244
9186
|
required: parameter.required,
|
|
8245
9187
|
deprecated: parameter.deprecated,
|
|
8246
9188
|
default: parameter.default,
|
|
8247
|
-
details: schemaDetails(parameter),
|
|
8248
|
-
children: /* @__PURE__ */ jsx(FieldChildren, { node: parameter })
|
|
9189
|
+
details: schemaDetails(parameter, labels),
|
|
9190
|
+
children: /* @__PURE__ */ jsx(FieldChildren$1, { node: parameter })
|
|
8249
9191
|
}, parameter.name))] })] }, location)),
|
|
8250
9192
|
operation.requestBody && /* @__PURE__ */ jsxs("section", { children: [
|
|
8251
9193
|
/* @__PURE__ */ jsx("h2", {
|
|
8252
|
-
id: sections.get("Request body"),
|
|
8253
|
-
children:
|
|
9194
|
+
id: sections.get(operation.webhook ? "Payload" : "Request body"),
|
|
9195
|
+
children: operation.webhook ? labels.apiPayload : labels.apiRequestBody
|
|
8254
9196
|
}),
|
|
8255
9197
|
/* @__PURE__ */ jsx(SchemaFields, { node: operation.requestBody.schema }),
|
|
8256
9198
|
operation.requestBody.example && /* @__PURE__ */ jsx(HighlightedCode, {
|
|
8257
9199
|
language: "json",
|
|
8258
|
-
title:
|
|
9200
|
+
title: labels.apiExampleRequest,
|
|
8259
9201
|
html: operation.requestBody.exampleHtml,
|
|
8260
9202
|
source: operation.requestBody.example
|
|
8261
9203
|
})
|
|
8262
9204
|
] }),
|
|
8263
9205
|
operation.responses.length > 0 && /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx("h2", {
|
|
8264
9206
|
id: sections.get("Responses"),
|
|
8265
|
-
children:
|
|
9207
|
+
children: labels.apiResponses
|
|
8266
9208
|
}), operation.responses.map((response) => /* @__PURE__ */ jsxs("div", {
|
|
8267
9209
|
className: "mt-6 first:mt-0",
|
|
8268
9210
|
children: [
|
|
@@ -8280,7 +9222,7 @@ function OpenApiOperation({ operation }) {
|
|
|
8280
9222
|
response.schema && /* @__PURE__ */ jsx(SchemaFields, { node: response.schema }),
|
|
8281
9223
|
response.example && /* @__PURE__ */ jsx(HighlightedCode, {
|
|
8282
9224
|
language: "json",
|
|
8283
|
-
title:
|
|
9225
|
+
title: labels.apiExampleResponse.replace("{status}", () => response.status),
|
|
8284
9226
|
html: response.exampleHtml,
|
|
8285
9227
|
source: response.example
|
|
8286
9228
|
})
|
|
@@ -8288,7 +9230,7 @@ function OpenApiOperation({ operation }) {
|
|
|
8288
9230
|
}, response.status))] }),
|
|
8289
9231
|
operation.samples.length > 0 && /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx("h2", {
|
|
8290
9232
|
id: sections.get("Code samples"),
|
|
8291
|
-
children:
|
|
9233
|
+
children: labels.apiCodeSamples
|
|
8292
9234
|
}), /* @__PURE__ */ jsx(CodeGroup, { children: operation.samples.map((sample) => /* @__PURE__ */ jsx(HighlightedCode, {
|
|
8293
9235
|
language: sample.language,
|
|
8294
9236
|
title: sample.label,
|
|
@@ -8300,6 +9242,67 @@ function OpenApiOperation({ operation }) {
|
|
|
8300
9242
|
});
|
|
8301
9243
|
}
|
|
8302
9244
|
|
|
9245
|
+
//#endregion
|
|
9246
|
+
//#region src/components/OpenApiSchema.tsx
|
|
9247
|
+
function FieldChildren({ node }) {
|
|
9248
|
+
const labels = useLabels();
|
|
9249
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [node.description, node.enum && node.enum.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
9250
|
+
className: "mt-1",
|
|
9251
|
+
children: [
|
|
9252
|
+
labels.fieldOptions,
|
|
9253
|
+
" ",
|
|
9254
|
+
node.enum.map((value, index) => /* @__PURE__ */ jsxs("span", { children: [index > 0 && ", ", /* @__PURE__ */ jsx("code", { children: value })] }, value))
|
|
9255
|
+
]
|
|
9256
|
+
})] });
|
|
9257
|
+
}
|
|
9258
|
+
function SchemaTable({ nodes, labels }) {
|
|
9259
|
+
return /* @__PURE__ */ jsx(PropertiesTable, { children: nodes.map((node) => /* @__PURE__ */ jsx(PropertiesTable.Row, {
|
|
9260
|
+
name: node.name || node.type,
|
|
9261
|
+
type: node.type,
|
|
9262
|
+
required: node.required,
|
|
9263
|
+
deprecated: node.deprecated,
|
|
9264
|
+
default: node.default,
|
|
9265
|
+
details: node.children?.length ? /* @__PURE__ */ jsx(Expandable, {
|
|
9266
|
+
title: node.type === "oneOf" || node.type === "anyOf" ? labels.allowedTypes : labels.properties,
|
|
9267
|
+
children: /* @__PURE__ */ jsx(SchemaTable, {
|
|
9268
|
+
nodes: node.children,
|
|
9269
|
+
labels
|
|
9270
|
+
})
|
|
9271
|
+
}) : void 0,
|
|
9272
|
+
children: /* @__PURE__ */ jsx(FieldChildren, { node })
|
|
9273
|
+
}, node.name || node.type)) });
|
|
9274
|
+
}
|
|
9275
|
+
/** The generated reference for one named component schema. */
|
|
9276
|
+
function OpenApiSchema({ page }) {
|
|
9277
|
+
const labels = useLabels();
|
|
9278
|
+
const sections = new Map(schemaSections(page, labels).map((entry) => [entry.id, entry.name]));
|
|
9279
|
+
const properties = sections.get("properties");
|
|
9280
|
+
const example = sections.get("example");
|
|
9281
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
9282
|
+
className: "docs-markdown",
|
|
9283
|
+
children: [properties && /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx("h2", {
|
|
9284
|
+
id: "properties",
|
|
9285
|
+
children: properties
|
|
9286
|
+
}), /* @__PURE__ */ jsx(SchemaTable, {
|
|
9287
|
+
nodes: page.schema.children ?? [],
|
|
9288
|
+
labels
|
|
9289
|
+
})] }), example && page.example && /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx("h2", {
|
|
9290
|
+
id: "example",
|
|
9291
|
+
children: example
|
|
9292
|
+
}), /* @__PURE__ */ jsx(CodeBlock, {
|
|
9293
|
+
"data-language": "json",
|
|
9294
|
+
"data-title": page.name,
|
|
9295
|
+
children: page.exampleHtml ? /* @__PURE__ */ jsx("code", {
|
|
9296
|
+
className: "language-json",
|
|
9297
|
+
dangerouslySetInnerHTML: { __html: page.exampleHtml }
|
|
9298
|
+
}) : /* @__PURE__ */ jsx("code", {
|
|
9299
|
+
className: "language-json",
|
|
9300
|
+
children: page.example
|
|
9301
|
+
})
|
|
9302
|
+
})] })]
|
|
9303
|
+
});
|
|
9304
|
+
}
|
|
9305
|
+
|
|
8303
9306
|
//#endregion
|
|
8304
9307
|
//#region src/components/PageActions.tsx
|
|
8305
9308
|
function editHref(template, filePath) {
|
|
@@ -8360,7 +9363,7 @@ function PageActions({ page, frontmatter, site, lastUpdated }) {
|
|
|
8360
9363
|
target: "_blank",
|
|
8361
9364
|
rel: "noopener noreferrer",
|
|
8362
9365
|
className: "ml-auto inline-flex shrink-0 items-center gap-1.5 text-right no-underline hover:text-primary",
|
|
8363
|
-
children: [site.editLink?.label ||
|
|
9366
|
+
children: [site.editLink?.label || site.labels.editPage, /* @__PURE__ */ jsx(ExternalLink, {
|
|
8364
9367
|
size: 14,
|
|
8365
9368
|
"aria-hidden": "true"
|
|
8366
9369
|
})]
|
|
@@ -8370,24 +9373,24 @@ function PageActions({ page, frontmatter, site, lastUpdated }) {
|
|
|
8370
9373
|
"aria-busy": status === "pending",
|
|
8371
9374
|
"data-pagefind-ignore": true,
|
|
8372
9375
|
children: [/* @__PURE__ */ jsxs("fieldset", {
|
|
8373
|
-
"aria-label": feedback.prompt ||
|
|
9376
|
+
"aria-label": feedback.prompt || site.labels.feedbackPrompt,
|
|
8374
9377
|
className: "flex flex-wrap items-center gap-2",
|
|
8375
9378
|
children: [/* @__PURE__ */ jsx("span", {
|
|
8376
9379
|
className: "mr-2 text-muted-foreground",
|
|
8377
|
-
children: feedback.prompt ||
|
|
9380
|
+
children: feedback.prompt || site.labels.feedbackPrompt
|
|
8378
9381
|
}), [true, false].map((helpful) => /* @__PURE__ */ jsx("button", {
|
|
8379
9382
|
type: "button",
|
|
8380
9383
|
"aria-pressed": rating === helpful,
|
|
8381
9384
|
disabled: status === "pending" || status === "success",
|
|
8382
9385
|
onClick: () => void submit(helpful),
|
|
8383
9386
|
className: "rounded-md border border-border px-3 py-1.5 text-foreground hover:bg-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:cursor-default disabled:opacity-60 aria-pressed:border-primary aria-pressed:text-primary",
|
|
8384
|
-
children: helpful ? feedback.helpfulLabel ||
|
|
9387
|
+
children: helpful ? feedback.helpfulLabel || site.labels.feedbackYes : feedback.unhelpfulLabel || site.labels.feedbackNo
|
|
8385
9388
|
}, String(helpful)))]
|
|
8386
9389
|
}), /* @__PURE__ */ jsxs("div", {
|
|
8387
9390
|
role: "status",
|
|
8388
9391
|
"aria-live": "polite",
|
|
8389
9392
|
className: "text-muted-foreground",
|
|
8390
|
-
children: [status === "success" && (feedback.successMessage ||
|
|
9393
|
+
children: [status === "success" && (feedback.successMessage || site.labels.feedbackSuccess), status === "error" && (feedback.errorMessage || site.labels.feedbackError)]
|
|
8391
9394
|
})]
|
|
8392
9395
|
})] });
|
|
8393
9396
|
}
|
|
@@ -8433,6 +9436,8 @@ function DocContent({ page, doc, site }) {
|
|
|
8433
9436
|
const contextualOptions = resolveContextualOptions(site.contextualOptions, page, site.labels);
|
|
8434
9437
|
const related = resolveRelated(doc.frontmatter?.related);
|
|
8435
9438
|
const operation = getOperation(doc.frontmatter?.openapi);
|
|
9439
|
+
const schema = operation ? void 0 : getSchema(doc.frontmatter?.["openapi-schema"]);
|
|
9440
|
+
const playground = operation && resolvePlaygroundDisplay(site.api.playground, doc.frontmatter) === "interactive" ? { proxy: site.api.playground.proxy } : false;
|
|
8436
9441
|
const dateFormat = new Intl.DateTimeFormat(resolveLocale(page.language, site.locale), {
|
|
8437
9442
|
dateStyle: "medium",
|
|
8438
9443
|
timeZone: "UTC"
|
|
@@ -8466,10 +9471,10 @@ function DocContent({ page, doc, site }) {
|
|
|
8466
9471
|
className: "mt-3 flex flex-wrap items-center gap-2",
|
|
8467
9472
|
children: [
|
|
8468
9473
|
/* @__PURE__ */ jsx(Badge, {
|
|
8469
|
-
color: methodColor(operation.method),
|
|
9474
|
+
color: methodColor(operation.webhook ? "WEBHOOK" : operation.method),
|
|
8470
9475
|
size: "sm",
|
|
8471
9476
|
className: "font-mono",
|
|
8472
|
-
children: operation.method
|
|
9477
|
+
children: operation.webhook ? "WEBHOOK" : operation.method
|
|
8473
9478
|
}),
|
|
8474
9479
|
/* @__PURE__ */ jsx("code", {
|
|
8475
9480
|
className: "font-mono text-muted-foreground text-sm",
|
|
@@ -8491,7 +9496,11 @@ function DocContent({ page, doc, site }) {
|
|
|
8491
9496
|
className: "docs-markdown",
|
|
8492
9497
|
children: /* @__PURE__ */ jsx(Content, {})
|
|
8493
9498
|
}),
|
|
8494
|
-
operation && /* @__PURE__ */ jsx(OpenApiOperation, {
|
|
9499
|
+
operation && /* @__PURE__ */ jsx(OpenApiOperation, {
|
|
9500
|
+
operation,
|
|
9501
|
+
playground
|
|
9502
|
+
}),
|
|
9503
|
+
schema && /* @__PURE__ */ jsx(OpenApiSchema, { page: schema }),
|
|
8495
9504
|
/* @__PURE__ */ jsx(PageActions, {
|
|
8496
9505
|
page,
|
|
8497
9506
|
frontmatter: doc.frontmatter,
|
|
@@ -8580,6 +9589,7 @@ const NavigationButton = ({ label, url, eyebrow, isPrev }) => {
|
|
|
8580
9589
|
//#endregion
|
|
8581
9590
|
//#region src/components/Footer.tsx
|
|
8582
9591
|
function Footer({ footer, className = "" }) {
|
|
9592
|
+
const labels = useLabels();
|
|
8583
9593
|
if (!footer) return null;
|
|
8584
9594
|
const { socials, links: columns, attribution } = footer;
|
|
8585
9595
|
return /* @__PURE__ */ jsxs("footer", {
|
|
@@ -8604,10 +9614,14 @@ function Footer({ footer, className = "" }) {
|
|
|
8604
9614
|
children: [attribution ? /* @__PURE__ */ jsxs("a", {
|
|
8605
9615
|
href: "https://shiso.umami.is?ref=docs-footer",
|
|
8606
9616
|
className: "text-sm hover:text-foreground",
|
|
8607
|
-
children: [
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
9617
|
+
children: [
|
|
9618
|
+
labels.poweredBy,
|
|
9619
|
+
" ",
|
|
9620
|
+
/* @__PURE__ */ jsx("span", {
|
|
9621
|
+
className: "font-bold",
|
|
9622
|
+
children: "shiso"
|
|
9623
|
+
})
|
|
9624
|
+
]
|
|
8611
9625
|
}) : /* @__PURE__ */ jsx("span", {}), socials.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
8612
9626
|
className: "flex items-center gap-1",
|
|
8613
9627
|
children: socials.map((link) => {
|
|
@@ -8833,7 +9847,7 @@ function NavNodes({ nodes, pathname, depth, drilldown, expandLabel, collapseLabe
|
|
|
8833
9847
|
color: methodColor(method),
|
|
8834
9848
|
size: "xs",
|
|
8835
9849
|
className: "w-10 shrink-0 justify-center whitespace-nowrap font-mono",
|
|
8836
|
-
children: method
|
|
9850
|
+
children: methodBadgeText(method)
|
|
8837
9851
|
}) : null,
|
|
8838
9852
|
label,
|
|
8839
9853
|
!method && tag ? /* @__PURE__ */ jsx(Badge$1, {
|
|
@@ -8911,6 +9925,7 @@ function SheetOverlay({ className, ...props }) {
|
|
|
8911
9925
|
});
|
|
8912
9926
|
}
|
|
8913
9927
|
function SheetContent({ className, children, side = "right", showCloseButton = true, ...props }) {
|
|
9928
|
+
const labels = useLabels();
|
|
8914
9929
|
return /* @__PURE__ */ jsxs(SheetPortal, { children: [/* @__PURE__ */ jsx(SheetOverlay, {}), /* @__PURE__ */ jsxs(DialogPopup, {
|
|
8915
9930
|
"data-slot": "sheet-content",
|
|
8916
9931
|
"data-side": side,
|
|
@@ -8925,7 +9940,7 @@ function SheetContent({ className, children, side = "right", showCloseButton = t
|
|
|
8925
9940
|
}),
|
|
8926
9941
|
children: [/* @__PURE__ */ jsx(X$1, {}), /* @__PURE__ */ jsx("span", {
|
|
8927
9942
|
className: "sr-only",
|
|
8928
|
-
children:
|
|
9943
|
+
children: labels.close
|
|
8929
9944
|
})]
|
|
8930
9945
|
})]
|
|
8931
9946
|
})] });
|
|
@@ -8966,7 +9981,8 @@ function Docs({ page, doc, site }) {
|
|
|
8966
9981
|
}), /* @__PURE__ */ jsx(Footer, { footer: site.footer })]
|
|
8967
9982
|
});
|
|
8968
9983
|
const operation = getOperation(doc.frontmatter?.openapi);
|
|
8969
|
-
const
|
|
9984
|
+
const schema = operation ? void 0 : getSchema(doc.frontmatter?.["openapi-schema"]);
|
|
9985
|
+
const toc = operation ? [...doc.toc || [], ...operationSections(operation, site.labels, { playground: resolvePlaygroundDisplay(site.api.playground, doc.frontmatter) === "interactive" })] : schema ? [...doc.toc || [], ...schemaSections(schema, site.labels)] : doc.toc;
|
|
8970
9986
|
return /* @__PURE__ */ jsx(PanelProvider, { children: /* @__PURE__ */ jsx(DocsBody, {
|
|
8971
9987
|
page,
|
|
8972
9988
|
doc,
|
|
@@ -9138,32 +10154,37 @@ const mdxComponents = {
|
|
|
9138
10154
|
pre: CodeBlock
|
|
9139
10155
|
};
|
|
9140
10156
|
function App() {
|
|
9141
|
-
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
|
|
9146
|
-
|
|
9147
|
-
|
|
9148
|
-
|
|
9149
|
-
|
|
9150
|
-
|
|
9151
|
-
|
|
9152
|
-
|
|
9153
|
-
|
|
9154
|
-
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
10157
|
+
const { pathname } = useLocation();
|
|
10158
|
+
const siteModel = getSiteModelByPathname(pathname);
|
|
10159
|
+
return /* @__PURE__ */ jsx(LabelContext.Provider, {
|
|
10160
|
+
value: siteModel.labels,
|
|
10161
|
+
children: /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(MDXProvider, {
|
|
10162
|
+
components: mdxComponents,
|
|
10163
|
+
children: /* @__PURE__ */ jsx(Layout, {
|
|
10164
|
+
site: siteModel,
|
|
10165
|
+
children: /* @__PURE__ */ jsxs(Routes, { children: [
|
|
10166
|
+
standalonePages.map((page) => /* @__PURE__ */ jsx(Route, {
|
|
10167
|
+
path: page.path,
|
|
10168
|
+
element: /* @__PURE__ */ jsx(StandalonePageView, {
|
|
10169
|
+
page,
|
|
10170
|
+
site: siteModel
|
|
10171
|
+
})
|
|
10172
|
+
}, page.path)),
|
|
10173
|
+
docsHomeUrl !== "/" && !hasRootStandalonePage ? /* @__PURE__ */ jsx(Route, {
|
|
10174
|
+
path: "/",
|
|
10175
|
+
element: /* @__PURE__ */ jsx(Navigate, {
|
|
10176
|
+
to: docsHomeUrl,
|
|
10177
|
+
replace: true
|
|
10178
|
+
})
|
|
10179
|
+
}) : null,
|
|
10180
|
+
/* @__PURE__ */ jsx(Route, {
|
|
10181
|
+
path: "*",
|
|
10182
|
+
element: /* @__PURE__ */ jsx(DocPage, { site: siteModel })
|
|
9158
10183
|
})
|
|
9159
|
-
})
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
})
|
|
9164
|
-
] })
|
|
9165
|
-
})
|
|
9166
|
-
}) });
|
|
10184
|
+
] })
|
|
10185
|
+
})
|
|
10186
|
+
}) })
|
|
10187
|
+
});
|
|
9167
10188
|
}
|
|
9168
10189
|
|
|
9169
10190
|
//#endregion
|