@@ -2,6 +2,9 @@ import { NextRequest, NextResponse } from 'next/server';
22import { updatePage } from '@/lib/db' ;
33import { getCurrentUser } from '@/lib/users' ;
44import type { DocumentSection } from '@/lib/docs' ;
5+ import { revalidateDocsNavData , revalidatePageCaches } from '@/lib/revalidate-docs-cache' ;
6+
7+ const debugSave = process . env . DEBUG_API_SAVE === '1' ;
58
69// Tiptap/ProseMirror JSON node types for type-safe HTML rendering
710interface TiptapMark {
@@ -35,16 +38,17 @@ function renderNodeToHTML(node: TiptapNode): string {
3538 } ;
3639
3740 const renderMarks = ( text : string , marks : TiptapMark [ ] = [ ] ) => {
38- // DEBUG: Log original text
39- console . log ( '🟡 [DEBUG renderMarks] Original text:' , {
40- text : JSON . stringify ( text ) ,
41- textLength : text . length ,
42- spaceCount : ( text . match ( / / g) || [ ] ) . length ,
43- nbspCount : ( text . match ( / \u00A0 / g) || [ ] ) . length ,
44- hasMultipleSpaces : / { 2 , } / . test ( text ) ,
45- hasNbsp : text . includes ( '\u00A0' )
46- } ) ;
47-
41+ if ( debugSave ) {
42+ console . log ( '[DEBUG renderMarks] Original text:' , {
43+ text : JSON . stringify ( text ) ,
44+ textLength : text . length ,
45+ spaceCount : ( text . match ( / / g) || [ ] ) . length ,
46+ nbspCount : ( text . match ( / \u00A0 / g) || [ ] ) . length ,
47+ hasMultipleSpaces : / { 2 , } / . test ( text ) ,
48+ hasNbsp : text . includes ( '\u00A0' ) ,
49+ } ) ;
50+ }
51+
4852 // First escape the text (this will escape & but not \u00A0)
4953 let result = escapeHTML ( text ) ;
5054
@@ -56,19 +60,22 @@ function renderNodeToHTML(node: TiptapNode): string {
5660 // This is a fallback in case non-breaking spaces weren't inserted
5761 const beforeReplace = result ;
5862 result = result . replace ( / { 2 , } / g, ( match ) => {
59- // Convert all spaces in the sequence to
6063 const replacement = ' ' . repeat ( match . length ) ;
61- console . log ( '🟡 [DEBUG renderMarks] Replacing' , match . length , 'spaces with' , replacement . length , ' entities' ) ;
64+ if ( debugSave ) {
65+ console . log ( '[DEBUG renderMarks] Replacing spaces' , match . length , replacement . length ) ;
66+ }
6267 return replacement ;
6368 } ) ;
64-
65- // DEBUG: Log after processing
66- if ( beforeReplace !== result || text . includes ( '\u00A0' ) ) {
67- console . log ( '🟡 [DEBUG renderMarks] After processing:' , {
69+
70+ if (
71+ debugSave &&
72+ ( beforeReplace !== result || text . includes ( '\u00A0' ) )
73+ ) {
74+ console . log ( '[DEBUG renderMarks] After processing:' , {
6875 original : JSON . stringify ( text ) ,
6976 result : JSON . stringify ( result ) ,
7077 containsNbsp : result . includes ( ' ' ) ,
71- nbspCount : ( result . match ( / & n b s p ; / g) || [ ] ) . length
78+ nbspCount : ( result . match ( / & n b s p ; / g) || [ ] ) . length ,
7279 } ) ;
7380 }
7481
@@ -113,14 +120,15 @@ function renderNodeToHTML(node: TiptapNode): string {
113120
114121 switch ( node . type ) {
115122 case 'text' :
116- // DEBUG: Log ALL text nodes to see what we're working with
117- console . log ( '🟡 [DEBUG renderNodeToHTML] Text node:' , {
118- text : JSON . stringify ( node . text ) ,
119- textLength : node . text ?. length || 0 ,
120- spaceCount : node . text ? ( node . text . match ( / / g) || [ ] ) . length : 0 ,
121- hasMultipleSpaces : node . text ? / { 2 , } / . test ( node . text ) : false ,
122- multipleSpaceSequences : node . text ? node . text . match ( / { 2 , } / g) : null
123- } ) ;
123+ if ( debugSave ) {
124+ console . log ( '[DEBUG renderNodeToHTML] Text node:' , {
125+ text : JSON . stringify ( node . text ) ,
126+ textLength : node . text ?. length || 0 ,
127+ spaceCount : node . text ? ( node . text . match ( / / g) || [ ] ) . length : 0 ,
128+ hasMultipleSpaces : node . text ? / { 2 , } / . test ( node . text ) : false ,
129+ multipleSpaceSequences : node . text ? node . text . match ( / { 2 , } / g) : null ,
130+ } ) ;
131+ }
124132 return renderMarks ( node . text || '' , node . marks ) ;
125133
126134 case 'paragraph' :
@@ -339,14 +347,17 @@ function convertTiptapJSONToSections(tiptapJSON: TiptapJSON, pageId: string) {
339347 // Add any content (paragraphs, lists, code blocks, etc.) as HTML
340348 const html = renderNodeToHTML ( node ) ;
341349
342- // DEBUG: Log HTML output for paragraphs with multiple spaces
343- if ( node . type === 'paragraph' && html . includes ( ' ' ) || html . includes ( ' ' ) ) {
350+ if (
351+ debugSave &&
352+ node . type === 'paragraph' &&
353+ ( html . includes ( ' ' ) || html . includes ( ' ' ) )
354+ ) {
344355 console . log ( '[DEBUG convertTiptapJSONToSections] Paragraph HTML:' , {
345356 nodeType : node . type ,
346- html : html . substring ( 0 , 200 ) , // First 200 chars
357+ html : html . substring ( 0 , 200 ) ,
347358 containsMultipleSpaces : / { 2 , } / . test ( html ) ,
348359 containsNbsp : html . includes ( ' ' ) ,
349- htmlLength : html . length
360+ htmlLength : html . length ,
350361 } ) ;
351362 }
352363
@@ -513,13 +524,14 @@ export async function PATCH(
513524 const body = await request . json ( ) ;
514525 const { content, projectId } = body ;
515526
516- // DEBUG: Log what the server receives
517- console . log ( '🟡 [DEBUG API PATCH] Received save request:' , {
518- docId,
519- pageId,
520- projectId,
521- contentPreview : JSON . stringify ( content ) . substring ( 0 , 500 )
522- } ) ;
527+ if ( debugSave ) {
528+ console . log ( '[DEBUG API PATCH] save request' , {
529+ docId,
530+ pageId,
531+ projectId,
532+ contentPreview : JSON . stringify ( content ) . substring ( 0 , 500 ) ,
533+ } ) ;
534+ }
523535
524536 if ( ! content ) {
525537 return NextResponse . json (
@@ -528,21 +540,24 @@ export async function PATCH(
528540 ) ;
529541 }
530542
531- // DEBUG: Log full content structure before conversion
532- console . log ( '🟡 [DEBUG API PATCH] Full content structure:' , JSON . stringify ( content , null , 2 ) ) ;
533-
543+ if ( debugSave ) {
544+ console . log ( '[DEBUG API PATCH] full content' , JSON . stringify ( content , null , 2 ) ) ;
545+ }
546+
534547 // Convert Tiptap JSON to sections and extract title
535548 const { title, sections } = convertTiptapJSONToSections ( content , pageId ) ;
536549
537550 // Extract headings for table of contents
538551 const toc = extractHeadingsForTOC ( content ) ;
539552
540- // DEBUG: Log sections after conversion
541- console . log ( '🟡 [DEBUG API PATCH] Converted sections: ' , JSON . stringify ( sections , null , 2 ) ) ;
542- console . log ( '🟡 [DEBUG API PATCH] Extracted TOC:' , JSON . stringify ( toc , null , 2 ) ) ;
553+ if ( debugSave ) {
554+ console . log ( '[DEBUG API PATCH] sections' , JSON . stringify ( sections , null , 2 ) , 'toc' , JSON . stringify ( toc ) ) ;
555+ }
543556
544557 // Update or create page using updatePage function (it will verify document ownership)
545558 const page = await updatePage ( docId , pageId , title , sections as DocumentSection [ ] , user . id , projectId ) ;
559+ revalidatePageCaches ( pageId ) ;
560+ revalidateDocsNavData ( ) ;
546561
547562 return NextResponse . json ( {
548563 success : true ,
0 commit comments