1- // /api/comments.js
2-
3- import fs from "fs" ;
4- import path from "path" ;
51import { kv } from "@vercel/kv" ;
62import sanitizeHtml from "sanitize-html" ;
3+ import fs from "fs/promises" ;
4+ import path from "path" ;
75
8- const USE_KV = process . env . USE_KV === "true" ;
9-
10- function filePath ( ) { return path . join ( process . cwd ( ) , "comments.json" ) ; }
6+ const USE_KV = process . env . VERCEL_ENV === "production" ;
7+ const COMMENTS_DIR = path . join ( process . cwd ( ) , "comments" ) ;
118
9+ // Always use KV—remove file‐based fallback to avoid race conditions
1210async function readComments ( slug ) {
13- if ( USE_KV ) return ( await kv . get ( `comments:${ slug } ` ) ) || [ ] ;
14- if ( ! fs . existsSync ( filePath ( ) ) ) fs . writeFileSync ( filePath ( ) , "{}" ) ;
15- const data = JSON . parse ( fs . readFileSync ( filePath ( ) , "utf8" ) ) ;
16- return data [ slug ] || [ ] ;
11+ if ( USE_KV ) {
12+ return ( await kv . get ( `comments:${ slug } ` ) ) || [ ] ;
13+ }
14+ try {
15+ const file = path . join ( COMMENTS_DIR , `${ slug } .json` ) ;
16+ const raw = await fs . readFile ( file , "utf8" ) ;
17+ return JSON . parse ( raw ) ;
18+ } catch {
19+ return [ ] ;
20+ }
1721}
1822
1923async function writeComments ( slug , arr ) {
20- if ( USE_KV ) return kv . set ( `comments:${ slug } ` , arr ) ;
21- const data = fs . existsSync ( filePath ( ) )
22- ? JSON . parse ( fs . readFileSync ( filePath ( ) , "utf8" ) )
23- : { } ;
24- data [ slug ] = arr ;
25- fs . writeFileSync ( filePath ( ) , JSON . stringify ( data , null , 2 ) ) ;
24+ if ( USE_KV ) {
25+ await kv . set ( `comments:${ slug } ` , arr ) ;
26+ return ;
27+ }
28+ await fs . mkdir ( COMMENTS_DIR , { recursive : true } ) ;
29+ const file = path . join ( COMMENTS_DIR , `${ slug } .json` ) ;
30+ await fs . writeFile ( file , JSON . stringify ( arr , null , 2 ) , "utf8" ) ;
2631}
2732
2833export default async function handler ( req , res ) {
29- if ( req . method === 'POST' && ! req . body ) {
30- return res . status ( 400 ) . json ( { error : "Invalid or missing request body" } ) ;
31- }
34+ if ( req . method === 'POST' && ! req . body ) {
35+ return res . status ( 400 ) . json ( { error : "Invalid or missing request body" } ) ;
36+ }
3237
33- if ( req . method === 'GET' ) {
34- const { slug } = req . query ;
35- if ( ! slug ) {
36- return res . status ( 400 ) . json ( { error : "Missing slug" } ) ;
37- }
38- const comments = await readComments ( slug ) ;
39- return res . status ( 200 ) . json ( comments ) ;
40- }
38+ if ( req . method === 'GET' ) {
39+ const { slug } = req . query ;
40+ if ( ! slug ) return res . status ( 400 ) . json ( { error : "Missing slug" } ) ;
41+ const comments = await readComments ( slug ) ;
42+ return res . status ( 200 ) . json ( comments ) ;
43+ }
4144
42- if ( req . method === 'POST' ) {
43- const { slug, text } = req . body ;
44- if ( ! slug || ! text ) {
45- return res . status ( 400 ) . json ( { error : "Missing slug or text" } ) ;
46- }
47-
48- const sanitizedText = sanitizeHtml ( text , {
49- allowedTags : [ ] ,
50- allowedAttributes : { } ,
51- } ) ;
52-
53- const timestamp = Date . now ( ) ;
54- const comments = await readComments ( slug ) ;
55- comments . push ( { text : sanitizedText , timestamp } ) ;
56- await writeComments ( slug , comments ) ;
57- return res . status ( 201 ) . json ( { text : sanitizedText , timestamp } ) ;
45+ if ( req . method === 'POST' ) {
46+ const { slug, text, author } = req . body ;
47+ if ( ! slug || ! text ) {
48+ return res . status ( 400 ) . json ( { error : "Missing slug or text" } ) ;
5849 }
5950
60- res . setHeader ( 'Allow' , [ 'GET' , 'POST' ] ) ;
61- res . status ( 405 ) . end ( `Method ${ req . method } Not Allowed` ) ;
62- }
51+ const sanitizedText = sanitizeHtml ( text , {
52+ allowedTags : [ ] ,
53+ allowedAttributes : { } ,
54+ } ) ;
55+ const sanitizedAuthor = sanitizeHtml ( author || "Anonymous" , {
56+ allowedTags : [ ] ,
57+ allowedAttributes : { } ,
58+ } ) ;
59+ const timestamp = new Date ( ) ;
60+
61+ const comments = await readComments ( slug ) ;
62+ comments . push ( { author : sanitizedAuthor , text : sanitizedText , timestamp } ) ;
63+ await writeComments ( slug , comments ) ;
64+
65+ return res . status ( 201 ) . json ( { author : sanitizedAuthor , text : sanitizedText , timestamp } ) ;
66+ }
67+
68+ res . setHeader ( 'Allow' , [ 'GET' , 'POST' ] ) ;
69+ res . status ( 405 ) . end ( `Method ${ req . method } Not Allowed` ) ;
70+ }
0 commit comments