Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 24 additions & 8 deletions src/commands/executeStepZenRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,19 @@ export async function executeStepZenRequest(options: {
let customHeaders: Record<string, string> = {};
let adminKey: string | undefined;
if (auth?.type === 'jwt') {
// Always need the admin key for debug header
adminKey = await services.request.getApiKey();
// JWT auth: use JWT for Authorization, admin key for debug
adminKey = await services.request.getAdminKey();
customHeaders = {
'Authorization': `Bearer ${auth.jwt}`,
'StepZen-Debug-Authorization': `apikey ${adminKey}`,
'stepzen-debug-level': String(debugLevel),
'Stepzen-Debug-Level': String(debugLevel),
};
} else {
// Default: admin key in Authorization
adminKey = await services.request.getApiKey();
// Admin auth: use admin key for Authorization
adminKey = await services.request.getAdminKey();
customHeaders = {
'Authorization': `Apikey ${adminKey}`,
'stepzen-debug-level': String(debugLevel),
'Stepzen-Debug-Level': String(debugLevel),
};
}

Expand All @@ -98,9 +98,17 @@ export async function executeStepZenRequest(options: {
operationName,
customHeaders
);
// Process results
// Process results and validate debug data
const rawDiags = (result.extensions?.stepzen?.diagnostics ?? []) as StepZenDiagnostic[];
services.logger.info("Processing diagnostics for persisted operation...");
services.logger.debug(`Received ${rawDiags.length} diagnostic entries from StepZen`);

if (debugLevel > 0 && rawDiags.length === 0) {
services.logger.warn(`Expected debug data with debug level ${debugLevel}, but received no diagnostics. Check if headers were sent correctly.`);
} else if (debugLevel > 0) {
services.logger.info(`Successfully received debug data: ${rawDiags.length} diagnostic entries`);
}

const summaries = summariseDiagnostics(rawDiags);
publishDiagnostics(summaries, runtimeDiag);
services.logger.info("Persisted document request completed successfully");
Expand Down Expand Up @@ -186,9 +194,17 @@ export async function executeStepZenRequest(options: {
parseErr
);
}
// Process results
// Process results and validate debug data
const rawDiags = (json.extensions?.stepzen?.diagnostics ?? []) as StepZenDiagnostic[];
services.logger.info("Processing diagnostics for file-based request...");
services.logger.debug(`Received ${rawDiags.length} diagnostic entries from StepZen`);

if (debugLevel > 0 && rawDiags.length === 0) {
services.logger.warn(`Expected debug data with debug level ${debugLevel}, but received no diagnostics. Check if Stepzen-Debug-Level header was sent correctly.`);
} else if (debugLevel > 0) {
services.logger.info(`Successfully received debug data: ${rawDiags.length} diagnostic entries`);
}

const summaries = summariseDiagnostics(rawDiags);
publishDiagnostics(summaries, runtimeDiag);
await openResultsPanel(json);
Expand Down
50 changes: 46 additions & 4 deletions src/services/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,32 @@ export class StepzenCliService {
}, TIMEOUTS.FILE_CLEANUP_DELAY_MS);
}

// Build headers array - always include debug level, plus any custom headers
const headerArgs: string[] = [];
if (customHeaders && Object.keys(customHeaders).length > 0) {
// Add custom headers
Object.entries(customHeaders).forEach(([k, v]) => {
headerArgs.push('--header', `"${k}: ${v}"`);
});
} else {
// Fallback: just add debug level header
headerArgs.push('--header', `"Stepzen-Debug-Level: ${debugLevel}"`);
}

// Build args array for the request command
const args = [
'request',
'--file', tmpFile,
...(operationName ? ['--operation-name', operationName] : []),
// Add each header as its own --header argument, value wrapped in double quotes
...(customHeaders ? Object.entries(customHeaders).flatMap(([k, v]) => ['--header', `"${k}: ${v}"`]) : ['--header', `"stepzen-debug-level: ${debugLevel}"`]),
...headerArgs,
...varArgs
];

// Execute the request
logger.debug(`Executing StepZen request with args: ${args.join(' ')}${operationName ? ` (operation: ${operationName})` : ''}, debug level: ${debugLevel}`);
// Log the full command for debugging
const fullCommand = `stepzen ${args.join(' ')}`;
logger.info(`Executing StepZen CLI command: ${fullCommand}`);
logger.debug(`Command details: operation=${operationName || 'default'}, debugLevel=${debugLevel}, headers=${JSON.stringify(customHeaders || {})}`);

let stdout;
try {
stdout = await this.spawnProcessWithOutput(args, {
Expand Down Expand Up @@ -163,6 +177,34 @@ export class StepzenCliService {
}
}

/**
* Get the admin key from StepZen CLI
*
* @returns Promise resolving to the admin key
* @throws CliError if the operation fails
*/
async getAdminKey(): Promise<string> {
try {
logger.debug('Retrieving admin key from StepZen CLI');

const result = await this.spawnProcessWithOutput(['whoami', '--adminkey']);
const adminKey = result.trim();

if (!adminKey) {
throw new CliError("Empty admin key returned from StepZen CLI", "EMPTY_ADMIN_KEY");
}

logger.debug("Successfully retrieved admin key from CLI");
return adminKey;
} catch (err) {
throw new CliError(
"Failed to retrieve admin key from StepZen CLI",
"ADMIN_KEY_RETRIEVAL_FAILED",
err
);
}
}

/**
* Get the API key from StepZen CLI
*
Expand Down
30 changes: 28 additions & 2 deletions src/services/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,32 @@ export class RequestService {
return { variables };
}

/**
* Get the admin key from StepZen CLI
*
* @returns Promise resolving to the admin key
*/
public async getAdminKey(): Promise<string> {
try {
this.logger.debug("Retrieving admin key from StepZen CLI");

// Import services here to avoid circular dependency
const { services } = await import('./index.js');

// Use the CLI service's getAdminKey method
const adminKey = await services.cli.getAdminKey();

this.logger.debug("Successfully retrieved admin key from CLI service");
return adminKey;
} catch (err) {
throw new ValidationError(
"Failed to retrieve admin key from StepZen CLI",
"ADMIN_KEY_RETRIEVAL_FAILED",
err
);
}
}

/**
* Get the API key from StepZen CLI
*
Expand Down Expand Up @@ -191,11 +217,11 @@ export class RequestService {
// Import services here to avoid circular dependency
const { services } = await import('./index.js');

// Get account, domain, and API key from the CLI
// Get account, domain, and admin key from the CLI
const [account, domain, apiKey] = await Promise.all([
services.cli.getAccount(),
services.cli.getDomain(),
this.getApiKey()
this.getAdminKey()
]);

// Construct the GraphQL endpoint URL using the correct pattern
Expand Down