Move from openapi-generator-cli to custom Axios approach, and add listFolders endpoint
This commit is contained in:
2503
package-lock.json
generated
2503
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -7,9 +7,6 @@
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"generate-api:infisical": "openapi-generator-cli generate -i https://app.infisical.com/api/docs/json -g typescript-axios -o ./src/infisicalapi_client --skip-validate-spec --additional-properties=useSingleRequestParameter=true,withSeparateModelsAndApi=true,apiPackage=server,modelPackage=model --openapi-normalizer REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true && npm run post-generate-api",
|
||||
"generate-api:infisical-dev": "openapi-generator-cli generate -i http://localhost:8080/api/docs/json -g typescript-axios -o ./src/infisicalapi_client --skip-validate-spec --additional-properties=useSingleRequestParameter=true,withSeparateModelsAndApi=true,apiPackage=server,modelPackage=model --openapi-normalizer REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true && npm run post-generate-api",
|
||||
"post-generate-api": "rm ./src/infisicalapi_client/git_push.sh",
|
||||
"build": "tsup src/index.ts --out-dir lib --dts --format cjs,esm --tsconfig tsconfig.json --no-splitting"
|
||||
},
|
||||
"keywords": [
|
||||
@@ -20,21 +17,30 @@
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/infisical/infisical-node-sdk"
|
||||
"url": "git+https://github.com/infisical/infisical-node-sdk.git"
|
||||
},
|
||||
"author": "Infisical Inc, <daniel@infisical.com>",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"description": "The Infisical SDK provides a convenient way to interact with the Infisical API.",
|
||||
"devDependencies": {
|
||||
"@openapitools/openapi-generator-cli": "^2.13.5",
|
||||
"@types/node": "^22.5.1",
|
||||
"tsc": "^2.0.4",
|
||||
"tsup": "^8.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@infisical/sdk": "file:",
|
||||
"aws-sdk": "2.1311.0",
|
||||
"axios": "^1.7.5",
|
||||
"typescript": "^5.5.4",
|
||||
"zod": "^3.23.8"
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"test": "test"
|
||||
},
|
||||
"types": "./lib/index.d.ts",
|
||||
"bugs": {
|
||||
"url": "https://github.com/infisical/infisical-node-sdk/issues"
|
||||
},
|
||||
"homepage": "https://github.com/infisical/infisical-node-sdk#readme"
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { InfisicalSDK } from "..";
|
||||
import { ApiV1AuthUniversalAuthLoginPostRequest } from "../infisicalapi_client";
|
||||
import { DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
||||
import { AuthApi } from "../api/endpoints/auth";
|
||||
import { UniversalAuthLoginRequest } from "../api/types";
|
||||
import { MACHINE_IDENTITY_ID_ENV_NAME } from "./constants";
|
||||
import { InfisicalSDKError, newInfisicalError } from "./errors";
|
||||
import { getAwsRegion, performAwsIamLogin } from "./util";
|
||||
@@ -8,97 +8,103 @@ import { getAwsRegion, performAwsIamLogin } from "./util";
|
||||
type AuthenticatorFunction = (accessToken: string) => InfisicalSDK;
|
||||
|
||||
type AwsAuthLoginOptions = {
|
||||
identityId?: string;
|
||||
identityId?: string;
|
||||
};
|
||||
|
||||
export const renewToken = async (apiClient: InfisicalApi, token?: string) => {
|
||||
try {
|
||||
if (!token) {
|
||||
throw new InfisicalSDKError("Unable to renew access token, no access token set. Are you sure you're authenticated?");
|
||||
}
|
||||
export const renewToken = async (apiClient: AuthApi, token?: string) => {
|
||||
try {
|
||||
if (!token) {
|
||||
throw new InfisicalSDKError(
|
||||
"Unable to renew access token, no access token set."
|
||||
);
|
||||
}
|
||||
|
||||
const res = await apiClient.apiV1AuthTokenRenewPost({
|
||||
apiV1AuthTokenRenewPostRequest: {
|
||||
accessToken: token
|
||||
}
|
||||
});
|
||||
|
||||
return res.data;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
const res = await apiClient.renewToken({ accessToken: token });
|
||||
return res;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
|
||||
export default class AuthClient {
|
||||
#sdkAuthenticator: AuthenticatorFunction;
|
||||
#apiClient: InfisicalApi;
|
||||
#accessToken?: string;
|
||||
#sdkAuthenticator: AuthenticatorFunction;
|
||||
#apiClient: AuthApi;
|
||||
#accessToken?: string;
|
||||
|
||||
constructor(authenticator: AuthenticatorFunction, apiInstance: InfisicalApi, accessToken?: string) {
|
||||
this.#sdkAuthenticator = authenticator;
|
||||
this.#apiClient = apiInstance;
|
||||
this.#accessToken = accessToken;
|
||||
}
|
||||
constructor(
|
||||
authenticator: AuthenticatorFunction,
|
||||
apiInstance: AuthApi,
|
||||
accessToken?: string
|
||||
) {
|
||||
this.#sdkAuthenticator = authenticator;
|
||||
this.#apiClient = apiInstance;
|
||||
this.#accessToken = accessToken;
|
||||
}
|
||||
|
||||
awsIamAuth = {
|
||||
login: async (options?: AwsAuthLoginOptions) => {
|
||||
try {
|
||||
const identityId = options?.identityId || process.env[MACHINE_IDENTITY_ID_ENV_NAME];
|
||||
awsIamAuth = {
|
||||
login: async (options?: AwsAuthLoginOptions) => {
|
||||
try {
|
||||
const identityId =
|
||||
options?.identityId || process.env[MACHINE_IDENTITY_ID_ENV_NAME];
|
||||
if (!identityId) {
|
||||
throw new InfisicalSDKError(
|
||||
"Identity ID is required for AWS IAM authentication"
|
||||
);
|
||||
}
|
||||
|
||||
if (!identityId) {
|
||||
throw new InfisicalSDKError("Identity ID is required for AWS IAM authentication");
|
||||
}
|
||||
const iamRequest = await performAwsIamLogin(await getAwsRegion());
|
||||
const res = await this.#apiClient.awsIamAuthLogin({
|
||||
iamHttpRequestMethod: iamRequest.iamHttpRequestMethod,
|
||||
iamRequestBody: Buffer.from(iamRequest.iamRequestBody).toString(
|
||||
"base64"
|
||||
),
|
||||
iamRequestHeaders: Buffer.from(
|
||||
JSON.stringify(iamRequest.iamRequestHeaders)
|
||||
).toString("base64"),
|
||||
identityId,
|
||||
});
|
||||
|
||||
const iamRequest = await performAwsIamLogin(await getAwsRegion());
|
||||
return this.#sdkAuthenticator(res.accessToken);
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
renew: async () => {
|
||||
try {
|
||||
const refreshedToken = await renewToken(
|
||||
this.#apiClient,
|
||||
this.#accessToken
|
||||
);
|
||||
return this.#sdkAuthenticator(refreshedToken.accessToken);
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const res = await this.#apiClient.apiV1AuthAwsAuthLoginPost({
|
||||
apiV1AuthAwsAuthLoginPostRequest: {
|
||||
iamHttpRequestMethod: iamRequest.iamHttpRequestMethod,
|
||||
iamRequestBody: Buffer.from(iamRequest.iamRequestBody).toString("base64"),
|
||||
iamRequestHeaders: Buffer.from(JSON.stringify(iamRequest.iamRequestHeaders)).toString("base64"),
|
||||
identityId
|
||||
}
|
||||
});
|
||||
universalAuth = {
|
||||
login: async (options: UniversalAuthLoginRequest) => {
|
||||
try {
|
||||
const res = await this.#apiClient.universalAuthLogin(options);
|
||||
return this.#sdkAuthenticator(res.accessToken);
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
renew: async () => {
|
||||
try {
|
||||
const refreshedToken = await renewToken(
|
||||
this.#apiClient,
|
||||
this.#accessToken
|
||||
);
|
||||
return this.#sdkAuthenticator(refreshedToken.accessToken);
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return this.#sdkAuthenticator(res.data.accessToken);
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
renew: async () => {
|
||||
try {
|
||||
const refreshedToken = await renewToken(this.#apiClient, this.#accessToken);
|
||||
return this.#sdkAuthenticator(refreshedToken.accessToken);
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
universalAuth = {
|
||||
login: async (options: ApiV1AuthUniversalAuthLoginPostRequest) => {
|
||||
try {
|
||||
const res = await this.#apiClient.apiV1AuthUniversalAuthLoginPost({
|
||||
apiV1AuthUniversalAuthLoginPostRequest: options
|
||||
});
|
||||
|
||||
return this.#sdkAuthenticator(res.data.accessToken);
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
|
||||
renew: async () => {
|
||||
try {
|
||||
const refreshedToken = await renewToken(this.#apiClient, this.#accessToken);
|
||||
return this.#sdkAuthenticator(refreshedToken.accessToken);
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
accessToken = (token: string) => {
|
||||
return this.#sdkAuthenticator(token);
|
||||
};
|
||||
accessToken = (token: string) => {
|
||||
return this.#sdkAuthenticator(token);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,119 +1,97 @@
|
||||
import { RawAxiosRequestConfig } from "axios";
|
||||
import { Configuration, DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
||||
import type {
|
||||
ApiV1DynamicSecretsGet200ResponseDynamicSecretsInner,
|
||||
ApiV1DynamicSecretsLeasesLeaseIdDelete200Response,
|
||||
ApiV1DynamicSecretsLeasesPost200Response,
|
||||
DefaultApiApiV1DynamicSecretsLeasesLeaseIdDeleteRequest,
|
||||
DefaultApiApiV1DynamicSecretsLeasesLeaseIdRenewPostRequest,
|
||||
DefaultApiApiV1DynamicSecretsLeasesPostRequest,
|
||||
DefaultApiApiV1DynamicSecretsNameDeleteRequest,
|
||||
DefaultApiApiV1DynamicSecretsPostRequest
|
||||
} from "../infisicalapi_client";
|
||||
|
||||
import type { TDynamicSecretProvider } from "./schemas/dynamic-secrets";
|
||||
import { DynamicSecretsApi } from "../api/endpoints/dynamic-secrets";
|
||||
import { TDynamicSecretProvider } from "./schemas/dynamic-secrets";
|
||||
import { newInfisicalError } from "./errors";
|
||||
|
||||
export type CreateDynamicSecretOptions = Omit<DefaultApiApiV1DynamicSecretsPostRequest["apiV1DynamicSecretsPostRequest"], "provider"> & {
|
||||
provider: TDynamicSecretProvider;
|
||||
export type CreateDynamicSecretOptions = {
|
||||
provider: TDynamicSecretProvider;
|
||||
defaultTTL: string;
|
||||
maxTTL: string;
|
||||
name: string;
|
||||
projectSlug: string;
|
||||
environmentSlug: string;
|
||||
path?: string;
|
||||
metadata?: Record<string, any>;
|
||||
};
|
||||
export type DeleteDynamicSecretOptions = DefaultApiApiV1DynamicSecretsNameDeleteRequest["apiV1DynamicSecretsNameDeleteRequest"];
|
||||
export type CreateDynamicSecretLeaseOptions = DefaultApiApiV1DynamicSecretsLeasesPostRequest["apiV1DynamicSecretsLeasesPostRequest"];
|
||||
export type DeleteDynamicSecretLeaseOptions =
|
||||
DefaultApiApiV1DynamicSecretsLeasesLeaseIdDeleteRequest["apiV1DynamicSecretsLeasesLeaseIdDeleteRequest"];
|
||||
export type RenewDynamicSecretLeaseOptions =
|
||||
DefaultApiApiV1DynamicSecretsLeasesLeaseIdRenewPostRequest["apiV1DynamicSecretsLeasesLeaseIdRenewPostRequest"];
|
||||
|
||||
export type CreateDynamicSecretResult = ApiV1DynamicSecretsGet200ResponseDynamicSecretsInner;
|
||||
export type DeleteDynamicSecretResult = ApiV1DynamicSecretsGet200ResponseDynamicSecretsInner;
|
||||
export type CreateDynamicSecretLeaseResult = ApiV1DynamicSecretsLeasesPost200Response;
|
||||
export type DeleteDynamicSecretLeaseResult = ApiV1DynamicSecretsLeasesLeaseIdDelete200Response;
|
||||
export type RenewDynamicSecretLeaseResult = ApiV1DynamicSecretsLeasesLeaseIdDelete200Response;
|
||||
export type DeleteDynamicSecretOptions = {
|
||||
environmentSlug: string;
|
||||
projectSlug: string;
|
||||
path?: string;
|
||||
isForced?: boolean;
|
||||
};
|
||||
|
||||
export type CreateDynamicSecretLeaseOptions = {
|
||||
dynamicSecretName: string;
|
||||
environmentSlug: string;
|
||||
projectSlug: string;
|
||||
path?: string;
|
||||
ttl?: string;
|
||||
};
|
||||
|
||||
export type DeleteDynamicSecretLeaseOptions = {
|
||||
environmentSlug: string;
|
||||
projectSlug: string;
|
||||
path?: string;
|
||||
isForced?: boolean;
|
||||
};
|
||||
|
||||
export type RenewDynamicSecretLeaseOptions = {
|
||||
environmentSlug: string;
|
||||
projectSlug: string;
|
||||
path?: string;
|
||||
ttl?: string;
|
||||
};
|
||||
|
||||
export default class DynamicSecretsClient {
|
||||
#apiInstance: InfisicalApi;
|
||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
||||
constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) {
|
||||
this.#apiInstance = apiInstance;
|
||||
this.#requestOptions = requestOptions;
|
||||
}
|
||||
constructor(private apiClient: DynamicSecretsApi) {}
|
||||
|
||||
async create(options: CreateDynamicSecretOptions): Promise<CreateDynamicSecretResult> {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV1DynamicSecretsPost(
|
||||
{
|
||||
apiV1DynamicSecretsPostRequest: options as DefaultApiApiV1DynamicSecretsPostRequest["apiV1DynamicSecretsPostRequest"]
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
async create(options: CreateDynamicSecretOptions) {
|
||||
try {
|
||||
const res = await this.apiClient.create(options);
|
||||
return res.dynamicSecret;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
}
|
||||
|
||||
return res.data.dynamicSecret;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
}
|
||||
async delete(dynamicSecretName: string, options: DeleteDynamicSecretOptions) {
|
||||
try {
|
||||
const res = await this.apiClient.delete(dynamicSecretName, options);
|
||||
return res.dynamicSecret;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
}
|
||||
|
||||
async delete(dynamicSecretName: string, options: DeleteDynamicSecretOptions): Promise<DeleteDynamicSecretResult> {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV1DynamicSecretsNameDelete(
|
||||
{
|
||||
name: dynamicSecretName,
|
||||
apiV1DynamicSecretsNameDeleteRequest: options
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
leases = {
|
||||
create: async (options: CreateDynamicSecretLeaseOptions) => {
|
||||
try {
|
||||
const res = await this.apiClient.leases.create(options);
|
||||
return res;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
|
||||
return res.data.dynamicSecret;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
}
|
||||
delete: async (
|
||||
leaseId: string,
|
||||
options: DeleteDynamicSecretLeaseOptions
|
||||
) => {
|
||||
try {
|
||||
const res = await this.apiClient.leases.delete(leaseId, options);
|
||||
return res;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
|
||||
leases = {
|
||||
create: async (options: CreateDynamicSecretLeaseOptions): Promise<CreateDynamicSecretLeaseResult> => {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV1DynamicSecretsLeasesPost(
|
||||
{
|
||||
apiV1DynamicSecretsLeasesPostRequest: options
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
|
||||
return res.data;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
delete: async (leaseId: string, options: DeleteDynamicSecretLeaseOptions): Promise<DeleteDynamicSecretLeaseResult> => {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV1DynamicSecretsLeasesLeaseIdDelete(
|
||||
{
|
||||
leaseId: leaseId,
|
||||
apiV1DynamicSecretsLeasesLeaseIdDeleteRequest: options
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
|
||||
return res.data;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
|
||||
renew: async (leaseId: string, options: RenewDynamicSecretLeaseOptions): Promise<RenewDynamicSecretLeaseResult> => {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV1DynamicSecretsLeasesLeaseIdRenewPost(
|
||||
{
|
||||
leaseId: leaseId,
|
||||
apiV1DynamicSecretsLeasesLeaseIdRenewPostRequest: options
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
|
||||
return res.data;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
renew: async (leaseId: string, options: RenewDynamicSecretLeaseOptions) => {
|
||||
try {
|
||||
const res = await this.apiClient.leases.renew(leaseId, options);
|
||||
return res;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,33 +1,22 @@
|
||||
import { RawAxiosRequestConfig } from "axios";
|
||||
import { DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
||||
import type { ApiV1WorkspaceWorkspaceIdEnvironmentsPostRequest, ApiV1WorkspaceWorkspaceIdEnvironmentsPost200Response } from "../infisicalapi_client";
|
||||
import { EnvironmentsApi } from "../api/endpoints/environments";
|
||||
import { newInfisicalError } from "./errors";
|
||||
|
||||
export type CreateEnvironmentOptions = {
|
||||
projectId: string;
|
||||
} & ApiV1WorkspaceWorkspaceIdEnvironmentsPostRequest;
|
||||
export type CreateEnvironmentResult = ApiV1WorkspaceWorkspaceIdEnvironmentsPost200Response;
|
||||
name: string;
|
||||
projectId: string;
|
||||
slug: string;
|
||||
position?: number;
|
||||
};
|
||||
|
||||
export default class EnvironmentsClient {
|
||||
#apiInstance: InfisicalApi;
|
||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
||||
constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) {
|
||||
this.#apiInstance = apiInstance;
|
||||
this.#requestOptions = requestOptions;
|
||||
}
|
||||
constructor(private apiClient: EnvironmentsApi) {}
|
||||
|
||||
create = async (options: CreateEnvironmentOptions): Promise<CreateEnvironmentResult["environment"]> => {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV1WorkspaceWorkspaceIdEnvironmentsPost(
|
||||
{
|
||||
workspaceId: options.projectId,
|
||||
apiV1WorkspaceWorkspaceIdEnvironmentsPostRequest: options
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
return res.data.environment;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
create = async (options: CreateEnvironmentOptions) => {
|
||||
try {
|
||||
const res = await this.apiClient.create(options);
|
||||
return res.environment;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,57 +1,49 @@
|
||||
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";
|
||||
}
|
||||
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";
|
||||
}
|
||||
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 (error?.isAxiosError) {
|
||||
const data = error?.response?.data;
|
||||
|
||||
if (data?.message) {
|
||||
let message = data.message;
|
||||
if (error.status === 422) {
|
||||
message = JSON.stringify(data);
|
||||
}
|
||||
if (data?.message) {
|
||||
let message = data.message;
|
||||
if (error.response?.status === 422) {
|
||||
message = JSON.stringify(data);
|
||||
}
|
||||
|
||||
return new InfisicalSDKRequestError(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 InfisicalSDKRequestError(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) {
|
||||
return new InfisicalSDKError(error.code);
|
||||
} else {
|
||||
return new InfisicalSDKError("Request failed with unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
return new InfisicalSDKError(error?.message || "An error occurred");
|
||||
return new InfisicalSDKError(error?.message || "An error occurred");
|
||||
};
|
||||
|
||||
@@ -1,35 +1,52 @@
|
||||
import { RawAxiosRequestConfig } from "axios";
|
||||
import { DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
||||
import type { ApiV1FoldersPostRequest, ApiV1FoldersPost200Response } from "../infisicalapi_client";
|
||||
import { FoldersApi } from "../api/endpoints/folders";
|
||||
import { newInfisicalError } from "./errors";
|
||||
|
||||
export type CreateFolderOptions = {
|
||||
projectId: string;
|
||||
} & Omit<ApiV1FoldersPostRequest, "workspaceId" | "directory">;
|
||||
export type CreateFolderResult = ApiV1FoldersPost200Response;
|
||||
name: string;
|
||||
path: string;
|
||||
projectId: string;
|
||||
environment: string;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
export type ListFoldersOptions = {
|
||||
environment: string;
|
||||
projectId: string;
|
||||
path?: string;
|
||||
recursive?: boolean;
|
||||
lastSecretModified?: string;
|
||||
};
|
||||
|
||||
export default class FoldersClient {
|
||||
#apiInstance: InfisicalApi;
|
||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
||||
constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) {
|
||||
this.#apiInstance = apiInstance;
|
||||
this.#requestOptions = requestOptions;
|
||||
}
|
||||
constructor(private apiClient: FoldersApi) {}
|
||||
|
||||
create = async (options: CreateFolderOptions): Promise<CreateFolderResult["folder"]> => {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV1FoldersPost(
|
||||
{
|
||||
apiV1FoldersPostRequest: {
|
||||
...options,
|
||||
workspaceId: options.projectId
|
||||
}
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
return res.data.folder;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
create = async (options: CreateFolderOptions) => {
|
||||
try {
|
||||
const res = await this.apiClient.create({
|
||||
name: options.name,
|
||||
path: options.path,
|
||||
workspaceId: options.projectId,
|
||||
environment: options.environment,
|
||||
description: options.description,
|
||||
});
|
||||
return res.folder;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
|
||||
listFolders = async (options: ListFoldersOptions) => {
|
||||
try {
|
||||
const res = await this.apiClient.listFolders({
|
||||
environment: options.environment,
|
||||
workspaceId: options.projectId,
|
||||
path: options.path,
|
||||
recursive: options.recursive,
|
||||
lastSecretModified: options.lastSecretModified,
|
||||
});
|
||||
return res.folders;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,56 +1,44 @@
|
||||
import { RawAxiosRequestConfig } from "axios";
|
||||
import { DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
||||
import type {
|
||||
ApiV2WorkspacePost200Response,
|
||||
ApiV2WorkspacePostRequest,
|
||||
ApiV2WorkspaceProjectIdMembershipsPost200Response,
|
||||
ApiV2WorkspaceProjectIdMembershipsPostRequest
|
||||
} from "../infisicalapi_client";
|
||||
import { ProjectsApi } from "../api/endpoints/projects";
|
||||
import { newInfisicalError } from "./errors";
|
||||
|
||||
export type CreateProjectOptions = ApiV2WorkspacePostRequest;
|
||||
export type CreateProjectResult = ApiV2WorkspacePost200Response;
|
||||
export type CreateProjectOptions = {
|
||||
projectName: string;
|
||||
type: string;
|
||||
projectDescription?: string;
|
||||
slug?: string;
|
||||
template?: string;
|
||||
kmsKeyId?: string;
|
||||
};
|
||||
|
||||
export type InviteMemberToProjectOptions = {
|
||||
projectId: string;
|
||||
emails?: string[];
|
||||
usernames?: string[];
|
||||
roleSlugs?: string[];
|
||||
};
|
||||
|
||||
export type InviteMemberToProjectOptions = { projectId: string } & ApiV2WorkspaceProjectIdMembershipsPostRequest;
|
||||
export type InviteMemberToProjectResult = ApiV2WorkspaceProjectIdMembershipsPost200Response;
|
||||
export default class ProjectsClient {
|
||||
#apiInstance: InfisicalApi;
|
||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
||||
constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) {
|
||||
this.#apiInstance = apiInstance;
|
||||
this.#requestOptions = requestOptions;
|
||||
}
|
||||
constructor(private apiClient: ProjectsApi) {}
|
||||
|
||||
create = async (options: CreateProjectOptions): Promise<CreateProjectResult["project"]> => {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV2WorkspacePost(
|
||||
{
|
||||
apiV2WorkspacePostRequest: options
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
return res.data.project;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
create = async (options: CreateProjectOptions) => {
|
||||
try {
|
||||
const res = await this.apiClient.create(options);
|
||||
return res.project;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
|
||||
inviteMembers = async (options: InviteMemberToProjectOptions): Promise<InviteMemberToProjectResult["memberships"]> => {
|
||||
try {
|
||||
if (!options.usernames?.length && !options.emails?.length) {
|
||||
throw new Error("Either usernames or emails must be provided");
|
||||
}
|
||||
inviteMembers = async (options: InviteMemberToProjectOptions) => {
|
||||
try {
|
||||
if (!options.usernames?.length && !options.emails?.length) {
|
||||
throw new Error("Either usernames or emails must be provided");
|
||||
}
|
||||
|
||||
const res = await this.#apiInstance.apiV2WorkspaceProjectIdMembershipsPost(
|
||||
{
|
||||
projectId: options.projectId,
|
||||
apiV2WorkspaceProjectIdMembershipsPostRequest: options
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
return res.data.memberships;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
const res = await this.apiClient.inviteMembers(options);
|
||||
return res.memberships;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,215 +1,192 @@
|
||||
import { RawAxiosRequestConfig } from "axios";
|
||||
import { DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
||||
import type {
|
||||
ApiV3SecretsRawGet200Response,
|
||||
ApiV3SecretsRawSecretNameGet200Response,
|
||||
ApiV3SecretsRawSecretNamePost200Response,
|
||||
DefaultApiApiV3SecretsRawSecretNameDeleteRequest,
|
||||
DefaultApiApiV3SecretsRawSecretNamePatchRequest,
|
||||
DefaultApiApiV3SecretsRawSecretNamePostRequest
|
||||
} from "../infisicalapi_client";
|
||||
import { SecretsApi } from "../api/endpoints/secrets";
|
||||
import { Secret } from "../api/types";
|
||||
import { newInfisicalError } from "./errors";
|
||||
import { getUniqueSecretsByKey } from "./util";
|
||||
|
||||
type SecretType = "shared" | "personal";
|
||||
|
||||
type ListSecretsOptions = {
|
||||
environment: string;
|
||||
projectId: string;
|
||||
expandSecretReferences?: boolean;
|
||||
includeImports?: boolean;
|
||||
recursive?: boolean;
|
||||
secretPath?: string;
|
||||
tagSlugs?: string[];
|
||||
viewSecretValue?: boolean;
|
||||
environment: string;
|
||||
projectId: string;
|
||||
expandSecretReferences?: boolean;
|
||||
includeImports?: boolean;
|
||||
recursive?: boolean;
|
||||
secretPath?: string;
|
||||
tagSlugs?: string[];
|
||||
viewSecretValue?: boolean;
|
||||
};
|
||||
|
||||
type GetSecretOptions = {
|
||||
environment: string;
|
||||
secretName: string;
|
||||
expandSecretReferences?: boolean;
|
||||
includeImports?: boolean;
|
||||
secretPath?: string;
|
||||
type?: SecretType;
|
||||
version?: number;
|
||||
projectId: string;
|
||||
viewSecretValue?: boolean;
|
||||
};
|
||||
|
||||
type BaseSecretOptions = {
|
||||
environment: string;
|
||||
secretName: string;
|
||||
expandSecretReferences?: boolean;
|
||||
includeImports?: boolean;
|
||||
projectId: string;
|
||||
secretComment?: string;
|
||||
secretPath?: string;
|
||||
secretReminderNote?: string;
|
||||
secretReminderRepeatDays?: number;
|
||||
skipMultilineEncoding?: boolean;
|
||||
tagIds?: string[];
|
||||
type?: SecretType;
|
||||
version?: number;
|
||||
projectId: string;
|
||||
viewSecretValue?: boolean;
|
||||
metadata?: Record<string, any>;
|
||||
secretMetadata?: Record<string, any>[];
|
||||
};
|
||||
|
||||
export type UpdateSecretOptions = Omit<DefaultApiApiV3SecretsRawSecretNamePatchRequest["apiV3SecretsRawSecretNamePatchRequest"], "workspaceId"> & {
|
||||
projectId: string;
|
||||
};
|
||||
export type UpdateSecretOptions = {
|
||||
secretValue?: string;
|
||||
newSecretName?: string;
|
||||
} & BaseSecretOptions;
|
||||
|
||||
export type CreateSecretOptions = Omit<DefaultApiApiV3SecretsRawSecretNamePostRequest["apiV3SecretsRawSecretNamePostRequest"], "workspaceId"> & {
|
||||
projectId: string;
|
||||
};
|
||||
export type CreateSecretOptions = {
|
||||
secretValue: string;
|
||||
} & BaseSecretOptions;
|
||||
|
||||
export type DeleteSecretOptions = Omit<DefaultApiApiV3SecretsRawSecretNameDeleteRequest["apiV3SecretsRawSecretNameDeleteRequest"], "workspaceId"> & {
|
||||
projectId: string;
|
||||
export type DeleteSecretOptions = {
|
||||
environment: string;
|
||||
projectId: string;
|
||||
secretPath?: string;
|
||||
type?: SecretType;
|
||||
};
|
||||
|
||||
export type ListSecretsResult = ApiV3SecretsRawGet200Response;
|
||||
export type GetSecretResult = ApiV3SecretsRawSecretNameGet200Response["secret"];
|
||||
export type UpdateSecretResult = ApiV3SecretsRawSecretNamePost200Response;
|
||||
export type CreateSecretResult = ApiV3SecretsRawSecretNamePost200Response;
|
||||
export type DeleteSecretResult = ApiV3SecretsRawSecretNamePost200Response;
|
||||
|
||||
const convertBool = (value?: boolean) => (value ? "true" : "false");
|
||||
|
||||
const defaultBoolean = (value?: boolean, defaultValue: boolean = false) => {
|
||||
if (value === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
if (value === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
export default class SecretsClient {
|
||||
#apiInstance: InfisicalApi;
|
||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
||||
constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) {
|
||||
this.#apiInstance = apiInstance;
|
||||
this.#requestOptions = requestOptions;
|
||||
}
|
||||
constructor(private apiClient: SecretsApi) {}
|
||||
|
||||
listSecrets = async (options: ListSecretsOptions): Promise<ListSecretsResult> => {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV3SecretsRawGet(
|
||||
{
|
||||
viewSecretValue: convertBool(options.viewSecretValue ?? true),
|
||||
environment: options.environment,
|
||||
workspaceId: options.projectId,
|
||||
expandSecretReferences: convertBool(defaultBoolean(options.expandSecretReferences, true)),
|
||||
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);
|
||||
}
|
||||
};
|
||||
listSecrets = async (options: ListSecretsOptions) => {
|
||||
try {
|
||||
return await this.apiClient.listSecrets({
|
||||
workspaceId: options.projectId,
|
||||
environment: options.environment,
|
||||
expandSecretReferences: convertBool(
|
||||
defaultBoolean(options.expandSecretReferences, true)
|
||||
),
|
||||
includeImports: convertBool(options.includeImports),
|
||||
recursive: convertBool(options.recursive),
|
||||
secretPath: options.secretPath,
|
||||
tagSlugs: options.tagSlugs ? options.tagSlugs.join(",") : undefined,
|
||||
viewSecretValue: convertBool(options.viewSecretValue ?? true),
|
||||
});
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
|
||||
listSecretsWithImports = async (options: Omit<ListSecretsOptions, "includeImports">): Promise<ListSecretsResult["secrets"]> => {
|
||||
const res = await this.listSecrets({
|
||||
...options,
|
||||
includeImports: true
|
||||
});
|
||||
listSecretsWithImports = async (
|
||||
options: Omit<ListSecretsOptions, "includeImports">
|
||||
) => {
|
||||
const res = await this.listSecrets({
|
||||
...options,
|
||||
includeImports: true,
|
||||
});
|
||||
|
||||
let { imports, secrets } = res;
|
||||
if (imports) {
|
||||
if (options.recursive) {
|
||||
secrets = getUniqueSecretsByKey(secrets);
|
||||
}
|
||||
let { imports, secrets } = res;
|
||||
if (imports) {
|
||||
for (const imp of imports) {
|
||||
for (const importedSecret of imp.secrets) {
|
||||
if (!secrets.find((s) => s.secretKey === importedSecret.secretKey)) {
|
||||
secrets.push({
|
||||
...importedSecret,
|
||||
secretPath: imp.secretPath,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
tags: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const imp of imports) {
|
||||
for (const importedSecret of imp.secrets) {
|
||||
// CASE: We need to ensure that the imported values don't override the "base" secrets.
|
||||
// Priority order is:
|
||||
// Local/Preset variables -> Actual secrets -> Imported secrets (high->low)
|
||||
return secrets;
|
||||
};
|
||||
|
||||
// Check if the secret already exists in the secrets list
|
||||
if (!secrets.find(s => s.secretKey === importedSecret.secretKey)) {
|
||||
secrets.push({
|
||||
...importedSecret,
|
||||
secretPath: imp.secretPath,
|
||||
// These fields are not returned by the API
|
||||
updatedAt: new Date().toISOString(),
|
||||
createdAt: new Date().toISOString(),
|
||||
tags: []
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
getSecret = async (options: GetSecretOptions) => {
|
||||
try {
|
||||
const res = await this.apiClient.getSecret({
|
||||
secretName: options.secretName,
|
||||
workspaceId: options.projectId,
|
||||
environment: options.environment,
|
||||
expandSecretReferences: convertBool(
|
||||
defaultBoolean(options.expandSecretReferences, true)
|
||||
),
|
||||
includeImports: convertBool(options.includeImports),
|
||||
secretPath: options.secretPath,
|
||||
type: options.type,
|
||||
version: options.version,
|
||||
viewSecretValue: convertBool(options.viewSecretValue ?? true),
|
||||
});
|
||||
return res.secret;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
|
||||
return secrets;
|
||||
};
|
||||
updateSecret = async (secretName: string, options: UpdateSecretOptions) => {
|
||||
try {
|
||||
return await this.apiClient.updateSecret(secretName, {
|
||||
workspaceId: options.projectId,
|
||||
environment: options.environment,
|
||||
secretValue: options.secretValue,
|
||||
newSecretName: options.newSecretName,
|
||||
secretComment: options.secretComment,
|
||||
secretPath: options.secretPath,
|
||||
secretReminderNote: options.secretReminderNote,
|
||||
secretReminderRepeatDays: options.secretReminderRepeatDays,
|
||||
skipMultilineEncoding: options.skipMultilineEncoding,
|
||||
tagIds: options.tagIds,
|
||||
type: options.type,
|
||||
metadata: options.metadata,
|
||||
});
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
|
||||
getSecret = async (options: GetSecretOptions): Promise<GetSecretResult> => {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV3SecretsRawSecretNameGet(
|
||||
{
|
||||
viewSecretValue: convertBool(options.viewSecretValue ?? true),
|
||||
environment: options.environment,
|
||||
secretName: options.secretName,
|
||||
workspaceId: options.projectId,
|
||||
expandSecretReferences: convertBool(defaultBoolean(options.expandSecretReferences, true)),
|
||||
includeImports: convertBool(options.includeImports),
|
||||
secretPath: options.secretPath,
|
||||
type: options.type,
|
||||
version: options.version
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
return res.data.secret;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
createSecret = async (secretName: string, options: CreateSecretOptions) => {
|
||||
try {
|
||||
return await this.apiClient.createSecret(secretName, {
|
||||
workspaceId: options.projectId,
|
||||
environment: options.environment,
|
||||
secretValue: options.secretValue,
|
||||
secretComment: options.secretComment,
|
||||
secretPath: options.secretPath,
|
||||
secretReminderNote: options.secretReminderNote,
|
||||
secretReminderRepeatDays: options.secretReminderRepeatDays,
|
||||
skipMultilineEncoding: options.skipMultilineEncoding,
|
||||
tagIds: options.tagIds,
|
||||
type: options.type,
|
||||
});
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
|
||||
updateSecret = async (
|
||||
secretName: DefaultApiApiV3SecretsRawSecretNamePatchRequest["secretName"],
|
||||
options: UpdateSecretOptions
|
||||
): Promise<UpdateSecretResult> => {
|
||||
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
|
||||
): Promise<CreateSecretResult> => {
|
||||
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
|
||||
): Promise<DeleteSecretResult> => {
|
||||
try {
|
||||
const res = await this.#apiInstance.apiV3SecretsRawSecretNameDelete(
|
||||
{
|
||||
secretName,
|
||||
apiV3SecretsRawSecretNameDeleteRequest: {
|
||||
...options,
|
||||
workspaceId: options.projectId
|
||||
}
|
||||
},
|
||||
this.#requestOptions
|
||||
);
|
||||
return res.data;
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
deleteSecret = async (secretName: string, options: DeleteSecretOptions) => {
|
||||
try {
|
||||
return await this.apiClient.deleteSecret(secretName, {
|
||||
workspaceId: options.projectId,
|
||||
environment: options.environment,
|
||||
secretPath: options.secretPath,
|
||||
type: options.type,
|
||||
});
|
||||
} catch (err) {
|
||||
throw newInfisicalError(err);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@ import axios from "axios";
|
||||
import { AWS_IDENTITY_DOCUMENT_URI, AWS_TOKEN_METADATA_URI } from "./constants";
|
||||
import AWS from "aws-sdk";
|
||||
import { InfisicalSDKError } from "./errors";
|
||||
import { ApiV3SecretsRawGet200Response } from "../infisicalapi_client";
|
||||
|
||||
type Secret = ApiV3SecretsRawGet200Response["secrets"][number];
|
||||
import { Secret } from "../api/types";
|
||||
|
||||
export const getUniqueSecretsByKey = (secrets: Secret[]) => {
|
||||
const secretMap = new Map<string, Secret>();
|
||||
|
||||
197
src/index.ts
197
src/index.ts
@@ -1,141 +1,106 @@
|
||||
import { Configuration, DefaultApi as InfisicalApi } from "./infisicalapi_client";
|
||||
import { DefaultApiApiV1DynamicSecretsLeasesPostRequest } from "./infisicalapi_client";
|
||||
import { ApiClient } from "./api/base";
|
||||
import { AuthApi } from "./api/endpoints/auth";
|
||||
import { SecretsApi } from "./api/endpoints/secrets";
|
||||
import { DynamicSecretsApi } from "./api/endpoints/dynamic-secrets";
|
||||
import { EnvironmentsApi } from "./api/endpoints/environments";
|
||||
import { ProjectsApi } from "./api/endpoints/projects";
|
||||
import { FoldersApi } from "./api/endpoints/folders";
|
||||
|
||||
import SecretsClient from "./custom/secrets";
|
||||
import AuthClient from "./custom/auth";
|
||||
import axios, { AxiosError, AxiosInstance, RawAxiosRequestConfig } from "axios";
|
||||
import DynamicSecretsClient from "./custom/dynamic-secrets";
|
||||
|
||||
import * as ApiClient from "./infisicalapi_client";
|
||||
import EnvironmentsClient from "./custom/environments";
|
||||
import ProjectsClient from "./custom/projects";
|
||||
import FoldersClient from "./custom/folders";
|
||||
|
||||
declare module "axios" {
|
||||
interface AxiosRequestConfig {
|
||||
_retryCount?: number;
|
||||
}
|
||||
}
|
||||
import * as ApiTypes from "./api/types";
|
||||
|
||||
const buildRestClient = (apiClient: InfisicalApi, requestOptions?: RawAxiosRequestConfig) => {
|
||||
return {
|
||||
// Add more as we go
|
||||
apiV1DynamicSecretsLeasesPost: (options: DefaultApiApiV1DynamicSecretsLeasesPostRequest) =>
|
||||
apiClient.apiV1DynamicSecretsLeasesPost(options, requestOptions)
|
||||
};
|
||||
};
|
||||
|
||||
const setupAxiosRetry = () => {
|
||||
const axiosInstance = axios.create();
|
||||
const maxRetries = 4;
|
||||
|
||||
const initialRetryDelay = 1000;
|
||||
const backoffFactor = 2;
|
||||
|
||||
axiosInstance.interceptors.response.use(null, (error: AxiosError) => {
|
||||
const config = error?.config;
|
||||
|
||||
if (!config) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
if (!config._retryCount) config._retryCount = 0;
|
||||
|
||||
// handle rate limits and network errors
|
||||
if ((error.response?.status === 429 || error.response?.status === undefined) && config && config._retryCount! < maxRetries) {
|
||||
config._retryCount!++;
|
||||
const baseDelay = initialRetryDelay * Math.pow(backoffFactor, config._retryCount! - 1);
|
||||
const jitter = baseDelay * 0.2; // 20% +/- jitter
|
||||
const exponentialDelay = baseDelay + (Math.random() * 2 - 1) * jitter;
|
||||
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve(axiosInstance(config));
|
||||
}, exponentialDelay);
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
return axiosInstance;
|
||||
};
|
||||
|
||||
// We need to do bind(this) because the authenticate method is a private method, and usually you can't call private methods from outside the class.
|
||||
type InfisicalSDKOptions = {
|
||||
siteUrl?: string;
|
||||
siteUrl?: string;
|
||||
};
|
||||
|
||||
class InfisicalSDK {
|
||||
#apiInstance: InfisicalApi;
|
||||
private apiClient: ApiClient;
|
||||
|
||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
||||
#secretsClient: SecretsClient;
|
||||
#dynamicSecretsClient: DynamicSecretsClient;
|
||||
#environmentsClient: EnvironmentsClient;
|
||||
#projectsClient: ProjectsClient;
|
||||
#foldersClient: FoldersClient;
|
||||
#authClient: AuthClient;
|
||||
#basePath: string;
|
||||
axiosInstance: AxiosInstance;
|
||||
// API instances
|
||||
private authApi: AuthApi;
|
||||
private secretsApi: SecretsApi;
|
||||
private dynamicSecretsApi: DynamicSecretsApi;
|
||||
private environmentsApi: EnvironmentsApi;
|
||||
private projectsApi: ProjectsApi;
|
||||
private foldersApi: FoldersApi;
|
||||
|
||||
constructor(options?: InfisicalSDKOptions) {
|
||||
this.#basePath = options?.siteUrl || "https://app.infisical.com";
|
||||
this.axiosInstance = setupAxiosRetry();
|
||||
// Domain clients
|
||||
private authClient: AuthClient;
|
||||
private secretsClient: SecretsClient;
|
||||
private dynamicSecretsClient: DynamicSecretsClient;
|
||||
private environmentsClient: EnvironmentsClient;
|
||||
private projectsClient: ProjectsClient;
|
||||
private foldersClient: FoldersClient;
|
||||
|
||||
this.#apiInstance = new InfisicalApi(
|
||||
new Configuration({
|
||||
basePath: this.#basePath
|
||||
}),
|
||||
undefined,
|
||||
this.axiosInstance
|
||||
);
|
||||
constructor(options?: InfisicalSDKOptions) {
|
||||
const baseURL = options?.siteUrl || "https://app.infisical.com";
|
||||
|
||||
this.#authClient = new AuthClient(this.authenticate.bind(this), this.#apiInstance);
|
||||
this.#dynamicSecretsClient = new DynamicSecretsClient(this.#apiInstance, this.#requestOptions);
|
||||
this.#secretsClient = new SecretsClient(this.#apiInstance, this.#requestOptions);
|
||||
this.#environmentsClient = new EnvironmentsClient(this.#apiInstance, this.#requestOptions);
|
||||
this.#projectsClient = new ProjectsClient(this.#apiInstance, this.#requestOptions);
|
||||
this.#foldersClient = new FoldersClient(this.#apiInstance, this.#requestOptions);
|
||||
this.rest = () => buildRestClient(this.#apiInstance, this.#requestOptions);
|
||||
}
|
||||
// Initialize the base API client
|
||||
this.apiClient = new ApiClient({ baseURL });
|
||||
|
||||
private authenticate(accessToken: string) {
|
||||
this.#apiInstance = new InfisicalApi(
|
||||
new Configuration({
|
||||
basePath: this.#basePath,
|
||||
accessToken
|
||||
}),
|
||||
undefined,
|
||||
this.axiosInstance
|
||||
);
|
||||
// Initialize API service instances
|
||||
this.authApi = new AuthApi(this.apiClient);
|
||||
this.secretsApi = new SecretsApi(this.apiClient);
|
||||
this.dynamicSecretsApi = new DynamicSecretsApi(this.apiClient);
|
||||
this.environmentsApi = new EnvironmentsApi(this.apiClient);
|
||||
this.projectsApi = new ProjectsApi(this.apiClient);
|
||||
this.foldersApi = new FoldersApi(this.apiClient);
|
||||
|
||||
this.#requestOptions = {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`
|
||||
}
|
||||
};
|
||||
// Initialize domain clients
|
||||
this.authClient = new AuthClient(
|
||||
this.authenticate.bind(this),
|
||||
this.authApi
|
||||
);
|
||||
this.secretsClient = new SecretsClient(this.secretsApi);
|
||||
this.dynamicSecretsClient = new DynamicSecretsClient(
|
||||
this.dynamicSecretsApi
|
||||
);
|
||||
this.environmentsClient = new EnvironmentsClient(this.environmentsApi);
|
||||
this.projectsClient = new ProjectsClient(this.projectsApi);
|
||||
this.foldersClient = new FoldersClient(this.foldersApi);
|
||||
}
|
||||
|
||||
this.rest = () => buildRestClient(this.#apiInstance, this.#requestOptions);
|
||||
this.#secretsClient = new SecretsClient(this.#apiInstance, this.#requestOptions);
|
||||
this.#dynamicSecretsClient = new DynamicSecretsClient(this.#apiInstance, this.#requestOptions);
|
||||
this.#authClient = new AuthClient(this.authenticate.bind(this), this.#apiInstance, accessToken);
|
||||
this.#environmentsClient = new EnvironmentsClient(this.#apiInstance, this.#requestOptions);
|
||||
this.#projectsClient = new ProjectsClient(this.#apiInstance, this.#requestOptions);
|
||||
this.#foldersClient = new FoldersClient(this.#apiInstance, this.#requestOptions);
|
||||
private authenticate(accessToken: string) {
|
||||
// Set the token on the API client
|
||||
this.apiClient.setAccessToken(accessToken);
|
||||
|
||||
return this;
|
||||
}
|
||||
// Reinitialize the auth client with the token
|
||||
this.authClient = new AuthClient(
|
||||
this.authenticate.bind(this),
|
||||
this.authApi,
|
||||
accessToken
|
||||
);
|
||||
|
||||
secrets = () => this.#secretsClient;
|
||||
environments = () => this.#environmentsClient;
|
||||
projects = () => this.#projectsClient;
|
||||
folders = () => this.#foldersClient;
|
||||
dynamicSecrets = () => this.#dynamicSecretsClient;
|
||||
auth = () => this.#authClient;
|
||||
rest = () => buildRestClient(this.#apiInstance, this.#requestOptions);
|
||||
return this;
|
||||
}
|
||||
|
||||
// Public methods to access domain clients
|
||||
secrets = () => this.secretsClient;
|
||||
environments = () => this.environmentsClient;
|
||||
projects = () => this.projectsClient;
|
||||
folders = () => this.foldersClient;
|
||||
dynamicSecrets = () => this.dynamicSecretsClient;
|
||||
auth = () => this.authClient;
|
||||
}
|
||||
|
||||
export { InfisicalSDK, ApiClient };
|
||||
export { TDynamicSecretProvider, DynamicSecretProviders } from "./custom/schemas";
|
||||
// Export main SDK class
|
||||
export { InfisicalSDK, ApiTypes };
|
||||
|
||||
// Export types and enums from schemas
|
||||
export {
|
||||
TDynamicSecretProvider,
|
||||
DynamicSecretProviders,
|
||||
} from "./custom/schemas";
|
||||
|
||||
// Export domain-specific types
|
||||
export type * from "./custom/secrets";
|
||||
export type * from "./custom/dynamic-secrets";
|
||||
export type * from "./custom/environments";
|
||||
export type * from "./custom/projects";
|
||||
export type * from "./custom/folders";
|
||||
|
||||
Reference in New Issue
Block a user