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,76 @@
1
+ /**
2
+ * MDX Security Layer
3
+ *
4
+ * Protects against:
5
+ * - XSS via malicious MDX expressions
6
+ * - Path traversal attacks
7
+ * - Dangerous component usage
8
+ * - Cross-domain vulnerabilities
9
+ */
10
+ /**
11
+ * Sanitize file paths to prevent path traversal attacks
12
+ * Blocks: ../, ..\, absolute paths, encoded traversal attempts
13
+ */
14
+ export declare function sanitizePath(userPath: string): string;
15
+ /**
16
+ * Validate that a file path is within allowed directory
17
+ */
18
+ export declare function validatePathWithinDirectory(filePath: string, allowedDir: string): boolean;
19
+ /**
20
+ * Scan MDX content for dangerous patterns
21
+ * Returns array of detected issues
22
+ * Note: Skips content inside code blocks to avoid false positives
23
+ */
24
+ export declare function scanMDXForDangerousPatterns(content: string): string[];
25
+ /**
26
+ * Sanitize MDX content by removing/escaping dangerous patterns
27
+ * This is a defensive measure - ideally content should be rejected if dangerous
28
+ */
29
+ export declare function sanitizeMDXContent(content: string, strict?: boolean): string;
30
+ /**
31
+ * Content Security Policy configuration
32
+ * Use this in your Next.js middleware or headers config
33
+ */
34
+ export declare const CSP_DIRECTIVES: {
35
+ readonly "default-src": readonly ["'self'"];
36
+ readonly "script-src": readonly ["'self'", "'unsafe-inline'", "'unsafe-eval'"];
37
+ readonly "style-src": readonly ["'self'", "'unsafe-inline'"];
38
+ readonly "img-src": readonly ["'self'", "data:", "https:"];
39
+ readonly "font-src": readonly ["'self'", "data:"];
40
+ readonly "connect-src": readonly ["'self'"];
41
+ readonly "frame-src": readonly ["'self'"];
42
+ readonly "object-src": readonly ["'none'"];
43
+ readonly "base-uri": readonly ["'self'"];
44
+ readonly "form-action": readonly ["'self'"];
45
+ readonly "frame-ancestors": readonly ["'self'"];
46
+ readonly "upgrade-insecure-requests": readonly [];
47
+ };
48
+ /**
49
+ * Generate CSP header value from directives
50
+ */
51
+ export declare function generateCSPHeader(customDirectives?: Partial<typeof CSP_DIRECTIVES>, production?: boolean): string;
52
+ /**
53
+ * Allowlist of safe MDX components
54
+ * Only these components can be used in MDX files
55
+ */
56
+ export declare const SAFE_MDX_COMPONENTS: Set<string>;
57
+ /**
58
+ * Validate component usage in MDX
59
+ */
60
+ export declare function validateMDXComponents(content: string): {
61
+ valid: boolean;
62
+ issues: string[];
63
+ };
64
+ /**
65
+ * Comprehensive MDX security check
66
+ * Use this before processing MDX content
67
+ */
68
+ export declare function validateMDXSecurity(content: string, options?: {
69
+ strictMode?: boolean;
70
+ allowCustomComponents?: boolean;
71
+ blockDangerousPatterns?: boolean;
72
+ }): {
73
+ valid: boolean;
74
+ issues: string[];
75
+ sanitized?: string;
76
+ };
@@ -0,0 +1,217 @@
1
+ /**
2
+ * MDX Security Layer
3
+ *
4
+ * Protects against:
5
+ * - XSS via malicious MDX expressions
6
+ * - Path traversal attacks
7
+ * - Dangerous component usage
8
+ * - Cross-domain vulnerabilities
9
+ */
10
+ import path from "path";
11
+ /**
12
+ * Sanitize file paths to prevent path traversal attacks
13
+ * Blocks: ../, ..\, absolute paths, encoded traversal attempts
14
+ */
15
+ export function sanitizePath(userPath) {
16
+ // Decode URI components to catch encoded traversal attempts
17
+ const decoded = decodeURIComponent(userPath);
18
+ // Block path traversal patterns
19
+ if (decoded.includes("../") ||
20
+ decoded.includes("..\\") ||
21
+ decoded.includes("%2e%2e") ||
22
+ decoded.includes("%252e%252e") ||
23
+ path.isAbsolute(decoded)) {
24
+ throw new Error("Path traversal detected");
25
+ }
26
+ // Normalize and validate the path
27
+ const normalized = path.normalize(decoded).replace(/\\/g, "/");
28
+ // Ensure path doesn't escape after normalization
29
+ if (normalized.startsWith("..") || normalized.includes("/../")) {
30
+ throw new Error("Invalid path detected");
31
+ }
32
+ return normalized;
33
+ }
34
+ /**
35
+ * Validate that a file path is within allowed directory
36
+ */
37
+ export function validatePathWithinDirectory(filePath, allowedDir) {
38
+ const resolvedPath = path.resolve(allowedDir, filePath);
39
+ const resolvedDir = path.resolve(allowedDir);
40
+ return resolvedPath.startsWith(resolvedDir + path.sep) || resolvedPath === resolvedDir;
41
+ }
42
+ /**
43
+ * Dangerous MDX patterns that should be blocked
44
+ * These patterns can execute arbitrary code during SSR
45
+ */
46
+ const DANGEROUS_PATTERNS = [
47
+ // JavaScript execution
48
+ /eval\s*\(/gi,
49
+ /Function\s*\(/gi,
50
+ /import\s*\(/gi,
51
+ /require\s*\(/gi,
52
+ // File system access
53
+ /fs\.[a-z]+/gi,
54
+ /readFile/gi,
55
+ /writeFile/gi,
56
+ /process\.env/gi,
57
+ // Network requests during SSR (legitimate client-side usage should use components)
58
+ /fetch\s*\(/gi,
59
+ // Dangerous Node.js modules
60
+ /child_process/gi,
61
+ /exec\s*\(/gi,
62
+ /spawn\s*\(/gi,
63
+ // Script tag injection
64
+ /<script[>\s]/gi,
65
+ /javascript:/gi,
66
+ /\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.
67
+ ];
68
+ /**
69
+ * Remove code blocks from content to avoid scanning code examples
70
+ * This prevents false positives from documentation code examples
71
+ */
72
+ function removeCodeBlocks(content) {
73
+ // Remove fenced code blocks (```...```)
74
+ let withoutCodeBlocks = content.replace(/```[\s\S]*?```/g, '');
75
+ // Remove inline code (`...`)
76
+ withoutCodeBlocks = withoutCodeBlocks.replace(/`[^`]*`/g, '');
77
+ return withoutCodeBlocks;
78
+ }
79
+ /**
80
+ * Scan MDX content for dangerous patterns
81
+ * Returns array of detected issues
82
+ * Note: Skips content inside code blocks to avoid false positives
83
+ */
84
+ export function scanMDXForDangerousPatterns(content) {
85
+ const issues = [];
86
+ // Remove code blocks before scanning to avoid false positives
87
+ const contentWithoutCode = removeCodeBlocks(content);
88
+ for (const pattern of DANGEROUS_PATTERNS) {
89
+ const matches = contentWithoutCode.match(pattern);
90
+ if (matches) {
91
+ issues.push(`Dangerous pattern detected: ${pattern.source}`);
92
+ }
93
+ }
94
+ return issues;
95
+ }
96
+ /**
97
+ * Sanitize MDX content by removing/escaping dangerous patterns
98
+ * This is a defensive measure - ideally content should be rejected if dangerous
99
+ */
100
+ export function sanitizeMDXContent(content, strict = false) {
101
+ if (strict) {
102
+ const issues = scanMDXForDangerousPatterns(content);
103
+ if (issues.length > 0) {
104
+ throw new Error(`MDX content contains dangerous patterns: ${issues.join(", ")}`);
105
+ }
106
+ }
107
+ // Remove inline script tags
108
+ let sanitized = content.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "");
109
+ // Remove event handlers from HTML tags
110
+ sanitized = sanitized.replace(/\s+on\w+\s*=\s*["'][^"']*["']/gi, "");
111
+ // Remove javascript: protocol
112
+ sanitized = sanitized.replace(/javascript:/gi, "");
113
+ return sanitized;
114
+ }
115
+ /**
116
+ * Content Security Policy configuration
117
+ * Use this in your Next.js middleware or headers config
118
+ */
119
+ export const CSP_DIRECTIVES = {
120
+ "default-src": ["'self'"],
121
+ "script-src": [
122
+ "'self'",
123
+ "'unsafe-inline'", // Required for Next.js
124
+ "'unsafe-eval'", // Required for dev mode - remove in production
125
+ ],
126
+ "style-src": ["'self'", "'unsafe-inline'"], // Required for styled-components/emotion
127
+ "img-src": ["'self'", "data:", "https:"],
128
+ "font-src": ["'self'", "data:"],
129
+ "connect-src": ["'self'"],
130
+ "frame-src": ["'self'"],
131
+ "object-src": ["'none'"],
132
+ "base-uri": ["'self'"],
133
+ "form-action": ["'self'"],
134
+ "frame-ancestors": ["'self'"],
135
+ "upgrade-insecure-requests": [],
136
+ };
137
+ /**
138
+ * Generate CSP header value from directives
139
+ */
140
+ export function generateCSPHeader(customDirectives, production = true) {
141
+ const directives = { ...CSP_DIRECTIVES, ...customDirectives };
142
+ // Remove unsafe-eval in production
143
+ if (production && directives["script-src"]) {
144
+ directives["script-src"] = directives["script-src"].filter((src) => src !== "'unsafe-eval'");
145
+ }
146
+ return Object.entries(directives)
147
+ .map(([key, values]) => `${key} ${values.join(" ")}`)
148
+ .join("; ");
149
+ }
150
+ /**
151
+ * Allowlist of safe MDX components
152
+ * Only these components can be used in MDX files
153
+ */
154
+ export const SAFE_MDX_COMPONENTS = new Set([
155
+ // Standard HTML elements (automatically allowed by MDX)
156
+ "h1", "h2", "h3", "h4", "h5", "h6",
157
+ "p", "a", "ul", "ol", "li", "code", "pre",
158
+ "blockquote", "table", "thead", "tbody", "tr", "th", "td",
159
+ "img", "video", "audio", "br", "hr", "strong", "em",
160
+ // Custom safe components
161
+ "Callout", "CodeBlock", "Accordion", "AccordionItem",
162
+ "Tabs", "Tab", "Image", "Video", "Card", "CardGrid",
163
+ "ImageCard", "ImageCardGrid", "Steps", "Step",
164
+ "Icon", "Mermaid", "Math", "Columns", "Column",
165
+ "Badge", "Tooltip", "Frame",
166
+ "ApiEndpoint", "ApiParams", "ApiResponse", "ApiPlayground", "ApiReference",
167
+ ]);
168
+ /**
169
+ * Validate component usage in MDX
170
+ */
171
+ export function validateMDXComponents(content) {
172
+ const issues = [];
173
+ // Find all JSX-like component usage
174
+ const componentRegex = /<([A-Z][a-zA-Z0-9]*)/g;
175
+ let match;
176
+ while ((match = componentRegex.exec(content)) !== null) {
177
+ const componentName = match[1];
178
+ if (!SAFE_MDX_COMPONENTS.has(componentName)) {
179
+ issues.push(`Unsafe component detected: ${componentName}`);
180
+ }
181
+ }
182
+ return {
183
+ valid: issues.length === 0,
184
+ issues,
185
+ };
186
+ }
187
+ /**
188
+ * Comprehensive MDX security check
189
+ * Use this before processing MDX content
190
+ */
191
+ export function validateMDXSecurity(content, options = {}) {
192
+ const { strictMode = false, allowCustomComponents = true, blockDangerousPatterns = true, } = options;
193
+ const issues = [];
194
+ // Check for dangerous patterns
195
+ if (blockDangerousPatterns) {
196
+ const patternIssues = scanMDXForDangerousPatterns(content);
197
+ issues.push(...patternIssues);
198
+ }
199
+ // Validate components
200
+ if (!allowCustomComponents) {
201
+ const componentValidation = validateMDXComponents(content);
202
+ if (!componentValidation.valid) {
203
+ issues.push(...componentValidation.issues);
204
+ }
205
+ }
206
+ // In strict mode, reject any issues
207
+ if (strictMode && issues.length > 0) {
208
+ return { valid: false, issues };
209
+ }
210
+ // Otherwise, sanitize and warn
211
+ const sanitized = sanitizeMDXContent(content, false);
212
+ return {
213
+ valid: true,
214
+ issues,
215
+ sanitized,
216
+ };
217
+ }
package/dist/mdx.d.ts ADDED
@@ -0,0 +1,73 @@
1
+ import type { I18nConfig } from "./config.types";
2
+ /**
3
+ * Structured node type for MDX content rendering.
4
+ * Used to pass a JSON-serializable tree from server to client,
5
+ * allowing the client-side recursive renderer to instantiate
6
+ * real Svelte components for custom tags.
7
+ */
8
+ export interface MdxNode {
9
+ type: 'html' | 'component';
10
+ content?: string;
11
+ name?: string;
12
+ props?: Record<string, any>;
13
+ children?: MdxNode[];
14
+ }
15
+ export interface DocMeta {
16
+ title: string;
17
+ description?: string;
18
+ slug?: string;
19
+ section?: string;
20
+ group?: string;
21
+ sidebar?: string;
22
+ order?: number;
23
+ sidebar_position?: number;
24
+ content?: string;
25
+ last_updated?: string;
26
+ draft?: boolean;
27
+ authors?: Array<{
28
+ id: string;
29
+ name?: string;
30
+ }>;
31
+ tags?: string[];
32
+ redirect_from?: string[];
33
+ reading_time?: number;
34
+ word_count?: number;
35
+ icon?: string;
36
+ tab_group?: string;
37
+ locale?: string;
38
+ protected?: boolean;
39
+ isProtected?: boolean;
40
+ }
41
+ export interface Doc {
42
+ slug: string;
43
+ filePath: string;
44
+ title: string;
45
+ meta: DocMeta;
46
+ content: string;
47
+ contentNodes?: MdxNode[];
48
+ categoryLabel?: string;
49
+ categoryPosition?: number;
50
+ categoryCollapsible?: boolean;
51
+ categoryCollapsed?: boolean;
52
+ categoryIcon?: string;
53
+ categoryTabGroup?: string;
54
+ locale?: string;
55
+ }
56
+ export interface TocItem {
57
+ id: string;
58
+ title: string;
59
+ level: number;
60
+ }
61
+ export declare function getVersions(): string[];
62
+ export declare function getI18nConfig(): I18nConfig | null;
63
+ export declare function getDocBySlug(slug: string, version?: string, locale?: string): Promise<Doc | null>;
64
+ export declare function getAllDocs(version?: string, locale?: string): Doc[];
65
+ export declare function getAdjacentDocs(currentSlug: string, allDocs: Doc[]): {
66
+ previous?: Doc;
67
+ next?: Doc;
68
+ };
69
+ export declare function extractTableOfContents(content: string): TocItem[];
70
+ /**
71
+ * Check if a slug represents a category (has child documents)
72
+ */
73
+ export declare function isCategoryPage(slug: string, allDocs: Doc[]): boolean;