11import { Credential , LeetCodeCN } from "leetcode-query" ;
2+ import {
3+ assertRunStartResponse ,
4+ assertSubmitStartResponse ,
5+ buildLeetCodeHeaders ,
6+ buildLeetCodeHttpAuth ,
7+ pollCheck ,
8+ postJson
9+ } from "../utils/leetcode-http.js" ;
210import logger from "../utils/logger.js" ;
311import {
412 NOTE_AGGREGATE_QUERY ,
@@ -19,12 +27,27 @@ import { LeetCodeBaseService } from "./leetcode-base-service.js";
1927export class LeetCodeCNService implements LeetCodeBaseService {
2028 private readonly leetCodeApi : LeetCodeCN ;
2129 private readonly credential : Credential ;
30+ private readonly origin = "https://leetcode.cn" ;
2231
2332 constructor ( leetCodeApi : LeetCodeCN , credential : Credential ) {
2433 this . leetCodeApi = leetCodeApi ;
2534 this . credential = credential ;
2635 }
2736
37+ private getHttpHeaders ( titleSlug : string ) : HeadersInit {
38+ const auth = buildLeetCodeHttpAuth ( {
39+ session : this . credential . session ?? "" ,
40+ csrfToken : this . credential . csrf ?? ""
41+ } ) ;
42+
43+ const referer = `${ this . origin } /problems/${ titleSlug } /` ;
44+ return buildLeetCodeHeaders ( {
45+ auth,
46+ origin : this . origin ,
47+ referer
48+ } ) ;
49+ }
50+
2851 async fetchUserSubmissionDetail ( id : number ) : Promise < any > {
2952 if ( ! this . isAuthenticated ( ) ) {
3053 throw new Error (
@@ -538,6 +561,88 @@ export class LeetCodeCNService implements LeetCodeBaseService {
538561 } ) ;
539562 }
540563
564+ async runCode ( params : {
565+ titleSlug : string ;
566+ questionId : string ;
567+ lang : string ;
568+ typedCode : string ;
569+ dataInput ?: string ;
570+ timeoutMs ?: number ;
571+ pollIntervalMs ?: number ;
572+ } ) : Promise < {
573+ start : Record < string , unknown > ;
574+ checkUrl : string ;
575+ check : Record < string , unknown > ;
576+ } > {
577+ if ( ! this . isAuthenticated ( ) ) {
578+ throw new Error ( "Authentication required to run code" ) ;
579+ }
580+
581+ const headers = this . getHttpHeaders ( params . titleSlug ) ;
582+ const startUrl = `${ this . origin } /problems/${ params . titleSlug } /interpret_solution/` ;
583+
584+ const start = await postJson (
585+ startUrl ,
586+ {
587+ data_input : params . dataInput ?? "" ,
588+ lang : params . lang ,
589+ question_id : params . questionId ,
590+ typed_code : params . typedCode
591+ } ,
592+ headers
593+ ) ;
594+
595+ assertRunStartResponse ( start , `POST ${ startUrl } ` ) ;
596+
597+ const checkUrl = `${ this . origin } /submissions/detail/${ start . interpret_id } /check/` ;
598+ const check = await pollCheck ( checkUrl , headers , {
599+ timeoutMs : params . timeoutMs ,
600+ pollIntervalMs : params . pollIntervalMs
601+ } ) ;
602+
603+ return { start, checkUrl, check } ;
604+ }
605+
606+ async submitSolution ( params : {
607+ titleSlug : string ;
608+ questionId : string ;
609+ lang : string ;
610+ typedCode : string ;
611+ timeoutMs ?: number ;
612+ pollIntervalMs ?: number ;
613+ } ) : Promise < {
614+ start : Record < string , unknown > ;
615+ checkUrl : string ;
616+ check : Record < string , unknown > ;
617+ } > {
618+ if ( ! this . isAuthenticated ( ) ) {
619+ throw new Error ( "Authentication required to submit solution" ) ;
620+ }
621+
622+ const headers = this . getHttpHeaders ( params . titleSlug ) ;
623+ const startUrl = `${ this . origin } /problems/${ params . titleSlug } /submit/` ;
624+
625+ const start = await postJson (
626+ startUrl ,
627+ {
628+ lang : params . lang ,
629+ question_id : params . questionId ,
630+ typed_code : params . typedCode
631+ } ,
632+ headers
633+ ) ;
634+
635+ assertSubmitStartResponse ( start , `POST ${ startUrl } ` ) ;
636+
637+ const checkUrl = `${ this . origin } /submissions/detail/${ start . submission_id } /check/` ;
638+ const check = await pollCheck ( checkUrl , headers , {
639+ timeoutMs : params . timeoutMs ,
640+ pollIntervalMs : params . pollIntervalMs
641+ } ) ;
642+
643+ return { start, checkUrl, check } ;
644+ }
645+
541646 isAuthenticated ( ) : boolean {
542647 return (
543648 ! ! this . credential &&
0 commit comments