@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.
Files changed (64) hide show
  1. package/dist/chunks/App.js +1217 -196
  2. package/dist/chunks/architectureDiagram-5GKGNRK7.js +1 -1
  3. package/dist/chunks/chunk-GMAD6QVW.js +1 -1
  4. package/dist/chunks/cose-bilkent-JH36ORCC.js +1 -1
  5. package/dist/chunks/dist.js +1 -1
  6. package/dist/chunks/docs.js +843 -22
  7. package/dist/chunks/ganttDiagram-EL5Y4UJY.js +1 -1
  8. package/dist/chunks/src.js +1 -1
  9. package/dist/components.js +1 -1
  10. package/dist/entry-client.js +1 -1
  11. package/dist/entry-server.js +1 -1
  12. package/docs.schema.json +1164 -1131
  13. package/package.json +1 -2
  14. package/scripts/check-content.mjs +44 -15
  15. package/scripts/expand-openapi-navigation.mjs +47 -21
  16. package/scripts/generate-openapi.mjs +36 -11
  17. package/scripts/generate-search-index.mjs +19 -18
  18. package/scripts/lib/openapi-project.mjs +197 -0
  19. package/scripts/lib/openapi.mjs +257 -111
  20. package/scripts/lib/request-samples.mjs +323 -0
  21. package/scripts/load-docs-config.mjs +23 -15
  22. package/scripts/load-shiso-config.mjs +30 -1
  23. package/scripts/prerender.mjs +17 -14
  24. package/scripts/vite-docs-config.mjs +1 -0
  25. package/src/App.tsx +32 -22
  26. package/src/components/ApiPlayground.tsx +522 -0
  27. package/src/components/CodeBlock.tsx +3 -1
  28. package/src/components/DocContent.tsx +15 -4
  29. package/src/components/Docs.tsx +19 -2
  30. package/src/components/Footer.tsx +3 -1
  31. package/src/components/Header.tsx +4 -3
  32. package/src/components/LanguageSwitcher.tsx +38 -29
  33. package/src/components/OpenApiOperation.tsx +73 -20
  34. package/src/components/OpenApiSchema.tsx +97 -0
  35. package/src/components/PageActions.tsx +8 -7
  36. package/src/components/SideNav.tsx +2 -2
  37. package/src/components/docs/Changelog.tsx +5 -5
  38. package/src/components/docs/CodeGroup.tsx +3 -1
  39. package/src/components/docs/Mermaid.tsx +8 -6
  40. package/src/components/docs/PropertiesTable.tsx +11 -6
  41. package/src/components/docs/Tabs.tsx +3 -1
  42. package/src/components/docs/Tree.tsx +3 -1
  43. package/src/components/docs/ZoomableImage.tsx +4 -2
  44. package/src/components/ui/dialog.tsx +7 -2
  45. package/src/components/ui/sheet.tsx +5 -2
  46. package/src/lib/label-context.tsx +7 -0
  47. package/src/lib/labels.ts +37 -0
  48. package/src/lib/openapi.generated.ts +2 -1
  49. package/src/lib/openapi.ts +123 -16
  50. package/src/lib/site-config.ts +66 -2
  51. package/src/lib/site-model.ts +14 -32
  52. package/src/lib/standalone-pages.ts +15 -1
  53. package/src/lib/translations/de.json +99 -0
  54. package/src/lib/translations/en.json +99 -0
  55. package/src/lib/translations/es.json +99 -0
  56. package/src/lib/translations/fr.json +99 -0
  57. package/src/lib/translations/ja.json +99 -0
  58. package/src/lib/translations/zh-Hans.json +99 -0
  59. package/src/lib/translations/zh-Hant.json +99 -0
  60. package/src/lib/types.ts +109 -37
  61. package/types/config.d.ts +7 -1
  62. package/types/labels.d.ts +101 -0
  63. package/vite.config.ts +3 -4
  64. package/CHANGELOG.md +0 -8
@@ -1,8 +1,8 @@
1
- import { $ as useFloatingNodeId, $n as useRenderElement, $t as resolveIcon, A as safePolygon, An as isElementVisible, B as attachPreventUnmountOnClose, Bn as getTarget, Cn as getNextTabbable, D as useAnchorPositioning, Dn as findNonDisabledListIndex, Dt as Collapsible, E as getDisabledMountTransitionStyles, En as isOutsideEvent, Er as useNavigate, Et as Expandable, F as createInitialPopupStoreState, Fn as stopEvent, Ft as useCompositeItem, G as useTriggerDataForwarding, Gn as jsdom, H as useImplicitActiveTrigger, Hn as ARROW_LEFT, I as popupStoreSelectors, In as getFloatingFocusElement, J as useDismiss, Jn as useBaseUiId, K as useSyncedFloatingRootContext, Kn as webkit, L as PopupTriggerMap, Ln as isTypeableCombobox, M as useHoverFloatingInteraction, Mn as isListIndexDisabled, Mt as CodeGroup, N as useFocus, Nn as isVirtualClick, Nt as COMPOSITE_KEYS, O as popupTransitionStateMapping, On as getMaxListIndex, Ot as CollapsibleContent, P as usePopupHandleStore, Pn as isVirtualPointerEvent, Pt as inertValue, Q as FloatingTree, Qn as cn, R as FOCUSABLE_POPUP_PROPS, Rn as activeElement, Sn as useDirection, Sr as Route, T as usePositioner, Tn as getTabbableBeforeElement, Tr as useLocation, Tt as renderInlineMarkdown, U as useOpenStateTransitions, Un as ARROW_RIGHT, V as setPopupOpenState, Vn as ARROW_DOWN, W as usePopupInteractionProps, Wn as ARROW_UP, X as FloatingFocusManager, Xn as useTimeout, Xt as Badge$1, Y as useClick, Yn as useId$2, Yt as Badge, Z as FloatingNode, Zn as Button, _n as triggerPress, _r as Check, a as DialogTitle, an as useAnimationFrame, ar as ownerDocument, at as POPUP_COLLISION_AVOIDANCE, br as Link, bt as usePanelContent, c as useOpenInteractionType, cn as escapeKey, cr as useIsoLayoutEffect, ct as fastComponent, d as useScrollLock, dn as itemPress, dr as getParentNode, en as getIcon, er as EMPTY_ARRAY, et as useFloatingParentNodeId, f as DialogPortal$1, fn as listNavigation, fr as getWindow, g as DialogBackdrop, gn as triggerHover, gr as ChevronRight, gt as PropertiesTable, h as DialogClose, hn as triggerFocus, hr as X$1, i as DialogContent$1, in as useCompositeListItem, ir as dispatchClickWithModifiers, it as DROPDOWN_COLLISION_AVOIDANCE, j as useHoverReferenceInteraction, jn as isIndexOutOfListBounds, k as pressableTriggerOpenStateMapping, kn as getMinListIndex, kt as CollapsibleTrigger, l as DialogTitle$1, ln as focusOut, lr as useStableCallback, lt as fastComponentRef, m as DialogPopup, mn as siblingOpen, mr as isLastTraversableNode, n as ZoomableImage, nn as useAnimationsFinished, nr as useMergedRefs, nt as FloatingTreeStore, o as DialogTrigger, on as createChangeEventDetails, or as useCompositeRootContext, ot as enqueueFocus, p as InternalBackdrop, pn as outsidePress, pr as isHTMLElement, q as ReactStore, qn as mac, r as Dialog$1, rn as useValueAsRef, rr as useButton, rt as FloatingPortal, s as DialogTrigger$1, sn as cancelOpen, sr as mergeProps$1, st as FocusGuard, t as docs_exports, tn as useOpenChangeComplete, tr as EMPTY_OBJECT, tt as useFloatingTree, u as DialogRoot, un as imperativeAction, ur as useRefWithInit, vn as CompositeList, vr as createLucideIcon, w as TooltipProvider, wn as getTabbableAfterElement, wr as Routes, xn as addEventListener, xr as Navigate, yn as Mermaid, yt as PanelProvider, z as PopupHandleAttachment, zn as contains } from "./docs.js";
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": "Copy code",
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: SHISO_THEME_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 = SHISO_THEME_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
- /** Scope that owns the current pathname; the default scope for unknown paths. */
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
- return page ? getScopeForPage(docsSite, page) : getDefaultScope(docsSite);
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 always lands
4569
- * on that language's default-version first page. Hidden languages never
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
- variant: "outline",
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: options.map((scope) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
4589
- onClick: () => {
4590
- if (scope.language !== current.language) navigate(scope.firstPageUrl);
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: [/* @__PURE__ */ jsx("span", {
4593
- className: "grow",
4594
- lang: isValidLocale(scope.language) ? scope.language : void 0,
4595
- children: scope.language ? getLanguageName(scope.language) : null
4596
- }), scope.language === current.language ? /* @__PURE__ */ jsx(Check, { className: "size-3.5" }) : null]
4597
- }, scope.id))
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 || (hasRootStandalonePage ? "/" : docsHomeUrl);
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
- if (typeof key !== "string" || !key.trim()) return;
8131
- const [method, ...rest] = key.trim().split(/\s+/);
8132
- return OPENAPI_OPERATIONS[`${method.toUpperCase()} ${rest.join(" ")}`];
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: "Headers"
8423
+ name: labels.apiHeaders
8140
8424
  },
8141
8425
  {
8142
8426
  location: "path",
8143
- name: "Path parameters"
8427
+ name: labels.apiPathParameters
8144
8428
  },
8145
8429
  {
8146
8430
  location: "query",
8147
- name: "Query parameters"
8431
+ name: labels.apiQueryParameters
8148
8432
  },
8149
8433
  {
8150
8434
  location: "cookie",
8151
- name: "Cookie parameters"
8435
+ name: labels.apiCookieParameters
8152
8436
  }
8153
- ].filter(({ location }) => operation.parameters[location].length > 0 || location === "header" && operation.security.length > 0);
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
- return [
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)).map((name) => ({
8168
- name,
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
- "Options:",
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" ? "Allowed types" : "properties",
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 sections = new Map(operationSections(operation).map((entry) => [entry.name, entry.id]));
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
- operationParameterSections(operation).map(({ location, name }) => /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx("h2", {
8230
- id: sections.get(name),
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 === "header" && operation.security.length > 0 && /* @__PURE__ */ jsxs(PropertiesTable.Row, {
8233
- name: "Authorization",
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
- "Authentication credentials, e.g. ",
8238
- /* @__PURE__ */ jsx("code", { children: "Bearer <token>" }),
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: "Request body"
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: "Example request",
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: "Responses"
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: `${response.status} example`,
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: "Code samples"
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 || "Edit this page", /* @__PURE__ */ jsx(ExternalLink, {
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 || "Was this page helpful?",
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 || "Was this page helpful?"
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 || "Yes" : feedback.unhelpfulLabel || "No"
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 || "Thanks for your feedback!"), status === "error" && (feedback.errorMessage || "Could not send feedback. Please try again.")]
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, { operation }),
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: ["Powered by ", /* @__PURE__ */ jsx("span", {
8608
- className: "font-bold",
8609
- children: "shiso"
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 === "DELETE" ? "DEL" : 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: "Close"
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 toc = operation ? [...doc.toc || [], ...operationSections(operation)] : doc.toc;
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
- return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(MDXProvider, {
9142
- components: mdxComponents,
9143
- children: /* @__PURE__ */ jsx(Layout, {
9144
- site: siteModel,
9145
- children: /* @__PURE__ */ jsxs(Routes, { children: [
9146
- standalonePages.map((page) => /* @__PURE__ */ jsx(Route, {
9147
- path: page.path,
9148
- element: /* @__PURE__ */ jsx(StandalonePageView, {
9149
- page,
9150
- site: siteModel
9151
- })
9152
- }, page.path)),
9153
- docsHomeUrl !== "/" && !hasRootStandalonePage ? /* @__PURE__ */ jsx(Route, {
9154
- path: "/",
9155
- element: /* @__PURE__ */ jsx(Navigate, {
9156
- to: docsHomeUrl,
9157
- replace: true
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
- }) : null,
9160
- /* @__PURE__ */ jsx(Route, {
9161
- path: "*",
9162
- element: /* @__PURE__ */ jsx(DocPage, { site: siteModel })
9163
- })
9164
- ] })
9165
- })
9166
- }) });
10184
+ ] })
10185
+ })
10186
+ }) })
10187
+ });
9167
10188
  }
9168
10189
 
9169
10190
  //#endregion