Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | 17x 17x 17x 17x 17x 17x 7x 7x 7x 7x 7x 7x 2x 2x 2x 1x 7x 7x 7x 7x 2x 5x 5x 5x | import { STACKONE_HEADER_KEYS } from './headers';
import {
type RpcActionRequest,
type RpcActionResponse,
type RpcClientConfig,
rpcActionRequestSchema,
rpcActionResponseSchema,
rpcClientConfigSchema,
} from './schema';
import { StackOneAPIError } from './utils/errors';
// Re-export types for consumers and to make types portable
export type { RpcActionResponse } from './schema';
/**
* Custom RPC client for StackOne API.
* Replaces the @stackone/stackone-client-ts dependency.
*
* @see https://docs.stackone.com/platform/api-reference/actions/list-all-actions-metadata
* @see https://docs.stackone.com/platform/api-reference/actions/make-an-rpc-call-to-an-action
*/
export class RpcClient {
private readonly baseUrl: string;
private readonly authHeader: string;
constructor(config: RpcClientConfig) {
const validatedConfig = rpcClientConfigSchema.parse(config);
this.baseUrl = validatedConfig.serverURL || 'https://api.stackone.com';
const username = validatedConfig.security.username;
const password = validatedConfig.security.password || '';
this.authHeader = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
}
/**
* Actions namespace containing RPC methods
*/
readonly actions: {
rpcAction: (request: RpcActionRequest) => Promise<RpcActionResponse>;
} = {
/**
* Execute an RPC action
* @param request The RPC action request
* @returns The RPC action response matching server's ActionsRpcResponseApiModel
*/
rpcAction: async (request: RpcActionRequest): Promise<RpcActionResponse> => {
const validatedRequest = rpcActionRequestSchema.parse(request);
const url = `${this.baseUrl}/actions/rpc`;
const requestBody = {
action: validatedRequest.action,
body: validatedRequest.body,
headers: validatedRequest.headers,
path: validatedRequest.path,
query: validatedRequest.query,
} as const satisfies RpcActionRequest;
// Forward StackOne-specific headers as HTTP headers
const requestHeaders = validatedRequest.headers;
const forwardedHeaders: Record<string, string> = {};
if (requestHeaders) {
for (const key of STACKONE_HEADER_KEYS) {
const value = requestHeaders[key];
if (value !== undefined) {
forwardedHeaders[key] = value;
}
}
}
const httpHeaders = {
'Content-Type': 'application/json',
Authorization: this.authHeader,
'User-Agent': 'stackone-ai-node',
...forwardedHeaders,
} satisfies Record<string, string>;
const response = await fetch(url, {
method: 'POST',
headers: httpHeaders,
body: JSON.stringify(requestBody),
});
const responseBody: unknown = await response.json();
if (!response.ok) {
throw new StackOneAPIError(
`RPC action failed for ${url}`,
response.status,
responseBody,
requestBody,
);
}
const validation = rpcActionResponseSchema.safeParse(responseBody);
Iif (!validation.success) {
throw new StackOneAPIError(
`Invalid RPC action response for ${url}`,
response.status,
responseBody,
requestBody,
);
}
return validation.data;
},
};
}
|