@@ -2,23 +2,15 @@ import * as vscode from "vscode";
22import * as fs from "fs" ;
33import * as path from "path" ;
44import * as os from "os" ;
5- import * as https from "https" ;
65import { resolveStepZenProjectRoot } from "../utils/stepzenProject" ;
76import { clearResultsPanel , openResultsPanel } from "../panels/resultsPanel" ;
87import { summariseDiagnostics , publishDiagnostics } from "../utils/runtimeDiagnostics" ;
98import { runtimeDiag } from "../extension" ;
10- import { UI , TIMEOUTS , TEMP_FILE_PATTERNS , FILE_PATTERNS } from "../utils/constants" ;
9+ import { UI , TIMEOUTS , TEMP_FILE_PATTERNS } from "../utils/constants" ;
1110import { services } from "../services" ;
1211import { StepZenResponse , StepZenDiagnostic } from "../types" ;
13- import { ValidationError , NetworkError , handleError } from "../errors" ;
12+ import { ValidationError , handleError } from "../errors" ;
1413
15- /* CLEANUP - DELETE WHEN SAFE
16- // Export utility functions for use in other files
17- export {
18- createTempGraphQLFile,
19- cleanupLater
20- };
21- */
2214
2315/**
2416 * Creates a temporary GraphQL file with the provided query content
@@ -93,33 +85,17 @@ function cleanupLater(filePath: string) {
9385 */
9486export async function executeStepZenRequest ( options : {
9587 queryText ?: string ;
96- documentId ?: string ;
88+ documentContent ?: string ;
9789 operationName ?: string ;
9890 varArgs ?: string [ ] ;
9991} ) : Promise < void > {
100- // Validate options object
101- if ( ! options || typeof options !== 'object' ) {
102- handleError ( new ValidationError ( "Invalid request options provided" , "INVALID_OPTIONS" ) ) ;
103- return ;
104- }
105-
106- const { queryText, documentId, operationName, varArgs = [ ] } = options ;
107-
108- // Validate at least one of queryText or documentId is provided and valid
109- if ( documentId === undefined && ( ! queryText || typeof queryText !== 'string' ) ) {
110- handleError ( new ValidationError ( "Invalid request: either documentId or queryText must be provided" , "MISSING_QUERY" ) ) ;
111- return ;
112- }
113-
114- // Validate operationName if provided
115- if ( operationName !== undefined && typeof operationName !== 'string' ) {
116- handleError ( new ValidationError ( "Invalid operation name provided" , "INVALID_OPERATION_NAME" ) ) ;
117- return ;
118- }
92+ const { queryText, documentContent, operationName, varArgs = [ ] } = options ;
11993
120- // Validate varArgs is an array
121- if ( ! Array . isArray ( varArgs ) ) {
122- handleError ( new ValidationError ( "Invalid variable arguments: expected an array" , "INVALID_VAR_ARGS" ) ) ;
94+ // Validate request options using the request service
95+ try {
96+ services . request . validateRequestOptions ( { queryText, documentContent, operationName, varArgs } ) ;
97+ } catch ( err ) {
98+ handleError ( err ) ;
12399 return ;
124100 }
125101
@@ -136,90 +112,13 @@ export async function executeStepZenRequest(options: {
136112 const debugLevel = cfg . get < number > ( "request.debugLevel" , 1 ) ;
137113
138114 // For persisted documents, we need to make an HTTP request directly
139- if ( documentId ) {
115+ if ( documentContent ) {
140116 try {
141- // Get StepZen config to build the endpoint URL
142- const configPath = path . join ( projectRoot , FILE_PATTERNS . CONFIG_FILE ) ;
143- services . logger . debug ( `Looking for config file at: ${ configPath } ` ) ;
144-
145- // Verify config file exists
146- if ( ! fs . existsSync ( configPath ) ) {
147- handleError ( new ValidationError (
148- `StepZen configuration file not found at: ${ configPath } ` ,
149- "CONFIG_NOT_FOUND"
150- ) ) ;
151- return ;
152- }
153-
154- let endpoint : string ;
155- let apiKey : string ;
117+ // Load endpoint configuration using the request service
118+ const endpointConfig = await services . request . loadEndpointConfig ( projectRoot ) ;
156119
157- try {
158- const configContent = fs . readFileSync ( configPath , "utf8" ) ;
159-
160- if ( ! configContent ) {
161- handleError ( new ValidationError ( "StepZen configuration file is empty" , "EMPTY_CONFIG" ) ) ;
162- return ;
163- }
164-
165- const config = JSON . parse ( configContent ) ;
166-
167- if ( ! config || ! config . endpoint ) {
168- handleError ( new ValidationError ( "Invalid StepZen configuration: missing endpoint" , "MISSING_ENDPOINT" ) ) ;
169- return ;
170- }
171-
172- endpoint = config . endpoint ;
173- apiKey = config . apiKey || "" ;
174- } catch ( err ) {
175- handleError ( new ValidationError (
176- "Failed to parse StepZen configuration file" ,
177- "CONFIG_PARSE_ERROR" ,
178- err
179- ) ) ;
180- return ;
181- }
182-
183- // Parse endpoint to extract account and domain
184- const endpointParts = endpoint . split ( "/" ) ;
185- if ( endpointParts . length < 2 ) {
186- handleError ( new ValidationError (
187- `Invalid StepZen endpoint format: ${ endpoint } ` ,
188- "INVALID_ENDPOINT_FORMAT"
189- ) ) ;
190- return ;
191- }
192-
193- // Construct the GraphQL endpoint URL
194- const graphqlUrl = `https://${ endpoint } /graphql` ;
195-
196- // Prepare variables from varArgs
197- let variables : Record < string , string > = { } ;
198- for ( let i = 0 ; i < varArgs . length ; i += 2 ) {
199- if ( varArgs [ i ] === "--var" && i + 1 < varArgs . length ) {
200- const [ name , value ] = varArgs [ i + 1 ] . split ( "=" ) ;
201- variables [ name ] = value ;
202- } else if ( varArgs [ i ] === "--var-file" && i + 1 < varArgs . length ) {
203- try {
204- const fileContent = fs . readFileSync ( varArgs [ i + 1 ] , "utf8" ) ;
205- variables = JSON . parse ( fileContent ) ;
206- } catch ( err ) {
207- handleError ( new ValidationError (
208- "Failed to read variables file" ,
209- "VAR_FILE_READ_ERROR" ,
210- err
211- ) ) ;
212- return ;
213- }
214- }
215- }
216-
217- // Prepare the request body
218- const requestBody = {
219- documentId,
220- operationName,
221- variables
222- } ;
120+ // Parse variables using the request service
121+ const { variables } = services . request . parseVariables ( varArgs ) ;
223122
224123 // Show a progress notification
225124 await vscode . window . withProgress (
@@ -229,53 +128,13 @@ export async function executeStepZenRequest(options: {
229128 cancellable : false
230129 } ,
231130 async ( ) => {
232- services . logger . info ( "Making HTTP request to StepZen API for persisted document" ) ;
233- // Use Node.js https module to make the request
234- const result = await new Promise < StepZenResponse > ( ( resolve , reject ) => {
235- const postData = JSON . stringify ( requestBody ) ;
236-
237- const options = {
238- method : 'POST' ,
239- headers : {
240- 'Content-Type' : 'application/json' ,
241- 'Content-Length' : Buffer . byteLength ( postData ) ,
242- 'Authorization' : apiKey ? `Apikey ${ apiKey } ` : '' ,
243- 'stepzen-debug-level' : debugLevel . toString ( ) ,
244- }
245- } ;
246-
247- const req = https . request ( graphqlUrl , options , ( res ) => {
248- let responseData = '' ;
249-
250- res . on ( 'data' , ( chunk ) => {
251- responseData += chunk ;
252- } ) ;
253-
254- res . on ( 'end' , ( ) => {
255- try {
256- const json = JSON . parse ( responseData ) ;
257- resolve ( json ) ;
258- } catch ( err ) {
259- reject ( new ValidationError (
260- "Failed to parse StepZen response" ,
261- "RESPONSE_PARSE_ERROR" ,
262- err
263- ) ) ;
264- }
265- } ) ;
266- } ) ;
267-
268- req . on ( 'error' , ( err ) => {
269- reject ( new NetworkError (
270- "Failed to connect to StepZen API" ,
271- "API_CONNECTION_ERROR" ,
272- err
273- ) ) ;
274- } ) ;
275-
276- req . write ( postData ) ;
277- req . end ( ) ;
278- } ) ;
131+ // Execute the persisted document request using the request service
132+ const result = await services . request . executePersistedDocumentRequest (
133+ endpointConfig ,
134+ documentContent ,
135+ variables ,
136+ operationName
137+ ) ;
279138
280139 // Process results
281140 const rawDiags = ( result . extensions ?. stepzen ?. diagnostics ?? [ ] ) as StepZenDiagnostic [ ] ;
@@ -355,37 +214,8 @@ export async function executeStepZenRequest(options: {
355214 } ,
356215 async ( ) => {
357216 try {
358- // Parse varArgs into variables object
359- const variables : Record < string , any > = { } ;
360- for ( let i = 0 ; i < varArgs . length ; i += 2 ) {
361- if ( varArgs [ i ] === "--var" && i + 1 < varArgs . length ) {
362- const [ name , value ] = varArgs [ i + 1 ] . split ( "=" ) ;
363- if ( name && value !== undefined ) {
364- variables [ name ] = value ;
365- services . logger . debug ( `Setting variable ${ name } =${ value } ` ) ;
366- } else {
367- services . logger . warn ( `Invalid variable format: ${ varArgs [ i + 1 ] } ` ) ;
368- }
369- } else if ( varArgs [ i ] === "--var-file" && i + 1 < varArgs . length ) {
370- try {
371- const varFilePath = varArgs [ i + 1 ] ;
372- services . logger . debug ( `Reading variables from file: ${ varFilePath } ` ) ;
373- if ( ! fs . existsSync ( varFilePath ) ) {
374- throw new ValidationError ( `Variables file not found: ${ varFilePath } ` , "VAR_FILE_NOT_FOUND" ) ;
375- }
376- const fileContent = fs . readFileSync ( varFilePath , "utf8" ) ;
377- const fileVars = JSON . parse ( fileContent ) ;
378- services . logger . debug ( `Loaded ${ Object . keys ( fileVars ) . length } variables from file` ) ;
379- Object . assign ( variables , fileVars ) ;
380- } catch ( err ) {
381- throw new ValidationError (
382- "Failed to read variables file" ,
383- "VAR_FILE_READ_ERROR" ,
384- err
385- ) ;
386- }
387- }
388- }
217+ // Parse variables using the request service
218+ const { variables } = services . request . parseVariables ( varArgs ) ;
389219
390220 // Use the CLI service to execute the request
391221 services . logger . info ( `Executing StepZen request${ operationName ? ` for operation "${ operationName } "` : ' (anonymous operation)' } with debug level ${ debugLevel } ` ) ;
0 commit comments