@aravindc26/velu 0.13.4 → 0.13.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aravindc26/velu",
3
- "version": "0.13.4",
3
+ "version": "0.13.5",
4
4
  "description": "A modern documentation site generator powered by Markdown and JSON configuration",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -141,10 +141,15 @@ function prefixMdxComponentLinks(
141
141
  export default async function PreviewPage({ params }: PageProps) {
142
142
  const { sessionId, slug } = await params;
143
143
 
144
+ console.log(`[PREVIEW:page] START session=${sessionId} slug=${slug.join('/')}`);
145
+
144
146
  const src = await getSessionSource(sessionId);
145
147
  const page = src.getPage(slug);
146
148
 
147
- if (!page) notFound();
149
+ if (!page) {
150
+ console.log(`[PREVIEW:page] Page NOT FOUND for slug=${slug.join('/')}`);
151
+ notFound();
152
+ }
148
153
 
149
154
  const pageDataRecord = page.data as unknown as Record<string, unknown>;
150
155
 
@@ -154,17 +159,22 @@ export default async function PreviewPage({ params }: PageProps) {
154
159
  let pageToc: any;
155
160
 
156
161
  if (typeof loadFn === 'function') {
157
- // Dynamic/async entry compile MDX on demand
162
+ console.log(`[PREVIEW:page] Calling load() for slug=${slug.join('/')}`);
158
163
  const loaded = await loadFn();
159
164
  MDX = loaded.body;
160
165
  pageToc = loaded.toc;
166
+ console.log(`[PREVIEW:page] load() returned MDX=${typeof MDX} toc=${typeof pageToc}`);
161
167
  } else {
162
168
  // Fallback: pre-compiled entry (shouldn't happen in preview mode, but safe)
169
+ console.log(`[PREVIEW:page] No load() — using pre-compiled body for slug=${slug.join('/')}`);
163
170
  MDX = pageDataRecord.body as any;
164
171
  pageToc = pageDataRecord.toc as any;
165
172
  }
166
173
 
167
- if (typeof MDX !== 'function') notFound();
174
+ if (typeof MDX !== 'function') {
175
+ console.log(`[PREVIEW:page] MDX is not a function (type=${typeof MDX}), returning 404`);
176
+ notFound();
177
+ }
168
178
 
169
179
  const configSource = loadSessionConfigSource(sessionId);
170
180
  const footerSocials = configSource ? getFooterSocials(configSource) : [];
@@ -176,6 +186,7 @@ export default async function PreviewPage({ params }: PageProps) {
176
186
  if (pageInfo?.fullPath) {
177
187
  try {
178
188
  effectiveMarkdown = readFileSync(pageInfo.fullPath, 'utf-8');
189
+ console.log(`[PREVIEW:page] Read markdown from ${pageInfo.fullPath} (${effectiveMarkdown.length} chars, first 120: ${JSON.stringify(effectiveMarkdown.slice(0, 120))})`);
179
190
  } catch { /* file may not exist */ }
180
191
  }
181
192
 
@@ -11,12 +11,16 @@ export async function POST(
11
11
 
12
12
  const { sessionId } = await params;
13
13
 
14
+ console.log(`[PREVIEW:init] START session=${sessionId}`);
15
+
14
16
  try {
15
17
  const result = generateSessionContent(sessionId);
18
+ console.log(`[PREVIEW:init] generateSessionContent result:`, JSON.stringify(result));
16
19
 
17
20
  // Invalidate the cached dynamic source so the next page request
18
21
  // re-scans the content directory and picks up the new files.
19
22
  invalidateSessionSource(sessionId);
23
+ console.log(`[PREVIEW:init] DONE session=${sessionId}`);
20
24
 
21
25
  return Response.json({
22
26
  status: 'ready',
@@ -26,7 +30,7 @@ export async function POST(
26
30
  });
27
31
  } catch (error) {
28
32
  const message = error instanceof Error ? error.message : 'Unknown error';
29
- console.error(`[PREVIEW] Init failed for session ${sessionId}:`, message);
33
+ console.error(`[PREVIEW:init] FAILED session=${sessionId}:`, message);
30
34
  return Response.json(
31
35
  { status: 'error', error: message },
32
36
  { status: 500 },
@@ -12,6 +12,8 @@ export async function POST(
12
12
  const { sessionId } = await params;
13
13
  const file = request.nextUrl.searchParams.get('file');
14
14
 
15
+ console.log(`[PREVIEW:sync] START session=${sessionId} file=${file}`);
16
+
15
17
  if (!file) {
16
18
  return Response.json(
17
19
  { error: 'Missing "file" query parameter' },
@@ -21,9 +23,11 @@ export async function POST(
21
23
 
22
24
  try {
23
25
  const result = syncSessionFile(sessionId, file);
26
+ console.log(`[PREVIEW:sync] syncSessionFile result:`, JSON.stringify(result));
24
27
 
25
28
  // Invalidate cached source so next page request re-scans content
26
29
  invalidateSessionSource(sessionId);
30
+ console.log(`[PREVIEW:sync] DONE session=${sessionId} file=${file}`);
27
31
 
28
32
  return Response.json({
29
33
  status: 'synced',
@@ -32,7 +36,7 @@ export async function POST(
32
36
  });
33
37
  } catch (error) {
34
38
  const message = error instanceof Error ? error.message : 'Unknown error';
35
- console.error(`[PREVIEW] Sync failed for session ${sessionId}, file ${file}:`, message);
39
+ console.error(`[PREVIEW:sync] FAILED session=${sessionId} file=${file}:`, message);
36
40
  return Response.json(
37
41
  { status: 'error', error: message },
38
42
  { status: 500 },
@@ -755,7 +755,10 @@ export function syncSessionFile(
755
755
  const workspaceDir = join(WORKSPACE_DIR, sessionId);
756
756
  const outputDir = join(PREVIEW_CONTENT_DIR, sessionId);
757
757
 
758
+ console.log(`[PREVIEW:syncFile] session=${sessionId} file=${filePath} workspace=${workspaceDir} output=${outputDir}`);
759
+
758
760
  if (filePath === PRIMARY_CONFIG_NAME || filePath === LEGACY_CONFIG_NAME) {
761
+ console.log(`[PREVIEW:syncFile] Config file changed — regenerating all content`);
759
762
  generateSessionContent(sessionId);
760
763
  return { synced: true };
761
764
  }
@@ -777,9 +780,13 @@ export function syncSessionFile(
777
780
  srcPath = join(workspaceDir, `${stripped}.md`);
778
781
  }
779
782
  if (!existsSync(srcPath)) {
783
+ console.log(`[PREVIEW:syncFile] Source file NOT FOUND at any candidate path for ${filePath}`);
780
784
  return { synced: false };
781
785
  }
782
786
 
787
+ const srcContent = readFileSync(srcPath, 'utf-8');
788
+ console.log(`[PREVIEW:syncFile] Source file: ${srcPath} (${srcContent.length} chars, first 120: ${JSON.stringify(srcContent.slice(0, 120))})`);
789
+
783
790
  try {
784
791
  const { config } = loadConfig(workspaceDir);
785
792
  const artifacts = buildArtifacts(config, workspaceDir);
@@ -789,15 +796,22 @@ export function syncSessionFile(
789
796
 
790
797
  if (mapping) {
791
798
  const destPath = join(outputDir, `${mapping.dest}.mdx`);
799
+ console.log(`[PREVIEW:syncFile] Mapped: ${stripped} -> ${mapping.dest}, writing to ${destPath}`);
792
800
  processPage(srcPath, destPath, stripped, variables, sessionId);
801
+ const written = readFileSync(destPath, 'utf-8');
802
+ console.log(`[PREVIEW:syncFile] Written dest (${written.length} chars, first 120: ${JSON.stringify(written.slice(0, 120))})`);
793
803
  return { synced: true };
794
804
  }
795
- } catch {
796
- // Fall through to direct copy
805
+ console.log(`[PREVIEW:syncFile] No mapping found for ${stripped} in pageMap (${artifacts.pageMap.length} entries)`);
806
+ } catch (err) {
807
+ console.log(`[PREVIEW:syncFile] Mapping lookup failed, falling through to direct copy:`, err instanceof Error ? err.message : err);
797
808
  }
798
809
 
799
810
  const destPath = join(outputDir, `${stripped}.mdx`);
811
+ console.log(`[PREVIEW:syncFile] Direct copy: ${srcPath} -> ${destPath}`);
800
812
  processPage(srcPath, destPath, stripped, variables, sessionId);
813
+ const written = readFileSync(destPath, 'utf-8');
814
+ console.log(`[PREVIEW:syncFile] Written dest (${written.length} chars, first 120: ${JSON.stringify(written.slice(0, 120))})`);
801
815
  return { synced: true };
802
816
  }
803
817
 
@@ -9,7 +9,7 @@
9
9
  * Used only in preview mode (PREVIEW_MODE=true) — production builds still use
10
10
  * the standard `source.ts` with build-time collections.
11
11
  */
12
- import { existsSync, readFileSync, readdirSync } from 'node:fs';
12
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
13
13
  import { join, relative } from 'node:path';
14
14
  import { loader } from 'fumadocs-core/source';
15
15
  import { dynamic } from 'fumadocs-mdx/runtime/dynamic';
@@ -24,6 +24,11 @@ import * as sourceConfigExports from '../source.config';
24
24
 
25
25
  const PREVIEW_CONTENT_DIR = process.env.PREVIEW_CONTENT_DIR || './content';
26
26
 
27
+ function log(tag: string, msg: string, data?: Record<string, unknown>) {
28
+ const payload = data ? ' ' + JSON.stringify(data) : '';
29
+ console.log(`[PREVIEW:${tag}] ${msg}${payload}`);
30
+ }
31
+
27
32
  // ── Cache ──────────────────────────────────────────────────────────────────
28
33
 
29
34
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -37,6 +42,7 @@ async function getDynamic() {
37
42
  if (dynamicInstance) return dynamicInstance;
38
43
  if (dynamicInitPromise) return dynamicInitPromise;
39
44
 
45
+ log('dynamic', 'Initializing new dynamic() instance');
40
46
  dynamicInitPromise = dynamic(
41
47
  sourceConfigExports,
42
48
  {
@@ -47,6 +53,7 @@ async function getDynamic() {
47
53
  ).then((inst) => {
48
54
  dynamicInstance = inst;
49
55
  dynamicInitPromise = null;
56
+ log('dynamic', 'dynamic() instance ready');
50
57
  return inst;
51
58
  });
52
59
 
@@ -146,11 +153,16 @@ function scanContentDir(sessionDir: string): {
146
153
  */
147
154
  export async function getSessionSource(sessionId: string) {
148
155
  const cached = sourceCache.get(sessionId);
149
- if (cached) return cached.source;
156
+ if (cached) {
157
+ const age = Date.now() - cached.createdAt;
158
+ log('source', `Cache HIT for session ${sessionId}`, { ageMs: age });
159
+ return cached.source;
160
+ }
161
+ log('source', `Cache MISS for session ${sessionId}`);
150
162
 
151
163
  const sessionDir = join(PREVIEW_CONTENT_DIR, sessionId);
152
164
  if (!existsSync(sessionDir)) {
153
- // Return an empty source if no content yet
165
+ log('source', `Session dir does not exist: ${sessionDir}`);
154
166
  const emptySource = loader({
155
167
  baseUrl: '/',
156
168
  source: { files: [] },
@@ -161,6 +173,20 @@ export async function getSessionSource(sessionId: string) {
161
173
  const dyn = await getDynamic();
162
174
  const { entries, metaFiles } = scanContentDir(sessionDir);
163
175
 
176
+ log('source', `Scanned ${sessionDir}`, {
177
+ entryCount: entries.length,
178
+ metaFileCount: Object.keys(metaFiles).length,
179
+ files: entries.map((e) => {
180
+ const stat = statSync(e.info.fullPath, { throwIfNoEntry: false });
181
+ return {
182
+ path: e.info.path,
183
+ title: e.data.title,
184
+ sizeBytes: stat?.size,
185
+ mtimeMs: stat?.mtimeMs,
186
+ };
187
+ }),
188
+ });
189
+
164
190
  const collection = await dyn.docs('docs', sessionDir, metaFiles, entries);
165
191
  const fumadocsSource = collection.toFumadocsSource();
166
192
 
@@ -188,6 +214,9 @@ export async function getSessionSource(sessionId: string) {
188
214
  });
189
215
 
190
216
  sourceCache.set(sessionId, { source: src, createdAt: Date.now() });
217
+ log('source', `Built and cached source for session ${sessionId}`, {
218
+ pageCount: src.getPages().length,
219
+ });
191
220
  return src;
192
221
  }
193
222
 
@@ -196,7 +225,9 @@ export async function getSessionSource(sessionId: string) {
196
225
  * Call after content generation or sync so the next request re-scans.
197
226
  */
198
227
  export function invalidateSessionSource(sessionId: string): void {
228
+ const had = sourceCache.has(sessionId);
199
229
  sourceCache.delete(sessionId);
230
+ log('invalidate', `session=${sessionId} hadCache=${had} remainingKeys=[${[...sourceCache.keys()].join(',')}]`);
200
231
  }
201
232
 
202
233
  /**