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
package/dist/chunk-BE7EROIW.mjs
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
// src/lib/mdx-security.ts
|
|
2
|
-
import path from "path";
|
|
3
|
-
function sanitizePath(userPath) {
|
|
4
|
-
const decoded = decodeURIComponent(userPath);
|
|
5
|
-
if (decoded.includes("../") || decoded.includes("..\\") || decoded.includes("%2e%2e") || decoded.includes("%252e%252e") || path.isAbsolute(decoded)) {
|
|
6
|
-
throw new Error("Path traversal detected");
|
|
7
|
-
}
|
|
8
|
-
const normalized = path.normalize(decoded).replace(/\\/g, "/");
|
|
9
|
-
if (normalized.startsWith("..") || normalized.includes("/../")) {
|
|
10
|
-
throw new Error("Invalid path detected");
|
|
11
|
-
}
|
|
12
|
-
return normalized;
|
|
13
|
-
}
|
|
14
|
-
function validatePathWithinDirectory(filePath, allowedDir) {
|
|
15
|
-
const resolvedPath = path.resolve(allowedDir, filePath);
|
|
16
|
-
const resolvedDir = path.resolve(allowedDir);
|
|
17
|
-
return resolvedPath.startsWith(resolvedDir + path.sep) || resolvedPath === resolvedDir;
|
|
18
|
-
}
|
|
19
|
-
var DANGEROUS_PATTERNS = [
|
|
20
|
-
// JavaScript execution
|
|
21
|
-
/eval\s*\(/gi,
|
|
22
|
-
/Function\s*\(/gi,
|
|
23
|
-
/import\s*\(/gi,
|
|
24
|
-
/require\s*\(/gi,
|
|
25
|
-
// File system access
|
|
26
|
-
/fs\.[a-z]+/gi,
|
|
27
|
-
/readFile/gi,
|
|
28
|
-
/writeFile/gi,
|
|
29
|
-
/process\.env/gi,
|
|
30
|
-
// Network requests during SSR (legitimate client-side usage should use components)
|
|
31
|
-
/fetch\s*\(/gi,
|
|
32
|
-
// Dangerous Node.js modules
|
|
33
|
-
/child_process/gi,
|
|
34
|
-
/exec\s*\(/gi,
|
|
35
|
-
/spawn\s*\(/gi,
|
|
36
|
-
// Script tag injection
|
|
37
|
-
/<script[>\s]/gi,
|
|
38
|
-
/javascript:/gi,
|
|
39
|
-
/\bon(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|wheel)\s*=/gi
|
|
40
|
-
// onclick, onerror, onload, etc.
|
|
41
|
-
];
|
|
42
|
-
function removeCodeBlocks(content) {
|
|
43
|
-
let withoutCodeBlocks = content.replace(/```[\s\S]*?```/g, "");
|
|
44
|
-
withoutCodeBlocks = withoutCodeBlocks.replace(/`[^`]*`/g, "");
|
|
45
|
-
return withoutCodeBlocks;
|
|
46
|
-
}
|
|
47
|
-
function scanMDXForDangerousPatterns(content) {
|
|
48
|
-
const issues = [];
|
|
49
|
-
const contentWithoutCode = removeCodeBlocks(content);
|
|
50
|
-
for (const pattern of DANGEROUS_PATTERNS) {
|
|
51
|
-
const matches = contentWithoutCode.match(pattern);
|
|
52
|
-
if (matches) {
|
|
53
|
-
issues.push(`Dangerous pattern detected: ${pattern.source}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return issues;
|
|
57
|
-
}
|
|
58
|
-
function sanitizeMDXContent(content, strict = false) {
|
|
59
|
-
if (strict) {
|
|
60
|
-
const issues = scanMDXForDangerousPatterns(content);
|
|
61
|
-
if (issues.length > 0) {
|
|
62
|
-
throw new Error(`MDX content contains dangerous patterns: ${issues.join(", ")}`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
let sanitized = content.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "");
|
|
66
|
-
sanitized = sanitized.replace(/\s+on\w+\s*=\s*["'][^"']*["']/gi, "");
|
|
67
|
-
sanitized = sanitized.replace(/javascript:/gi, "");
|
|
68
|
-
return sanitized;
|
|
69
|
-
}
|
|
70
|
-
var CSP_DIRECTIVES = {
|
|
71
|
-
"default-src": ["'self'"],
|
|
72
|
-
"script-src": [
|
|
73
|
-
"'self'",
|
|
74
|
-
"'unsafe-inline'",
|
|
75
|
-
// Required for Next.js
|
|
76
|
-
"'unsafe-eval'"
|
|
77
|
-
// Required for dev mode - remove in production
|
|
78
|
-
],
|
|
79
|
-
"style-src": ["'self'", "'unsafe-inline'"],
|
|
80
|
-
// Required for styled-components/emotion
|
|
81
|
-
"img-src": ["'self'", "data:", "https:"],
|
|
82
|
-
"font-src": ["'self'", "data:"],
|
|
83
|
-
"connect-src": ["'self'"],
|
|
84
|
-
"frame-src": ["'self'"],
|
|
85
|
-
"object-src": ["'none'"],
|
|
86
|
-
"base-uri": ["'self'"],
|
|
87
|
-
"form-action": ["'self'"],
|
|
88
|
-
"frame-ancestors": ["'self'"],
|
|
89
|
-
"upgrade-insecure-requests": []
|
|
90
|
-
};
|
|
91
|
-
function generateCSPHeader(customDirectives, production = true) {
|
|
92
|
-
const directives = { ...CSP_DIRECTIVES, ...customDirectives };
|
|
93
|
-
if (production && directives["script-src"]) {
|
|
94
|
-
directives["script-src"] = directives["script-src"].filter(
|
|
95
|
-
(src) => src !== "'unsafe-eval'"
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
return Object.entries(directives).map(([key, values]) => `${key} ${values.join(" ")}`).join("; ");
|
|
99
|
-
}
|
|
100
|
-
var SAFE_MDX_COMPONENTS = /* @__PURE__ */ new Set([
|
|
101
|
-
// Standard HTML elements (automatically allowed by MDX)
|
|
102
|
-
"h1",
|
|
103
|
-
"h2",
|
|
104
|
-
"h3",
|
|
105
|
-
"h4",
|
|
106
|
-
"h5",
|
|
107
|
-
"h6",
|
|
108
|
-
"p",
|
|
109
|
-
"a",
|
|
110
|
-
"ul",
|
|
111
|
-
"ol",
|
|
112
|
-
"li",
|
|
113
|
-
"code",
|
|
114
|
-
"pre",
|
|
115
|
-
"blockquote",
|
|
116
|
-
"table",
|
|
117
|
-
"thead",
|
|
118
|
-
"tbody",
|
|
119
|
-
"tr",
|
|
120
|
-
"th",
|
|
121
|
-
"td",
|
|
122
|
-
"img",
|
|
123
|
-
"video",
|
|
124
|
-
"audio",
|
|
125
|
-
"br",
|
|
126
|
-
"hr",
|
|
127
|
-
"strong",
|
|
128
|
-
"em",
|
|
129
|
-
// Custom safe components
|
|
130
|
-
"Callout",
|
|
131
|
-
"CodeBlock",
|
|
132
|
-
"Accordion",
|
|
133
|
-
"AccordionItem",
|
|
134
|
-
"Tabs",
|
|
135
|
-
"Tab",
|
|
136
|
-
"Image",
|
|
137
|
-
"Video",
|
|
138
|
-
"Card",
|
|
139
|
-
"CardGrid",
|
|
140
|
-
"ImageCard",
|
|
141
|
-
"ImageCardGrid",
|
|
142
|
-
"Steps",
|
|
143
|
-
"Step",
|
|
144
|
-
"Icon",
|
|
145
|
-
"Mermaid",
|
|
146
|
-
"Math",
|
|
147
|
-
"Columns",
|
|
148
|
-
"Column",
|
|
149
|
-
"Badge",
|
|
150
|
-
"Tooltip",
|
|
151
|
-
"Frame",
|
|
152
|
-
"ApiEndpoint",
|
|
153
|
-
"ApiParams",
|
|
154
|
-
"ApiResponse",
|
|
155
|
-
"ApiPlayground",
|
|
156
|
-
"ApiReference"
|
|
157
|
-
]);
|
|
158
|
-
function validateMDXComponents(content) {
|
|
159
|
-
const issues = [];
|
|
160
|
-
const componentRegex = /<([A-Z][a-zA-Z0-9]*)/g;
|
|
161
|
-
let match;
|
|
162
|
-
while ((match = componentRegex.exec(content)) !== null) {
|
|
163
|
-
const componentName = match[1];
|
|
164
|
-
if (!SAFE_MDX_COMPONENTS.has(componentName)) {
|
|
165
|
-
issues.push(`Unsafe component detected: ${componentName}`);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return {
|
|
169
|
-
valid: issues.length === 0,
|
|
170
|
-
issues
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
function validateMDXSecurity(content, options = {}) {
|
|
174
|
-
const {
|
|
175
|
-
strictMode = false,
|
|
176
|
-
allowCustomComponents = true,
|
|
177
|
-
blockDangerousPatterns = true
|
|
178
|
-
} = options;
|
|
179
|
-
const issues = [];
|
|
180
|
-
if (blockDangerousPatterns) {
|
|
181
|
-
const patternIssues = scanMDXForDangerousPatterns(content);
|
|
182
|
-
issues.push(...patternIssues);
|
|
183
|
-
}
|
|
184
|
-
if (!allowCustomComponents) {
|
|
185
|
-
const componentValidation = validateMDXComponents(content);
|
|
186
|
-
if (!componentValidation.valid) {
|
|
187
|
-
issues.push(...componentValidation.issues);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (strictMode && issues.length > 0) {
|
|
191
|
-
return { valid: false, issues };
|
|
192
|
-
}
|
|
193
|
-
const sanitized = sanitizeMDXContent(content, false);
|
|
194
|
-
return {
|
|
195
|
-
valid: true,
|
|
196
|
-
issues,
|
|
197
|
-
sanitized
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export {
|
|
202
|
-
sanitizePath,
|
|
203
|
-
validatePathWithinDirectory,
|
|
204
|
-
scanMDXForDangerousPatterns,
|
|
205
|
-
sanitizeMDXContent,
|
|
206
|
-
CSP_DIRECTIVES,
|
|
207
|
-
generateCSPHeader,
|
|
208
|
-
SAFE_MDX_COMPONENTS,
|
|
209
|
-
validateMDXComponents,
|
|
210
|
-
validateMDXSecurity
|
|
211
|
-
};
|
|
212
|
-
//# sourceMappingURL=chunk-BE7EROIW.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/mdx-security.ts"],"sourcesContent":["/**\n * MDX Security Layer\n *\n * Protects against:\n * - XSS via malicious MDX expressions\n * - Path traversal attacks\n * - Dangerous component usage\n * - Cross-domain vulnerabilities\n */\n\nimport path from \"path\"\n\n/**\n * Sanitize file paths to prevent path traversal attacks\n * Blocks: ../, ..\\, absolute paths, encoded traversal attempts\n */\nexport function sanitizePath(userPath: string): string {\n // Decode URI components to catch encoded traversal attempts\n const decoded = decodeURIComponent(userPath)\n\n // Block path traversal patterns\n if (\n decoded.includes(\"../\") ||\n decoded.includes(\"..\\\\\") ||\n decoded.includes(\"%2e%2e\") ||\n decoded.includes(\"%252e%252e\") ||\n path.isAbsolute(decoded)\n ) {\n throw new Error(\"Path traversal detected\")\n }\n\n // Normalize and validate the path\n const normalized = path.normalize(decoded).replace(/\\\\/g, \"/\")\n\n // Ensure path doesn't escape after normalization\n if (normalized.startsWith(\"..\") || normalized.includes(\"/../\")) {\n throw new Error(\"Invalid path detected\")\n }\n\n return normalized\n}\n\n/**\n * Validate that a file path is within allowed directory\n */\nexport function validatePathWithinDirectory(filePath: string, allowedDir: string): boolean {\n const resolvedPath = path.resolve(allowedDir, filePath)\n const resolvedDir = path.resolve(allowedDir)\n\n return resolvedPath.startsWith(resolvedDir + path.sep) || resolvedPath === resolvedDir\n}\n\n/**\n * Dangerous MDX patterns that should be blocked\n * These patterns can execute arbitrary code during SSR\n */\nconst DANGEROUS_PATTERNS = [\n // JavaScript execution\n /eval\\s*\\(/gi,\n /Function\\s*\\(/gi,\n /import\\s*\\(/gi,\n /require\\s*\\(/gi,\n\n // File system access\n /fs\\.[a-z]+/gi,\n /readFile/gi,\n /writeFile/gi,\n /process\\.env/gi,\n\n // Network requests during SSR (legitimate client-side usage should use components)\n /fetch\\s*\\(/gi,\n\n // Dangerous Node.js modules\n /child_process/gi,\n /exec\\s*\\(/gi,\n /spawn\\s*\\(/gi,\n\n // Script tag injection\n /<script[>\\s]/gi,\n /javascript:/gi,\n /\\bon(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|wheel)\\s*=/gi, // onclick, onerror, onload, etc.\n]\n\n/**\n * Remove code blocks from content to avoid scanning code examples\n * This prevents false positives from documentation code examples\n */\nfunction removeCodeBlocks(content: string): string {\n // Remove fenced code blocks (```...```)\n let withoutCodeBlocks = content.replace(/```[\\s\\S]*?```/g, '')\n\n // Remove inline code (`...`)\n withoutCodeBlocks = withoutCodeBlocks.replace(/`[^`]*`/g, '')\n\n return withoutCodeBlocks\n}\n\n/**\n * Scan MDX content for dangerous patterns\n * Returns array of detected issues\n * Note: Skips content inside code blocks to avoid false positives\n */\nexport function scanMDXForDangerousPatterns(content: string): string[] {\n const issues: string[] = []\n\n // Remove code blocks before scanning to avoid false positives\n const contentWithoutCode = removeCodeBlocks(content)\n\n for (const pattern of DANGEROUS_PATTERNS) {\n const matches = contentWithoutCode.match(pattern)\n if (matches) {\n issues.push(`Dangerous pattern detected: ${pattern.source}`)\n }\n }\n\n return issues\n}\n\n/**\n * Sanitize MDX content by removing/escaping dangerous patterns\n * This is a defensive measure - ideally content should be rejected if dangerous\n */\nexport function sanitizeMDXContent(content: string, strict: boolean = false): string {\n if (strict) {\n const issues = scanMDXForDangerousPatterns(content)\n if (issues.length > 0) {\n throw new Error(`MDX content contains dangerous patterns: ${issues.join(\", \")}`)\n }\n }\n\n // Remove inline script tags\n let sanitized = content.replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, \"\")\n\n // Remove event handlers from HTML tags\n sanitized = sanitized.replace(/\\s+on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n\n // Remove javascript: protocol\n sanitized = sanitized.replace(/javascript:/gi, \"\")\n\n return sanitized\n}\n\n/**\n * Content Security Policy configuration\n * Use this in your Next.js middleware or headers config\n */\nexport const CSP_DIRECTIVES = {\n \"default-src\": [\"'self'\"],\n \"script-src\": [\n \"'self'\",\n \"'unsafe-inline'\", // Required for Next.js\n \"'unsafe-eval'\", // Required for dev mode - remove in production\n ],\n \"style-src\": [\"'self'\", \"'unsafe-inline'\"], // Required for styled-components/emotion\n \"img-src\": [\"'self'\", \"data:\", \"https:\"],\n \"font-src\": [\"'self'\", \"data:\"],\n \"connect-src\": [\"'self'\"],\n \"frame-src\": [\"'self'\"],\n \"object-src\": [\"'none'\"],\n \"base-uri\": [\"'self'\"],\n \"form-action\": [\"'self'\"],\n \"frame-ancestors\": [\"'self'\"],\n \"upgrade-insecure-requests\": [],\n} as const\n\n/**\n * Generate CSP header value from directives\n */\nexport function generateCSPHeader(\n customDirectives?: Partial<typeof CSP_DIRECTIVES>,\n production: boolean = true\n): string {\n const directives: Record<string, readonly string[]> = { ...CSP_DIRECTIVES, ...customDirectives }\n\n // Remove unsafe-eval in production\n if (production && directives[\"script-src\"]) {\n directives[\"script-src\"] = directives[\"script-src\"].filter(\n (src) => src !== \"'unsafe-eval'\"\n )\n }\n\n return Object.entries(directives)\n .map(([key, values]) => `${key} ${values.join(\" \")}`)\n .join(\"; \")\n}\n\n/**\n * Allowlist of safe MDX components\n * Only these components can be used in MDX files\n */\nexport const SAFE_MDX_COMPONENTS = new Set([\n // Standard HTML elements (automatically allowed by MDX)\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\",\n \"p\", \"a\", \"ul\", \"ol\", \"li\", \"code\", \"pre\",\n \"blockquote\", \"table\", \"thead\", \"tbody\", \"tr\", \"th\", \"td\",\n \"img\", \"video\", \"audio\", \"br\", \"hr\", \"strong\", \"em\",\n\n // Custom safe components\n \"Callout\", \"CodeBlock\", \"Accordion\", \"AccordionItem\",\n \"Tabs\", \"Tab\", \"Image\", \"Video\", \"Card\", \"CardGrid\",\n \"ImageCard\", \"ImageCardGrid\", \"Steps\", \"Step\",\n \"Icon\", \"Mermaid\", \"Math\", \"Columns\", \"Column\",\n \"Badge\", \"Tooltip\", \"Frame\",\n \"ApiEndpoint\", \"ApiParams\", \"ApiResponse\", \"ApiPlayground\", \"ApiReference\",\n])\n\n/**\n * Validate component usage in MDX\n */\nexport function validateMDXComponents(content: string): { valid: boolean; issues: string[] } {\n const issues: string[] = []\n\n // Find all JSX-like component usage\n const componentRegex = /<([A-Z][a-zA-Z0-9]*)/g\n let match\n\n while ((match = componentRegex.exec(content)) !== null) {\n const componentName = match[1]\n if (!SAFE_MDX_COMPONENTS.has(componentName)) {\n issues.push(`Unsafe component detected: ${componentName}`)\n }\n }\n\n return {\n valid: issues.length === 0,\n issues,\n }\n}\n\n/**\n * Comprehensive MDX security check\n * Use this before processing MDX content\n */\nexport function validateMDXSecurity(\n content: string,\n options: {\n strictMode?: boolean\n allowCustomComponents?: boolean\n blockDangerousPatterns?: boolean\n } = {}\n): { valid: boolean; issues: string[]; sanitized?: string } {\n const {\n strictMode = false,\n allowCustomComponents = true,\n blockDangerousPatterns = true,\n } = options\n\n const issues: string[] = []\n\n // Check for dangerous patterns\n if (blockDangerousPatterns) {\n const patternIssues = scanMDXForDangerousPatterns(content)\n issues.push(...patternIssues)\n }\n\n // Validate components\n if (!allowCustomComponents) {\n const componentValidation = validateMDXComponents(content)\n if (!componentValidation.valid) {\n issues.push(...componentValidation.issues)\n }\n }\n\n // In strict mode, reject any issues\n if (strictMode && issues.length > 0) {\n return { valid: false, issues }\n }\n\n // Otherwise, sanitize and warn\n const sanitized = sanitizeMDXContent(content, false)\n\n return {\n valid: true,\n issues,\n sanitized,\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-CWHRZHZO.mjs
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getConfig
|
|
3
|
-
} from "./chunk-6S3EJVEO.mjs";
|
|
4
|
-
|
|
5
|
-
// src/components/docs/breadcrumb.tsx
|
|
6
|
-
import Link from "next/link";
|
|
7
|
-
import { ChevronRight } from "lucide-react";
|
|
8
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
function Breadcrumb({ version, slug, title }) {
|
|
10
|
-
const config = getConfig();
|
|
11
|
-
const i18n = config.features?.i18n;
|
|
12
|
-
const locales = typeof i18n === "object" ? i18n.locales : i18n ? ["en"] : [];
|
|
13
|
-
const defaultLocale = typeof i18n === "object" ? i18n.defaultLocale : "en";
|
|
14
|
-
const parts = slug.split("/");
|
|
15
|
-
const potentialLocale = parts[0];
|
|
16
|
-
const isLc = locales.includes(potentialLocale);
|
|
17
|
-
const isDefaultLc = potentialLocale === defaultLocale;
|
|
18
|
-
const homeHref = isLc ? `/docs/${version}/${potentialLocale}` : `/docs/${version}`;
|
|
19
|
-
const breadcrumbs = [
|
|
20
|
-
{ label: "Docs", href: homeHref }
|
|
21
|
-
];
|
|
22
|
-
let currentPath = "";
|
|
23
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
24
|
-
const part = parts[i];
|
|
25
|
-
currentPath += (currentPath ? "/" : "") + part;
|
|
26
|
-
if (i === 0 && isLc) {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
breadcrumbs.push({
|
|
30
|
-
label: part.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
31
|
-
href: `/docs/${version}/${currentPath}`
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
breadcrumbs.push({
|
|
35
|
-
label: title,
|
|
36
|
-
href: `/docs/${version}/${slug}`
|
|
37
|
-
});
|
|
38
|
-
return /* @__PURE__ */ jsx("nav", { className: "flex items-center gap-2 text-sm text-muted-foreground mb-4", "aria-label": "Breadcrumb", children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
39
|
-
index > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" }),
|
|
40
|
-
index === breadcrumbs.length - 1 ? /* @__PURE__ */ jsx("span", { className: "text-foreground font-medium", children: crumb.label }) : /* @__PURE__ */ jsx(
|
|
41
|
-
Link,
|
|
42
|
-
{
|
|
43
|
-
href: crumb.href,
|
|
44
|
-
className: "hover:text-foreground transition-colors",
|
|
45
|
-
children: crumb.label
|
|
46
|
-
}
|
|
47
|
-
)
|
|
48
|
-
] }, crumb.href)) });
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// src/components/docs/doc-metadata.tsx
|
|
52
|
-
import { Clock, Calendar, User } from "lucide-react";
|
|
53
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
54
|
-
function DocMetadata({ meta, config }) {
|
|
55
|
-
const showReadingTime = config.features?.showReadingTime && meta.reading_time;
|
|
56
|
-
const showLastUpdated = config.features?.showLastUpdated && meta.last_updated;
|
|
57
|
-
const showAuthors = config.features?.showAuthors && meta.authors?.length;
|
|
58
|
-
const hasMetadata = showReadingTime || showLastUpdated || showAuthors;
|
|
59
|
-
if (!hasMetadata) {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
return /* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center gap-4 text-sm text-muted-foreground border-b border-border pb-4 mb-6", children: [
|
|
63
|
-
showReadingTime && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5", children: [
|
|
64
|
-
/* @__PURE__ */ jsx2(Clock, { className: "h-4 w-4" }),
|
|
65
|
-
/* @__PURE__ */ jsxs2("span", { children: [
|
|
66
|
-
meta.reading_time,
|
|
67
|
-
" min read"
|
|
68
|
-
] })
|
|
69
|
-
] }),
|
|
70
|
-
showLastUpdated && meta.last_updated && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5", children: [
|
|
71
|
-
/* @__PURE__ */ jsx2(Calendar, { className: "h-4 w-4" }),
|
|
72
|
-
/* @__PURE__ */ jsxs2("span", { children: [
|
|
73
|
-
"Updated ",
|
|
74
|
-
new Date(meta.last_updated).toLocaleDateString(meta.locale || "en")
|
|
75
|
-
] })
|
|
76
|
-
] }),
|
|
77
|
-
showAuthors && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5", children: [
|
|
78
|
-
/* @__PURE__ */ jsx2(User, { className: "h-4 w-4" }),
|
|
79
|
-
/* @__PURE__ */ jsx2("span", { children: meta.authors.map((author, idx) => /* @__PURE__ */ jsxs2("span", { children: [
|
|
80
|
-
author.name || author.id,
|
|
81
|
-
idx < meta.authors.length - 1 && ", "
|
|
82
|
-
] }, author.id)) })
|
|
83
|
-
] })
|
|
84
|
-
] });
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// src/components/docs/doc-navigation.tsx
|
|
88
|
-
import Link2 from "next/link";
|
|
89
|
-
import { ChevronLeft, ChevronRight as ChevronRight2 } from "lucide-react";
|
|
90
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
91
|
-
function DocNavigation({ previousDoc, nextDoc, version }) {
|
|
92
|
-
if (!previousDoc && !nextDoc) return null;
|
|
93
|
-
return /* @__PURE__ */ jsxs3("div", { className: "mt-12 pt-8 border-t border-border grid grid-cols-2 gap-4", children: [
|
|
94
|
-
previousDoc ? /* @__PURE__ */ jsxs3(
|
|
95
|
-
Link2,
|
|
96
|
-
{
|
|
97
|
-
href: `/docs/${version}/${previousDoc.slug}`,
|
|
98
|
-
className: "group flex flex-col gap-2 p-4 rounded-xl border border-border hover:border-primary/50 hover:bg-muted/50 transition-all",
|
|
99
|
-
style: {
|
|
100
|
-
textDecoration: "none !important"
|
|
101
|
-
},
|
|
102
|
-
children: [
|
|
103
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
104
|
-
/* @__PURE__ */ jsx3(ChevronLeft, { className: "h-4 w-4" }),
|
|
105
|
-
/* @__PURE__ */ jsx3("span", { children: "Previous" })
|
|
106
|
-
] }),
|
|
107
|
-
/* @__PURE__ */ jsx3("div", { className: "text-base font-medium text-foreground group-hover:text-primary transition-colors", children: previousDoc.title })
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
|
-
) : /* @__PURE__ */ jsx3("div", {}),
|
|
111
|
-
nextDoc ? /* @__PURE__ */ jsxs3(
|
|
112
|
-
Link2,
|
|
113
|
-
{
|
|
114
|
-
href: `/docs/${version}/${nextDoc.slug}`,
|
|
115
|
-
className: "group flex flex-col gap-2 p-4 rounded-xl border border-border hover:border-primary/50 hover:bg-muted/50 transition-all text-right",
|
|
116
|
-
style: {
|
|
117
|
-
textDecoration: "none !important"
|
|
118
|
-
},
|
|
119
|
-
children: [
|
|
120
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-end gap-2 text-sm text-muted-foreground", children: [
|
|
121
|
-
/* @__PURE__ */ jsx3("span", { children: "Next" }),
|
|
122
|
-
/* @__PURE__ */ jsx3(ChevronRight2, { className: "h-4 w-4" })
|
|
123
|
-
] }),
|
|
124
|
-
/* @__PURE__ */ jsx3("div", { className: "text-base font-medium text-foreground group-hover:text-primary transition-colors", children: nextDoc.title })
|
|
125
|
-
]
|
|
126
|
-
}
|
|
127
|
-
) : /* @__PURE__ */ jsx3("div", {})
|
|
128
|
-
] });
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// src/components/docs/doc-tags.tsx
|
|
132
|
-
import { Tag } from "lucide-react";
|
|
133
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
134
|
-
function DocTags({ tags }) {
|
|
135
|
-
if (!tags || tags.length === 0) {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
return /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-2 mt-6 pt-6 border-t border-border", children: [
|
|
139
|
-
/* @__PURE__ */ jsx4(Tag, { className: "h-4 w-4 text-muted-foreground" }),
|
|
140
|
-
tags.map((tag) => /* @__PURE__ */ jsx4(
|
|
141
|
-
"span",
|
|
142
|
-
{
|
|
143
|
-
className: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-primary/10 text-primary border border-primary/20",
|
|
144
|
-
children: tag
|
|
145
|
-
},
|
|
146
|
-
tag
|
|
147
|
-
))
|
|
148
|
-
] });
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// src/components/docs/draft-badge.tsx
|
|
152
|
-
import { FileWarning } from "lucide-react";
|
|
153
|
-
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
154
|
-
function DraftBadge() {
|
|
155
|
-
return /* @__PURE__ */ jsxs5("div", { className: "inline-flex items-center gap-2 px-3 py-1.5 rounded-md bg-yellow-500/10 border border-yellow-500/20 text-yellow-600 dark:text-yellow-400 text-sm font-medium mb-4", children: [
|
|
156
|
-
/* @__PURE__ */ jsx5(FileWarning, { className: "h-4 w-4" }),
|
|
157
|
-
/* @__PURE__ */ jsx5("span", { children: "Draft - Not visible in production" })
|
|
158
|
-
] });
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export {
|
|
162
|
-
Breadcrumb,
|
|
163
|
-
DocMetadata,
|
|
164
|
-
DocNavigation,
|
|
165
|
-
DocTags,
|
|
166
|
-
DraftBadge
|
|
167
|
-
};
|
|
168
|
-
//# sourceMappingURL=chunk-CWHRZHZO.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/docs/breadcrumb.tsx","../src/components/docs/doc-metadata.tsx","../src/components/docs/doc-navigation.tsx","../src/components/docs/doc-tags.tsx","../src/components/docs/draft-badge.tsx"],"sourcesContent":["import Link from \"next/link\"\nimport { ChevronRight } from \"lucide-react\"\n\nimport { getConfig } from \"@/lib/config\"\n\ninterface BreadcrumbProps {\n version: string\n slug: string\n title: string\n}\n\nexport function Breadcrumb({ version, slug, title }: BreadcrumbProps) {\n const config = getConfig()\n const i18n = config.features?.i18n\n const locales = typeof i18n === 'object' ? i18n.locales : (i18n ? ['en'] : [])\n const defaultLocale = typeof i18n === 'object' ? i18n.defaultLocale : 'en'\n\n const parts = slug.split(\"/\")\n\n // Check if first part is a locale\n const potentialLocale = parts[0]\n const isLc = locales.includes(potentialLocale)\n const isDefaultLc = potentialLocale === defaultLocale\n\n // If slug starts with locale, we might want to skip showing it as a breadcrumb item\n // But we want the \"Docs\" home link to point to it (if it's not default provided we prefix default?)\n\n const homeHref = isLc\n ? `/docs/${version}/${potentialLocale}`\n : `/docs/${version}`\n\n const breadcrumbs = [\n { label: \"Docs\", href: homeHref },\n ]\n\n // Build breadcrumb path\n let currentPath = \"\"\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]\n currentPath += (currentPath ? \"/\" : \"\") + part\n\n // Skip the locale part in the breadcrumb visual trail if it's the first part\n if (i === 0 && isLc) {\n continue\n }\n\n breadcrumbs.push({\n label: part.replace(/-/g, \" \").replace(/\\b\\w/g, (l) => l.toUpperCase()),\n href: `/docs/${version}/${currentPath}`,\n })\n }\n\n // Add current page\n breadcrumbs.push({\n label: title,\n href: `/docs/${version}/${slug}`,\n })\n\n return (\n <nav className=\"flex items-center gap-2 text-sm text-muted-foreground mb-4\" aria-label=\"Breadcrumb\">\n {breadcrumbs.map((crumb, index) => (\n <div key={crumb.href} className=\"flex items-center gap-2\">\n {index > 0 && <ChevronRight className=\"h-4 w-4\" />}\n {index === breadcrumbs.length - 1 ? (\n <span className=\"text-foreground font-medium\">{crumb.label}</span>\n ) : (\n <Link\n href={crumb.href}\n className=\"hover:text-foreground transition-colors\"\n >\n {crumb.label}\n </Link>\n )}\n </div>\n ))}\n </nav>\n )\n}\n","import { Clock, Calendar, User } from \"lucide-react\"\nimport type { DocMeta } from \"@/lib/mdx\"\nimport { getConfig, SpecraConfig } from \"@/lib/config\"\n\ninterface DocMetadataProps {\n meta: DocMeta\n config: SpecraConfig\n}\n\nexport function DocMetadata({ meta, config }: DocMetadataProps) {\n // Server component - can use getConfig directly\n // const config = getConfig()\n\n const showReadingTime = config.features?.showReadingTime && meta.reading_time\n const showLastUpdated = config.features?.showLastUpdated && meta.last_updated\n const showAuthors = config.features?.showAuthors && meta.authors?.length\n\n const hasMetadata = showReadingTime || showLastUpdated || showAuthors\n\n if (!hasMetadata) {\n return null\n }\n\n return (\n <div className=\"flex flex-wrap items-center gap-4 text-sm text-muted-foreground border-b border-border pb-4 mb-6\">\n {showReadingTime && (\n <div className=\"flex items-center gap-1.5\">\n <Clock className=\"h-4 w-4\" />\n <span>{meta.reading_time} min read</span>\n </div>\n )}\n\n {showLastUpdated && meta.last_updated && (\n <div className=\"flex items-center gap-1.5\">\n <Calendar className=\"h-4 w-4\" />\n <span>Updated {new Date(meta.last_updated).toLocaleDateString(meta.locale || 'en')}</span>\n </div>\n )}\n\n {showAuthors && (\n <div className=\"flex items-center gap-1.5\">\n <User className=\"h-4 w-4\" />\n <span>\n {meta.authors!.map((author, idx) => (\n <span key={author.id}>\n {author.name || author.id}\n {idx < meta.authors!.length - 1 && \", \"}\n </span>\n ))}\n </span>\n </div>\n )}\n </div>\n )\n}\n","import Link from \"next/link\"\nimport { ChevronLeft, ChevronRight } from \"lucide-react\"\n\ninterface DocNavigationProps {\n previousDoc?: {\n title: string\n slug: string\n }\n nextDoc?: {\n title: string\n slug: string\n }\n version: string\n}\n\nexport function DocNavigation({ previousDoc, nextDoc, version }: DocNavigationProps) {\n if (!previousDoc && !nextDoc) return null\n\n return (\n <div className=\"mt-12 pt-8 border-t border-border grid grid-cols-2 gap-4\">\n {previousDoc ? (\n <Link\n href={`/docs/${version}/${previousDoc.slug}`}\n className=\"group flex flex-col gap-2 p-4 rounded-xl border border-border hover:border-primary/50 hover:bg-muted/50 transition-all\"\n style={{\n textDecoration: \"none !important\"\n }}\n >\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <ChevronLeft className=\"h-4 w-4\" />\n <span>Previous</span>\n </div>\n <div className=\"text-base font-medium text-foreground group-hover:text-primary transition-colors\">\n {previousDoc.title}\n </div>\n </Link>\n ) : (\n <div />\n )}\n\n {nextDoc ? (\n <Link\n href={`/docs/${version}/${nextDoc.slug}`}\n className=\"group flex flex-col gap-2 p-4 rounded-xl border border-border hover:border-primary/50 hover:bg-muted/50 transition-all text-right\"\n style={{\n textDecoration: \"none !important\"\n }}\n >\n <div className=\"flex items-center justify-end gap-2 text-sm text-muted-foreground\">\n <span>Next</span>\n <ChevronRight className=\"h-4 w-4\" />\n </div>\n <div className=\"text-base font-medium text-foreground group-hover:text-primary transition-colors\">\n {nextDoc.title}\n </div>\n </Link>\n ) : (\n <div />\n )}\n </div>\n )\n}\n","import { Tag } from \"lucide-react\"\n\ninterface DocTagsProps {\n tags: string[]\n}\n\nexport function DocTags({ tags }: DocTagsProps) {\n if (!tags || tags.length === 0) {\n return null\n }\n\n return (\n <div className=\"flex flex-wrap items-center gap-2 mt-6 pt-6 border-t border-border\">\n <Tag className=\"h-4 w-4 text-muted-foreground\" />\n {tags.map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-primary/10 text-primary border border-primary/20\"\n >\n {tag}\n </span>\n ))}\n </div>\n )\n}\n","import { FileWarning } from \"lucide-react\"\n\nexport function DraftBadge() {\n return (\n <div className=\"inline-flex items-center gap-2 px-3 py-1.5 rounded-md bg-yellow-500/10 border border-yellow-500/20 text-yellow-600 dark:text-yellow-400 text-sm font-medium mb-4\">\n <FileWarning className=\"h-4 w-4\" />\n <span>Draft - Not visible in production</span>\n </div>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs","Link","ChevronRight","jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
|