specra 0.1.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 (142) hide show
  1. package/LICENSE.MD +21 -0
  2. package/README.md +157 -0
  3. package/dist/app/api/mdx-watch/route.d.mts +12 -0
  4. package/dist/app/api/mdx-watch/route.d.ts +12 -0
  5. package/dist/app/api/mdx-watch/route.js +98 -0
  6. package/dist/app/api/mdx-watch/route.js.map +1 -0
  7. package/dist/app/api/mdx-watch/route.mjs +71 -0
  8. package/dist/app/api/mdx-watch/route.mjs.map +1 -0
  9. package/dist/app/docs-page.d.mts +32 -0
  10. package/dist/app/docs-page.d.ts +32 -0
  11. package/dist/app/docs-page.js +4072 -0
  12. package/dist/app/docs-page.js.map +1 -0
  13. package/dist/app/docs-page.mjs +14 -0
  14. package/dist/app/docs-page.mjs.map +1 -0
  15. package/dist/app/layout.css +297 -0
  16. package/dist/app/layout.css.map +1 -0
  17. package/dist/app/layout.d.mts +19 -0
  18. package/dist/app/layout.d.ts +19 -0
  19. package/dist/app/layout.js +112 -0
  20. package/dist/app/layout.js.map +1 -0
  21. package/dist/app/layout.mjs +13 -0
  22. package/dist/app/layout.mjs.map +1 -0
  23. package/dist/chunk-DR4EPLMT.mjs +1013 -0
  24. package/dist/chunk-DR4EPLMT.mjs.map +1 -0
  25. package/dist/chunk-INL2EC72.mjs +170 -0
  26. package/dist/chunk-INL2EC72.mjs.map +1 -0
  27. package/dist/chunk-IZFGEAD6.mjs +61 -0
  28. package/dist/chunk-IZFGEAD6.mjs.map +1 -0
  29. package/dist/chunk-KTRWWAGL.mjs +50 -0
  30. package/dist/chunk-KTRWWAGL.mjs.map +1 -0
  31. package/dist/chunk-MZJHJ6BV.mjs +21 -0
  32. package/dist/chunk-MZJHJ6BV.mjs.map +1 -0
  33. package/dist/chunk-NXRIAL7T.mjs +3119 -0
  34. package/dist/chunk-NXRIAL7T.mjs.map +1 -0
  35. package/dist/components/index.d.mts +822 -0
  36. package/dist/components/index.d.ts +822 -0
  37. package/dist/components/index.js +3738 -0
  38. package/dist/components/index.js.map +1 -0
  39. package/dist/components/index.mjs +3627 -0
  40. package/dist/components/index.mjs.map +1 -0
  41. package/dist/index.css +297 -0
  42. package/dist/index.css.map +1 -0
  43. package/dist/index.d.mts +545 -0
  44. package/dist/index.d.ts +545 -0
  45. package/dist/index.js +4648 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/index.mjs +347 -0
  48. package/dist/index.mjs.map +1 -0
  49. package/dist/lib/index.d.mts +798 -0
  50. package/dist/lib/index.d.ts +798 -0
  51. package/dist/lib/index.js +1301 -0
  52. package/dist/lib/index.js.map +1 -0
  53. package/dist/lib/index.mjs +89 -0
  54. package/dist/lib/index.mjs.map +1 -0
  55. package/package.json +119 -0
  56. package/src/app/api/mdx-watch/route.ts +86 -0
  57. package/src/app/docs-page.tsx +212 -0
  58. package/src/app/layout.tsx +74 -0
  59. package/src/components/docs/accordion.tsx +53 -0
  60. package/src/components/docs/api/api-endpoint.tsx +59 -0
  61. package/src/components/docs/api/api-params.tsx +43 -0
  62. package/src/components/docs/api/api-playground.tsx +233 -0
  63. package/src/components/docs/api/api-reference.tsx +291 -0
  64. package/src/components/docs/api/api-response.tsx +48 -0
  65. package/src/components/docs/api/index.ts +5 -0
  66. package/src/components/docs/badge.tsx +22 -0
  67. package/src/components/docs/breadcrumb.tsx +51 -0
  68. package/src/components/docs/callout.tsx +109 -0
  69. package/src/components/docs/card.tsx +84 -0
  70. package/src/components/docs/category-index.tsx +112 -0
  71. package/src/components/docs/code-block.tsx +129 -0
  72. package/src/components/docs/columns.tsx +45 -0
  73. package/src/components/docs/componentTextProps.ts +85 -0
  74. package/src/components/docs/dev-mode-badge.tsx +35 -0
  75. package/src/components/docs/doc-layout-wrapper.tsx +54 -0
  76. package/src/components/docs/doc-layout.tsx +111 -0
  77. package/src/components/docs/doc-loading.tsx +15 -0
  78. package/src/components/docs/doc-metadata.tsx +55 -0
  79. package/src/components/docs/doc-navigation.tsx +62 -0
  80. package/src/components/docs/doc-tags.tsx +25 -0
  81. package/src/components/docs/draft-badge.tsx +10 -0
  82. package/src/components/docs/footer.tsx +47 -0
  83. package/src/components/docs/frame.tsx +22 -0
  84. package/src/components/docs/header.tsx +122 -0
  85. package/src/components/docs/hot-reload-indicator.tsx +77 -0
  86. package/src/components/docs/icon.tsx +70 -0
  87. package/src/components/docs/image-card.tsx +95 -0
  88. package/src/components/docs/image.tsx +73 -0
  89. package/src/components/docs/index.ts +48 -0
  90. package/src/components/docs/math.tsx +46 -0
  91. package/src/components/docs/mdx-components.tsx +166 -0
  92. package/src/components/docs/mdx-hot-reload.tsx +37 -0
  93. package/src/components/docs/mermaid.tsx +77 -0
  94. package/src/components/docs/mobile-doc-layout.tsx +115 -0
  95. package/src/components/docs/not-found-content.tsx +55 -0
  96. package/src/components/docs/search-highlight.tsx +127 -0
  97. package/src/components/docs/search-modal.tsx +223 -0
  98. package/src/components/docs/sidebar-skeleton.tsx +39 -0
  99. package/src/components/docs/sidebar.tsx +323 -0
  100. package/src/components/docs/site-banner.tsx +92 -0
  101. package/src/components/docs/steps.tsx +29 -0
  102. package/src/components/docs/tab-context.tsx +28 -0
  103. package/src/components/docs/tab-groups.tsx +50 -0
  104. package/src/components/docs/table-of-contents.tsx +104 -0
  105. package/src/components/docs/tabs.tsx +63 -0
  106. package/src/components/docs/theme-toggle.tsx +39 -0
  107. package/src/components/docs/tooltip.tsx +37 -0
  108. package/src/components/docs/version-switcher.tsx +52 -0
  109. package/src/components/docs/video.tsx +80 -0
  110. package/src/components/global/index.ts +3 -0
  111. package/src/components/global/version-not-found.tsx +26 -0
  112. package/src/components/index.ts +8 -0
  113. package/src/components/theme-provider.tsx +11 -0
  114. package/src/components/ui/badge.tsx +46 -0
  115. package/src/components/ui/button.tsx +60 -0
  116. package/src/components/ui/dialog.tsx +143 -0
  117. package/src/components/ui/index.ts +6 -0
  118. package/src/components/ui/input.tsx +21 -0
  119. package/src/components/ui/textarea.tsx +18 -0
  120. package/src/index.ts +41 -0
  121. package/src/lib/api-parser.types.ts +78 -0
  122. package/src/lib/api.types.ts +202 -0
  123. package/src/lib/category.ts +71 -0
  124. package/src/lib/config.server.ts +170 -0
  125. package/src/lib/config.ts +20 -0
  126. package/src/lib/config.types.ts +295 -0
  127. package/src/lib/dev-utils.ts +75 -0
  128. package/src/lib/index.ts +27 -0
  129. package/src/lib/mdx-cache.ts +200 -0
  130. package/src/lib/mdx.ts +402 -0
  131. package/src/lib/parsers/base-parser.ts +16 -0
  132. package/src/lib/parsers/index.ts +69 -0
  133. package/src/lib/parsers/openapi-parser.ts +251 -0
  134. package/src/lib/parsers/postman-parser.ts +301 -0
  135. package/src/lib/parsers/specra-parser.ts +24 -0
  136. package/src/lib/redirects.ts +40 -0
  137. package/src/lib/remark-code-meta.ts +23 -0
  138. package/src/lib/sidebar-utils.ts +188 -0
  139. package/src/lib/toc.ts +24 -0
  140. package/src/lib/utils.ts +36 -0
  141. package/src/specra.config.json +124 -0
  142. package/src/styles/globals.css +427 -0
@@ -0,0 +1,1013 @@
1
+ // src/lib/category.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ var DOCS_DIR = path.join(process.cwd(), "docs");
5
+ function getCategoryConfig(folderPath) {
6
+ try {
7
+ const categoryPath = path.join(folderPath, "_category_.json");
8
+ if (!fs.existsSync(categoryPath)) {
9
+ return null;
10
+ }
11
+ const content = fs.readFileSync(categoryPath, "utf8");
12
+ return JSON.parse(content);
13
+ } catch (error) {
14
+ console.error(`Error reading category config from ${folderPath}:`, error);
15
+ return null;
16
+ }
17
+ }
18
+ function getAllCategoryConfigs(version) {
19
+ const configs = /* @__PURE__ */ new Map();
20
+ const versionDir = path.join(DOCS_DIR, version);
21
+ if (!fs.existsSync(versionDir)) {
22
+ return configs;
23
+ }
24
+ function scanDirectory(dir, relativePath = "") {
25
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
26
+ for (const entry of entries) {
27
+ if (entry.isDirectory()) {
28
+ const fullPath = path.join(dir, entry.name);
29
+ const relPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
30
+ const config = getCategoryConfig(fullPath);
31
+ if (config) {
32
+ configs.set(relPath, config);
33
+ }
34
+ scanDirectory(fullPath, relPath);
35
+ }
36
+ }
37
+ }
38
+ scanDirectory(versionDir);
39
+ return configs;
40
+ }
41
+
42
+ // src/lib/sidebar-utils.ts
43
+ function sortSidebarItems(items) {
44
+ return [...items].sort((a, b) => {
45
+ const posA = a.sidebar_position ?? a.meta?.sidebar_position ?? a.meta?.order ?? 999;
46
+ const posB = b.sidebar_position ?? b.meta?.sidebar_position ?? b.meta?.order ?? 999;
47
+ return posA - posB;
48
+ });
49
+ }
50
+ function sortSidebarGroups(groups) {
51
+ return Object.entries(groups).sort(([, a], [, b]) => {
52
+ const posA = a.position ?? 999;
53
+ const posB = b.position ?? 999;
54
+ return posA - posB;
55
+ });
56
+ }
57
+ function buildSidebarStructure(docs) {
58
+ const rootGroups = {};
59
+ const standalone = [];
60
+ const categoryMetadata = /* @__PURE__ */ new Map();
61
+ docs.forEach((doc) => {
62
+ const pathParts = doc.filePath.split("/");
63
+ const folderPath = pathParts.length > 1 ? pathParts.slice(0, -1).join("/") : "";
64
+ if (folderPath && doc.categoryLabel) {
65
+ categoryMetadata.set(folderPath, {
66
+ label: doc.categoryLabel,
67
+ position: doc.categoryPosition,
68
+ icon: doc.categoryIcon,
69
+ collapsible: doc.categoryCollapsible,
70
+ collapsed: doc.categoryCollapsed
71
+ });
72
+ }
73
+ });
74
+ docs.forEach((doc) => {
75
+ const pathParts = doc.filePath.split("/");
76
+ const isIndexFile = doc.filePath.endsWith("/index") || doc.filePath === "index" || pathParts.length > 1 && doc.slug === pathParts.slice(0, -1).join("/");
77
+ const customGroup = doc.meta.sidebar || doc.meta.group;
78
+ if (customGroup) {
79
+ const groupName = customGroup.charAt(0).toUpperCase() + customGroup.slice(1);
80
+ if (!rootGroups[groupName]) {
81
+ rootGroups[groupName] = {
82
+ label: groupName,
83
+ path: customGroup,
84
+ items: [],
85
+ position: 999,
86
+ collapsible: doc.categoryCollapsible ?? true,
87
+ defaultCollapsed: doc.categoryCollapsed ?? false,
88
+ children: {}
89
+ };
90
+ }
91
+ if (isIndexFile) {
92
+ rootGroups[groupName].position = doc.categoryPosition ?? doc.meta.sidebar_position ?? 999;
93
+ rootGroups[groupName].icon = doc.categoryIcon;
94
+ } else {
95
+ rootGroups[groupName].items.push(doc);
96
+ }
97
+ return;
98
+ }
99
+ if (pathParts.length > 1) {
100
+ const folderParts = pathParts.slice(0, -1);
101
+ let currentLevel = rootGroups;
102
+ let currentPath = "";
103
+ for (let i = 0; i < folderParts.length; i++) {
104
+ const folder = folderParts[i];
105
+ currentPath = currentPath ? `${currentPath}/${folder}` : folder;
106
+ const folderLabel = folder.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
107
+ const metadata = categoryMetadata.get(currentPath);
108
+ if (!currentLevel[folder]) {
109
+ currentLevel[folder] = {
110
+ label: metadata?.label ?? folderLabel,
111
+ path: currentPath,
112
+ icon: metadata?.icon,
113
+ items: [],
114
+ position: metadata?.position ?? 999,
115
+ collapsible: metadata?.collapsible ?? true,
116
+ defaultCollapsed: metadata?.collapsed ?? false,
117
+ children: {}
118
+ };
119
+ }
120
+ if (i === folderParts.length - 1) {
121
+ if (isIndexFile) {
122
+ currentLevel[folder].position = doc.categoryPosition ?? doc.meta.sidebar_position ?? currentLevel[folder].position;
123
+ if (doc.categoryLabel) {
124
+ currentLevel[folder].label = doc.categoryLabel;
125
+ }
126
+ if (doc.categoryIcon) {
127
+ currentLevel[folder].icon = doc.categoryIcon;
128
+ }
129
+ if (doc.categoryCollapsible !== void 0) {
130
+ currentLevel[folder].collapsible = doc.categoryCollapsible;
131
+ }
132
+ if (doc.categoryCollapsed !== void 0) {
133
+ currentLevel[folder].defaultCollapsed = doc.categoryCollapsed;
134
+ }
135
+ } else {
136
+ currentLevel[folder].items.push(doc);
137
+ }
138
+ }
139
+ currentLevel = currentLevel[folder].children;
140
+ }
141
+ } else {
142
+ if (!isIndexFile) {
143
+ standalone.push(doc);
144
+ }
145
+ }
146
+ });
147
+ return { rootGroups, standalone };
148
+ }
149
+
150
+ // src/lib/mdx.ts
151
+ import fs2 from "fs";
152
+ import path2 from "path";
153
+ import matter from "gray-matter";
154
+ var DOCS_DIR2 = path2.join(process.cwd(), "docs");
155
+ function calculateReadingTime(content) {
156
+ const words = content.trim().split(/\s+/).length;
157
+ const minutes = Math.ceil(words / 200);
158
+ return { minutes, words };
159
+ }
160
+ function getVersions() {
161
+ try {
162
+ const versions = fs2.readdirSync(DOCS_DIR2);
163
+ return versions.filter((v) => fs2.statSync(path2.join(DOCS_DIR2, v)).isDirectory());
164
+ } catch (error) {
165
+ return ["v1.0.0"];
166
+ }
167
+ }
168
+ function findMdxFiles(dir, baseDir = dir) {
169
+ const files = [];
170
+ try {
171
+ const entries = fs2.readdirSync(dir, { withFileTypes: true });
172
+ for (const entry of entries) {
173
+ const fullPath = path2.join(dir, entry.name);
174
+ if (entry.isDirectory()) {
175
+ files.push(...findMdxFiles(fullPath, baseDir));
176
+ } else if (entry.isFile() && entry.name.endsWith(".mdx")) {
177
+ const relativePath = path2.relative(baseDir, fullPath).replace(/\\/g, "/");
178
+ files.push(relativePath);
179
+ }
180
+ }
181
+ } catch (error) {
182
+ console.error(`Error reading directory ${dir}:`, error);
183
+ }
184
+ return files;
185
+ }
186
+ function readDocFromFile(filePath, originalSlug) {
187
+ try {
188
+ if (!fs2.existsSync(filePath)) {
189
+ return null;
190
+ }
191
+ const fileContents = fs2.readFileSync(filePath, "utf8");
192
+ const { data, content } = matter(fileContents);
193
+ const { minutes, words } = calculateReadingTime(content);
194
+ let finalSlug = originalSlug;
195
+ if (data.slug) {
196
+ const customSlug = data.slug.replace(/^\//, "");
197
+ const parts = originalSlug.split("/");
198
+ if (parts.length > 1) {
199
+ parts[parts.length - 1] = customSlug;
200
+ finalSlug = parts.join("/");
201
+ } else {
202
+ finalSlug = customSlug;
203
+ }
204
+ }
205
+ return {
206
+ slug: finalSlug,
207
+ filePath: originalSlug,
208
+ // Keep original file path for sidebar
209
+ title: data.title || originalSlug,
210
+ meta: {
211
+ ...data,
212
+ content,
213
+ reading_time: minutes,
214
+ word_count: words
215
+ },
216
+ content
217
+ };
218
+ } catch (error) {
219
+ console.error(`Error reading file ${filePath}:`, error);
220
+ return null;
221
+ }
222
+ }
223
+ async function getDocBySlug(slug, version = "v1.0.0") {
224
+ try {
225
+ let filePath = path2.join(DOCS_DIR2, version, `${slug}.mdx`);
226
+ let doc = readDocFromFile(filePath, slug);
227
+ if (doc) return doc;
228
+ filePath = path2.join(DOCS_DIR2, version, slug, "index.mdx");
229
+ doc = readDocFromFile(filePath, slug);
230
+ if (doc) return doc;
231
+ const versionDir = path2.join(DOCS_DIR2, version);
232
+ if (!fs2.existsSync(versionDir)) {
233
+ return null;
234
+ }
235
+ const mdxFiles = findMdxFiles(versionDir);
236
+ for (const file of mdxFiles) {
237
+ const fileSlug = file.replace(/\.mdx$/, "");
238
+ const testPath = path2.join(versionDir, file.endsWith("index.mdx") ? file : `${fileSlug}.mdx`);
239
+ const testDoc = readDocFromFile(testPath, fileSlug);
240
+ if (testDoc && testDoc.slug === slug) {
241
+ return testDoc;
242
+ }
243
+ }
244
+ return null;
245
+ } catch (error) {
246
+ console.error(`Error reading doc ${slug}:`, error);
247
+ return null;
248
+ }
249
+ }
250
+ async function getAllDocs(version = "v1.0.0") {
251
+ try {
252
+ const versionDir = path2.join(DOCS_DIR2, version);
253
+ if (!fs2.existsSync(versionDir)) {
254
+ return [];
255
+ }
256
+ const mdxFiles = findMdxFiles(versionDir);
257
+ const categoryConfigs = getAllCategoryConfigs(version);
258
+ const docs = await Promise.all(
259
+ mdxFiles.map(async (file) => {
260
+ const originalFilePath = file.replace(/\.mdx$/, "");
261
+ let slug = originalFilePath;
262
+ if (file.endsWith("/index.mdx") || file === "index.mdx") {
263
+ slug = path2.dirname(file).replace(/\\/g, "/");
264
+ if (slug === ".") slug = "";
265
+ }
266
+ const doc = await getDocBySlug(slug, version);
267
+ if (doc) {
268
+ doc.filePath = originalFilePath;
269
+ const folderPath = path2.dirname(originalFilePath).replace(/\\/g, "/");
270
+ if (folderPath !== ".") {
271
+ const categoryConfig = categoryConfigs.get(folderPath);
272
+ if (categoryConfig) {
273
+ doc.categoryLabel = categoryConfig.label;
274
+ doc.categoryPosition = categoryConfig.position ?? categoryConfig.sidebar_position;
275
+ doc.categoryCollapsible = categoryConfig.collapsible;
276
+ doc.categoryCollapsed = categoryConfig.collapsed;
277
+ doc.categoryIcon = categoryConfig.icon;
278
+ doc.categoryTabGroup = categoryConfig.tab_group;
279
+ }
280
+ }
281
+ }
282
+ return doc;
283
+ })
284
+ );
285
+ const isDevelopment3 = process.env.NODE_ENV === "development";
286
+ const uniqueDocs = /* @__PURE__ */ new Map();
287
+ docs.filter((doc) => doc !== null).filter((doc) => isDevelopment3 || !doc.meta.draft).forEach((doc) => {
288
+ uniqueDocs.set(doc.slug, doc);
289
+ });
290
+ return Array.from(uniqueDocs.values()).sort((a, b) => {
291
+ const orderA = a.meta.sidebar_position ?? a.meta.order ?? 999;
292
+ const orderB = b.meta.sidebar_position ?? b.meta.order ?? 999;
293
+ return orderA - orderB;
294
+ });
295
+ } catch (error) {
296
+ console.error(`Error getting all docs for version ${version}:`, error);
297
+ return [];
298
+ }
299
+ }
300
+ function flattenSidebarOrder(rootGroups, standalone) {
301
+ const flatDocs = [];
302
+ const flattenGroup = (group) => {
303
+ const sortedChildren = sortSidebarGroups(group.children);
304
+ const sortedItems = sortSidebarItems(group.items);
305
+ const merged = [
306
+ ...sortedChildren.map(([, childGroup]) => ({
307
+ type: "group",
308
+ group: childGroup,
309
+ position: childGroup.position
310
+ })),
311
+ ...sortedItems.map((doc) => ({
312
+ type: "item",
313
+ doc,
314
+ position: doc.meta.sidebar_position ?? doc.meta.order ?? 999
315
+ }))
316
+ ];
317
+ merged.sort((a, b) => a.position - b.position);
318
+ merged.forEach((item) => {
319
+ if (item.type === "group") {
320
+ flattenGroup(item.group);
321
+ } else {
322
+ flatDocs.push(item.doc);
323
+ }
324
+ });
325
+ };
326
+ sortSidebarItems(standalone).forEach((doc) => {
327
+ flatDocs.push(doc);
328
+ });
329
+ const sortedRootGroups = sortSidebarGroups(rootGroups);
330
+ sortedRootGroups.forEach(([, group]) => {
331
+ flattenGroup(group);
332
+ });
333
+ return flatDocs;
334
+ }
335
+ function getAdjacentDocs(currentSlug, allDocs) {
336
+ const { rootGroups, standalone } = buildSidebarStructure(allDocs);
337
+ const orderedDocs = flattenSidebarOrder(rootGroups, standalone);
338
+ const currentIndex = orderedDocs.findIndex((doc) => doc.slug === currentSlug);
339
+ if (currentIndex === -1) {
340
+ return {};
341
+ }
342
+ const currentDoc = orderedDocs[currentIndex];
343
+ const currentTabGroup = currentDoc.meta?.tab_group || currentDoc.categoryTabGroup;
344
+ const filteredDocs = orderedDocs.filter((doc) => {
345
+ const docTabGroup = doc.meta?.tab_group || doc.categoryTabGroup;
346
+ if (currentTabGroup) {
347
+ return docTabGroup === currentTabGroup;
348
+ }
349
+ return !docTabGroup;
350
+ });
351
+ const filteredIndex = filteredDocs.findIndex((doc) => doc.slug === currentSlug);
352
+ if (filteredIndex === -1) {
353
+ return {};
354
+ }
355
+ return {
356
+ previous: filteredIndex > 0 ? filteredDocs[filteredIndex - 1] : void 0,
357
+ next: filteredIndex < filteredDocs.length - 1 ? filteredDocs[filteredIndex + 1] : void 0
358
+ };
359
+ }
360
+ function extractTableOfContents(content) {
361
+ const headingRegex = /^(#{2,3})\s+(.+)$/gm;
362
+ const toc = [];
363
+ let match;
364
+ while ((match = headingRegex.exec(content)) !== null) {
365
+ const level = match[1].length;
366
+ const text = match[2];
367
+ const id = text.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/^-|-$/g, "");
368
+ toc.push({ id, title: text, level });
369
+ }
370
+ return toc;
371
+ }
372
+ function isCategoryPage(slug, allDocs) {
373
+ return allDocs.some((doc) => {
374
+ const parts = doc.slug.split("/");
375
+ const docParent = parts.slice(0, -1).join("/");
376
+ return docParent === slug && doc.slug !== slug;
377
+ });
378
+ }
379
+
380
+ // src/lib/dev-utils.ts
381
+ var isDevelopment = process.env.NODE_ENV === "development";
382
+ var PerfTimer = class {
383
+ constructor(label) {
384
+ this.label = label;
385
+ this.startTime = isDevelopment ? performance.now() : 0;
386
+ }
387
+ end() {
388
+ if (!isDevelopment) return;
389
+ const duration = performance.now() - this.startTime;
390
+ const color = duration > 1e3 ? "\x1B[31m" : duration > 500 ? "\x1B[33m" : "\x1B[32m";
391
+ const reset = "\x1B[0m";
392
+ console.log(`${color}\u23F1\uFE0F ${this.label}: ${duration.toFixed(2)}ms${reset}`);
393
+ }
394
+ };
395
+ function logFsOperation(operation, path3, details) {
396
+ if (!isDevelopment) return;
397
+ console.log(`\u{1F4C1} [FS] ${operation}: ${path3}`, details || "");
398
+ }
399
+ function logCacheOperation(operation, key) {
400
+ if (!isDevelopment) return;
401
+ const emoji = operation === "hit" ? "\u2705" : operation === "miss" ? "\u274C" : "\u{1F504}";
402
+ console.log(`${emoji} [Cache] ${operation}: ${key}`);
403
+ }
404
+ function logMemoryUsage(label) {
405
+ if (!isDevelopment) return;
406
+ const used = process.memoryUsage();
407
+ const prefix = label ? `[${label}] ` : "";
408
+ console.log(`\u{1F4BE} ${prefix}Memory Usage:`, {
409
+ rss: `${Math.round(used.rss / 1024 / 1024)}MB`,
410
+ heapTotal: `${Math.round(used.heapTotal / 1024 / 1024)}MB`,
411
+ heapUsed: `${Math.round(used.heapUsed / 1024 / 1024)}MB`
412
+ });
413
+ }
414
+ function debugLog(label, data) {
415
+ if (!isDevelopment) return;
416
+ console.log(`
417
+ \u{1F50D} ${label}:`);
418
+ console.dir(data, { depth: null, colors: true });
419
+ console.log("");
420
+ }
421
+
422
+ // src/lib/mdx-cache.ts
423
+ import { watch } from "fs";
424
+ import { join } from "path";
425
+ var isDevelopment2 = process.env.NODE_ENV === "development";
426
+ var versionsCache = {
427
+ data: null,
428
+ timestamp: 0
429
+ };
430
+ var allDocsCache = /* @__PURE__ */ new Map();
431
+ var docBySlugCache = /* @__PURE__ */ new Map();
432
+ var CACHE_TTL = isDevelopment2 ? 5e3 : 6e4;
433
+ var watchersInitialized = false;
434
+ function initializeWatchers() {
435
+ if (!isDevelopment2 || watchersInitialized) return;
436
+ watchersInitialized = true;
437
+ const docsPath = join(process.cwd(), "docs");
438
+ try {
439
+ watch(docsPath, { recursive: true }, (eventType, filename) => {
440
+ if (!filename) return;
441
+ if (filename.endsWith(".mdx") || filename.endsWith(".json")) {
442
+ const parts = filename.split(/[/\\]/);
443
+ const version = parts[0];
444
+ allDocsCache.delete(version);
445
+ const cacheKeysToDelete = [];
446
+ docBySlugCache.forEach((_, key) => {
447
+ if (key.startsWith(`${version}:`)) {
448
+ cacheKeysToDelete.push(key);
449
+ }
450
+ });
451
+ cacheKeysToDelete.forEach((key) => docBySlugCache.delete(key));
452
+ if (eventType === "rename") {
453
+ versionsCache.data = null;
454
+ }
455
+ console.log(`[MDX Cache] Invalidated cache for: ${filename}`);
456
+ }
457
+ });
458
+ console.log("[MDX Cache] File watchers initialized");
459
+ } catch (error) {
460
+ console.error("[MDX Cache] Failed to initialize watchers:", error);
461
+ }
462
+ }
463
+ function isCacheValid(timestamp) {
464
+ return Date.now() - timestamp < CACHE_TTL;
465
+ }
466
+ function getCachedVersions() {
467
+ initializeWatchers();
468
+ if (versionsCache.data && isCacheValid(versionsCache.timestamp)) {
469
+ logCacheOperation("hit", "versions");
470
+ return versionsCache.data;
471
+ }
472
+ logCacheOperation("miss", "versions");
473
+ const timer = new PerfTimer("getVersions");
474
+ const versions = getVersions();
475
+ timer.end();
476
+ versionsCache.data = versions;
477
+ versionsCache.timestamp = Date.now();
478
+ return versions;
479
+ }
480
+ async function getCachedAllDocs(version = "v1.0.0") {
481
+ initializeWatchers();
482
+ const cached = allDocsCache.get(version);
483
+ if (cached && isCacheValid(cached.timestamp)) {
484
+ logCacheOperation("hit", `getAllDocs:${version}`);
485
+ return cached.data;
486
+ }
487
+ logCacheOperation("miss", `getAllDocs:${version}`);
488
+ const timer = new PerfTimer(`getAllDocs(${version})`);
489
+ const docs = await getAllDocs(version);
490
+ timer.end();
491
+ allDocsCache.set(version, {
492
+ data: docs,
493
+ timestamp: Date.now()
494
+ });
495
+ return docs;
496
+ }
497
+ async function getCachedDocBySlug(slug, version = "v1.0.0") {
498
+ initializeWatchers();
499
+ const cacheKey = `${version}:${slug}`;
500
+ const cached = docBySlugCache.get(cacheKey);
501
+ if (cached && isCacheValid(cached.timestamp)) {
502
+ logCacheOperation("hit", `getDocBySlug:${cacheKey}`);
503
+ return cached.data;
504
+ }
505
+ logCacheOperation("miss", `getDocBySlug:${cacheKey}`);
506
+ const timer = new PerfTimer(`getDocBySlug(${slug})`);
507
+ const doc = await getDocBySlug(slug, version);
508
+ timer.end();
509
+ docBySlugCache.set(cacheKey, {
510
+ data: doc,
511
+ timestamp: Date.now()
512
+ });
513
+ return doc;
514
+ }
515
+ function clearAllCaches() {
516
+ versionsCache.data = null;
517
+ allDocsCache.clear();
518
+ docBySlugCache.clear();
519
+ console.log("[MDX Cache] All caches cleared");
520
+ }
521
+ function getCacheStats() {
522
+ return {
523
+ versions: {
524
+ cached: versionsCache.data !== null,
525
+ age: versionsCache.timestamp ? Date.now() - versionsCache.timestamp : 0
526
+ },
527
+ allDocs: {
528
+ entries: allDocsCache.size,
529
+ versions: Array.from(allDocsCache.keys())
530
+ },
531
+ docBySlug: {
532
+ entries: docBySlugCache.size
533
+ }
534
+ };
535
+ }
536
+
537
+ // src/lib/parsers/specra-parser.ts
538
+ var SpecraParser = class {
539
+ validate(input) {
540
+ return typeof input === "object" && input !== null && "endpoints" in input && Array.isArray(input.endpoints);
541
+ }
542
+ parse(input) {
543
+ if (!this.validate(input)) {
544
+ throw new Error("Invalid Specra API spec format");
545
+ }
546
+ return input;
547
+ }
548
+ };
549
+
550
+ // src/lib/parsers/openapi-parser.ts
551
+ var OpenApiParser = class {
552
+ validate(input) {
553
+ return typeof input === "object" && input !== null && ("openapi" in input || "swagger" in input) && "paths" in input;
554
+ }
555
+ parse(input) {
556
+ if (!this.validate(input)) {
557
+ throw new Error("Invalid OpenAPI spec format");
558
+ }
559
+ const baseUrl = this.extractBaseUrl(input);
560
+ const endpoints = [];
561
+ for (const [path3, pathItem] of Object.entries(input.paths || {})) {
562
+ const methods = ["get", "post", "put", "patch", "delete"];
563
+ for (const method of methods) {
564
+ const operation = pathItem[method];
565
+ if (!operation) continue;
566
+ const endpoint = this.parseOperation(path3, method.toUpperCase(), operation, input);
567
+ endpoints.push(endpoint);
568
+ }
569
+ }
570
+ return {
571
+ version: input.info?.version,
572
+ title: input.info?.title,
573
+ description: input.info?.description,
574
+ baseUrl,
575
+ auth: this.extractAuth(input),
576
+ endpoints
577
+ };
578
+ }
579
+ extractBaseUrl(spec) {
580
+ if (spec.servers && spec.servers.length > 0) {
581
+ return spec.servers[0].url;
582
+ }
583
+ if (spec.host) {
584
+ const scheme = spec.schemes?.[0] || "https";
585
+ const basePath = spec.basePath || "";
586
+ return `${scheme}://${spec.host}${basePath}`;
587
+ }
588
+ return "";
589
+ }
590
+ extractAuth(spec) {
591
+ const securitySchemes = spec.components?.securitySchemes || spec.securityDefinitions;
592
+ if (!securitySchemes) return void 0;
593
+ const firstScheme = Object.values(securitySchemes)[0];
594
+ if (!firstScheme) return void 0;
595
+ if (firstScheme.type === "http" && firstScheme.scheme === "bearer") {
596
+ return {
597
+ type: "bearer",
598
+ description: firstScheme.description,
599
+ tokenPrefix: "Bearer"
600
+ };
601
+ }
602
+ if (firstScheme.type === "apiKey") {
603
+ return {
604
+ type: "apiKey",
605
+ description: firstScheme.description,
606
+ headerName: firstScheme.name || "X-API-Key"
607
+ };
608
+ }
609
+ if (firstScheme.type === "http" && firstScheme.scheme === "basic") {
610
+ return {
611
+ type: "basic",
612
+ description: firstScheme.description
613
+ };
614
+ }
615
+ return void 0;
616
+ }
617
+ parseOperation(path3, method, operation, spec) {
618
+ const endpoint = {
619
+ title: operation.summary || operation.operationId || `${method} ${path3}`,
620
+ method,
621
+ path: this.convertPathParams(path3),
622
+ description: operation.description
623
+ };
624
+ const params = this.parseParameters(operation.parameters || [], spec);
625
+ if (params.path.length > 0) endpoint.pathParams = params.path;
626
+ if (params.query.length > 0) endpoint.queryParams = params.query;
627
+ if (params.header.length > 0) {
628
+ endpoint.headers = params.header.map((p) => ({
629
+ name: p.name,
630
+ value: p.example || "",
631
+ description: p.description
632
+ }));
633
+ }
634
+ if (operation.requestBody) {
635
+ endpoint.body = this.parseRequestBody(operation.requestBody, spec);
636
+ }
637
+ const responses = this.parseResponses(operation.responses || {}, spec);
638
+ if (responses.success) endpoint.successResponse = responses.success;
639
+ if (responses.errors.length > 0) endpoint.errorResponses = responses.errors;
640
+ return endpoint;
641
+ }
642
+ convertPathParams(path3) {
643
+ return path3.replace(/\{([^}]+)\}/g, ":$1");
644
+ }
645
+ parseParameters(parameters, spec) {
646
+ const result = { path: [], query: [], header: [] };
647
+ for (const param of parameters) {
648
+ const resolved = param.$ref ? this.resolveRef(param.$ref, spec) : param;
649
+ const apiParam = {
650
+ name: resolved.name,
651
+ type: resolved.schema?.type || resolved.type || "string",
652
+ required: resolved.required,
653
+ description: resolved.description,
654
+ example: resolved.example || resolved.schema?.example
655
+ };
656
+ if (resolved.in === "path") result.path.push(apiParam);
657
+ else if (resolved.in === "query") result.query.push(apiParam);
658
+ else if (resolved.in === "header") result.header.push(apiParam);
659
+ }
660
+ return result;
661
+ }
662
+ parseRequestBody(requestBody, spec) {
663
+ const content = requestBody.content?.["application/json"];
664
+ if (!content) return void 0;
665
+ return {
666
+ description: requestBody.description,
667
+ example: content.example || this.generateExample(content.schema, spec),
668
+ schema: content.schema
669
+ };
670
+ }
671
+ parseResponses(responses, spec) {
672
+ const result = { errors: [] };
673
+ for (const [statusCode, response] of Object.entries(responses)) {
674
+ const status = parseInt(statusCode);
675
+ if (isNaN(status)) continue;
676
+ const resolved = response.$ref ? this.resolveRef(response.$ref, spec) : response;
677
+ const content = resolved.content?.["application/json"];
678
+ const apiResponse = {
679
+ status,
680
+ description: resolved.description,
681
+ example: content?.example || this.generateExample(content?.schema, spec),
682
+ schema: content?.schema
683
+ };
684
+ if (status >= 200 && status < 300) {
685
+ result.success = apiResponse;
686
+ } else {
687
+ result.errors.push(apiResponse);
688
+ }
689
+ }
690
+ return result;
691
+ }
692
+ generateExample(schema, spec) {
693
+ if (!schema) return void 0;
694
+ if (schema.$ref) schema = this.resolveRef(schema.$ref, spec);
695
+ if (schema.example) return schema.example;
696
+ if (schema.type === "object" && schema.properties) {
697
+ const example = {};
698
+ for (const [key, prop] of Object.entries(schema.properties)) {
699
+ example[key] = this.generateExample(prop, spec);
700
+ }
701
+ return example;
702
+ }
703
+ if (schema.type === "array" && schema.items) {
704
+ return [this.generateExample(schema.items, spec)];
705
+ }
706
+ const defaults = {
707
+ string: "string",
708
+ number: 0,
709
+ integer: 0,
710
+ boolean: false,
711
+ object: {},
712
+ array: []
713
+ };
714
+ return defaults[schema.type] || null;
715
+ }
716
+ resolveRef(ref, spec) {
717
+ const path3 = ref.replace(/^#\//, "").split("/");
718
+ let current = spec;
719
+ for (const segment of path3) {
720
+ current = current[segment];
721
+ if (!current) return {};
722
+ }
723
+ return current;
724
+ }
725
+ };
726
+
727
+ // src/lib/parsers/postman-parser.ts
728
+ var PostmanParser = class {
729
+ validate(input) {
730
+ return typeof input === "object" && input !== null && "info" in input && input.info?.schema?.includes("v2");
731
+ }
732
+ parse(input) {
733
+ if (!this.validate(input)) {
734
+ throw new Error("Invalid Postman Collection format (requires v2.0 or v2.1)");
735
+ }
736
+ const baseUrl = this.extractBaseUrl(input);
737
+ const endpoints = [];
738
+ this.parseItems(input.item || [], endpoints, baseUrl, input);
739
+ return {
740
+ version: input.info?.version,
741
+ title: input.info?.name,
742
+ description: input.info?.description,
743
+ baseUrl,
744
+ auth: this.extractAuth(input.auth),
745
+ globalHeaders: this.extractGlobalHeaders(input),
746
+ endpoints
747
+ };
748
+ }
749
+ extractBaseUrl(collection) {
750
+ const baseUrlVar = collection.variable?.find(
751
+ (v) => v.key === "baseUrl" || v.key === "base_url" || v.key === "url"
752
+ );
753
+ if (baseUrlVar) return baseUrlVar.value;
754
+ if (collection.item && collection.item.length > 0) {
755
+ const firstRequest = this.findFirstRequest(collection.item);
756
+ if (firstRequest?.request?.url) {
757
+ const url = this.parseUrl(firstRequest.request.url);
758
+ if (url.host) {
759
+ return `${url.protocol}://${url.host.join(".")}`;
760
+ }
761
+ }
762
+ }
763
+ return "";
764
+ }
765
+ findFirstRequest(items) {
766
+ for (const item of items) {
767
+ if (item.request) return item;
768
+ if (item.item) {
769
+ const found = this.findFirstRequest(item.item);
770
+ if (found) return found;
771
+ }
772
+ }
773
+ return null;
774
+ }
775
+ extractAuth(auth) {
776
+ if (!auth) return void 0;
777
+ if (auth.type === "bearer") {
778
+ return {
779
+ type: "bearer",
780
+ tokenPrefix: "Bearer"
781
+ };
782
+ }
783
+ if (auth.type === "apikey") {
784
+ const keyData = auth.apikey?.find((a) => a.key === "key");
785
+ const keyName = keyData?.value || "X-API-Key";
786
+ return {
787
+ type: "apiKey",
788
+ headerName: keyName
789
+ };
790
+ }
791
+ if (auth.type === "basic") {
792
+ return {
793
+ type: "basic"
794
+ };
795
+ }
796
+ return void 0;
797
+ }
798
+ extractGlobalHeaders(collection) {
799
+ return [];
800
+ }
801
+ parseItems(items, endpoints, baseUrl, collection) {
802
+ for (const item of items) {
803
+ if (item.item && Array.isArray(item.item)) {
804
+ this.parseItems(item.item, endpoints, baseUrl, collection);
805
+ } else if (item.request) {
806
+ const endpoint = this.parseRequest(item, baseUrl, collection);
807
+ endpoints.push(endpoint);
808
+ }
809
+ }
810
+ }
811
+ parseRequest(item, baseUrl, collection) {
812
+ const request = item.request;
813
+ const url = this.parseUrl(request.url);
814
+ const endpoint = {
815
+ title: item.name,
816
+ method: request.method.toUpperCase(),
817
+ path: this.buildPath(url, baseUrl),
818
+ description: item.request.description || item.description
819
+ };
820
+ const params = this.parseUrlParams(url);
821
+ if (params.path.length > 0) endpoint.pathParams = params.path;
822
+ if (params.query.length > 0) endpoint.queryParams = params.query;
823
+ if (request.header && request.header.length > 0) {
824
+ endpoint.headers = request.header.filter((h) => !h.disabled).map((h) => ({
825
+ name: h.key,
826
+ value: h.value || "",
827
+ description: h.description
828
+ }));
829
+ }
830
+ if (request.body) {
831
+ endpoint.body = this.parseBody(request.body);
832
+ }
833
+ const responses = this.parseResponses(item.response || []);
834
+ if (responses.success) endpoint.successResponse = responses.success;
835
+ if (responses.errors.length > 0) endpoint.errorResponses = responses.errors;
836
+ return endpoint;
837
+ }
838
+ parseUrl(url) {
839
+ if (typeof url === "string") {
840
+ const urlObj = new URL(url);
841
+ return {
842
+ protocol: urlObj.protocol.replace(":", ""),
843
+ host: urlObj.hostname.split("."),
844
+ path: urlObj.pathname.split("/").filter(Boolean),
845
+ query: [],
846
+ variable: []
847
+ };
848
+ }
849
+ return {
850
+ protocol: url.protocol || "https",
851
+ host: url.host || [],
852
+ path: url.path || [],
853
+ query: url.query || [],
854
+ variable: url.variable || []
855
+ };
856
+ }
857
+ buildPath(url, baseUrl) {
858
+ let path3 = "/";
859
+ if (url.path && url.path.length > 0) {
860
+ path3 += url.path.join("/");
861
+ }
862
+ path3 = path3.replace(/\{\{([^}]+)\}\}/g, ":$1");
863
+ return path3;
864
+ }
865
+ parseUrlParams(url) {
866
+ const result = { path: [], query: [] };
867
+ if (url.variable && url.variable.length > 0) {
868
+ for (const v of url.variable) {
869
+ result.path.push({
870
+ name: v.key,
871
+ type: v.type || "string",
872
+ description: v.description,
873
+ example: v.value
874
+ });
875
+ }
876
+ }
877
+ if (url.path && url.path.length > 0) {
878
+ for (const segment of url.path) {
879
+ if (segment.startsWith(":")) {
880
+ const paramName = segment.slice(1);
881
+ if (!result.path.find((p) => p.name === paramName)) {
882
+ result.path.push({
883
+ name: paramName,
884
+ type: "string"
885
+ });
886
+ }
887
+ }
888
+ }
889
+ }
890
+ if (url.query && url.query.length > 0) {
891
+ for (const q of url.query) {
892
+ if (q.disabled) continue;
893
+ result.query.push({
894
+ name: q.key,
895
+ type: "string",
896
+ description: q.description,
897
+ example: q.value
898
+ });
899
+ }
900
+ }
901
+ return result;
902
+ }
903
+ parseBody(body) {
904
+ if (!body) return void 0;
905
+ let example;
906
+ let description = body.description;
907
+ if (body.mode === "raw") {
908
+ try {
909
+ example = JSON.parse(body.raw);
910
+ } catch {
911
+ example = body.raw;
912
+ }
913
+ } else if (body.mode === "formdata" || body.mode === "urlencoded") {
914
+ example = {};
915
+ for (const item of body[body.mode] || []) {
916
+ if (!item.disabled) {
917
+ example[item.key] = item.value;
918
+ }
919
+ }
920
+ }
921
+ return {
922
+ description,
923
+ example
924
+ };
925
+ }
926
+ parseResponses(responses) {
927
+ const result = { errors: [] };
928
+ for (const response of responses) {
929
+ let example;
930
+ try {
931
+ example = JSON.parse(response.body);
932
+ } catch {
933
+ example = response.body;
934
+ }
935
+ const apiResponse = {
936
+ status: response.code || 200,
937
+ description: response.name,
938
+ example
939
+ };
940
+ if (apiResponse.status >= 200 && apiResponse.status < 300) {
941
+ if (!result.success) result.success = apiResponse;
942
+ } else {
943
+ result.errors.push(apiResponse);
944
+ }
945
+ }
946
+ return result;
947
+ }
948
+ };
949
+
950
+ // src/lib/parsers/index.ts
951
+ var parsers = /* @__PURE__ */ new Map([
952
+ ["specra", new SpecraParser()],
953
+ ["openapi", new OpenApiParser()],
954
+ ["postman", new PostmanParser()]
955
+ ]);
956
+ function detectParserType(input) {
957
+ if (!input || typeof input !== "object") {
958
+ throw new Error("Invalid API spec: input must be an object");
959
+ }
960
+ if (input.info?.schema?.includes("v2")) {
961
+ return "postman";
962
+ }
963
+ if (input.openapi || input.swagger) {
964
+ return "openapi";
965
+ }
966
+ if (input.endpoints && Array.isArray(input.endpoints)) {
967
+ return "specra";
968
+ }
969
+ throw new Error(
970
+ "Unable to auto-detect API spec format. Supported formats: Specra, OpenAPI 3.x, Postman Collection v2.x"
971
+ );
972
+ }
973
+ function parseApiSpec(input, parserType = "auto") {
974
+ const actualType = parserType === "auto" ? detectParserType(input) : parserType;
975
+ const parser = parsers.get(actualType);
976
+ if (!parser) {
977
+ throw new Error(`Unknown parser type: ${actualType}`);
978
+ }
979
+ if (!parser.validate(input)) {
980
+ throw new Error(`Input does not match ${actualType} format`);
981
+ }
982
+ return parser.parse(input);
983
+ }
984
+
985
+ export {
986
+ getCategoryConfig,
987
+ getAllCategoryConfigs,
988
+ sortSidebarItems,
989
+ sortSidebarGroups,
990
+ buildSidebarStructure,
991
+ getVersions,
992
+ getDocBySlug,
993
+ getAllDocs,
994
+ getAdjacentDocs,
995
+ extractTableOfContents,
996
+ isCategoryPage,
997
+ PerfTimer,
998
+ logFsOperation,
999
+ logCacheOperation,
1000
+ logMemoryUsage,
1001
+ debugLog,
1002
+ getCachedVersions,
1003
+ getCachedAllDocs,
1004
+ getCachedDocBySlug,
1005
+ clearAllCaches,
1006
+ getCacheStats,
1007
+ SpecraParser,
1008
+ OpenApiParser,
1009
+ PostmanParser,
1010
+ detectParserType,
1011
+ parseApiSpec
1012
+ };
1013
+ //# sourceMappingURL=chunk-DR4EPLMT.mjs.map