boltdocs 1.3.0 → 1.3.1

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 (101) hide show
  1. package/dist/node/index.js +21 -6
  2. package/dist/node/index.mjs +21 -6
  3. package/package.json +1 -1
  4. package/src/client/app/index.tsx +344 -344
  5. package/src/client/app/preload.tsx +56 -56
  6. package/src/client/index.ts +40 -40
  7. package/src/client/ssr.tsx +51 -51
  8. package/src/client/theme/components/CodeBlock/CodeBlock.tsx +76 -76
  9. package/src/client/theme/components/CodeBlock/index.ts +1 -1
  10. package/src/client/theme/components/PackageManagerTabs/PackageManagerTabs.tsx +154 -154
  11. package/src/client/theme/components/PackageManagerTabs/index.ts +1 -1
  12. package/src/client/theme/components/PackageManagerTabs/pkg-tabs.css +64 -64
  13. package/src/client/theme/components/Playground/Playground.tsx +124 -124
  14. package/src/client/theme/components/Playground/index.ts +1 -1
  15. package/src/client/theme/components/Playground/playground.css +168 -168
  16. package/src/client/theme/components/Video/Video.tsx +84 -84
  17. package/src/client/theme/components/Video/index.ts +1 -1
  18. package/src/client/theme/components/Video/video.css +41 -41
  19. package/src/client/theme/components/mdx/Admonition.tsx +80 -80
  20. package/src/client/theme/components/mdx/Badge.tsx +31 -31
  21. package/src/client/theme/components/mdx/Button.tsx +50 -50
  22. package/src/client/theme/components/mdx/Card.tsx +80 -80
  23. package/src/client/theme/components/mdx/List.tsx +57 -57
  24. package/src/client/theme/components/mdx/Tabs.tsx +94 -94
  25. package/src/client/theme/components/mdx/index.ts +18 -18
  26. package/src/client/theme/components/mdx/mdx-components.css +424 -424
  27. package/src/client/theme/icons/bun.tsx +62 -62
  28. package/src/client/theme/icons/deno.tsx +20 -20
  29. package/src/client/theme/icons/discord.tsx +12 -12
  30. package/src/client/theme/icons/github.tsx +15 -15
  31. package/src/client/theme/icons/npm.tsx +13 -13
  32. package/src/client/theme/icons/pnpm.tsx +72 -72
  33. package/src/client/theme/icons/twitter.tsx +12 -12
  34. package/src/client/theme/styles/markdown.css +343 -343
  35. package/src/client/theme/styles/variables.css +162 -162
  36. package/src/client/theme/styles.css +37 -37
  37. package/src/client/theme/ui/BackgroundGradient/BackgroundGradient.tsx +10 -10
  38. package/src/client/theme/ui/BackgroundGradient/index.ts +1 -1
  39. package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +68 -68
  40. package/src/client/theme/ui/Breadcrumbs/index.ts +1 -1
  41. package/src/client/theme/ui/Footer/footer.css +32 -32
  42. package/src/client/theme/ui/Head/Head.tsx +69 -69
  43. package/src/client/theme/ui/Head/index.ts +1 -1
  44. package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +125 -125
  45. package/src/client/theme/ui/LanguageSwitcher/index.ts +1 -1
  46. package/src/client/theme/ui/LanguageSwitcher/language-switcher.css +98 -98
  47. package/src/client/theme/ui/Layout/Layout.tsx +202 -202
  48. package/src/client/theme/ui/Layout/base.css +76 -76
  49. package/src/client/theme/ui/Layout/index.ts +2 -2
  50. package/src/client/theme/ui/Layout/pagination.css +72 -72
  51. package/src/client/theme/ui/Layout/responsive.css +36 -36
  52. package/src/client/theme/ui/Link/Link.tsx +254 -254
  53. package/src/client/theme/ui/Link/index.ts +2 -2
  54. package/src/client/theme/ui/Loading/Loading.tsx +10 -10
  55. package/src/client/theme/ui/Loading/index.ts +1 -1
  56. package/src/client/theme/ui/Loading/loading.css +30 -30
  57. package/src/client/theme/ui/Navbar/GithubStars.tsx +27 -27
  58. package/src/client/theme/ui/Navbar/Navbar.tsx +145 -145
  59. package/src/client/theme/ui/Navbar/index.ts +2 -2
  60. package/src/client/theme/ui/Navbar/navbar.css +233 -233
  61. package/src/client/theme/ui/NotFound/NotFound.tsx +19 -19
  62. package/src/client/theme/ui/NotFound/index.ts +1 -1
  63. package/src/client/theme/ui/NotFound/not-found.css +64 -64
  64. package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +235 -235
  65. package/src/client/theme/ui/OnThisPage/index.ts +1 -1
  66. package/src/client/theme/ui/OnThisPage/toc.css +132 -132
  67. package/src/client/theme/ui/PoweredBy/PoweredBy.tsx +18 -18
  68. package/src/client/theme/ui/PoweredBy/index.ts +1 -1
  69. package/src/client/theme/ui/PoweredBy/powered-by.css +76 -76
  70. package/src/client/theme/ui/SearchDialog/SearchDialog.tsx +199 -199
  71. package/src/client/theme/ui/SearchDialog/index.ts +1 -1
  72. package/src/client/theme/ui/SearchDialog/search.css +152 -152
  73. package/src/client/theme/ui/Sidebar/Sidebar.tsx +204 -204
  74. package/src/client/theme/ui/Sidebar/index.ts +1 -1
  75. package/src/client/theme/ui/Sidebar/sidebar.css +236 -236
  76. package/src/client/theme/ui/ThemeToggle/ThemeToggle.tsx +69 -69
  77. package/src/client/theme/ui/ThemeToggle/index.ts +1 -1
  78. package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +136 -136
  79. package/src/client/theme/ui/VersionSwitcher/index.ts +1 -1
  80. package/src/client/types.ts +50 -50
  81. package/src/client/utils.ts +26 -26
  82. package/src/node/cache.ts +408 -408
  83. package/src/node/config.ts +192 -192
  84. package/src/node/index.ts +21 -21
  85. package/src/node/mdx.ts +120 -120
  86. package/src/node/plugin/entry.ts +58 -58
  87. package/src/node/plugin/html.ts +55 -55
  88. package/src/node/plugin/index.ts +193 -193
  89. package/src/node/plugin/types.ts +11 -11
  90. package/src/node/routes/cache.ts +28 -28
  91. package/src/node/routes/index.ts +167 -167
  92. package/src/node/routes/parser.ts +153 -127
  93. package/src/node/routes/sorter.ts +42 -42
  94. package/src/node/routes/types.ts +49 -49
  95. package/src/node/ssg/index.ts +114 -114
  96. package/src/node/ssg/meta.ts +34 -34
  97. package/src/node/ssg/options.ts +13 -13
  98. package/src/node/ssg/sitemap.ts +54 -54
  99. package/src/node/utils.ts +134 -134
  100. package/tsconfig.json +20 -20
  101. package/tsup.config.ts +22 -22
@@ -445,8 +445,18 @@ var import_path2 = __toESM(require("path"));
445
445
  var import_github_slugger = __toESM(require("github-slugger"));
446
446
  init_utils();
447
447
  function parseDocFile(file, docsDir, basePath, config) {
448
+ const decodedFile = decodeURIComponent(file);
449
+ const absoluteFile = import_path2.default.resolve(decodedFile);
450
+ const absoluteDocsDir = import_path2.default.resolve(docsDir);
451
+ const relativePath = normalizePath(
452
+ import_path2.default.relative(absoluteDocsDir, absoluteFile)
453
+ );
454
+ if (relativePath.startsWith("../") || relativePath === ".." || absoluteFile.includes("\0")) {
455
+ throw new Error(
456
+ `Security breach: File is outside of docs directory or contains null bytes: ${file}`
457
+ );
458
+ }
448
459
  const { data, content } = parseFrontmatter(file);
449
- const relativePath = normalizePath(import_path2.default.relative(docsDir, file));
450
460
  let parts = relativePath.split("/");
451
461
  let locale;
452
462
  let version;
@@ -492,25 +502,30 @@ function parseDocFile(file, docsDir, basePath, config) {
492
502
  const level = match[1].length;
493
503
  const text = match[2].replace(/\[([^\]]+)\]\([^\)]+\)/g, "$1").replace(/[_*`]/g, "").trim();
494
504
  const id = slugger.slug(text);
495
- headings.push({ level, text, id });
505
+ headings.push({ level, text: escapeHtml(text), id });
496
506
  }
507
+ const sanitizedTitle = data.title ? escapeHtml(data.title) : inferredTitle;
508
+ const sanitizedDescription = data.description ? escapeHtml(data.description) : "";
509
+ const sanitizedBadge = data.badge ? escapeHtml(data.badge) : void 0;
497
510
  return {
498
511
  route: {
499
512
  path: finalPath,
500
513
  componentPath: file,
501
514
  filePath: relativePath,
502
- title: data.title || inferredTitle,
503
- description: data.description || "",
515
+ title: sanitizedTitle,
516
+ description: sanitizedDescription,
504
517
  sidebarPosition,
505
518
  headings,
506
519
  locale,
507
520
  version,
508
- badge: data.badge
521
+ badge: sanitizedBadge
509
522
  },
510
523
  relativeDir: cleanDirName,
511
524
  isGroupIndex,
512
525
  groupMeta: isGroupIndex ? {
513
- title: data.groupTitle || data.title || (cleanDirName ? capitalize(cleanDirName) : ""),
526
+ title: escapeHtml(
527
+ data.groupTitle || data.title || (cleanDirName ? capitalize(cleanDirName) : "")
528
+ ),
514
529
  position: data.groupPosition ?? data.sidebarPosition ?? (rawDirName ? extractNumberPrefix(rawDirName) : void 0)
515
530
  } : void 0,
516
531
  inferredGroupPosition: rawDirName ? extractNumberPrefix(rawDirName) : void 0
@@ -30,8 +30,18 @@ function invalidateFile(filePath) {
30
30
  import path from "path";
31
31
  import GithubSlugger from "github-slugger";
32
32
  function parseDocFile(file, docsDir, basePath, config) {
33
+ const decodedFile = decodeURIComponent(file);
34
+ const absoluteFile = path.resolve(decodedFile);
35
+ const absoluteDocsDir = path.resolve(docsDir);
36
+ const relativePath = normalizePath(
37
+ path.relative(absoluteDocsDir, absoluteFile)
38
+ );
39
+ if (relativePath.startsWith("../") || relativePath === ".." || absoluteFile.includes("\0")) {
40
+ throw new Error(
41
+ `Security breach: File is outside of docs directory or contains null bytes: ${file}`
42
+ );
43
+ }
33
44
  const { data, content } = parseFrontmatter(file);
34
- const relativePath = normalizePath(path.relative(docsDir, file));
35
45
  let parts = relativePath.split("/");
36
46
  let locale;
37
47
  let version;
@@ -77,25 +87,30 @@ function parseDocFile(file, docsDir, basePath, config) {
77
87
  const level = match[1].length;
78
88
  const text = match[2].replace(/\[([^\]]+)\]\([^\)]+\)/g, "$1").replace(/[_*`]/g, "").trim();
79
89
  const id = slugger.slug(text);
80
- headings.push({ level, text, id });
90
+ headings.push({ level, text: escapeHtml(text), id });
81
91
  }
92
+ const sanitizedTitle = data.title ? escapeHtml(data.title) : inferredTitle;
93
+ const sanitizedDescription = data.description ? escapeHtml(data.description) : "";
94
+ const sanitizedBadge = data.badge ? escapeHtml(data.badge) : void 0;
82
95
  return {
83
96
  route: {
84
97
  path: finalPath,
85
98
  componentPath: file,
86
99
  filePath: relativePath,
87
- title: data.title || inferredTitle,
88
- description: data.description || "",
100
+ title: sanitizedTitle,
101
+ description: sanitizedDescription,
89
102
  sidebarPosition,
90
103
  headings,
91
104
  locale,
92
105
  version,
93
- badge: data.badge
106
+ badge: sanitizedBadge
94
107
  },
95
108
  relativeDir: cleanDirName,
96
109
  isGroupIndex,
97
110
  groupMeta: isGroupIndex ? {
98
- title: data.groupTitle || data.title || (cleanDirName ? capitalize(cleanDirName) : ""),
111
+ title: escapeHtml(
112
+ data.groupTitle || data.title || (cleanDirName ? capitalize(cleanDirName) : "")
113
+ ),
99
114
  position: data.groupPosition ?? data.sidebarPosition ?? (rawDirName ? extractNumberPrefix(rawDirName) : void 0)
100
115
  } : void 0,
101
116
  inferredGroupPosition: rawDirName ? extractNumberPrefix(rawDirName) : void 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "boltdocs",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "A lightweight documentation generator for React projects.",
5
5
  "main": "dist/node/index.js",
6
6
  "module": "dist/node/index.mjs",