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.
- package/LICENSE.MD +25 -4
- package/README.md +67 -58
- package/config/specra.config.schema.json +16 -0
- package/config/svelte-config.js +63 -0
- package/dist/api-parser.types.d.ts +59 -0
- package/dist/api-parser.types.js +5 -0
- package/dist/api.types.d.ts +137 -0
- package/dist/api.types.js +5 -0
- package/dist/category.d.ts +21 -0
- package/dist/category.js +48 -0
- package/dist/components/ConfigProvider.svelte +13 -0
- package/dist/components/ConfigProvider.svelte.d.ts +31 -0
- package/dist/components/docs/Accordion.svelte +18 -0
- package/dist/components/docs/Accordion.svelte.d.ts +10 -0
- package/dist/components/docs/AccordionItem.svelte +41 -0
- package/dist/components/docs/AccordionItem.svelte.d.ts +10 -0
- package/dist/components/docs/Badge.svelte +28 -0
- package/dist/components/docs/Badge.svelte.d.ts +9 -0
- package/dist/components/docs/Breadcrumb.svelte +80 -0
- package/dist/components/docs/Breadcrumb.svelte.d.ts +8 -0
- package/dist/components/docs/Callout.svelte +96 -0
- package/dist/components/docs/Callout.svelte.d.ts +10 -0
- package/dist/components/docs/Card.svelte +63 -0
- package/dist/components/docs/Card.svelte.d.ts +12 -0
- package/dist/components/docs/CardGrid.svelte +24 -0
- package/dist/components/docs/CardGrid.svelte.d.ts +8 -0
- package/dist/components/docs/CategoryIndex.svelte +110 -0
- package/dist/components/docs/CategoryIndex.svelte.d.ts +29 -0
- package/dist/components/docs/CodeBlock.svelte +172 -0
- package/dist/components/docs/CodeBlock.svelte.d.ts +8 -0
- package/dist/components/docs/Column.svelte +25 -0
- package/dist/components/docs/Column.svelte.d.ts +8 -0
- package/dist/components/docs/Columns.svelte +38 -0
- package/dist/components/docs/Columns.svelte.d.ts +13 -0
- package/dist/components/docs/DevModeBadge.svelte +15 -0
- package/dist/components/docs/DevModeBadge.svelte.d.ts +18 -0
- package/dist/components/docs/DocBadge.svelte +28 -0
- package/dist/components/docs/DocBadge.svelte.d.ts +9 -0
- package/dist/components/docs/DocLayout.svelte +107 -0
- package/dist/components/docs/DocLayout.svelte.d.ts +32 -0
- package/dist/components/docs/DocLoading.svelte +53 -0
- package/dist/components/docs/DocLoading.svelte.d.ts +18 -0
- package/dist/components/docs/DocMetadata.svelte +106 -0
- package/dist/components/docs/DocMetadata.svelte.d.ts +18 -0
- package/dist/components/docs/DocNavigation.svelte +56 -0
- package/dist/components/docs/DocNavigation.svelte.d.ts +12 -0
- package/dist/components/docs/DocTags.svelte +22 -0
- package/dist/components/docs/DocTags.svelte.d.ts +6 -0
- package/dist/components/docs/DraftBadge.svelte +10 -0
- package/dist/components/docs/DraftBadge.svelte.d.ts +18 -0
- package/dist/components/docs/Footer.svelte +72 -0
- package/dist/components/docs/Footer.svelte.d.ts +7 -0
- package/dist/components/docs/Frame.svelte +27 -0
- package/dist/components/docs/Frame.svelte.d.ts +9 -0
- package/dist/components/docs/Header.svelte +123 -0
- package/dist/components/docs/Header.svelte.d.ts +9 -0
- package/dist/components/docs/HeaderWithMenu.svelte +34 -0
- package/dist/components/docs/HeaderWithMenu.svelte.d.ts +17 -0
- package/dist/components/docs/HotReloadIndicator.svelte +44 -0
- package/dist/components/docs/HotReloadIndicator.svelte.d.ts +3 -0
- package/dist/components/docs/Icon.svelte +103 -0
- package/dist/components/docs/Icon.svelte.d.ts +11 -0
- package/dist/components/docs/Image.svelte +88 -0
- package/dist/components/docs/Image.svelte.d.ts +11 -0
- package/dist/components/docs/ImageCard.svelte +91 -0
- package/dist/components/docs/ImageCard.svelte.d.ts +12 -0
- package/dist/components/docs/ImageCardGrid.svelte +25 -0
- package/dist/components/docs/ImageCardGrid.svelte.d.ts +8 -0
- package/dist/components/docs/LayoutProviders.svelte +57 -0
- package/dist/components/docs/LayoutProviders.svelte.d.ts +9 -0
- package/dist/components/docs/Logo.svelte +25 -0
- package/dist/components/docs/Logo.svelte.d.ts +11 -0
- package/dist/components/docs/Math.svelte +54 -0
- package/dist/components/docs/Math.svelte.d.ts +7 -0
- package/dist/components/docs/MdxContent.svelte +41 -0
- package/dist/components/docs/MdxHotReload.svelte +78 -0
- package/dist/components/docs/MdxHotReload.svelte.d.ts +9 -0
- package/dist/components/docs/MdxLayout.svelte +16 -0
- package/dist/components/docs/MdxLayout.svelte.d.ts +6 -0
- package/dist/components/docs/Mermaid.svelte +88 -0
- package/dist/components/docs/Mermaid.svelte.d.ts +7 -0
- package/dist/components/docs/MobileDocLayout.svelte +211 -0
- package/dist/components/docs/MobileDocLayout.svelte.d.ts +35 -0
- package/dist/components/docs/MobileSidebar.svelte +122 -0
- package/dist/components/docs/MobileSidebar.svelte.d.ts +31 -0
- package/dist/components/docs/MobileSidebarWrapper.svelte +122 -0
- package/dist/components/docs/MobileSidebarWrapper.svelte.d.ts +32 -0
- package/dist/components/docs/NotFoundContent.svelte +40 -0
- package/dist/components/docs/NotFoundContent.svelte.d.ts +6 -0
- package/dist/components/docs/SearchHighlight.svelte +116 -0
- package/dist/components/docs/SearchHighlight.svelte.d.ts +3 -0
- package/dist/components/docs/SearchModal.svelte +239 -0
- package/dist/components/docs/SearchModal.svelte.d.ts +9 -0
- package/dist/components/docs/Sidebar.svelte +69 -0
- package/dist/components/docs/Sidebar.svelte.d.ts +31 -0
- package/dist/components/docs/SidebarMenuItems.svelte +344 -0
- package/dist/components/docs/SidebarMenuItems.svelte.d.ts +33 -0
- package/dist/components/docs/SidebarSkeleton.svelte +50 -0
- package/dist/components/docs/SidebarSkeleton.svelte.d.ts +18 -0
- package/dist/components/docs/SiteBanner.svelte +92 -0
- package/dist/components/docs/SiteBanner.svelte.d.ts +7 -0
- package/dist/components/docs/Step.svelte +44 -0
- package/dist/components/docs/Step.svelte.d.ts +8 -0
- package/dist/components/docs/Steps.svelte +15 -0
- package/dist/components/docs/Steps.svelte.d.ts +7 -0
- package/dist/components/docs/Tab.svelte +40 -0
- package/dist/components/docs/Tab.svelte.d.ts +8 -0
- package/dist/components/docs/TabGroups.svelte +183 -0
- package/dist/components/docs/TabGroups.svelte.d.ts +25 -0
- package/dist/components/docs/TableOfContents.svelte +100 -0
- package/dist/components/docs/TableOfContents.svelte.d.ts +9 -0
- package/dist/components/docs/Tabs.svelte +69 -0
- package/dist/components/docs/Tabs.svelte.d.ts +8 -0
- package/dist/components/docs/ThemeToggle.svelte +16 -0
- package/dist/components/docs/ThemeToggle.svelte.d.ts +18 -0
- package/dist/components/docs/Tooltip.svelte +44 -0
- package/dist/components/docs/Tooltip.svelte.d.ts +10 -0
- package/dist/components/docs/VersionSwitcher.svelte +95 -0
- package/dist/components/docs/VersionSwitcher.svelte.d.ts +7 -0
- package/dist/components/docs/Video.svelte +84 -0
- package/dist/components/docs/Video.svelte.d.ts +12 -0
- package/dist/components/docs/api/ApiEndpoint.svelte +61 -0
- package/dist/components/docs/api/ApiEndpoint.svelte.d.ts +11 -0
- package/dist/components/docs/api/ApiParams.svelte +80 -0
- package/dist/components/docs/api/ApiParams.svelte.d.ts +14 -0
- package/dist/components/docs/api/ApiPlayground.svelte +259 -0
- package/dist/components/docs/api/ApiPlayground.svelte.d.ts +16 -0
- package/dist/components/docs/api/ApiReference.svelte +278 -0
- package/dist/components/docs/api/ApiReference.svelte.d.ts +23 -0
- package/dist/components/docs/api/ApiResponse.svelte +66 -0
- package/dist/components/docs/api/ApiResponse.svelte.d.ts +9 -0
- package/dist/components/docs/api/index.d.ts +5 -0
- package/dist/components/docs/api/index.js +5 -0
- package/dist/components/docs/componentTextProps.d.ts +3 -0
- package/dist/components/docs/componentTextProps.js +61 -0
- package/dist/components/docs/index.d.ts +54 -0
- package/dist/components/docs/index.js +56 -0
- package/dist/components/global/VersionNotFound.svelte +48 -0
- package/dist/components/global/VersionNotFound.svelte.d.ts +7 -0
- package/dist/components/global/index.d.ts +1 -0
- package/dist/components/global/index.js +1 -0
- package/dist/components/index.d.ts +6 -822
- package/dist/components/index.js +11 -3854
- package/dist/components/ui/Badge.svelte +48 -0
- package/dist/components/ui/Badge.svelte.d.ts +15 -0
- package/dist/components/ui/Button.svelte +58 -0
- package/dist/components/ui/Button.svelte.d.ts +17 -0
- package/dist/components/ui/Dialog.svelte +16 -0
- package/dist/components/ui/Dialog.svelte.d.ts +9 -0
- package/dist/components/ui/DialogClose.svelte +16 -0
- package/dist/components/ui/DialogClose.svelte.d.ts +9 -0
- package/dist/components/ui/DialogContent.svelte +43 -0
- package/dist/components/ui/DialogContent.svelte.d.ts +10 -0
- package/dist/components/ui/DialogDescription.svelte +21 -0
- package/dist/components/ui/DialogDescription.svelte.d.ts +9 -0
- package/dist/components/ui/DialogFooter.svelte +20 -0
- package/dist/components/ui/DialogFooter.svelte.d.ts +9 -0
- package/dist/components/ui/DialogHeader.svelte +20 -0
- package/dist/components/ui/DialogHeader.svelte.d.ts +9 -0
- package/dist/components/ui/DialogTitle.svelte +21 -0
- package/dist/components/ui/DialogTitle.svelte.d.ts +9 -0
- package/dist/components/ui/Input.svelte +23 -0
- package/dist/components/ui/Input.svelte.d.ts +8 -0
- package/dist/components/ui/Textarea.svelte +19 -0
- package/dist/components/ui/Textarea.svelte.d.ts +7 -0
- package/dist/components/ui/index.d.ts +11 -0
- package/dist/components/ui/index.js +11 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +9 -0
- package/dist/config.schema.json +471 -0
- package/dist/config.server.d.ts +46 -0
- package/dist/config.server.js +149 -0
- package/dist/{mdx-ColN3Cyg.d.mts → config.types.d.ts} +22 -75
- package/dist/config.types.js +39 -0
- package/dist/dev-utils.d.ts +29 -0
- package/dist/dev-utils.js +63 -0
- package/dist/index.d.ts +19 -4
- package/dist/index.js +25 -4861
- package/dist/mdx-cache.d.ts +41 -0
- package/dist/mdx-cache.js +160 -0
- package/dist/mdx-components.js +50 -1931
- package/dist/mdx-security.d.ts +76 -0
- package/dist/mdx-security.js +217 -0
- package/dist/mdx.d.ts +73 -0
- package/dist/mdx.js +1099 -0
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.js +2 -0
- package/dist/middleware/security.d.ts +22 -47
- package/dist/middleware/security.js +111 -137
- package/dist/parsers/base-parser.d.ts +14 -0
- package/dist/parsers/base-parser.js +1 -0
- package/dist/parsers/index.d.ts +16 -0
- package/dist/parsers/index.js +51 -0
- package/dist/parsers/openapi-parser.d.ts +18 -0
- package/dist/parsers/openapi-parser.js +209 -0
- package/dist/parsers/postman-parser.d.ts +20 -0
- package/dist/parsers/postman-parser.js +260 -0
- package/dist/parsers/specra-parser.d.ts +10 -0
- package/dist/parsers/specra-parser.js +18 -0
- package/dist/redirects.d.ts +12 -0
- package/dist/redirects.js +30 -0
- package/dist/remark-code-meta.d.ts +6 -0
- package/dist/remark-code-meta.js +21 -0
- package/dist/sidebar-utils.d.ts +59 -0
- package/dist/sidebar-utils.js +144 -0
- package/dist/stores/config.d.ts +20 -0
- package/dist/stores/config.js +45 -0
- package/dist/stores/index.d.ts +4 -0
- package/dist/stores/index.js +4 -0
- package/dist/stores/sidebar.d.ts +7 -0
- package/dist/stores/sidebar.js +12 -0
- package/dist/stores/tabs.d.ts +6 -0
- package/dist/stores/tabs.js +41 -0
- package/dist/stores/theme.d.ts +7 -0
- package/dist/stores/theme.js +75 -0
- package/dist/{styles.css → styles/globals.css} +136 -6
- package/dist/toc.d.ts +9 -0
- package/dist/toc.js +15 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.js +30 -0
- package/package.json +47 -90
- package/dist/app/api/mdx-watch/route.d.mts +0 -10
- package/dist/app/api/mdx-watch/route.d.ts +0 -10
- package/dist/app/api/mdx-watch/route.js +0 -118
- package/dist/app/api/mdx-watch/route.js.map +0 -1
- package/dist/app/api/mdx-watch/route.mjs +0 -91
- package/dist/app/api/mdx-watch/route.mjs.map +0 -1
- package/dist/chunk-6S3EJVEO.mjs +0 -259
- package/dist/chunk-6S3EJVEO.mjs.map +0 -1
- package/dist/chunk-BE7EROIW.mjs +0 -212
- package/dist/chunk-BE7EROIW.mjs.map +0 -1
- package/dist/chunk-CWHRZHZO.mjs +0 -168
- package/dist/chunk-CWHRZHZO.mjs.map +0 -1
- package/dist/chunk-D5VDVYFY.mjs +0 -1325
- package/dist/chunk-D5VDVYFY.mjs.map +0 -1
- package/dist/chunk-WMCO2UX5.mjs +0 -585
- package/dist/chunk-WMCO2UX5.mjs.map +0 -1
- package/dist/chunk-XEMGCPZZ.mjs +0 -475
- package/dist/chunk-XEMGCPZZ.mjs.map +0 -1
- package/dist/components/index.d.mts +0 -822
- package/dist/components/index.js.map +0 -1
- package/dist/components/index.mjs +0 -3741
- package/dist/components/index.mjs.map +0 -1
- package/dist/index.d.mts +0 -4
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -1897
- package/dist/index.mjs.map +0 -1
- package/dist/layouts/index.d.mts +0 -34
- package/dist/layouts/index.d.ts +0 -34
- package/dist/layouts/index.js +0 -453
- package/dist/layouts/index.js.map +0 -1
- package/dist/layouts/index.mjs +0 -173
- package/dist/layouts/index.mjs.map +0 -1
- package/dist/lib/index.d.mts +0 -583
- package/dist/lib/index.d.ts +0 -583
- package/dist/lib/index.js +0 -1595
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/index.mjs +0 -111
- package/dist/lib/index.mjs.map +0 -1
- package/dist/mdx-ColN3Cyg.d.ts +0 -352
- package/dist/mdx-components.d.mts +0 -86
- package/dist/mdx-components.d.ts +0 -86
- package/dist/mdx-components.js.map +0 -1
- package/dist/mdx-components.mjs +0 -206
- package/dist/mdx-components.mjs.map +0 -1
- package/dist/middleware/security.d.mts +0 -82
- package/dist/middleware/security.js.map +0 -1
- package/dist/middleware/security.mjs +0 -84
- package/dist/middleware/security.mjs.map +0 -1
- package/dist/styles.css.map +0 -1
- package/dist/styles.d.mts +0 -2
- package/dist/styles.d.ts +0 -2
- package/dist/styles.js +0 -2
- package/dist/styles.js.map +0 -1
- package/dist/styles.mjs +0 -1
- 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;
|