specra 0.1.13 → 0.2.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 (276) hide show
  1. package/LICENSE.MD +25 -4
  2. package/README.md +67 -58
  3. package/config/specra.config.schema.json +16 -0
  4. package/config/svelte-config.js +63 -0
  5. package/dist/api-parser.types.d.ts +59 -0
  6. package/dist/api-parser.types.js +5 -0
  7. package/dist/api.types.d.ts +137 -0
  8. package/dist/api.types.js +5 -0
  9. package/dist/category.d.ts +21 -0
  10. package/dist/category.js +48 -0
  11. package/dist/components/ConfigProvider.svelte +13 -0
  12. package/dist/components/ConfigProvider.svelte.d.ts +31 -0
  13. package/dist/components/docs/Accordion.svelte +18 -0
  14. package/dist/components/docs/Accordion.svelte.d.ts +10 -0
  15. package/dist/components/docs/AccordionItem.svelte +41 -0
  16. package/dist/components/docs/AccordionItem.svelte.d.ts +10 -0
  17. package/dist/components/docs/Badge.svelte +28 -0
  18. package/dist/components/docs/Badge.svelte.d.ts +9 -0
  19. package/dist/components/docs/Breadcrumb.svelte +80 -0
  20. package/dist/components/docs/Breadcrumb.svelte.d.ts +8 -0
  21. package/dist/components/docs/Callout.svelte +96 -0
  22. package/dist/components/docs/Callout.svelte.d.ts +10 -0
  23. package/dist/components/docs/Card.svelte +63 -0
  24. package/dist/components/docs/Card.svelte.d.ts +12 -0
  25. package/dist/components/docs/CardGrid.svelte +24 -0
  26. package/dist/components/docs/CardGrid.svelte.d.ts +8 -0
  27. package/dist/components/docs/CategoryIndex.svelte +110 -0
  28. package/dist/components/docs/CategoryIndex.svelte.d.ts +29 -0
  29. package/dist/components/docs/CodeBlock.svelte +172 -0
  30. package/dist/components/docs/CodeBlock.svelte.d.ts +8 -0
  31. package/dist/components/docs/Column.svelte +25 -0
  32. package/dist/components/docs/Column.svelte.d.ts +8 -0
  33. package/dist/components/docs/Columns.svelte +38 -0
  34. package/dist/components/docs/Columns.svelte.d.ts +13 -0
  35. package/dist/components/docs/DevModeBadge.svelte +15 -0
  36. package/dist/components/docs/DevModeBadge.svelte.d.ts +18 -0
  37. package/dist/components/docs/DocBadge.svelte +28 -0
  38. package/dist/components/docs/DocBadge.svelte.d.ts +9 -0
  39. package/dist/components/docs/DocLayout.svelte +107 -0
  40. package/dist/components/docs/DocLayout.svelte.d.ts +32 -0
  41. package/dist/components/docs/DocLoading.svelte +53 -0
  42. package/dist/components/docs/DocLoading.svelte.d.ts +18 -0
  43. package/dist/components/docs/DocMetadata.svelte +106 -0
  44. package/dist/components/docs/DocMetadata.svelte.d.ts +18 -0
  45. package/dist/components/docs/DocNavigation.svelte +56 -0
  46. package/dist/components/docs/DocNavigation.svelte.d.ts +12 -0
  47. package/dist/components/docs/DocTags.svelte +22 -0
  48. package/dist/components/docs/DocTags.svelte.d.ts +6 -0
  49. package/dist/components/docs/DraftBadge.svelte +10 -0
  50. package/dist/components/docs/DraftBadge.svelte.d.ts +18 -0
  51. package/dist/components/docs/Footer.svelte +72 -0
  52. package/dist/components/docs/Footer.svelte.d.ts +7 -0
  53. package/dist/components/docs/Frame.svelte +27 -0
  54. package/dist/components/docs/Frame.svelte.d.ts +9 -0
  55. package/dist/components/docs/Header.svelte +123 -0
  56. package/dist/components/docs/Header.svelte.d.ts +9 -0
  57. package/dist/components/docs/HeaderWithMenu.svelte +34 -0
  58. package/dist/components/docs/HeaderWithMenu.svelte.d.ts +17 -0
  59. package/dist/components/docs/HotReloadIndicator.svelte +44 -0
  60. package/dist/components/docs/HotReloadIndicator.svelte.d.ts +3 -0
  61. package/dist/components/docs/Icon.svelte +103 -0
  62. package/dist/components/docs/Icon.svelte.d.ts +11 -0
  63. package/dist/components/docs/Image.svelte +88 -0
  64. package/dist/components/docs/Image.svelte.d.ts +11 -0
  65. package/dist/components/docs/ImageCard.svelte +91 -0
  66. package/dist/components/docs/ImageCard.svelte.d.ts +12 -0
  67. package/dist/components/docs/ImageCardGrid.svelte +25 -0
  68. package/dist/components/docs/ImageCardGrid.svelte.d.ts +8 -0
  69. package/dist/components/docs/LayoutProviders.svelte +57 -0
  70. package/dist/components/docs/LayoutProviders.svelte.d.ts +9 -0
  71. package/dist/components/docs/Logo.svelte +25 -0
  72. package/dist/components/docs/Logo.svelte.d.ts +11 -0
  73. package/dist/components/docs/Math.svelte +54 -0
  74. package/dist/components/docs/Math.svelte.d.ts +7 -0
  75. package/dist/components/docs/MdxContent.svelte +41 -0
  76. package/dist/components/docs/MdxHotReload.svelte +78 -0
  77. package/dist/components/docs/MdxHotReload.svelte.d.ts +9 -0
  78. package/dist/components/docs/MdxLayout.svelte +16 -0
  79. package/dist/components/docs/MdxLayout.svelte.d.ts +6 -0
  80. package/dist/components/docs/Mermaid.svelte +88 -0
  81. package/dist/components/docs/Mermaid.svelte.d.ts +7 -0
  82. package/dist/components/docs/MobileDocLayout.svelte +211 -0
  83. package/dist/components/docs/MobileDocLayout.svelte.d.ts +35 -0
  84. package/dist/components/docs/MobileSidebar.svelte +122 -0
  85. package/dist/components/docs/MobileSidebar.svelte.d.ts +31 -0
  86. package/dist/components/docs/MobileSidebarWrapper.svelte +122 -0
  87. package/dist/components/docs/MobileSidebarWrapper.svelte.d.ts +32 -0
  88. package/dist/components/docs/NotFoundContent.svelte +40 -0
  89. package/dist/components/docs/NotFoundContent.svelte.d.ts +6 -0
  90. package/dist/components/docs/SearchHighlight.svelte +116 -0
  91. package/dist/components/docs/SearchHighlight.svelte.d.ts +3 -0
  92. package/dist/components/docs/SearchModal.svelte +239 -0
  93. package/dist/components/docs/SearchModal.svelte.d.ts +9 -0
  94. package/dist/components/docs/Sidebar.svelte +69 -0
  95. package/dist/components/docs/Sidebar.svelte.d.ts +31 -0
  96. package/dist/components/docs/SidebarMenuItems.svelte +344 -0
  97. package/dist/components/docs/SidebarMenuItems.svelte.d.ts +33 -0
  98. package/dist/components/docs/SidebarSkeleton.svelte +50 -0
  99. package/dist/components/docs/SidebarSkeleton.svelte.d.ts +18 -0
  100. package/dist/components/docs/SiteBanner.svelte +92 -0
  101. package/dist/components/docs/SiteBanner.svelte.d.ts +7 -0
  102. package/dist/components/docs/Step.svelte +44 -0
  103. package/dist/components/docs/Step.svelte.d.ts +8 -0
  104. package/dist/components/docs/Steps.svelte +15 -0
  105. package/dist/components/docs/Steps.svelte.d.ts +7 -0
  106. package/dist/components/docs/Tab.svelte +40 -0
  107. package/dist/components/docs/Tab.svelte.d.ts +8 -0
  108. package/dist/components/docs/TabGroups.svelte +183 -0
  109. package/dist/components/docs/TabGroups.svelte.d.ts +25 -0
  110. package/dist/components/docs/TableOfContents.svelte +100 -0
  111. package/dist/components/docs/TableOfContents.svelte.d.ts +9 -0
  112. package/dist/components/docs/Tabs.svelte +69 -0
  113. package/dist/components/docs/Tabs.svelte.d.ts +8 -0
  114. package/dist/components/docs/ThemeToggle.svelte +16 -0
  115. package/dist/components/docs/ThemeToggle.svelte.d.ts +18 -0
  116. package/dist/components/docs/Tooltip.svelte +44 -0
  117. package/dist/components/docs/Tooltip.svelte.d.ts +10 -0
  118. package/dist/components/docs/VersionSwitcher.svelte +95 -0
  119. package/dist/components/docs/VersionSwitcher.svelte.d.ts +7 -0
  120. package/dist/components/docs/Video.svelte +84 -0
  121. package/dist/components/docs/Video.svelte.d.ts +12 -0
  122. package/dist/components/docs/api/ApiEndpoint.svelte +61 -0
  123. package/dist/components/docs/api/ApiEndpoint.svelte.d.ts +11 -0
  124. package/dist/components/docs/api/ApiParams.svelte +80 -0
  125. package/dist/components/docs/api/ApiParams.svelte.d.ts +14 -0
  126. package/dist/components/docs/api/ApiPlayground.svelte +259 -0
  127. package/dist/components/docs/api/ApiPlayground.svelte.d.ts +16 -0
  128. package/dist/components/docs/api/ApiReference.svelte +278 -0
  129. package/dist/components/docs/api/ApiReference.svelte.d.ts +23 -0
  130. package/dist/components/docs/api/ApiResponse.svelte +66 -0
  131. package/dist/components/docs/api/ApiResponse.svelte.d.ts +9 -0
  132. package/dist/components/docs/api/index.d.ts +5 -0
  133. package/dist/components/docs/api/index.js +5 -0
  134. package/dist/components/docs/componentTextProps.d.ts +3 -0
  135. package/dist/components/docs/componentTextProps.js +61 -0
  136. package/dist/components/docs/index.d.ts +54 -0
  137. package/dist/components/docs/index.js +56 -0
  138. package/dist/components/global/VersionNotFound.svelte +48 -0
  139. package/dist/components/global/VersionNotFound.svelte.d.ts +7 -0
  140. package/dist/components/global/index.d.ts +1 -0
  141. package/dist/components/global/index.js +1 -0
  142. package/dist/components/index.d.ts +6 -822
  143. package/dist/components/index.js +11 -3854
  144. package/dist/components/ui/Badge.svelte +48 -0
  145. package/dist/components/ui/Badge.svelte.d.ts +15 -0
  146. package/dist/components/ui/Button.svelte +58 -0
  147. package/dist/components/ui/Button.svelte.d.ts +17 -0
  148. package/dist/components/ui/Dialog.svelte +16 -0
  149. package/dist/components/ui/Dialog.svelte.d.ts +9 -0
  150. package/dist/components/ui/DialogClose.svelte +16 -0
  151. package/dist/components/ui/DialogClose.svelte.d.ts +9 -0
  152. package/dist/components/ui/DialogContent.svelte +43 -0
  153. package/dist/components/ui/DialogContent.svelte.d.ts +10 -0
  154. package/dist/components/ui/DialogDescription.svelte +21 -0
  155. package/dist/components/ui/DialogDescription.svelte.d.ts +9 -0
  156. package/dist/components/ui/DialogFooter.svelte +20 -0
  157. package/dist/components/ui/DialogFooter.svelte.d.ts +9 -0
  158. package/dist/components/ui/DialogHeader.svelte +20 -0
  159. package/dist/components/ui/DialogHeader.svelte.d.ts +9 -0
  160. package/dist/components/ui/DialogTitle.svelte +21 -0
  161. package/dist/components/ui/DialogTitle.svelte.d.ts +9 -0
  162. package/dist/components/ui/Input.svelte +23 -0
  163. package/dist/components/ui/Input.svelte.d.ts +8 -0
  164. package/dist/components/ui/Textarea.svelte +19 -0
  165. package/dist/components/ui/Textarea.svelte.d.ts +7 -0
  166. package/dist/components/ui/index.d.ts +11 -0
  167. package/dist/components/ui/index.js +11 -0
  168. package/dist/config.d.ts +8 -0
  169. package/dist/config.js +9 -0
  170. package/dist/config.schema.json +471 -0
  171. package/dist/config.server.d.ts +46 -0
  172. package/dist/config.server.js +149 -0
  173. package/dist/{mdx-ColN3Cyg.d.mts → config.types.d.ts} +22 -75
  174. package/dist/config.types.js +39 -0
  175. package/dist/dev-utils.d.ts +29 -0
  176. package/dist/dev-utils.js +63 -0
  177. package/dist/index.d.ts +19 -4
  178. package/dist/index.js +25 -4861
  179. package/dist/mdx-cache.d.ts +41 -0
  180. package/dist/mdx-cache.js +160 -0
  181. package/dist/mdx-components.js +50 -1931
  182. package/dist/mdx-security.d.ts +76 -0
  183. package/dist/mdx-security.js +217 -0
  184. package/dist/mdx.d.ts +73 -0
  185. package/dist/mdx.js +1099 -0
  186. package/dist/middleware/index.d.ts +1 -0
  187. package/dist/middleware/index.js +2 -0
  188. package/dist/middleware/security.d.ts +22 -47
  189. package/dist/middleware/security.js +111 -137
  190. package/dist/parsers/base-parser.d.ts +14 -0
  191. package/dist/parsers/base-parser.js +1 -0
  192. package/dist/parsers/index.d.ts +16 -0
  193. package/dist/parsers/index.js +51 -0
  194. package/dist/parsers/openapi-parser.d.ts +18 -0
  195. package/dist/parsers/openapi-parser.js +209 -0
  196. package/dist/parsers/postman-parser.d.ts +20 -0
  197. package/dist/parsers/postman-parser.js +260 -0
  198. package/dist/parsers/specra-parser.d.ts +10 -0
  199. package/dist/parsers/specra-parser.js +18 -0
  200. package/dist/redirects.d.ts +12 -0
  201. package/dist/redirects.js +30 -0
  202. package/dist/remark-code-meta.d.ts +6 -0
  203. package/dist/remark-code-meta.js +21 -0
  204. package/dist/sidebar-utils.d.ts +59 -0
  205. package/dist/sidebar-utils.js +144 -0
  206. package/dist/stores/config.d.ts +20 -0
  207. package/dist/stores/config.js +45 -0
  208. package/dist/stores/index.d.ts +4 -0
  209. package/dist/stores/index.js +4 -0
  210. package/dist/stores/sidebar.d.ts +7 -0
  211. package/dist/stores/sidebar.js +12 -0
  212. package/dist/stores/tabs.d.ts +6 -0
  213. package/dist/stores/tabs.js +41 -0
  214. package/dist/stores/theme.d.ts +7 -0
  215. package/dist/stores/theme.js +75 -0
  216. package/dist/{styles.css → styles/globals.css} +136 -6
  217. package/dist/toc.d.ts +9 -0
  218. package/dist/toc.js +15 -0
  219. package/dist/utils.d.ts +13 -0
  220. package/dist/utils.js +30 -0
  221. package/package.json +47 -90
  222. package/dist/app/api/mdx-watch/route.d.mts +0 -10
  223. package/dist/app/api/mdx-watch/route.d.ts +0 -10
  224. package/dist/app/api/mdx-watch/route.js +0 -118
  225. package/dist/app/api/mdx-watch/route.js.map +0 -1
  226. package/dist/app/api/mdx-watch/route.mjs +0 -91
  227. package/dist/app/api/mdx-watch/route.mjs.map +0 -1
  228. package/dist/chunk-6S3EJVEO.mjs +0 -259
  229. package/dist/chunk-6S3EJVEO.mjs.map +0 -1
  230. package/dist/chunk-BE7EROIW.mjs +0 -212
  231. package/dist/chunk-BE7EROIW.mjs.map +0 -1
  232. package/dist/chunk-CWHRZHZO.mjs +0 -168
  233. package/dist/chunk-CWHRZHZO.mjs.map +0 -1
  234. package/dist/chunk-D5VDVYFY.mjs +0 -1325
  235. package/dist/chunk-D5VDVYFY.mjs.map +0 -1
  236. package/dist/chunk-WMCO2UX5.mjs +0 -585
  237. package/dist/chunk-WMCO2UX5.mjs.map +0 -1
  238. package/dist/chunk-XEMGCPZZ.mjs +0 -475
  239. package/dist/chunk-XEMGCPZZ.mjs.map +0 -1
  240. package/dist/components/index.d.mts +0 -822
  241. package/dist/components/index.js.map +0 -1
  242. package/dist/components/index.mjs +0 -3741
  243. package/dist/components/index.mjs.map +0 -1
  244. package/dist/index.d.mts +0 -4
  245. package/dist/index.js.map +0 -1
  246. package/dist/index.mjs +0 -1897
  247. package/dist/index.mjs.map +0 -1
  248. package/dist/layouts/index.d.mts +0 -34
  249. package/dist/layouts/index.d.ts +0 -34
  250. package/dist/layouts/index.js +0 -453
  251. package/dist/layouts/index.js.map +0 -1
  252. package/dist/layouts/index.mjs +0 -173
  253. package/dist/layouts/index.mjs.map +0 -1
  254. package/dist/lib/index.d.mts +0 -583
  255. package/dist/lib/index.d.ts +0 -583
  256. package/dist/lib/index.js +0 -1595
  257. package/dist/lib/index.js.map +0 -1
  258. package/dist/lib/index.mjs +0 -111
  259. package/dist/lib/index.mjs.map +0 -1
  260. package/dist/mdx-ColN3Cyg.d.ts +0 -352
  261. package/dist/mdx-components.d.mts +0 -86
  262. package/dist/mdx-components.d.ts +0 -86
  263. package/dist/mdx-components.js.map +0 -1
  264. package/dist/mdx-components.mjs +0 -206
  265. package/dist/mdx-components.mjs.map +0 -1
  266. package/dist/middleware/security.d.mts +0 -82
  267. package/dist/middleware/security.js.map +0 -1
  268. package/dist/middleware/security.mjs +0 -84
  269. package/dist/middleware/security.mjs.map +0 -1
  270. package/dist/styles.css.map +0 -1
  271. package/dist/styles.d.mts +0 -2
  272. package/dist/styles.d.ts +0 -2
  273. package/dist/styles.js +0 -2
  274. package/dist/styles.js.map +0 -1
  275. package/dist/styles.mjs +0 -1
  276. package/dist/styles.mjs.map +0 -1
@@ -0,0 +1,12 @@
1
+ interface Props {
2
+ src: string;
3
+ caption?: string;
4
+ autoplay?: boolean;
5
+ loop?: boolean;
6
+ muted?: boolean;
7
+ controls?: boolean;
8
+ poster?: string;
9
+ }
10
+ declare const Video: import("svelte").Component<Props, {}, "">;
11
+ type Video = ReturnType<typeof Video>;
12
+ export default Video;
@@ -0,0 +1,61 @@
1
+ <script lang="ts">
2
+ import { ChevronDown } from 'lucide-svelte';
3
+ import { cn } from '../../../utils.js';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ interface Props {
7
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
8
+ path: string;
9
+ summary?: string;
10
+ children?: Snippet;
11
+ defaultOpen?: boolean;
12
+ }
13
+
14
+ let { method, path, summary, children, defaultOpen = false }: Props = $props();
15
+
16
+ let isOpen = $state(defaultOpen);
17
+
18
+ const methodColors: Record<string, string> = {
19
+ GET: 'bg-blue-500/10 text-blue-600 dark:text-blue-400',
20
+ POST: 'bg-green-500/10 text-green-600 dark:text-green-400',
21
+ PUT: 'bg-orange-500/10 text-orange-600 dark:text-orange-400',
22
+ PATCH: 'bg-purple-500/10 text-purple-600 dark:text-purple-400',
23
+ DELETE: 'bg-red-500/10 text-red-600 dark:text-red-400',
24
+ };
25
+ </script>
26
+
27
+ <div class="not-prose mb-4 rounded-xl border border-border overflow-hidden">
28
+ <!-- Accordion Header -->
29
+ <button
30
+ onclick={() => (isOpen = !isOpen)}
31
+ class="w-full flex items-center gap-3 px-4 py-3 text-left bg-muted/30 hover:bg-muted/50 transition-colors"
32
+ >
33
+ <span
34
+ class={cn(
35
+ 'text-xs font-semibold px-2 py-0.5 rounded',
36
+ methodColors[method]
37
+ )}
38
+ >
39
+ {method}
40
+ </span>
41
+ <code class="text-sm font-mono">{path}</code>
42
+ {#if summary}
43
+ <span class="text-sm text-muted-foreground ml-auto mr-2">{summary}</span>
44
+ {/if}
45
+ <ChevronDown
46
+ class={cn(
47
+ 'h-5 w-5 text-muted-foreground transition-transform flex-shrink-0',
48
+ isOpen ? 'rotate-180' : ''
49
+ )}
50
+ />
51
+ </button>
52
+
53
+ <!-- Accordion Content -->
54
+ {#if isOpen && children}
55
+ <div class="border-t border-border bg-background">
56
+ <div class="px-4 py-4 space-y-6">
57
+ {@render children()}
58
+ </div>
59
+ </div>
60
+ {/if}
61
+ </div>
@@ -0,0 +1,11 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
4
+ path: string;
5
+ summary?: string;
6
+ children?: Snippet;
7
+ defaultOpen?: boolean;
8
+ }
9
+ declare const ApiEndpoint: import("svelte").Component<Props, {}, "">;
10
+ type ApiEndpoint = ReturnType<typeof ApiEndpoint>;
11
+ export default ApiEndpoint;
@@ -0,0 +1,80 @@
1
+ <script lang="ts">
2
+ export interface ApiParam {
3
+ name: string;
4
+ type: string;
5
+ required?: boolean;
6
+ description?: string;
7
+ default?: string;
8
+ }
9
+
10
+ interface Props {
11
+ title?: string;
12
+ params: ApiParam[];
13
+ }
14
+
15
+ let { title = 'Parameters', params }: Props = $props();
16
+ </script>
17
+
18
+ {#if params && params.length > 0}
19
+ <div class="mb-6">
20
+ <h4 class="text-sm font-semibold text-foreground mb-3">{title}</h4>
21
+ <div class="overflow-x-auto">
22
+ <table class="w-full border-collapse">
23
+ <thead>
24
+ <tr class="border-b border-border">
25
+ <th class="text-left py-2 px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider">
26
+ Property
27
+ </th>
28
+ <th class="text-left py-2 px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider">
29
+ Type
30
+ </th>
31
+ <th class="text-left py-2 px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider">
32
+ Required
33
+ </th>
34
+ <th class="text-left py-2 px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider">
35
+ Default
36
+ </th>
37
+ <th class="text-left py-2 px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider">
38
+ Description
39
+ </th>
40
+ </tr>
41
+ </thead>
42
+ <tbody>
43
+ {#each params as param, index}
44
+ <tr
45
+ class={index !== params.length - 1 ? 'border-b border-border/50' : ''}
46
+ >
47
+ <td class="py-2.5 px-3">
48
+ <code class="text-sm font-mono text-foreground">{param.name}</code>
49
+ </td>
50
+ <td class="py-2.5 px-3">
51
+ <span class="text-sm text-muted-foreground font-mono">{param.type}</span>
52
+ </td>
53
+ <td class="py-2.5 px-3">
54
+ {#if param.required}
55
+ <span class="text-sm text-red-600 dark:text-red-400">Yes</span>
56
+ {:else}
57
+ <span class="text-sm text-muted-foreground">No</span>
58
+ {/if}
59
+ </td>
60
+ <td class="py-2.5 px-3">
61
+ {#if param.default}
62
+ <code class="text-sm font-mono text-muted-foreground">{param.default}</code>
63
+ {:else}
64
+ <span class="text-sm text-muted-foreground">-</span>
65
+ {/if}
66
+ </td>
67
+ <td class="py-2.5 px-3">
68
+ {#if param.description}
69
+ <span class="text-sm text-muted-foreground">{param.description}</span>
70
+ {:else}
71
+ <span class="text-sm text-muted-foreground">-</span>
72
+ {/if}
73
+ </td>
74
+ </tr>
75
+ {/each}
76
+ </tbody>
77
+ </table>
78
+ </div>
79
+ </div>
80
+ {/if}
@@ -0,0 +1,14 @@
1
+ export interface ApiParam {
2
+ name: string;
3
+ type: string;
4
+ required?: boolean;
5
+ description?: string;
6
+ default?: string;
7
+ }
8
+ interface Props {
9
+ title?: string;
10
+ params: ApiParam[];
11
+ }
12
+ declare const ApiParams: import("svelte").Component<Props, {}, "">;
13
+ type ApiParams = ReturnType<typeof ApiParams>;
14
+ export default ApiParams;
@@ -0,0 +1,259 @@
1
+ <script lang="ts">
2
+ import Button from '../../ui/Button.svelte';
3
+ import Input from '../../ui/Input.svelte';
4
+ import Textarea from '../../ui/Textarea.svelte';
5
+ import Badge from '../../ui/Badge.svelte';
6
+ import CodeBlock from '../CodeBlock.svelte';
7
+ import { Play, Loader2 } from 'lucide-svelte';
8
+
9
+ export interface PathParam {
10
+ name: string;
11
+ type: string;
12
+ example?: any;
13
+ }
14
+
15
+ interface Props {
16
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
17
+ path: string;
18
+ baseUrl?: string;
19
+ headers?: Record<string, string>;
20
+ defaultBody?: string;
21
+ pathParams?: PathParam[];
22
+ }
23
+
24
+ let {
25
+ method,
26
+ path,
27
+ baseUrl = '',
28
+ headers = {},
29
+ defaultBody,
30
+ pathParams = [],
31
+ }: Props = $props();
32
+
33
+ let loading = $state(false);
34
+ let response = $state<any>(null);
35
+ let error = $state<string | null>(null);
36
+ let requestBody = $state(defaultBody || '');
37
+
38
+ // Initialize headers with empty strings if not provided
39
+ let initialHeaders = $derived(() => {
40
+ const cleanHeaders: Record<string, string> = {};
41
+ Object.entries(headers).forEach(([key, value]) => {
42
+ cleanHeaders[key] = value || '';
43
+ });
44
+ return cleanHeaders;
45
+ });
46
+
47
+ let requestHeaders = $state(JSON.stringify(
48
+ (() => {
49
+ const cleanHeaders: Record<string, string> = {};
50
+ Object.entries(headers).forEach(([key, value]) => {
51
+ cleanHeaders[key] = value || '';
52
+ });
53
+ return cleanHeaders;
54
+ })(),
55
+ null,
56
+ 2
57
+ ));
58
+
59
+ // Extract path parameters and initialize with defaults
60
+ let extractedParams = $derived(() => {
61
+ const params: Record<string, string> = {};
62
+ const pathParamPattern = /:(\w+)/g;
63
+ let match;
64
+
65
+ while ((match = pathParamPattern.exec(path)) !== null) {
66
+ const paramName = match[1];
67
+ const paramConfig = pathParams.find((p) => p.name === paramName);
68
+
69
+ // Set default value based on example or type
70
+ if (paramConfig?.example !== undefined) {
71
+ params[paramName] = String(paramConfig.example);
72
+ } else if (paramConfig?.type === 'number') {
73
+ params[paramName] = '1';
74
+ } else {
75
+ params[paramName] = '';
76
+ }
77
+ }
78
+
79
+ return params;
80
+ });
81
+
82
+ let pathParamValues = $state<Record<string, string>>(
83
+ (() => {
84
+ const params: Record<string, string> = {};
85
+ const pathParamPattern = /:(\w+)/g;
86
+ let match;
87
+
88
+ while ((match = pathParamPattern.exec(path)) !== null) {
89
+ const paramName = match[1];
90
+ const paramConfig = pathParams.find((p) => p.name === paramName);
91
+
92
+ if (paramConfig?.example !== undefined) {
93
+ params[paramName] = String(paramConfig.example);
94
+ } else if (paramConfig?.type === 'number') {
95
+ params[paramName] = '1';
96
+ } else {
97
+ params[paramName] = '';
98
+ }
99
+ }
100
+
101
+ return params;
102
+ })()
103
+ );
104
+
105
+ // Build the final URL with path params replaced
106
+ function buildUrl(): string {
107
+ let finalPath = path;
108
+ Object.entries(pathParamValues).forEach(([key, value]) => {
109
+ finalPath = finalPath.replace(`:${key}`, value);
110
+ });
111
+ return `${baseUrl}${finalPath}`;
112
+ }
113
+
114
+ let builtUrl = $derived(buildUrl());
115
+
116
+ async function handleSend() {
117
+ loading = true;
118
+ error = null;
119
+ response = null;
120
+
121
+ try {
122
+ const url = buildUrl();
123
+ const parsedHeaders = JSON.parse(requestHeaders);
124
+
125
+ const options: RequestInit = {
126
+ method,
127
+ headers: {
128
+ 'Content-Type': 'application/json',
129
+ ...parsedHeaders,
130
+ },
131
+ };
132
+
133
+ if (method !== 'GET' && method !== 'DELETE' && requestBody) {
134
+ options.body = requestBody;
135
+ }
136
+
137
+ const res = await fetch(url, options);
138
+ const data = await res.json();
139
+
140
+ response = {
141
+ status: res.status,
142
+ statusText: res.statusText,
143
+ headers: Object.fromEntries(res.headers.entries()),
144
+ body: data,
145
+ };
146
+ } catch (err) {
147
+ error = err instanceof Error ? err.message : 'An error occurred';
148
+ } finally {
149
+ loading = false;
150
+ }
151
+ }
152
+
153
+ let hasPathParams = $derived(Object.keys(pathParamValues).length > 0);
154
+ </script>
155
+
156
+ <div class="not-prose border border-border rounded-lg overflow-hidden bg-card/30">
157
+ <div class="bg-muted/50 px-4 py-2 border-b border-border">
158
+ <h4 class="text-sm font-semibold text-foreground">API Playground</h4>
159
+ </div>
160
+
161
+ <div class="p-4 space-y-4">
162
+ <!-- Path Parameters -->
163
+ {#if hasPathParams}
164
+ <div>
165
+ <label class="text-xs font-semibold text-muted-foreground mb-2 block">
166
+ Path Parameters
167
+ </label>
168
+ <div class="space-y-2">
169
+ {#each Object.entries(pathParamValues) as [paramName, paramValue]}
170
+ {@const paramConfig = pathParams.find((p) => p.name === paramName)}
171
+ <div class="flex items-center gap-2">
172
+ <span class="text-xs text-muted-foreground min-w-[80px]">
173
+ :{paramName}
174
+ </span>
175
+ <Input
176
+ value={paramValue}
177
+ oninput={(e) => {
178
+ pathParamValues = { ...pathParamValues, [paramName]: e.currentTarget.value };
179
+ }}
180
+ placeholder={paramConfig?.example || paramConfig?.type || 'value'}
181
+ class="font-mono text-sm"
182
+ />
183
+ </div>
184
+ {/each}
185
+ </div>
186
+ </div>
187
+ {/if}
188
+
189
+ <!-- URL -->
190
+ <div>
191
+ <label class="text-xs font-semibold text-muted-foreground mb-2 block">
192
+ Request URL
193
+ </label>
194
+ <div class="flex items-center gap-2">
195
+ <Badge variant="outline" class="font-mono">
196
+ {method}
197
+ </Badge>
198
+ <Input value={builtUrl} readonly class="font-mono text-sm" />
199
+ </div>
200
+ </div>
201
+
202
+ <!-- Headers -->
203
+ <div>
204
+ <label class="text-xs font-semibold text-muted-foreground mb-2 block">
205
+ Headers (JSON)
206
+ </label>
207
+ <Textarea
208
+ value={requestHeaders}
209
+ oninput={(e) => (requestHeaders = e.currentTarget.value)}
210
+ class="font-mono text-sm"
211
+ rows={4}
212
+ />
213
+ </div>
214
+
215
+ <!-- Body (for POST, PUT, PATCH) -->
216
+ {#if method !== 'GET' && method !== 'DELETE'}
217
+ <div>
218
+ <label class="text-xs font-semibold text-muted-foreground mb-2 block">
219
+ Request Body (JSON)
220
+ </label>
221
+ <Textarea
222
+ value={requestBody}
223
+ oninput={(e) => (requestBody = e.currentTarget.value)}
224
+ class="font-mono text-sm"
225
+ rows={6}
226
+ placeholder={'{\n "key": "value"\n}'}
227
+ />
228
+ </div>
229
+ {/if}
230
+
231
+ <!-- Send Button -->
232
+ <Button onclick={handleSend} disabled={loading} class="w-full">
233
+ {#if loading}
234
+ <Loader2 class="mr-2 h-4 w-4 animate-spin" />
235
+ Sending...
236
+ {:else}
237
+ <Play class="mr-2 h-4 w-4" />
238
+ Send Request
239
+ {/if}
240
+ </Button>
241
+
242
+ <!-- Response -->
243
+ {#if response}
244
+ <div class="mt-4">
245
+ <label class="text-xs font-semibold text-muted-foreground mb-2 block">
246
+ Response ({response.status} {response.statusText})
247
+ </label>
248
+ <CodeBlock code={JSON.stringify(response.body, null, 2)} language="json" />
249
+ </div>
250
+ {/if}
251
+
252
+ <!-- Error -->
253
+ {#if error}
254
+ <div class="mt-4 p-3 bg-red-500/10 border border-red-500/20 rounded-md">
255
+ <p class="text-sm text-red-600 dark:text-red-400">{error}</p>
256
+ </div>
257
+ {/if}
258
+ </div>
259
+ </div>
@@ -0,0 +1,16 @@
1
+ export interface PathParam {
2
+ name: string;
3
+ type: string;
4
+ example?: any;
5
+ }
6
+ interface Props {
7
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
8
+ path: string;
9
+ baseUrl?: string;
10
+ headers?: Record<string, string>;
11
+ defaultBody?: string;
12
+ pathParams?: PathParam[];
13
+ }
14
+ declare const ApiPlayground: import("svelte").Component<Props, {}, "">;
15
+ type ApiPlayground = ReturnType<typeof ApiPlayground>;
16
+ export default ApiPlayground;