From 1bbf3cabed3554dc8bf876bcab62a7e7bb6759dd Mon Sep 17 00:00:00 2001 From: ghou9khub Date: Sun, 18 Jan 2026 22:52:30 -0800 Subject: [PATCH 1/2] Added header override options for codegen --- graphql/codegen/src/cli/commands/generate.ts | 4 +- .../src/cli/introspect/fetch-schema.ts | 70 +++++++++++++------ packages/cli/src/commands/codegen.ts | 17 ++++- 3 files changed, 67 insertions(+), 24 deletions(-) diff --git a/graphql/codegen/src/cli/commands/generate.ts b/graphql/codegen/src/cli/commands/generate.ts index 911465612..256f3d118 100644 --- a/graphql/codegen/src/cli/commands/generate.ts +++ b/graphql/codegen/src/cli/commands/generate.ts @@ -31,6 +31,8 @@ export interface GenerateOptions { output?: string; /** Authorization header */ authorization?: string; + /** Additional HTTP headers for endpoint requests */ + headers?: Record; /** Verbose output */ verbose?: boolean; /** Dry run - don't write files */ @@ -93,7 +95,7 @@ export async function generateCommand( endpoint: config.endpoint || undefined, schema: config.schema || undefined, authorization: options.authorization || config.headers['Authorization'], - headers: config.headers, + headers: options.headers || config.headers, }); // 3. Run the codegen pipeline diff --git a/graphql/codegen/src/cli/introspect/fetch-schema.ts b/graphql/codegen/src/cli/introspect/fetch-schema.ts index 3002ac944..d902eb64e 100644 --- a/graphql/codegen/src/cli/introspect/fetch-schema.ts +++ b/graphql/codegen/src/cli/introspect/fetch-schema.ts @@ -2,6 +2,9 @@ * Fetch GraphQL schema introspection from an endpoint */ import { SCHEMA_INTROSPECTION_QUERY } from './schema-query'; +import * as http from 'node:http'; +import * as https from 'node:https'; +import { URL } from 'node:url'; import type { IntrospectionQueryResponse } from '../../types/introspection'; export interface FetchSchemaOptions { @@ -41,59 +44,82 @@ export async function fetchSchema( requestHeaders['Authorization'] = authorization; } - // Create abort controller for timeout const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); try { - const response = await fetch(endpoint, { + const url = new URL(endpoint); + const isHttps = url.protocol === 'https:'; + const client = isHttps ? https : http; + const body = JSON.stringify({ query: SCHEMA_INTROSPECTION_QUERY, variables: {} }); + const reqHeaders: Record = { + ...requestHeaders, + 'Content-Length': Buffer.byteLength(body), + }; + + const reqOptions: http.RequestOptions = { + protocol: url.protocol, + hostname: url.hostname, + port: url.port ? Number(url.port) : isHttps ? 443 : 80, + path: url.pathname + url.search, method: 'POST', - headers: requestHeaders, - body: JSON.stringify({ - query: SCHEMA_INTROSPECTION_QUERY, - variables: {}, - }), - signal: controller.signal, + headers: reqHeaders, + }; + + const jsonResult = await new Promise<{ statusCode: number; json: any }>((resolve, reject) => { + const req = client.request(reqOptions, (res) => { + const chunks: Buffer[] = []; + res.on('data', (c) => chunks.push(c as Buffer)); + res.on('end', () => { + try { + const text = Buffer.concat(chunks).toString('utf8'); + const parsed = text ? JSON.parse(text) : {}; + resolve({ statusCode: res.statusCode || 0, json: parsed }); + } catch (e) { + reject(e); + } + }); + }); + req.on('error', reject); + req.setTimeout(timeout, () => { + req.destroy(new Error(`Request timeout after ${timeout}ms`)); + }); + req.write(body); + req.end(); }); clearTimeout(timeoutId); - if (!response.ok) { + const { statusCode = 0, json } = jsonResult; + if (statusCode < 200 || statusCode >= 300) { return { success: false, - error: `HTTP ${response.status}: ${response.statusText}`, - statusCode: response.status, + error: `HTTP ${statusCode}: ${json?.errors?.[0]?.message || 'Request failed'}`, + statusCode, }; } - const json = (await response.json()) as { - data?: IntrospectionQueryResponse; - errors?: Array<{ message: string }>; - }; - - // Check for GraphQL errors if (json.errors && json.errors.length > 0) { - const errorMessages = json.errors.map((e) => e.message).join('; '); + const errorMessages = json.errors.map((e: any) => e.message).join('; '); return { success: false, error: `GraphQL errors: ${errorMessages}`, - statusCode: response.status, + statusCode, }; } - // Check if __schema is present if (!json.data?.__schema) { return { success: false, error: 'No __schema field in response. Introspection may be disabled on this endpoint.', - statusCode: response.status, + statusCode, }; } return { success: true, data: json.data, - statusCode: response.status, + statusCode, }; } catch (err) { clearTimeout(timeoutId); diff --git a/packages/cli/src/commands/codegen.ts b/packages/cli/src/commands/codegen.ts index df220bb96..06a555392 100644 --- a/packages/cli/src/commands/codegen.ts +++ b/packages/cli/src/commands/codegen.ts @@ -16,7 +16,8 @@ Options: --config Path to graphql-codegen config file --endpoint GraphQL endpoint URL --auth Authorization header value (e.g., "Bearer 123") - --out Output directory (default: graphql/codegen/dist) + --header "Name: Value" Optional HTTP header; repeat to add multiple + --out Output directory --dry-run Preview without writing files -v, --verbose Verbose output @@ -45,6 +46,19 @@ export default async ( const options: ConstructiveOptions = selectedDb ? getEnvOptions({ pg: { database: selectedDb } }) : getEnvOptions() const schemasArg = (argv.schemas as string) || '' + // Parse repeatable --header args into a headers object + const headerArg = argv.header as string | string[] | undefined + const headerList = Array.isArray(headerArg) ? headerArg : headerArg ? [headerArg] : [] + const headers: Record = {} + for (const h of headerList) { + const idx = typeof h === 'string' ? h.indexOf(':') : -1 + if (idx <= 0) continue + const name = h.slice(0, idx).trim() + const value = h.slice(idx + 1).trim() + if (!name) continue + headers[name] = value + } + const runGenerate = async ({ endpoint, schema }: { endpoint?: string; schema?: string }) => { const result = await generateCommand({ config: configPath || undefined, @@ -52,6 +66,7 @@ export default async ( schema, output: outDir, authorization: auth || undefined, + headers, verbose, dryRun, }) From b35ce1ab83343e8e8c54ddc502566519d6bf4029 Mon Sep 17 00:00:00 2001 From: ghou9khub Date: Sun, 18 Jan 2026 22:56:20 -0800 Subject: [PATCH 2/2] Merge main --- packages/cli/src/commands/codegen.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cli/src/commands/codegen.ts b/packages/cli/src/commands/codegen.ts index afeb9d7d9..a22265e1e 100644 --- a/packages/cli/src/commands/codegen.ts +++ b/packages/cli/src/commands/codegen.ts @@ -61,7 +61,6 @@ export default async ( : getEnvOptions(); const schemasArg = (argv.schemas as string) || ''; - // Parse repeatable --header args into a headers object const headerArg = argv.header as string | string[] | undefined const headerList = Array.isArray(headerArg) ? headerArg : headerArg ? [headerArg] : []