@umami/shiso 1.18.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 +1081 -47
- 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 +183 -8
- 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 -1135
- package/package.json +1 -2
- package/scripts/check-content.mjs +42 -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/prerender.mjs +17 -14
- package/scripts/vite-docs-config.mjs +1 -0
- package/src/components/ApiPlayground.tsx +522 -0
- package/src/components/DocContent.tsx +15 -4
- package/src/components/Docs.tsx +18 -3
- package/src/components/LanguageSwitcher.tsx +26 -30
- package/src/components/OpenApiOperation.tsx +58 -12
- package/src/components/OpenApiSchema.tsx +97 -0
- package/src/components/SideNav.tsx +2 -2
- package/src/lib/openapi.generated.ts +2 -1
- package/src/lib/openapi.ts +104 -10
- package/src/lib/site-model.ts +12 -0
- package/src/lib/translations/de.json +26 -1
- package/src/lib/translations/en.json +26 -1
- package/src/lib/translations/es.json +26 -1
- package/src/lib/translations/fr.json +26 -1
- package/src/lib/translations/ja.json +26 -1
- package/src/lib/translations/zh-Hans.json +26 -1
- package/src/lib/translations/zh-Hant.json +26 -1
- package/src/lib/types.ts +89 -5
- package/types/labels.d.ts +25 -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
|
/**
|
|
@@ -2172,6 +2172,43 @@ function useMenuItem(params) {
|
|
|
2172
2172
|
}), [getItemProps, mergedRef]);
|
|
2173
2173
|
}
|
|
2174
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
|
+
|
|
2175
2212
|
//#endregion
|
|
2176
2213
|
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menu/item/MenuItem.mjs
|
|
2177
2214
|
/**
|
|
@@ -2595,6 +2632,187 @@ const MenuPositioner = /*#__PURE__*/ React.forwardRef(function MenuPositioner(co
|
|
|
2595
2632
|
});
|
|
2596
2633
|
MenuPositioner.displayName = "MenuPositioner";
|
|
2597
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
|
+
|
|
2598
2816
|
//#endregion
|
|
2599
2817
|
//#region ../../node_modules/.pnpm/@base-ui+react@1.7.0_@types_e9c1e83f6bc6140c3efaf3427f2fbf0a/node_modules/@base-ui/react/menubar/MenubarContext.mjs
|
|
2600
2818
|
const MenubarContext = /*#__PURE__*/ React.createContext(null);
|
|
@@ -3403,6 +3621,25 @@ function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
|
|
|
3403
3621
|
...props
|
|
3404
3622
|
});
|
|
3405
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
|
+
}
|
|
3406
3643
|
|
|
3407
3644
|
//#endregion
|
|
3408
3645
|
//#region src/lib/paths.ts
|
|
@@ -4208,6 +4445,15 @@ function normalizeNavbar(config) {
|
|
|
4208
4445
|
primary
|
|
4209
4446
|
} : null;
|
|
4210
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
|
+
}
|
|
4211
4457
|
function normalizeFooter(config) {
|
|
4212
4458
|
const socials = (config?.socials || []).filter((link) => !!link?.href).map(normalizeLink);
|
|
4213
4459
|
const links = (config?.links || []).filter((column) => column?.items?.length).map((column) => ({
|
|
@@ -4265,6 +4511,7 @@ function resolveSiteModel(config, docs, shiso) {
|
|
|
4265
4511
|
drilldown: config.interaction?.drilldown,
|
|
4266
4512
|
locale: shiso?.locale || "en-US",
|
|
4267
4513
|
labels: resolveLabels(shiso?.locale || "en-US", shiso?.translations),
|
|
4514
|
+
api: { playground: normalizePlayground(config.api) },
|
|
4268
4515
|
docs
|
|
4269
4516
|
};
|
|
4270
4517
|
}
|
|
@@ -4538,27 +4785,29 @@ function LanguageSwitcher() {
|
|
|
4538
4785
|
const standalone = getStandalonePage(pathname);
|
|
4539
4786
|
if (!current.language || options.length < 2 && !current.hidden) return null;
|
|
4540
4787
|
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
|
|
4541
|
-
render: /* @__PURE__ */ jsx(Button, {
|
|
4542
|
-
|
|
4543
|
-
className: "h-auto gap-1.5 rounded-md bg-card px-2.5 py-1.5 text-sm font-medium text-foreground"
|
|
4544
|
-
}),
|
|
4788
|
+
render: /* @__PURE__ */ jsx(Button, { variant: "outline" }),
|
|
4789
|
+
"aria-label": `Language: ${getLanguageName(current.language)}`,
|
|
4545
4790
|
children: [getLanguageName(current.language), /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 rotate-90 text-muted-foreground" })]
|
|
4546
4791
|
}), /* @__PURE__ */ jsx(DropdownMenuContent, {
|
|
4547
4792
|
align: "start",
|
|
4548
4793
|
className: "min-w-32",
|
|
4549
|
-
children:
|
|
4550
|
-
|
|
4551
|
-
|
|
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) {
|
|
4552
4799
|
const counterpart = standalone && scope.language ? getStandaloneCounterpart(standalone, scope.language) : null;
|
|
4553
4800
|
navigate(counterpart?.path || scope.firstPageUrl);
|
|
4554
4801
|
}
|
|
4555
4802
|
},
|
|
4556
|
-
children:
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
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
|
+
})
|
|
4562
4811
|
})] });
|
|
4563
4812
|
}
|
|
4564
4813
|
|
|
@@ -8078,8 +8327,39 @@ const METHOD_COLORS = {
|
|
|
8078
8327
|
POST: "blue",
|
|
8079
8328
|
PUT: "orange",
|
|
8080
8329
|
PATCH: "purple",
|
|
8081
|
-
DELETE: "red"
|
|
8330
|
+
DELETE: "red",
|
|
8331
|
+
WEBHOOK: "yellow"
|
|
8082
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
|
+
}
|
|
8083
8363
|
function methodColor(method) {
|
|
8084
8364
|
return method && METHOD_COLORS[method.toUpperCase()] || "gray";
|
|
8085
8365
|
}
|
|
@@ -8089,11 +8369,51 @@ function statusColor(status) {
|
|
|
8089
8369
|
if (status.startsWith("4") || status.startsWith("5")) return "red";
|
|
8090
8370
|
return "gray";
|
|
8091
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
|
+
}
|
|
8092
8381
|
/** Looks up the operation bound by an `openapi:` frontmatter value. */
|
|
8093
8382
|
function getOperation(key) {
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
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";
|
|
8097
8417
|
}
|
|
8098
8418
|
/** Parameter groups shared by the renderer and table of contents. */
|
|
8099
8419
|
function operationParameterSections(operation, labels = englishLabels) {
|
|
@@ -8114,24 +8434,27 @@ function operationParameterSections(operation, labels = englishLabels) {
|
|
|
8114
8434
|
location: "cookie",
|
|
8115
8435
|
name: labels.apiCookieParameters
|
|
8116
8436
|
}
|
|
8117
|
-
].filter(({ location }) => operation.parameters[location].length > 0 || location
|
|
8437
|
+
].filter(({ location }) => operation.parameters[location].length > 0 || securityForLocation(operation, location).length > 0);
|
|
8118
8438
|
}
|
|
8119
8439
|
/**
|
|
8120
8440
|
* Section headings for an operation, in render order. The single source of
|
|
8121
8441
|
* truth for section ids: the component, the table of contents, the content
|
|
8122
8442
|
* checker, and the search indexer all derive their anchors from these labels.
|
|
8123
8443
|
*/
|
|
8124
|
-
function operationSections(operation, labels = englishLabels) {
|
|
8444
|
+
function operationSections(operation, labels = englishLabels, options = {}) {
|
|
8125
8445
|
const slugger = createSlugger();
|
|
8446
|
+
const playground = options.playground && !operation.webhook;
|
|
8126
8447
|
const names = [
|
|
8448
|
+
playground ? "Try it" : void 0,
|
|
8127
8449
|
...operationParameterSections(operation).map((section) => section.name),
|
|
8128
|
-
operation.requestBody ? "Request body" : void 0,
|
|
8450
|
+
operation.requestBody ? operation.webhook ? "Payload" : "Request body" : void 0,
|
|
8129
8451
|
operation.responses.length ? "Responses" : void 0,
|
|
8130
8452
|
operation.samples.length ? "Code samples" : void 0
|
|
8131
8453
|
].filter((name) => Boolean(name));
|
|
8132
8454
|
const translated = [
|
|
8455
|
+
...playground ? [labels.apiPlayground] : [],
|
|
8133
8456
|
...operationParameterSections(operation, labels).map((section) => section.name),
|
|
8134
|
-
...operation.requestBody ? [labels.apiRequestBody] : [],
|
|
8457
|
+
...operation.requestBody ? [operation.webhook ? labels.apiPayload : labels.apiRequestBody] : [],
|
|
8135
8458
|
...operation.responses.length ? [labels.apiResponses] : [],
|
|
8136
8459
|
...operation.samples.length ? [labels.apiCodeSamples] : []
|
|
8137
8460
|
];
|
|
@@ -8142,9 +8465,635 @@ function operationSections(operation, labels = englishLabels) {
|
|
|
8142
8465
|
}));
|
|
8143
8466
|
}
|
|
8144
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
|
+
|
|
8145
9094
|
//#endregion
|
|
8146
9095
|
//#region src/components/OpenApiOperation.tsx
|
|
8147
|
-
function FieldChildren({ node }) {
|
|
9096
|
+
function FieldChildren$1({ node }) {
|
|
8148
9097
|
const labels = useLabels();
|
|
8149
9098
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [node.description, node.enum && node.enum.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
8150
9099
|
className: "mt-1",
|
|
@@ -8159,10 +9108,10 @@ function schemaDetails(node, labels) {
|
|
|
8159
9108
|
if (!node.children?.length) return void 0;
|
|
8160
9109
|
return /* @__PURE__ */ jsx(Expandable, {
|
|
8161
9110
|
title: node.type === "oneOf" || node.type === "anyOf" ? labels.allowedTypes : labels.properties,
|
|
8162
|
-
children: /* @__PURE__ */ jsx(SchemaTable, { nodes: node.children })
|
|
9111
|
+
children: /* @__PURE__ */ jsx(SchemaTable$1, { nodes: node.children })
|
|
8163
9112
|
});
|
|
8164
9113
|
}
|
|
8165
|
-
function SchemaTable({ nodes }) {
|
|
9114
|
+
function SchemaTable$1({ nodes }) {
|
|
8166
9115
|
const labels = useLabels();
|
|
8167
9116
|
return /* @__PURE__ */ jsx(PropertiesTable, { children: nodes.map((node) => /* @__PURE__ */ jsx(PropertiesTable.Row, {
|
|
8168
9117
|
name: node.name || node.type,
|
|
@@ -8171,13 +9120,13 @@ function SchemaTable({ nodes }) {
|
|
|
8171
9120
|
deprecated: node.deprecated,
|
|
8172
9121
|
default: node.default,
|
|
8173
9122
|
details: schemaDetails(node, labels),
|
|
8174
|
-
children: /* @__PURE__ */ jsx(FieldChildren, { node })
|
|
9123
|
+
children: /* @__PURE__ */ jsx(FieldChildren$1, { node })
|
|
8175
9124
|
}, node.name || node.type)) });
|
|
8176
9125
|
}
|
|
8177
9126
|
/** Renders a schema tree: a root object's properties, or the node itself. */
|
|
8178
9127
|
function SchemaFields({ node }) {
|
|
8179
9128
|
const isUnion = node.type === "oneOf" || node.type === "anyOf";
|
|
8180
|
-
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] });
|
|
8181
9130
|
}
|
|
8182
9131
|
function HighlightedCode({ language, title, html, source, lineCount }) {
|
|
8183
9132
|
return /* @__PURE__ */ jsx(CodeBlock, {
|
|
@@ -8193,40 +9142,57 @@ function HighlightedCode({ language, title, html, source, lineCount }) {
|
|
|
8193
9142
|
})
|
|
8194
9143
|
});
|
|
8195
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
|
+
}
|
|
8196
9151
|
/** The generated reference for one API operation, rendered under the page body. */
|
|
8197
|
-
function OpenApiOperation({ operation }) {
|
|
9152
|
+
function OpenApiOperation({ operation, playground: requested = false }) {
|
|
8198
9153
|
const labels = useLabels();
|
|
8199
|
-
const
|
|
8200
|
-
const
|
|
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;
|
|
8201
9160
|
return /* @__PURE__ */ jsxs("div", {
|
|
8202
9161
|
className: "docs-markdown",
|
|
8203
9162
|
children: [
|
|
8204
|
-
|
|
8205
|
-
id:
|
|
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,
|
|
8206
9172
|
children: name
|
|
8207
|
-
}), /* @__PURE__ */ jsxs(PropertiesTable, { children: [location
|
|
8208
|
-
name:
|
|
9173
|
+
}), /* @__PURE__ */ jsxs(PropertiesTable, { children: [securityForLocation(operation, location).map((scheme) => /* @__PURE__ */ jsxs(PropertiesTable.Row, {
|
|
9174
|
+
name: securityFieldName(scheme),
|
|
8209
9175
|
type: "string",
|
|
8210
9176
|
required: true,
|
|
8211
9177
|
children: [
|
|
8212
|
-
labels.apiCredentials,
|
|
9178
|
+
scheme.description || labels.apiCredentials,
|
|
8213
9179
|
" ",
|
|
8214
|
-
/* @__PURE__ */ jsx("code", { children:
|
|
9180
|
+
/* @__PURE__ */ jsx("code", { children: credentialExample(scheme) }),
|
|
8215
9181
|
"."
|
|
8216
9182
|
]
|
|
8217
|
-
}), operation.parameters[location].map((parameter) => /* @__PURE__ */ jsx(PropertiesTable.Row, {
|
|
9183
|
+
}, `security:${scheme.name}`)), operation.parameters[location].map((parameter) => /* @__PURE__ */ jsx(PropertiesTable.Row, {
|
|
8218
9184
|
name: parameter.name || parameter.type,
|
|
8219
9185
|
type: parameter.type,
|
|
8220
9186
|
required: parameter.required,
|
|
8221
9187
|
deprecated: parameter.deprecated,
|
|
8222
9188
|
default: parameter.default,
|
|
8223
9189
|
details: schemaDetails(parameter, labels),
|
|
8224
|
-
children: /* @__PURE__ */ jsx(FieldChildren, { node: parameter })
|
|
9190
|
+
children: /* @__PURE__ */ jsx(FieldChildren$1, { node: parameter })
|
|
8225
9191
|
}, parameter.name))] })] }, location)),
|
|
8226
9192
|
operation.requestBody && /* @__PURE__ */ jsxs("section", { children: [
|
|
8227
9193
|
/* @__PURE__ */ jsx("h2", {
|
|
8228
|
-
id: sections.get("Request body"),
|
|
8229
|
-
children: labels.apiRequestBody
|
|
9194
|
+
id: sections.get(operation.webhook ? "Payload" : "Request body"),
|
|
9195
|
+
children: operation.webhook ? labels.apiPayload : labels.apiRequestBody
|
|
8230
9196
|
}),
|
|
8231
9197
|
/* @__PURE__ */ jsx(SchemaFields, { node: operation.requestBody.schema }),
|
|
8232
9198
|
operation.requestBody.example && /* @__PURE__ */ jsx(HighlightedCode, {
|
|
@@ -8276,6 +9242,67 @@ function OpenApiOperation({ operation }) {
|
|
|
8276
9242
|
});
|
|
8277
9243
|
}
|
|
8278
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
|
+
|
|
8279
9306
|
//#endregion
|
|
8280
9307
|
//#region src/components/PageActions.tsx
|
|
8281
9308
|
function editHref(template, filePath) {
|
|
@@ -8409,6 +9436,8 @@ function DocContent({ page, doc, site }) {
|
|
|
8409
9436
|
const contextualOptions = resolveContextualOptions(site.contextualOptions, page, site.labels);
|
|
8410
9437
|
const related = resolveRelated(doc.frontmatter?.related);
|
|
8411
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;
|
|
8412
9441
|
const dateFormat = new Intl.DateTimeFormat(resolveLocale(page.language, site.locale), {
|
|
8413
9442
|
dateStyle: "medium",
|
|
8414
9443
|
timeZone: "UTC"
|
|
@@ -8442,10 +9471,10 @@ function DocContent({ page, doc, site }) {
|
|
|
8442
9471
|
className: "mt-3 flex flex-wrap items-center gap-2",
|
|
8443
9472
|
children: [
|
|
8444
9473
|
/* @__PURE__ */ jsx(Badge, {
|
|
8445
|
-
color: methodColor(operation.method),
|
|
9474
|
+
color: methodColor(operation.webhook ? "WEBHOOK" : operation.method),
|
|
8446
9475
|
size: "sm",
|
|
8447
9476
|
className: "font-mono",
|
|
8448
|
-
children: operation.method
|
|
9477
|
+
children: operation.webhook ? "WEBHOOK" : operation.method
|
|
8449
9478
|
}),
|
|
8450
9479
|
/* @__PURE__ */ jsx("code", {
|
|
8451
9480
|
className: "font-mono text-muted-foreground text-sm",
|
|
@@ -8467,7 +9496,11 @@ function DocContent({ page, doc, site }) {
|
|
|
8467
9496
|
className: "docs-markdown",
|
|
8468
9497
|
children: /* @__PURE__ */ jsx(Content, {})
|
|
8469
9498
|
}),
|
|
8470
|
-
operation && /* @__PURE__ */ jsx(OpenApiOperation, {
|
|
9499
|
+
operation && /* @__PURE__ */ jsx(OpenApiOperation, {
|
|
9500
|
+
operation,
|
|
9501
|
+
playground
|
|
9502
|
+
}),
|
|
9503
|
+
schema && /* @__PURE__ */ jsx(OpenApiSchema, { page: schema }),
|
|
8471
9504
|
/* @__PURE__ */ jsx(PageActions, {
|
|
8472
9505
|
page,
|
|
8473
9506
|
frontmatter: doc.frontmatter,
|
|
@@ -8814,7 +9847,7 @@ function NavNodes({ nodes, pathname, depth, drilldown, expandLabel, collapseLabe
|
|
|
8814
9847
|
color: methodColor(method),
|
|
8815
9848
|
size: "xs",
|
|
8816
9849
|
className: "w-10 shrink-0 justify-center whitespace-nowrap font-mono",
|
|
8817
|
-
children: method
|
|
9850
|
+
children: methodBadgeText(method)
|
|
8818
9851
|
}) : null,
|
|
8819
9852
|
label,
|
|
8820
9853
|
!method && tag ? /* @__PURE__ */ jsx(Badge$1, {
|
|
@@ -8948,7 +9981,8 @@ function Docs({ page, doc, site }) {
|
|
|
8948
9981
|
}), /* @__PURE__ */ jsx(Footer, { footer: site.footer })]
|
|
8949
9982
|
});
|
|
8950
9983
|
const operation = getOperation(doc.frontmatter?.openapi);
|
|
8951
|
-
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;
|
|
8952
9986
|
return /* @__PURE__ */ jsx(PanelProvider, { children: /* @__PURE__ */ jsx(DocsBody, {
|
|
8953
9987
|
page,
|
|
8954
9988
|
doc,
|