Move from openapi-generator-cli to custom Axios approach, and add listFolders endpoint
This commit is contained in:
92
src/api/base.ts
Normal file
92
src/api/base.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
|
||||
|
||||
export interface ApiClientConfig {
|
||||
baseURL: string;
|
||||
headers?: Record<string, string>;
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
export class ApiClient {
|
||||
private client: AxiosInstance;
|
||||
|
||||
constructor(config: ApiClientConfig) {
|
||||
this.client = axios.create({
|
||||
baseURL: config.baseURL,
|
||||
headers: config.headers || {},
|
||||
timeout: config.timeout || 10000,
|
||||
});
|
||||
|
||||
this.setupRetryInterceptor();
|
||||
}
|
||||
|
||||
private setupRetryInterceptor() {
|
||||
const maxRetries = 4;
|
||||
const initialRetryDelay = 1000;
|
||||
const backoffFactor = 2;
|
||||
|
||||
this.client.interceptors.response.use(null, (error) => {
|
||||
const config = error?.config;
|
||||
if (!config) return Promise.reject(error);
|
||||
|
||||
if (!config._retryCount) config._retryCount = 0;
|
||||
|
||||
if (
|
||||
(error.response?.status === 429 ||
|
||||
error.response?.status === undefined) &&
|
||||
config._retryCount < maxRetries
|
||||
) {
|
||||
config._retryCount++;
|
||||
const baseDelay =
|
||||
initialRetryDelay * Math.pow(backoffFactor, config._retryCount - 1);
|
||||
const jitter = baseDelay * 0.2;
|
||||
const exponentialDelay = baseDelay + (Math.random() * 2 - 1) * jitter;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => resolve(this.client(config)), exponentialDelay);
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
public setAccessToken(token: string) {
|
||||
this.client.defaults.headers.common["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
public async get<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
||||
const response: AxiosResponse<T> = await this.client.get(url, config);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async post<T>(
|
||||
url: string,
|
||||
data?: any,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<T> {
|
||||
const response: AxiosResponse<T> = await this.client.post(
|
||||
url,
|
||||
data,
|
||||
config
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async patch<T>(
|
||||
url: string,
|
||||
data?: any,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<T> {
|
||||
const response: AxiosResponse<T> = await this.client.patch(
|
||||
url,
|
||||
data,
|
||||
config
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async delete<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
||||
const response: AxiosResponse<T> = await this.client.delete(url, config);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
38
src/api/endpoints/auth.ts
Normal file
38
src/api/endpoints/auth.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { ApiClient } from "../base";
|
||||
import {
|
||||
UniversalAuthLoginRequest,
|
||||
UniversalAuthLoginResponse,
|
||||
AwsIamAuthLoginRequest,
|
||||
AwsIamAuthLoginResponse,
|
||||
TokenRenewRequest,
|
||||
TokenRenewResponse,
|
||||
} from "../types";
|
||||
|
||||
export class AuthApi {
|
||||
constructor(private apiClient: ApiClient) {}
|
||||
|
||||
async universalAuthLogin(
|
||||
data: UniversalAuthLoginRequest
|
||||
): Promise<UniversalAuthLoginResponse> {
|
||||
return this.apiClient.post<UniversalAuthLoginResponse>(
|
||||
"/api/v1/auth/universal-auth/login",
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
async awsIamAuthLogin(
|
||||
data: AwsIamAuthLoginRequest
|
||||
): Promise<AwsIamAuthLoginResponse> {
|
||||
return this.apiClient.post<AwsIamAuthLoginResponse>(
|
||||
"/api/v1/auth/aws-auth/login",
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
async renewToken(data: TokenRenewRequest): Promise<TokenRenewResponse> {
|
||||
return this.apiClient.post<TokenRenewResponse>(
|
||||
"/api/v1/auth/token/renew",
|
||||
data
|
||||
);
|
||||
}
|
||||
}
|
||||
65
src/api/endpoints/dynamic-secrets.ts
Normal file
65
src/api/endpoints/dynamic-secrets.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { ApiClient } from "../base";
|
||||
import {
|
||||
CreateDynamicSecretRequest,
|
||||
CreateDynamicSecretResponse,
|
||||
DeleteDynamicSecretRequest,
|
||||
DeleteDynamicSecretResponse,
|
||||
CreateLeaseRequest,
|
||||
CreateLeaseResponse,
|
||||
DeleteLeaseRequest,
|
||||
DeleteLeaseResponse,
|
||||
RenewLeaseRequest,
|
||||
RenewLeaseResponse,
|
||||
} from "../types";
|
||||
|
||||
export class DynamicSecretsApi {
|
||||
constructor(private apiClient: ApiClient) {}
|
||||
|
||||
async create(
|
||||
data: CreateDynamicSecretRequest
|
||||
): Promise<CreateDynamicSecretResponse> {
|
||||
return this.apiClient.post<CreateDynamicSecretResponse>(
|
||||
"/api/v1/dynamic-secrets",
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
async delete(
|
||||
secretName: string,
|
||||
data: DeleteDynamicSecretRequest
|
||||
): Promise<DeleteDynamicSecretResponse> {
|
||||
return this.apiClient.delete<DeleteDynamicSecretResponse>(
|
||||
`/api/v1/dynamic-secrets/${encodeURIComponent(secretName)}`,
|
||||
{ data }
|
||||
);
|
||||
}
|
||||
|
||||
leases = {
|
||||
create: async (data: CreateLeaseRequest): Promise<CreateLeaseResponse> => {
|
||||
return this.apiClient.post<CreateLeaseResponse>(
|
||||
"/api/v1/dynamic-secrets/leases",
|
||||
data
|
||||
);
|
||||
},
|
||||
|
||||
delete: async (
|
||||
leaseId: string,
|
||||
data: DeleteLeaseRequest
|
||||
): Promise<DeleteLeaseResponse> => {
|
||||
return this.apiClient.delete<DeleteLeaseResponse>(
|
||||
`/api/v1/dynamic-secrets/leases/${leaseId}`,
|
||||
{ data }
|
||||
);
|
||||
},
|
||||
|
||||
renew: async (
|
||||
leaseId: string,
|
||||
data: RenewLeaseRequest
|
||||
): Promise<RenewLeaseResponse> => {
|
||||
return this.apiClient.post<RenewLeaseResponse>(
|
||||
`/api/v1/dynamic-secrets/leases/${leaseId}/renew`,
|
||||
data
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
19
src/api/endpoints/environments.ts
Normal file
19
src/api/endpoints/environments.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { ApiClient } from "../base";
|
||||
import { CreateEnvironmentRequest, CreateEnvironmentResponse } from "../types";
|
||||
|
||||
export class EnvironmentsApi {
|
||||
constructor(private apiClient: ApiClient) {}
|
||||
|
||||
async create(
|
||||
data: CreateEnvironmentRequest
|
||||
): Promise<CreateEnvironmentResponse> {
|
||||
return this.apiClient.post<CreateEnvironmentResponse>(
|
||||
`/api/v1/workspace/${data.projectId}/environments`,
|
||||
{
|
||||
name: data.name,
|
||||
slug: data.slug,
|
||||
position: data.position,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
16
src/api/endpoints/folders.ts
Normal file
16
src/api/endpoints/folders.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ApiClient } from "../base";
|
||||
import { CreateFolderRequest, CreateFolderResponse, ListFoldersRequest, ListFoldersResponse } from "../types";
|
||||
|
||||
export class FoldersApi {
|
||||
constructor(private apiClient: ApiClient) {}
|
||||
|
||||
async create(data: CreateFolderRequest): Promise<CreateFolderResponse> {
|
||||
return this.apiClient.post<CreateFolderResponse>("/api/v1/folders", data);
|
||||
}
|
||||
|
||||
async listFolders(queryParams: ListFoldersRequest): Promise<ListFoldersResponse> {
|
||||
return this.apiClient.get<ListFoldersResponse>("/api/v1/folders", {
|
||||
params: queryParams
|
||||
});
|
||||
}
|
||||
}
|
||||
31
src/api/endpoints/projects.ts
Normal file
31
src/api/endpoints/projects.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { ApiClient } from "../base";
|
||||
import {
|
||||
CreateProjectRequest,
|
||||
CreateProjectResponse,
|
||||
InviteMembersRequest,
|
||||
InviteMembersResponse,
|
||||
} from "../types";
|
||||
|
||||
export class ProjectsApi {
|
||||
constructor(private apiClient: ApiClient) {}
|
||||
|
||||
async create(data: CreateProjectRequest): Promise<CreateProjectResponse> {
|
||||
return this.apiClient.post<CreateProjectResponse>(
|
||||
"/api/v2/workspace",
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
async inviteMembers(
|
||||
data: InviteMembersRequest
|
||||
): Promise<InviteMembersResponse> {
|
||||
return this.apiClient.post<InviteMembersResponse>(
|
||||
`/api/v2/workspace/${data.projectId}/memberships`,
|
||||
{
|
||||
emails: data.emails,
|
||||
usernames: data.usernames,
|
||||
roleSlugs: data.roleSlugs,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
61
src/api/endpoints/secrets.ts
Normal file
61
src/api/endpoints/secrets.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { ApiClient } from "../base";
|
||||
import {
|
||||
ListSecretsRequest,
|
||||
ListSecretsResponse,
|
||||
GetSecretRequest,
|
||||
GetSecretResponse,
|
||||
CreateSecretRequest,
|
||||
CreateSecretResponse,
|
||||
UpdateSecretRequest,
|
||||
UpdateSecretResponse,
|
||||
DeleteSecretRequest,
|
||||
DeleteSecretResponse,
|
||||
} from "../types";
|
||||
|
||||
export class SecretsApi {
|
||||
constructor(private apiClient: ApiClient) {}
|
||||
|
||||
async listSecrets(params: ListSecretsRequest): Promise<ListSecretsResponse> {
|
||||
return this.apiClient.get<ListSecretsResponse>("/api/v3/secrets/raw", {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
async getSecret(params: GetSecretRequest): Promise<GetSecretResponse> {
|
||||
const { secretName, ...queryParams } = params;
|
||||
return this.apiClient.get<GetSecretResponse>(
|
||||
`/api/v3/secrets/raw/${encodeURIComponent(secretName)}`,
|
||||
{ params: queryParams }
|
||||
);
|
||||
}
|
||||
|
||||
async createSecret(
|
||||
secretName: string,
|
||||
data: CreateSecretRequest
|
||||
): Promise<CreateSecretResponse> {
|
||||
return this.apiClient.post<CreateSecretResponse>(
|
||||
`/api/v3/secrets/raw/${encodeURIComponent(secretName)}`,
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
async updateSecret(
|
||||
secretName: string,
|
||||
data: UpdateSecretRequest
|
||||
): Promise<UpdateSecretResponse> {
|
||||
return this.apiClient.patch<UpdateSecretResponse>(
|
||||
`/api/v3/secrets/raw/${encodeURIComponent(secretName)}`,
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
async deleteSecret(
|
||||
secretName: string,
|
||||
data: DeleteSecretRequest
|
||||
): Promise<DeleteSecretResponse> {
|
||||
return this.apiClient.delete<DeleteSecretResponse>(
|
||||
`/api/v3/secrets/raw/${encodeURIComponent(secretName)}`,
|
||||
{ data }
|
||||
);
|
||||
}
|
||||
}
|
||||
30
src/api/types/auth.ts
Normal file
30
src/api/types/auth.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
export interface UniversalAuthLoginRequest {
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
}
|
||||
|
||||
export interface UniversalAuthLoginResponse {
|
||||
accessToken: string;
|
||||
expiresIn: number;
|
||||
}
|
||||
|
||||
export interface AwsIamAuthLoginRequest {
|
||||
identityId: string;
|
||||
iamHttpRequestMethod: string;
|
||||
iamRequestBody: string;
|
||||
iamRequestHeaders: string;
|
||||
}
|
||||
|
||||
export interface AwsIamAuthLoginResponse {
|
||||
accessToken: string;
|
||||
expiresIn: number;
|
||||
}
|
||||
|
||||
export interface TokenRenewRequest {
|
||||
accessToken: string;
|
||||
}
|
||||
|
||||
export interface TokenRenewResponse {
|
||||
accessToken: string;
|
||||
expiresIn: number;
|
||||
}
|
||||
89
src/api/types/dynamic-secrets.ts
Normal file
89
src/api/types/dynamic-secrets.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { DynamicSecretProviders } from "../../custom/schemas";
|
||||
import { TDynamicSecretProvider } from "../../custom/schemas";
|
||||
|
||||
export interface CreateDynamicSecretRequest {
|
||||
provider: TDynamicSecretProvider;
|
||||
defaultTTL: string;
|
||||
maxTTL: string;
|
||||
name: string;
|
||||
projectSlug: string;
|
||||
environmentSlug: string;
|
||||
}
|
||||
|
||||
export interface DynamicSecret {
|
||||
id: string;
|
||||
name: string;
|
||||
defaultTTL: string;
|
||||
maxTTL: string;
|
||||
provider: {
|
||||
type: DynamicSecretProviders;
|
||||
inputs: Record<string, any>;
|
||||
};
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
version: number;
|
||||
type: string;
|
||||
folderId: string;
|
||||
status: string;
|
||||
statusDetails: string;
|
||||
projectGatewayId: string;
|
||||
metadata: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface CreateDynamicSecretResponse {
|
||||
dynamicSecret: DynamicSecret;
|
||||
}
|
||||
|
||||
export interface DeleteDynamicSecretRequest {
|
||||
environmentSlug: string;
|
||||
projectSlug: string;
|
||||
path?: string;
|
||||
isForced?: boolean;
|
||||
}
|
||||
|
||||
export interface DeleteDynamicSecretResponse {
|
||||
dynamicSecret: DynamicSecret;
|
||||
}
|
||||
|
||||
export interface CreateLeaseRequest {
|
||||
dynamicSecretName: string;
|
||||
environmentSlug: string;
|
||||
projectSlug: string;
|
||||
path?: string;
|
||||
ttl?: string;
|
||||
}
|
||||
|
||||
export interface Lease {
|
||||
id: string;
|
||||
dynamicSecretId: string;
|
||||
data: Record<string, any>;
|
||||
expiresAt: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface CreateLeaseResponse {
|
||||
lease: Lease;
|
||||
}
|
||||
|
||||
export interface DeleteLeaseRequest {
|
||||
environmentSlug: string;
|
||||
projectSlug: string;
|
||||
path?: string;
|
||||
isForced?: boolean;
|
||||
}
|
||||
|
||||
export interface DeleteLeaseResponse {
|
||||
lease: Lease;
|
||||
}
|
||||
|
||||
export interface RenewLeaseRequest {
|
||||
environmentSlug: string;
|
||||
projectSlug: string;
|
||||
path?: string;
|
||||
ttl?: string;
|
||||
}
|
||||
|
||||
export interface RenewLeaseResponse {
|
||||
lease: Lease;
|
||||
}
|
||||
20
src/api/types/environments.ts
Normal file
20
src/api/types/environments.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export interface Environment {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
position: number;
|
||||
projectId: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface CreateEnvironmentRequest {
|
||||
name: string;
|
||||
projectId: string;
|
||||
slug: string;
|
||||
position?: number;
|
||||
}
|
||||
|
||||
export type CreateEnvironmentResponse = {
|
||||
environment: Environment;
|
||||
};
|
||||
35
src/api/types/folders.ts
Normal file
35
src/api/types/folders.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
export interface Folder {
|
||||
id: string;
|
||||
name: string;
|
||||
path: string;
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
description?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface CreateFolderRequest {
|
||||
name: string;
|
||||
path: string;
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface ListFoldersRequest {
|
||||
environment: string;
|
||||
workspaceId: string;
|
||||
path?: string;
|
||||
recursive?: boolean;
|
||||
lastSecretModified?: string;
|
||||
}
|
||||
|
||||
export interface CreateFolderResponse {
|
||||
folder: Folder;
|
||||
}
|
||||
|
||||
export interface ListFoldersResponse {
|
||||
folders: Folder[];
|
||||
}
|
||||
|
||||
26
src/api/types/index.ts
Normal file
26
src/api/types/index.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Secret } from "./secrets";
|
||||
|
||||
export * from "./auth";
|
||||
export * from "./secrets";
|
||||
export * from "./dynamic-secrets";
|
||||
export * from "./environments";
|
||||
export * from "./projects";
|
||||
export * from "./folders";
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
statusCode: number;
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export interface CreateSecretResponse {
|
||||
secret: Secret;
|
||||
}
|
||||
|
||||
export interface UpdateSecretResponse {
|
||||
secret: Secret;
|
||||
}
|
||||
|
||||
export interface DeleteSecretResponse {
|
||||
secret: Secret;
|
||||
}
|
||||
43
src/api/types/projects.ts
Normal file
43
src/api/types/projects.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
export interface Project {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
description?: string;
|
||||
type: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface CreateProjectRequest {
|
||||
projectName: string;
|
||||
type: string;
|
||||
projectDescription?: string;
|
||||
slug?: string;
|
||||
template?: string;
|
||||
kmsKeyId?: string;
|
||||
}
|
||||
|
||||
export interface CreateProjectResponse {
|
||||
project: Project;
|
||||
}
|
||||
|
||||
export interface InviteMembersRequest {
|
||||
projectId: string;
|
||||
emails?: string[];
|
||||
usernames?: string[];
|
||||
roleSlugs?: string[];
|
||||
}
|
||||
|
||||
export interface Membership {
|
||||
id: string;
|
||||
userId: string;
|
||||
projectId: string;
|
||||
role: string;
|
||||
status: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface InviteMembersResponse {
|
||||
memberships: Membership[];
|
||||
}
|
||||
84
src/api/types/secrets.ts
Normal file
84
src/api/types/secrets.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
export interface Secret {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
secretKey: string;
|
||||
secretValue: string;
|
||||
secretComment?: string;
|
||||
secretPath?: string;
|
||||
type: "shared" | "personal";
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
version: number;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
export interface ListSecretsRequest {
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
expandSecretReferences?: string;
|
||||
includeImports?: string;
|
||||
recursive?: string;
|
||||
secretPath?: string;
|
||||
tagSlugs?: string;
|
||||
viewSecretValue?: string;
|
||||
}
|
||||
|
||||
export interface ListSecretsResponse {
|
||||
secrets: Secret[];
|
||||
imports?: Array<{
|
||||
secretPath: string;
|
||||
secrets: Secret[];
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface GetSecretRequest {
|
||||
secretName: string;
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
expandSecretReferences?: string;
|
||||
includeImports?: string;
|
||||
secretPath?: string;
|
||||
type?: "shared" | "personal";
|
||||
version?: number;
|
||||
viewSecretValue?: string;
|
||||
}
|
||||
|
||||
export interface GetSecretResponse {
|
||||
secret: Secret;
|
||||
}
|
||||
|
||||
export interface CreateSecretRequest {
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
secretValue: string;
|
||||
secretComment?: string;
|
||||
secretPath?: string;
|
||||
secretReminderNote?: string;
|
||||
secretReminderRepeatDays?: number;
|
||||
skipMultilineEncoding?: boolean;
|
||||
tagIds?: string[];
|
||||
type?: "shared" | "personal";
|
||||
}
|
||||
|
||||
export interface UpdateSecretRequest {
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
secretValue?: string;
|
||||
newSecretName?: string;
|
||||
secretComment?: string;
|
||||
secretPath?: string;
|
||||
secretReminderNote?: string;
|
||||
secretReminderRepeatDays?: number;
|
||||
skipMultilineEncoding?: boolean;
|
||||
tagIds?: string[];
|
||||
type?: "shared" | "personal";
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface DeleteSecretRequest {
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
secretPath?: string;
|
||||
type?: "shared" | "personal";
|
||||
}
|
||||
Reference in New Issue
Block a user