diff --git a/src/custom/errors.ts b/src/custom/errors.ts new file mode 100644 index 0000000..9b75307 --- /dev/null +++ b/src/custom/errors.ts @@ -0,0 +1,52 @@ +import { AxiosError } from "axios"; + +type TApiErrorResponse = { + statusCode: number; + message: string; + error: string; +}; +export class InfisicalSDKError extends Error { + constructor(message: string) { + super(message); + this.message = message; + this.name = "InfisicalSDKError"; + } +} + +export class InfisicalSDKRequestError extends Error { + constructor( + message: string, + requestData: { + url: string; + method: string; + statusCode: number; + } + ) { + super(message); + this.message = `[URL=${requestData.url}] [Method=${requestData.method}] [StatusCode=${requestData.statusCode}] ${message}`; + this.name = "InfisicalSDKRequestError"; + } +} + +export const newInfisicalError = (error: any) => { + if (error instanceof AxiosError) { + const data = error?.response?.data as TApiErrorResponse; + + if (data?.message) { + return new InfisicalSDKRequestError(data.message, { + url: error.response?.config.url || "", + method: error.response?.config.method || "", + statusCode: error.response?.status || 0 + }); + } else if (error.message) { + return new InfisicalSDKError(error.message); + } else if (error.code) { + // If theres no message but a code is present, it's likely to be an aggregation error. This is not specific to Axios, but it falls under the AxiosError type + return new InfisicalSDKError(error.code); + } else { + return new InfisicalSDKError("Request failed with unknown error"); + } + } + + return new InfisicalSDKError(error?.message || "An error occurred"); +}; diff --git a/src/custom/secrets.ts b/src/custom/secrets.ts index 1b4b8a8..185754d 100644 --- a/src/custom/secrets.ts +++ b/src/custom/secrets.ts @@ -5,6 +5,7 @@ import type { DefaultApiApiV3SecretsRawSecretNamePatchRequest, DefaultApiApiV3SecretsRawSecretNamePostRequest } from "../infisicalapi_client"; +import { newInfisicalError } from "./errors"; type SecretType = "shared" | "personal"; @@ -48,80 +49,101 @@ export default class SecretsClient { #requestOptions: RawAxiosRequestConfig | undefined; constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) { this.#apiInstance = apiInstance; + this.#requestOptions = requestOptions; } listSecrets = async (options: ListSecretsOptions) => { - const res = await this.#apiInstance.apiV3SecretsRawGet( - { - environment: options.environment, - workspaceId: options.projectId, - expandSecretReferences: convertBool(options.expandSecretReferences), - includeImports: convertBool(options.includeImports), - recursive: convertBool(options.recursive), - secretPath: options.secretPath, - tagSlugs: options.tagSlugs ? options.tagSlugs.join(",") : undefined - }, - this.#requestOptions - ); - return res.data; + try { + const res = await this.#apiInstance.apiV3SecretsRawGet( + { + environment: options.environment, + workspaceId: options.projectId, + expandSecretReferences: convertBool(options.expandSecretReferences), + includeImports: convertBool(options.includeImports), + recursive: convertBool(options.recursive), + secretPath: options.secretPath, + tagSlugs: options.tagSlugs ? options.tagSlugs.join(",") : undefined + }, + this.#requestOptions + ); + return res.data; + } catch (err) { + throw newInfisicalError(err); + } }; getSecret = async (options: GetSecretOptions) => { - const res = await this.#apiInstance.apiV3SecretsRawSecretNameGet( - { - environment: options.environment, - secretName: options.secretName, - workspaceId: options.projectId, - expandSecretReferences: convertBool(options.expandSecretReferences), - includeImports: convertBool(options.includeImports), - secretPath: options.secretPath, - type: options.type, - version: options.version - }, - this.#requestOptions - ); - return res.data.secret; + try { + const res = await this.#apiInstance.apiV3SecretsRawSecretNameGet( + { + environment: options.environment, + secretName: options.secretName, + workspaceId: options.projectId, + expandSecretReferences: convertBool(options.expandSecretReferences), + includeImports: convertBool(options.includeImports), + secretPath: options.secretPath, + type: options.type, + version: options.version + }, + this.#requestOptions + ); + return res.data.secret; + } catch (err) { + throw newInfisicalError(err); + } }; updateSecret = async (secretName: DefaultApiApiV3SecretsRawSecretNamePatchRequest["secretName"], options: UpdateSecretOptions) => { - const res = await this.#apiInstance.apiV3SecretsRawSecretNamePatch( - { - secretName, - apiV3SecretsRawSecretNamePatchRequest: { - ...options, - workspaceId: options.projectId - } - }, - this.#requestOptions - ); - return res.data; + try { + const res = await this.#apiInstance.apiV3SecretsRawSecretNamePatch( + { + secretName, + apiV3SecretsRawSecretNamePatchRequest: { + ...options, + workspaceId: options.projectId + } + }, + this.#requestOptions + ); + return res.data; + } catch (err) { + throw newInfisicalError(err); + } }; createSecret = async (secretName: DefaultApiApiV3SecretsRawSecretNamePostRequest["secretName"], options: CreateSecretOptions) => { - const res = await this.#apiInstance.apiV3SecretsRawSecretNamePost( - { - secretName, - apiV3SecretsRawSecretNamePostRequest: { - ...options, - workspaceId: options.projectId - } - }, - this.#requestOptions - ); - return res.data; + try { + const res = await this.#apiInstance.apiV3SecretsRawSecretNamePost( + { + secretName, + apiV3SecretsRawSecretNamePostRequest: { + ...options, + workspaceId: options.projectId + } + }, + this.#requestOptions + ); + return res.data; + } catch (err) { + throw newInfisicalError(err); + } }; deleteSecret = async (secretName: DefaultApiApiV3SecretsRawSecretNameDeleteRequest["secretName"], options: DeleteSecretOptions) => { - const res = await this.#apiInstance.apiV3SecretsRawSecretNameDelete( - { - secretName, - apiV3SecretsRawSecretNameDeleteRequest: { - ...options, - workspaceId: options.projectId - } - }, - this.#requestOptions - ); - return res.data; + try { + const res = await this.#apiInstance.apiV3SecretsRawSecretNameDelete( + { + secretName, + apiV3SecretsRawSecretNameDeleteRequest: { + ...options, + workspaceId: options.projectId + } + }, + this.#requestOptions + ); + return res.data; + } catch (err) { + throw newInfisicalError(err); + } }; }