@@ -18,6 +18,8 @@ interface ContentDocument {
1818 hashnode ?: string ;
1919 awsbuilder ?: string ;
2020 dailydev ?: string ;
21+ medium ?: string ;
22+ reddit ?: string ;
2123 tags ?: Array < { _key ?: string ; label ?: string ; value ?: string } > ;
2224 sponsor ?: Array < { _ref : string } > ;
2325 syndications ?: Array < { _type : "reference" ; _ref : string ; _key ?: string } > ;
@@ -169,10 +171,13 @@ export const handler = documentEventHandler<ContentDocument>(
169171 Boolean ( data . awsbuilder ) ||
170172 process . env . FORCE_AWS_BUILDER === "true" ;
171173
172- const platforms : Array < "devto" | "hashnode" | "dailydev" | "awsbuilder" > = [
174+ const platforms : Array <
175+ "devto" | "hashnode" | "dailydev" | "reddit" | "awsbuilder"
176+ > = [
173177 "devto" ,
174178 "hashnode" ,
175179 "dailydev" ,
180+ "reddit" ,
176181 ...( shouldSyndicateAws ? ( [ "awsbuilder" ] as const ) : [ ] ) ,
177182 ] ;
178183
@@ -199,7 +204,9 @@ export const handler = documentEventHandler<ContentDocument>(
199204 ? "hashnode.com"
200205 : platform === "dailydev"
201206 ? "daily.dev"
202- : "builder.aws.com" ;
207+ : platform === "reddit"
208+ ? "reddit.com/r/CodingCatDev"
209+ : "builder.aws.com" ;
203210 await client . createOrReplace ( {
204211 _id : syndicationDocId ,
205212 _type : "syndication" ,
@@ -1013,6 +1020,152 @@ export const handler = documentEventHandler<ContentDocument>(
10131020 console . log (
10141021 `[Syndicate Content] Successfully published to daily.dev Squad: ${ externalUrl } ` ,
10151022 ) ;
1023+ } else if ( platform === "reddit" ) {
1024+ const redditRefreshToken = process . env . REDDIT_REFRESH_TOKEN ;
1025+ if ( ! redditRefreshToken ) {
1026+ console . warn (
1027+ "[Syndicate Content] REDDIT_REFRESH_TOKEN not configured. Skipping Reddit (r/CodingCatDev) live dispatch." ,
1028+ ) ;
1029+ continue ;
1030+ }
1031+
1032+ const existingSyndication = await client
1033+ . getDocument ( syndicationDocId )
1034+ . catch ( ( ) => null ) ;
1035+ let redditUrl =
1036+ ( existingSyndication ?. externalUrl &&
1037+ ! String ( existingSyndication . externalUrl ) . includes ( "preview-simulated" )
1038+ ? String ( existingSyndication . externalUrl )
1039+ : null ) ||
1040+ data . reddit ||
1041+ null ;
1042+ let thingId = existingSyndication ?. externalId
1043+ ? String ( existingSyndication . externalId )
1044+ : null ;
1045+
1046+ if ( ! redditUrl ) {
1047+ const basicAuth = Buffer . from ( "TWTsqXa53CexlrYGBWaesQ:" ) . toString ( "base64" ) ;
1048+ const refreshRes = await fetch ( "https://www.reddit.com/api/v1/access_token" , {
1049+ method : "POST" ,
1050+ headers : {
1051+ Authorization : `Basic ${ basicAuth } ` ,
1052+ "Content-Type" : "application/x-www-form-urlencoded" ,
1053+ "User-Agent" : "codingcat-sync/0.1.0 by u/ajonp" ,
1054+ } ,
1055+ body : new URLSearchParams ( {
1056+ grant_type : "refresh_token" ,
1057+ refresh_token : redditRefreshToken ,
1058+ } ) ,
1059+ } ) ;
1060+ const { access_token : redditAccessToken } = ( await refreshRes . json ( ) ) as {
1061+ access_token ?: string ;
1062+ } ;
1063+ if ( ! redditAccessToken ) {
1064+ throw new Error ( "Could not refresh Reddit OAuth access_token" ) ;
1065+ }
1066+
1067+ const targetLinkUrl = topYouTubeWatchUrl || canonicalUrl ;
1068+ const prefix = data . _type === "podcast" ? "[Podcast] " : "" ;
1069+ const postTitle = `${ prefix } ${ data . title || "Untitled" } ` . slice ( 0 , 300 ) ;
1070+
1071+ const subRes = await fetch ( "https://oauth.reddit.com/api/submit" , {
1072+ method : "POST" ,
1073+ headers : {
1074+ Authorization : `Bearer ${ redditAccessToken } ` ,
1075+ "Content-Type" : "application/x-www-form-urlencoded" ,
1076+ "User-Agent" : "codingcat-sync/0.1.0 by u/ajonp" ,
1077+ } ,
1078+ body : new URLSearchParams ( {
1079+ api_type : "json" ,
1080+ sr : "CodingCatDev" ,
1081+ kind : "link" ,
1082+ title : postTitle ,
1083+ url : targetLinkUrl ,
1084+ resubmit : "true" ,
1085+ } ) ,
1086+ } ) ;
1087+ const subJson = ( await subRes . json ( ) ) as any ;
1088+ const subData = subJson ?. json ?. data ;
1089+ if ( ! subData ?. url ) {
1090+ throw new Error (
1091+ `Reddit api/submit error: ${ JSON . stringify ( subJson ?. json ?. errors || subJson ) } ` ,
1092+ ) ;
1093+ }
1094+
1095+ redditUrl = subData . url ;
1096+ thingId = subData . name || subData . id ;
1097+
1098+ const commentText = [
1099+ data . excerpt ? `> ${ data . excerpt . trim ( ) } ` : "" ,
1100+ "" ,
1101+ `📖 **Read the full guide, code snippets & transcript on CodingCat.dev:** [${ canonicalUrl } ](${ canonicalUrl } )` ,
1102+ topYouTubeWatchUrl
1103+ ? `📺 **Watch on YouTube & Subscribe:** [${ topYouTubeWatchUrl } ](${ topYouTubeWatchUrl } ${ topYouTubeWatchUrl . includes ( "?" ) ? "&" : "?" } sub_confirmation=1)`
1104+ : `📺 **Subscribe to CodingCat.dev on YouTube:** [https://www.youtube.com/@CodingCatDev](https://www.youtube.com/@CodingCatDev?sub_confirmation=1)` ,
1105+ ]
1106+ . filter ( Boolean )
1107+ . join ( "\n" ) ;
1108+
1109+ const comRes = await fetch ( "https://oauth.reddit.com/api/comment" , {
1110+ method : "POST" ,
1111+ headers : {
1112+ Authorization : `Bearer ${ redditAccessToken } ` ,
1113+ "Content-Type" : "application/x-www-form-urlencoded" ,
1114+ "User-Agent" : "codingcat-sync/0.1.0 by u/ajonp" ,
1115+ } ,
1116+ body : new URLSearchParams ( {
1117+ api_type : "json" ,
1118+ thing_id : String ( thingId ) ,
1119+ text : commentText ,
1120+ } ) ,
1121+ } ) ;
1122+ const comJson = ( await comRes . json ( ) ) as any ;
1123+ const comName = comJson ?. json ?. data ?. things ?. [ 0 ] ?. data ?. name ;
1124+ if ( comName ) {
1125+ await fetch ( "https://oauth.reddit.com/api/distinguish" , {
1126+ method : "POST" ,
1127+ headers : {
1128+ Authorization : `Bearer ${ redditAccessToken } ` ,
1129+ "Content-Type" : "application/x-www-form-urlencoded" ,
1130+ "User-Agent" : "codingcat-sync/0.1.0 by u/ajonp" ,
1131+ } ,
1132+ body : new URLSearchParams ( {
1133+ api_type : "json" ,
1134+ id : String ( comName ) ,
1135+ how : "yes" ,
1136+ sticky : "true" ,
1137+ } ) ,
1138+ } ) ;
1139+ }
1140+ }
1141+
1142+ if ( redditUrl ) {
1143+ const extractedId =
1144+ thingId ||
1145+ redditUrl . match ( / c o m m e n t s \/ ( [ a - z 0 - 9 ] + ) / i) ?. [ 1 ] ||
1146+ data . _id ;
1147+
1148+ await client . createOrReplace ( {
1149+ _id : syndicationDocId ,
1150+ _type : "syndication" ,
1151+ target : { _type : "reference" , _ref : data . _id } ,
1152+ platform : "reddit" ,
1153+ status : "published" ,
1154+ canonicalUrl,
1155+ externalUrl : redditUrl ,
1156+ externalId : String ( extractedId ) ,
1157+ syndicatedAt : new Date ( ) . toISOString ( ) ,
1158+ error : undefined ,
1159+ } ) ;
1160+
1161+ if ( data . reddit !== redditUrl ) {
1162+ parentPatch . reddit = redditUrl ;
1163+ }
1164+
1165+ console . log (
1166+ `[Syndicate Content] Successfully published to Reddit (r/CodingCatDev): ${ redditUrl } ` ,
1167+ ) ;
1168+ }
10161169 }
10171170 } catch ( publishErr ) {
10181171 const errMsg =
0 commit comments