@marlinjai/clearify 1.11.2 → 1.13.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.
@@ -2,18 +2,23 @@ import {
2
2
  parseOpenAPISpec
3
3
  } from "./chunk-B2Q23JW3.js";
4
4
  import {
5
+ ClearifyDataSchema,
6
+ deepMergeJsonWins,
7
+ loadDataConfig,
5
8
  loadUserConfig,
6
9
  resolveConfig,
7
10
  resolveSections,
8
- scanHubProjects
9
- } from "./chunk-PVTUVUBK.js";
11
+ scanHubProjects,
12
+ writeDataConfig
13
+ } from "./chunk-2WML2D77.js";
10
14
  import {
11
15
  buildSectionData
12
- } from "./chunk-QTGT76RY.js";
16
+ } from "./chunk-CTL4YL7C.js";
13
17
 
14
18
  // src/vite-plugin/index.ts
15
- import { resolve } from "path";
16
- import { existsSync, readFileSync } from "fs";
19
+ import { resolve, dirname } from "path";
20
+ import { fileURLToPath } from "url";
21
+ import { existsSync, readFileSync, readdirSync, statSync } from "fs";
17
22
  import { dereference } from "@scalar/openapi-parser";
18
23
  var VIRTUAL_CONFIG = "virtual:clearify/config";
19
24
  var RESOLVED_VIRTUAL_CONFIG = "\0" + VIRTUAL_CONFIG;
@@ -29,6 +34,8 @@ var VIRTUAL_OPENAPI_SPEC = "virtual:clearify/openapi-spec";
29
34
  var RESOLVED_VIRTUAL_OPENAPI_SPEC = "\0" + VIRTUAL_OPENAPI_SPEC;
30
35
  var VIRTUAL_HUB = "virtual:clearify/hub";
31
36
  var RESOLVED_VIRTUAL_HUB = "\0" + VIRTUAL_HUB;
37
+ var VIRTUAL_ADMIN_ENABLED = "virtual:clearify/admin-enabled";
38
+ var RESOLVED_VIRTUAL_ADMIN_ENABLED = "\0" + VIRTUAL_ADMIN_ENABLED;
32
39
  function findFirstNavPath(items) {
33
40
  for (const item of items) {
34
41
  if (item.path) return item.path;
@@ -52,7 +59,8 @@ function clearifyPlugin(options = {}) {
52
59
  function getRootFiles() {
53
60
  return {
54
61
  changelogPath: resolve(userRoot, "CHANGELOG.md"),
55
- roadmapPath: resolve(userRoot, "ROADMAP.md")
62
+ roadmapPath: resolve(userRoot, "ROADMAP.md"),
63
+ ...config.includeReadme ? { readmePath: resolve(userRoot, "README.md") } : {}
56
64
  };
57
65
  }
58
66
  async function refreshDocs() {
@@ -241,6 +249,7 @@ ${routeEntries.join(",\n")}
241
249
  if (id === VIRTUAL_MERMAID_SVGS) return RESOLVED_VIRTUAL_MERMAID_SVGS;
242
250
  if (id === VIRTUAL_OPENAPI_SPEC) return RESOLVED_VIRTUAL_OPENAPI_SPEC;
243
251
  if (id === VIRTUAL_HUB) return RESOLVED_VIRTUAL_HUB;
252
+ if (id === VIRTUAL_ADMIN_ENABLED) return RESOLVED_VIRTUAL_ADMIN_ENABLED;
244
253
  return null;
245
254
  },
246
255
  async load(id) {
@@ -266,6 +275,10 @@ ${routeEntries.join(",\n")}
266
275
  const hubData = config.hub ?? null;
267
276
  return `export default ${JSON.stringify(hubData)};`;
268
277
  }
278
+ if (id === RESOLVED_VIRTUAL_ADMIN_ENABLED) {
279
+ const enabled = resolvedViteConfig.command === "serve";
280
+ return `export default ${enabled};`;
281
+ }
269
282
  return null;
270
283
  },
271
284
  configureServer(server) {
@@ -273,7 +286,7 @@ ${routeEntries.join(",\n")}
273
286
  server.watcher.add(section.docsDir);
274
287
  }
275
288
  const rootFiles = getRootFiles();
276
- for (const rootFile of [rootFiles.changelogPath, rootFiles.roadmapPath]) {
289
+ for (const rootFile of [rootFiles.changelogPath, rootFiles.roadmapPath, rootFiles.readmePath]) {
277
290
  if (rootFile && existsSync(rootFile)) {
278
291
  server.watcher.add(rootFile);
279
292
  }
@@ -395,8 +408,9 @@ ${routeEntries.join(",\n")}
395
408
  server.watcher.on("all", (event, path) => {
396
409
  const isChangelog = path === rootFiles.changelogPath;
397
410
  const isRoadmap = path === rootFiles.roadmapPath;
411
+ const isReadme = path === rootFiles.readmePath;
398
412
  const isInSection = visibleSections.some((s) => path.startsWith(s.docsDir));
399
- if (!isChangelog && !isRoadmap && !isInSection) return;
413
+ if (!isChangelog && !isRoadmap && !isReadme && !isInSection) return;
400
414
  if (!path.endsWith(".md") && !path.endsWith(".mdx")) return;
401
415
  if (event === "add" || event === "unlink" || event === "change") {
402
416
  refreshDocs().then(() => {
@@ -410,6 +424,118 @@ ${routeEntries.join(",\n")}
410
424
  });
411
425
  }
412
426
  });
427
+ const dataJsonPath = resolve(userRoot, "clearify.data.json");
428
+ server.watcher.add(dataJsonPath);
429
+ server.watcher.on("change", (changedPath) => {
430
+ if (changedPath === dataJsonPath) {
431
+ for (const resolvedId of [
432
+ RESOLVED_VIRTUAL_CONFIG,
433
+ RESOLVED_VIRTUAL_ROUTES,
434
+ RESOLVED_VIRTUAL_NAVIGATION,
435
+ RESOLVED_VIRTUAL_SEARCH_INDEX
436
+ ]) {
437
+ const mod = server.moduleGraph.getModuleById(resolvedId);
438
+ if (mod) server.moduleGraph.invalidateModule(mod);
439
+ }
440
+ server.ws.send({ type: "full-reload" });
441
+ }
442
+ });
443
+ function readJsonBody(req) {
444
+ return new Promise((resolve2, reject) => {
445
+ const chunks = [];
446
+ req.on("data", (chunk) => chunks.push(chunk));
447
+ req.on("end", () => {
448
+ try {
449
+ resolve2(JSON.parse(Buffer.concat(chunks).toString()));
450
+ } catch {
451
+ reject(new Error("Invalid JSON"));
452
+ }
453
+ });
454
+ req.on("error", reject);
455
+ });
456
+ }
457
+ server.middlewares.use(async (req, res, next) => {
458
+ const url = req.url?.split("?") ?? [""];
459
+ const pathname = url[0];
460
+ const query = new URLSearchParams(url[1] ?? "");
461
+ if (!pathname.startsWith("/__clearify/api/")) return next();
462
+ res.setHeader("Content-Type", "application/json");
463
+ try {
464
+ if (req.method === "GET" && pathname === "/__clearify/api/config") {
465
+ res.end(JSON.stringify(config));
466
+ return;
467
+ }
468
+ if (req.method === "GET" && pathname === "/__clearify/api/config/data") {
469
+ const data = loadDataConfig(userRoot);
470
+ res.end(JSON.stringify(data));
471
+ return;
472
+ }
473
+ if (req.method === "PUT" && pathname === "/__clearify/api/config/data") {
474
+ const body = await readJsonBody(req);
475
+ const result = ClearifyDataSchema.safeParse(body);
476
+ if (!result.success) {
477
+ res.statusCode = 400;
478
+ res.end(JSON.stringify({ error: "Validation failed", issues: result.error.issues }));
479
+ return;
480
+ }
481
+ writeDataConfig(userRoot, body);
482
+ res.end(JSON.stringify({ ok: true }));
483
+ return;
484
+ }
485
+ if (req.method === "PATCH" && pathname === "/__clearify/api/config/data") {
486
+ const body = await readJsonBody(req);
487
+ const existing = loadDataConfig(userRoot);
488
+ const merged = deepMergeJsonWins(existing, body);
489
+ const result = ClearifyDataSchema.safeParse(merged);
490
+ if (!result.success) {
491
+ res.statusCode = 400;
492
+ res.end(JSON.stringify({ error: "Validation failed", issues: result.error.issues }));
493
+ return;
494
+ }
495
+ writeDataConfig(userRoot, merged);
496
+ res.end(JSON.stringify({ ok: true }));
497
+ return;
498
+ }
499
+ if (req.method === "GET" && pathname === "/__clearify/api/config/schema") {
500
+ const pkgDir = dirname(fileURLToPath(import.meta.url));
501
+ const schemaPath = resolve(pkgDir, "../../dist/config-schema.json");
502
+ if (existsSync(schemaPath)) {
503
+ res.end(readFileSync(schemaPath, "utf-8"));
504
+ } else {
505
+ res.statusCode = 404;
506
+ res.end(JSON.stringify({ error: "Schema file not found" }));
507
+ }
508
+ return;
509
+ }
510
+ if (req.method === "GET" && pathname === "/__clearify/api/fs/dirs") {
511
+ const rootParam = query.get("root") ?? ".";
512
+ const target = resolve(userRoot, rootParam);
513
+ if (!target.startsWith(userRoot)) {
514
+ res.statusCode = 403;
515
+ res.end(JSON.stringify({ error: "Path outside project root" }));
516
+ return;
517
+ }
518
+ if (!existsSync(target)) {
519
+ res.end(JSON.stringify({ dirs: [] }));
520
+ return;
521
+ }
522
+ const dirs = readdirSync(target).filter((entry) => {
523
+ try {
524
+ return statSync(resolve(target, entry)).isDirectory();
525
+ } catch {
526
+ return false;
527
+ }
528
+ });
529
+ res.end(JSON.stringify({ dirs }));
530
+ return;
531
+ }
532
+ res.statusCode = 404;
533
+ res.end(JSON.stringify({ error: "Not found" }));
534
+ } catch (err) {
535
+ res.statusCode = err.message === "Invalid JSON" ? 400 : 500;
536
+ res.end(JSON.stringify({ error: err.message ?? "Internal server error" }));
537
+ }
538
+ });
413
539
  return () => {
414
540
  server.middlewares.use((req, _res, next) => {
415
541
  if (req.method !== "GET" || !req.headers.accept?.includes("text/html")) {
@@ -2,10 +2,10 @@ import {
2
2
  loadUserConfig,
3
3
  resolveConfig,
4
4
  resolveSections
5
- } from "./chunk-PVTUVUBK.js";
5
+ } from "./chunk-2WML2D77.js";
6
6
  import {
7
7
  scanDocs
8
- } from "./chunk-QTGT76RY.js";
8
+ } from "./chunk-CTL4YL7C.js";
9
9
 
10
10
  // src/node/check.ts
11
11
  import { resolve, relative } from "path";
@@ -8,15 +8,15 @@ import {
8
8
  } from "./chunk-SCZZB7OE.js";
9
9
  import {
10
10
  clearifyPlugin
11
- } from "./chunk-PFX7LHRZ.js";
11
+ } from "./chunk-GWYMXKDL.js";
12
12
  import {
13
13
  loadUserConfig,
14
14
  resolveConfig,
15
15
  resolveSections
16
- } from "./chunk-PVTUVUBK.js";
16
+ } from "./chunk-2WML2D77.js";
17
17
  import {
18
18
  buildSectionData
19
- } from "./chunk-QTGT76RY.js";
19
+ } from "./chunk-CTL4YL7C.js";
20
20
 
21
21
  // src/node/build.ts
22
22
  import { build as viteBuild } from "vite";
@@ -157,7 +157,8 @@ async function buildSite() {
157
157
  const productionSections = allSections.filter((s) => !s.draft);
158
158
  const rootFiles = {
159
159
  changelogPath: resolve(userRoot, "CHANGELOG.md"),
160
- roadmapPath: resolve(userRoot, "ROADMAP.md")
160
+ roadmapPath: resolve(userRoot, "ROADMAP.md"),
161
+ ...config.includeReadme ? { readmePath: resolve(userRoot, "README.md") } : {}
161
162
  };
162
163
  const sectionDataList = productionSections.map(
163
164
  (section) => buildSectionData(section, rootFiles, config.navigation)
@@ -1,10 +1,86 @@
1
- import { ClearifyConfig, ResolvedSection } from '../types/index.js';
1
+ import { z } from 'zod';
2
+ import { ClearifyConfig, ClearifyDataConfig, ResolvedSection } from '../types/index.js';
2
3
  export { defineConfig } from '../types/index.js';
3
4
 
5
+ /** Zod schema for clearify.data.json — Tier 1+2 visual-config fields, all optional. */
6
+ declare const ClearifyDataSchema: z.ZodObject<{
7
+ name: z.ZodOptional<z.ZodString>;
8
+ siteUrl: z.ZodOptional<z.ZodString>;
9
+ theme: z.ZodOptional<z.ZodObject<{
10
+ primaryColor: z.ZodOptional<z.ZodString>;
11
+ mode: z.ZodOptional<z.ZodEnum<{
12
+ light: "light";
13
+ dark: "dark";
14
+ auto: "auto";
15
+ }>>;
16
+ }, z.core.$strip>>;
17
+ logo: z.ZodOptional<z.ZodObject<{
18
+ light: z.ZodOptional<z.ZodString>;
19
+ dark: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strip>>;
21
+ links: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
22
+ sections: z.ZodOptional<z.ZodArray<z.ZodObject<{
23
+ label: z.ZodString;
24
+ docsDir: z.ZodString;
25
+ basePath: z.ZodOptional<z.ZodString>;
26
+ draft: z.ZodOptional<z.ZodBoolean>;
27
+ sitemap: z.ZodOptional<z.ZodBoolean>;
28
+ exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
29
+ git: z.ZodOptional<z.ZodObject<{
30
+ repo: z.ZodString;
31
+ ref: z.ZodOptional<z.ZodString>;
32
+ path: z.ZodOptional<z.ZodString>;
33
+ sparse: z.ZodOptional<z.ZodBoolean>;
34
+ }, z.core.$strip>>;
35
+ }, z.core.$strip>>>;
36
+ hub: z.ZodOptional<z.ZodObject<{
37
+ projects: z.ZodDefault<z.ZodArray<z.ZodObject<{
38
+ name: z.ZodString;
39
+ description: z.ZodString;
40
+ href: z.ZodOptional<z.ZodString>;
41
+ repo: z.ZodOptional<z.ZodString>;
42
+ status: z.ZodDefault<z.ZodEnum<{
43
+ active: "active";
44
+ beta: "beta";
45
+ planned: "planned";
46
+ deprecated: "deprecated";
47
+ }>>;
48
+ icon: z.ZodOptional<z.ZodString>;
49
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
50
+ group: z.ZodOptional<z.ZodString>;
51
+ mode: z.ZodOptional<z.ZodEnum<{
52
+ link: "link";
53
+ embed: "embed";
54
+ inject: "inject";
55
+ }>>;
56
+ git: z.ZodOptional<z.ZodObject<{
57
+ repo: z.ZodString;
58
+ ref: z.ZodOptional<z.ZodString>;
59
+ path: z.ZodOptional<z.ZodString>;
60
+ sparse: z.ZodOptional<z.ZodBoolean>;
61
+ }, z.core.$strip>>;
62
+ embedSections: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodLiteral<"public">, z.ZodArray<z.ZodString>]>>;
63
+ injectInto: z.ZodOptional<z.ZodString>;
64
+ docsPath: z.ZodOptional<z.ZodString>;
65
+ }, z.core.$strip>>>;
66
+ scan: z.ZodOptional<z.ZodString>;
67
+ cacheDir: z.ZodOptional<z.ZodString>;
68
+ }, z.core.$strip>>;
69
+ }, z.core.$strip>;
70
+ /**
71
+ * Deep-merge utility where JSON (overlay) values win over base values.
72
+ * Plain objects merge recursively. Arrays are replaced entirely.
73
+ * Undefined values in the overlay are skipped.
74
+ */
75
+ declare function deepMergeJsonWins<T extends Record<string, any>>(base: T, json: Partial<T>): T;
76
+ /** Load and validate clearify.data.json from a project root. Returns `{}` on missing/invalid file. */
77
+ declare function loadDataConfig(root: string): ClearifyDataConfig;
78
+ /** Validate and atomically write clearify.data.json. */
79
+ declare function writeDataConfig(root: string, data: unknown): void;
4
80
  declare const defaultConfig: ClearifyConfig;
5
81
  declare function loadUserConfig(root: string): Promise<Partial<ClearifyConfig>>;
6
82
  declare function resolveConfig(userConfig?: Partial<ClearifyConfig>, root?: string): ClearifyConfig;
7
83
  declare function resolveSections(config: ClearifyConfig, root: string): Promise<ResolvedSection[]>;
8
84
  declare function scanHubProjects(config: ClearifyConfig, root: string): Promise<ClearifyConfig>;
9
85
 
10
- export { defaultConfig, loadUserConfig, resolveConfig, resolveSections, scanHubProjects };
86
+ export { ClearifyDataSchema, deepMergeJsonWins, defaultConfig, loadDataConfig, loadUserConfig, resolveConfig, resolveSections, scanHubProjects, writeDataConfig };
@@ -1,19 +1,27 @@
1
1
  import {
2
+ ClearifyDataSchema,
3
+ deepMergeJsonWins,
2
4
  defaultConfig,
5
+ loadDataConfig,
3
6
  loadUserConfig,
4
7
  resolveConfig,
5
8
  resolveSections,
6
- scanHubProjects
7
- } from "../chunk-PVTUVUBK.js";
9
+ scanHubProjects,
10
+ writeDataConfig
11
+ } from "../chunk-2WML2D77.js";
8
12
  import "../chunk-AJBCHKBP.js";
9
13
  import {
10
14
  defineConfig
11
15
  } from "../chunk-V7LLYIRO.js";
12
16
  export {
17
+ ClearifyDataSchema,
18
+ deepMergeJsonWins,
13
19
  defaultConfig,
14
20
  defineConfig,
21
+ loadDataConfig,
15
22
  loadUserConfig,
16
23
  resolveConfig,
17
24
  resolveSections,
18
- scanHubProjects
25
+ scanHubProjects,
26
+ writeDataConfig
19
27
  };
@@ -3,7 +3,7 @@ import {
3
3
  buildRoutes,
4
4
  buildSectionData,
5
5
  scanDocs
6
- } from "../chunk-QTGT76RY.js";
6
+ } from "../chunk-CTL4YL7C.js";
7
7
  import "../chunk-5TD7NQIW.js";
8
8
  export {
9
9
  buildNavigation,
@@ -29,6 +29,7 @@ interface SectionData {
29
29
  interface RootFileOptions {
30
30
  changelogPath?: string;
31
31
  roadmapPath?: string;
32
+ readmePath?: string;
32
33
  }
33
34
  declare function buildSectionData(section: ResolvedSection, rootFiles?: RootFileOptions, customNavigation?: NavigationItem[] | null): SectionData;
34
35
 
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  buildSite
3
- } from "../chunk-EMM4VLF7.js";
3
+ } from "../chunk-XR4WG237.js";
4
4
  import "../chunk-PRTER35L.js";
5
5
  import "../chunk-SCZZB7OE.js";
6
- import "../chunk-PFX7LHRZ.js";
6
+ import "../chunk-GWYMXKDL.js";
7
7
  import "../chunk-B2Q23JW3.js";
8
- import "../chunk-PVTUVUBK.js";
8
+ import "../chunk-2WML2D77.js";
9
9
  import "../chunk-AJBCHKBP.js";
10
10
  import "../chunk-V7LLYIRO.js";
11
- import "../chunk-QTGT76RY.js";
11
+ import "../chunk-CTL4YL7C.js";
12
12
  import "../chunk-5TD7NQIW.js";
13
13
  export {
14
14
  buildSite
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  checkFrontmatter,
3
3
  checkLinks
4
- } from "../chunk-NGWAMBXS.js";
5
- import "../chunk-PVTUVUBK.js";
4
+ } from "../chunk-HZRIVY25.js";
5
+ import "../chunk-2WML2D77.js";
6
6
  import "../chunk-AJBCHKBP.js";
7
7
  import "../chunk-V7LLYIRO.js";
8
- import "../chunk-QTGT76RY.js";
8
+ import "../chunk-CTL4YL7C.js";
9
9
  import "../chunk-5TD7NQIW.js";
10
10
  export {
11
11
  checkFrontmatter,
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  buildSite
3
- } from "../chunk-EMM4VLF7.js";
3
+ } from "../chunk-XR4WG237.js";
4
4
  import {
5
5
  remarkMermaidToComponent
6
6
  } from "../chunk-PRTER35L.js";
7
7
  import "../chunk-SCZZB7OE.js";
8
8
  import {
9
9
  clearifyPlugin
10
- } from "../chunk-PFX7LHRZ.js";
10
+ } from "../chunk-GWYMXKDL.js";
11
11
  import "../chunk-B2Q23JW3.js";
12
12
  import {
13
13
  init
@@ -15,14 +15,14 @@ import {
15
15
  import {
16
16
  checkFrontmatter,
17
17
  checkLinks
18
- } from "../chunk-NGWAMBXS.js";
18
+ } from "../chunk-HZRIVY25.js";
19
19
  import {
20
20
  loadUserConfig,
21
21
  resolveConfig
22
- } from "../chunk-PVTUVUBK.js";
22
+ } from "../chunk-2WML2D77.js";
23
23
  import "../chunk-AJBCHKBP.js";
24
24
  import "../chunk-V7LLYIRO.js";
25
- import "../chunk-QTGT76RY.js";
25
+ import "../chunk-CTL4YL7C.js";
26
26
  import "../chunk-5TD7NQIW.js";
27
27
 
28
28
  // src/node/index.ts
@@ -61,6 +61,7 @@ interface ClearifyConfig {
61
61
  hubProject?: Omit<HubProject, 'name'>;
62
62
  customCss?: string;
63
63
  headTags?: string[];
64
+ includeReadme?: boolean;
64
65
  }
65
66
  interface NavigationItem {
66
67
  label: string;
@@ -102,15 +103,36 @@ interface HubProject {
102
103
  group?: string;
103
104
  hubUrl?: string;
104
105
  hubName?: string;
105
- mode?: 'link' | 'embed';
106
+ mode?: 'link' | 'embed' | 'inject';
106
107
  git?: RemoteGitSource;
107
108
  embedSections?: 'all' | 'public' | string[];
109
+ injectInto?: string;
110
+ docsPath?: string;
108
111
  }
109
112
  interface HubConfig {
110
113
  projects: HubProject[];
111
114
  scan?: string;
112
115
  cacheDir?: string;
113
116
  }
117
+ /** Tier 1+2 fields that can live in clearify.data.json for visual editing. */
118
+ interface ClearifyDataConfig {
119
+ name?: string;
120
+ siteUrl?: string;
121
+ theme?: {
122
+ primaryColor?: string;
123
+ mode?: 'light' | 'dark' | 'auto';
124
+ };
125
+ logo?: {
126
+ light?: string;
127
+ dark?: string;
128
+ };
129
+ links?: {
130
+ github?: string;
131
+ [key: string]: string | undefined;
132
+ };
133
+ sections?: SectionConfig[];
134
+ hub?: HubConfig;
135
+ }
114
136
  declare function defineConfig(config: Partial<ClearifyConfig>): Partial<ClearifyConfig>;
115
137
 
116
- export { type ClearifyConfig, type DocCategory, type HubConfig, type HubProject, type NavigationItem, type PageFrontmatter, type RemoteGitSource, type ResolvedSection, type RouteEntry, type SectionConfig, type SectionNavigation, defineConfig };
138
+ export { type ClearifyConfig, type ClearifyDataConfig, type DocCategory, type HubConfig, type HubProject, type NavigationItem, type PageFrontmatter, type RemoteGitSource, type ResolvedSection, type RouteEntry, type SectionConfig, type SectionNavigation, defineConfig };
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  clearifyPlugin
3
- } from "../chunk-PFX7LHRZ.js";
3
+ } from "../chunk-GWYMXKDL.js";
4
4
  import "../chunk-B2Q23JW3.js";
5
- import "../chunk-PVTUVUBK.js";
5
+ import "../chunk-2WML2D77.js";
6
6
  import "../chunk-AJBCHKBP.js";
7
7
  import "../chunk-V7LLYIRO.js";
8
- import "../chunk-QTGT76RY.js";
8
+ import "../chunk-CTL4YL7C.js";
9
9
  import "../chunk-5TD7NQIW.js";
10
10
  export {
11
11
  clearifyPlugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marlinjai/clearify",
3
- "version": "1.11.2",
3
+ "version": "1.13.0",
4
4
  "description": "An open-source documentation site generator. Turn markdown into beautiful docs.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,8 @@
14
14
  "./config": {
15
15
  "types": "./dist/node/core/config.d.ts",
16
16
  "import": "./dist/node/core/config.js"
17
- }
17
+ },
18
+ "./config-schema.json": "./dist/config-schema.json"
18
19
  },
19
20
  "files": [
20
21
  "bin",
@@ -24,6 +25,7 @@
24
25
  ],
25
26
  "scripts": {
26
27
  "build": "tsup",
28
+ "postbuild": "node scripts/generate-schema.mjs",
27
29
  "dev:self": "node bin/clearify.js dev",
28
30
  "prepare": "husky",
29
31
  "release": "semantic-release"
@@ -7,12 +7,20 @@ import routes from 'virtual:clearify/routes';
7
7
  import config from 'virtual:clearify/config';
8
8
  // @ts-expect-error virtual module
9
9
  import sections from 'virtual:clearify/navigation';
10
+ // @ts-expect-error virtual module
11
+ import adminEnabled from 'virtual:clearify/admin-enabled';
10
12
  import { Layout } from '../theme/Layout.js';
11
13
  import { Head } from '../theme/Head.js';
12
14
  import { NotFound } from '../theme/NotFound.js';
13
15
  import { mdxComponents } from '../theme/MDXComponents.js';
14
16
  import '../theme/styles/globals.css';
15
17
 
18
+ const AdminLayout = React.lazy(() => import('../theme/admin/AdminLayout.js'));
19
+ const AdminDashboard = React.lazy(() => import('../theme/admin/AdminDashboard.js'));
20
+ const ProjectsManager = React.lazy(() => import('../theme/admin/ProjectsManager.js'));
21
+ const SectionsManager = React.lazy(() => import('../theme/admin/SectionsManager.js'));
22
+ const SiteSettings = React.lazy(() => import('../theme/admin/SiteSettings.js'));
23
+
16
24
  interface RouteEntry {
17
25
  path: string;
18
26
  component?: () => Promise<any>;
@@ -74,24 +82,59 @@ function PageWrapper({ loader, fallbackFrontmatter }: { loader: () => Promise<an
74
82
  );
75
83
  }
76
84
 
85
+ function AdminDisabled() {
86
+ return (
87
+ <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', color: 'var(--clearify-text-secondary)', fontFamily: 'var(--font-sans)' }}>
88
+ Admin panel is only available in dev mode.
89
+ </div>
90
+ );
91
+ }
92
+
77
93
  function AppRoutes() {
78
94
  return (
79
- <Layout config={config} sections={sections}>
80
- <Routes>
81
- {(routes as RouteEntry[]).map((route) =>
82
- route.redirectTo ? (
83
- <Route key={route.path} path={route.path} element={<Navigate to={route.redirectTo} replace />} />
84
- ) : (
85
- <Route
86
- key={route.path}
87
- path={route.path}
88
- element={<PageWrapper loader={route.component!} fallbackFrontmatter={route.frontmatter} />}
89
- />
90
- )
91
- )}
92
- <Route path="*" element={<NotFound />} />
93
- </Routes>
94
- </Layout>
95
+ <Routes>
96
+ {/* Admin routes — outside Layout, lazy-loaded */}
97
+ {adminEnabled ? (
98
+ <Route
99
+ path="/admin"
100
+ element={
101
+ <React.Suspense fallback={<div style={{ padding: '2rem', color: 'var(--clearify-text-secondary)' }}>Loading...</div>}>
102
+ <AdminLayout />
103
+ </React.Suspense>
104
+ }
105
+ >
106
+ <Route index element={<AdminDashboard />} />
107
+ <Route path="projects" element={<ProjectsManager />} />
108
+ <Route path="sections" element={<SectionsManager />} />
109
+ <Route path="settings" element={<SiteSettings />} />
110
+ </Route>
111
+ ) : (
112
+ <Route path="/admin/*" element={<AdminDisabled />} />
113
+ )}
114
+
115
+ {/* Docs routes — wrapped in Layout */}
116
+ <Route
117
+ path="*"
118
+ element={
119
+ <Layout config={config} sections={sections}>
120
+ <Routes>
121
+ {(routes as RouteEntry[]).map((route) =>
122
+ route.redirectTo ? (
123
+ <Route key={route.path} path={route.path} element={<Navigate to={route.redirectTo} replace />} />
124
+ ) : (
125
+ <Route
126
+ key={route.path}
127
+ path={route.path}
128
+ element={<PageWrapper loader={route.component!} fallbackFrontmatter={route.frontmatter} />}
129
+ />
130
+ )
131
+ )}
132
+ <Route path="*" element={<NotFound />} />
133
+ </Routes>
134
+ </Layout>
135
+ }
136
+ />
137
+ </Routes>
95
138
  );
96
139
  }
97
140