Merge pull request #19 from Infisical/feat/moveSdkToAxios
Refactor: openapi-generator-cli to Axios
This commit is contained in:
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@@ -28,9 +28,6 @@ jobs:
|
|||||||
- name: Set NPM version
|
- name: Set NPM version
|
||||||
run: npm version ${{ github.ref_name }} --allow-same-version --no-git-tag-version
|
run: npm version ${{ github.ref_name }} --allow-same-version --no-git-tag-version
|
||||||
|
|
||||||
- name: Build API client
|
|
||||||
run: npm run generate-api:infisical
|
|
||||||
|
|
||||||
- name: Build SDK
|
- name: Build SDK
|
||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
|
|||||||
55
README.md
55
README.md
@@ -42,6 +42,10 @@ The SDK methods are organized into the following high-level categories:
|
|||||||
|
|
||||||
1. `auth`: Handles authentication methods.
|
1. `auth`: Handles authentication methods.
|
||||||
2. `secrets`: Manages CRUD operations for secrets.
|
2. `secrets`: Manages CRUD operations for secrets.
|
||||||
|
3. `dynamicSecrets`: Manages dynamic secrets and leases.
|
||||||
|
4. `projects`: Creates and manages projects.
|
||||||
|
5. `environments`: Creates and manages environments.
|
||||||
|
6. `folders`: Creates and manages folders.
|
||||||
|
|
||||||
### `auth`
|
### `auth`
|
||||||
|
|
||||||
@@ -102,7 +106,6 @@ await client.auth().awsIamAuth.renew();
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### `secrets`
|
### `secrets`
|
||||||
|
|
||||||
This sub-class handles operations related to secrets:
|
This sub-class handles operations related to secrets:
|
||||||
@@ -132,7 +135,7 @@ const allSecrets = await client.secrets().listSecrets({
|
|||||||
- `tagFilters` (string[], optional): Tags to filter secrets.
|
- `tagFilters` (string[], optional): Tags to filter secrets.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV3SecretsRawGet200Response`: The response containing the list of secrets.
|
- `ListSecretsResponse`: The response containing the list of secrets.
|
||||||
|
|
||||||
#### List secrets with imports
|
#### List secrets with imports
|
||||||
|
|
||||||
@@ -159,7 +162,7 @@ const allSecrets = await client.secrets().listSecretsWithImports({
|
|||||||
- `tagFilters` (string[], optional): Tags to filter secrets.
|
- `tagFilters` (string[], optional): Tags to filter secrets.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV1DashboardSecretsOverviewGet200ResponseSecretsInner`: The response containing the list of secrets, with imports.
|
- `Secret[]`: Returns the list of secrets objects, with imports.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -195,7 +198,7 @@ const allSecrets = await client.secrets().listSecretsWithImports({
|
|||||||
- `type` (personal | shared, optional): Which type of secret to create.
|
- `type` (personal | shared, optional): Which type of secret to create.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV3SecretsRawSecretNamePost200Response`: The response after creating the secret.
|
- `CreateSecretResponse`: The response after creating the secret.
|
||||||
|
|
||||||
#### Update Secret
|
#### Update Secret
|
||||||
|
|
||||||
@@ -235,7 +238,7 @@ const updatedSecret = await client.secrets().updateSecret("SECRET_TO_UPDATE", {
|
|||||||
- `metadata` (object, optional): Assign additional details to the secret, accessible through the API.
|
- `metadata` (object, optional): Assign additional details to the secret, accessible through the API.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV3SecretsRawSecretNamePost200Response`: The response after updating the secret.
|
- `UpdateSecretResponse`: The response after updating the secret.
|
||||||
|
|
||||||
#### Get Secret by Name
|
#### Get Secret by Name
|
||||||
|
|
||||||
@@ -266,7 +269,7 @@ const updatedSecret = await client.secrets().updateSecret("SECRET_TO_UPDATE", {
|
|||||||
|
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV3SecretsRawSecretNameGet200Response`: The response containing the secret.
|
- `Secret`: Returns the secret object.
|
||||||
|
|
||||||
#### Delete Secret by Name
|
#### Delete Secret by Name
|
||||||
|
|
||||||
@@ -288,7 +291,7 @@ const deletedSecret = await client.secrets().deleteSecret("SECRET_TO_DELETE", {
|
|||||||
- `type` (personal | shared, optional): The type of secret to delete.
|
- `type` (personal | shared, optional): The type of secret to delete.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV3SecretsRawSecretNamePost200Response`: The response after deleting the secret.
|
- `DeleteSecretResponse`: The response after deleting the secret.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -338,7 +341,7 @@ console.log(dynamicSecret);
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV1DynamicSecretsPost200Response['dynamicSecret']`: The response after creating the dynamic secret
|
- `DynamicSecret`: The created dynamic secret.
|
||||||
|
|
||||||
|
|
||||||
#### Delete a dynamic secret
|
#### Delete a dynamic secret
|
||||||
@@ -359,7 +362,7 @@ const deletedDynamicSecret = await client.dynamicSecrets().delete("dynamic-secre
|
|||||||
- `environment` (str): The environment in which to delete the secret.
|
- `environment` (str): The environment in which to delete the secret.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV1DynamicSecretsDelete200Response['dynamicSecret']`: The response after deleting the dynamic secret
|
- `DynamicSecret`: The deleted dynamic secret.
|
||||||
|
|
||||||
### `dynamicSecrets.leases`
|
### `dynamicSecrets.leases`
|
||||||
In this section you'll learn how to work with dynamic secret leases
|
In this section you'll learn how to work with dynamic secret leases
|
||||||
@@ -389,7 +392,7 @@ console.log(lease);
|
|||||||
- `ttl` (string, optional): A [vercel/ms](https://github.com/vercel/ms) encoded string representation of how long the lease credentials should be valid for. This will default to the dynamic secret's default TTL if not specified.
|
- `ttl` (string, optional): A [vercel/ms](https://github.com/vercel/ms) encoded string representation of how long the lease credentials should be valid for. This will default to the dynamic secret's default TTL if not specified.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV1DynamicSecretsLeasesPost200Response`: The dynamic secret lease result.
|
- `CreateLeaseResponse`: The dynamic secret lease result.
|
||||||
|
|
||||||
|
|
||||||
#### Delete a lease
|
#### Delete a lease
|
||||||
@@ -411,7 +414,7 @@ const deletedLease = await client.dynamicSecrets().leases.delete(newLease.lease.
|
|||||||
- `isForced` (bool, optional): Wether or not to forcefully delete the lease. This can't guarantee that the lease will be deleted from the external provider, and is potentially unsafe for sensitive dynamic secrets.
|
- `isForced` (bool, optional): Wether or not to forcefully delete the lease. This can't guarantee that the lease will be deleted from the external provider, and is potentially unsafe for sensitive dynamic secrets.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV1DynamicSecretsLeasesLeaseIdDelete200Response`: The deleted lease result.
|
- `DeleteLeaseResponse`: The deleted lease result.
|
||||||
|
|
||||||
#### Renew a lease
|
#### Renew a lease
|
||||||
|
|
||||||
@@ -435,7 +438,7 @@ const renewedLease = await client.dynamicSecrets().leases.renew(newLease.lease.i
|
|||||||
- `ttl` (string, optional): A [vercel/ms](https://github.com/vercel/ms) encoded string representation of how long the lease credentials should be valid for. This will default to the dynamic secret's default TTL if not specified.
|
- `ttl` (string, optional): A [vercel/ms](https://github.com/vercel/ms) encoded string representation of how long the lease credentials should be valid for. This will default to the dynamic secret's default TTL if not specified.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV1DynamicSecretsLeasesLeaseIdDelete200Response`: The renewed lease response _(doesn't contain new credentials)_.
|
- `RenewLeaseResponse`: The renewed lease response _(doesn't contain new credentials)_.
|
||||||
|
|
||||||
### `projects`
|
### `projects`
|
||||||
|
|
||||||
@@ -461,7 +464,7 @@ const project = await client.projects().create({
|
|||||||
- `kmsKeyId` (string): The ID of the KMS key to use for the project. Will use the Infisical KMS by default.
|
- `kmsKeyId` (string): The ID of the KMS key to use for the project. Will use the Infisical KMS by default.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV1WorkspaceWorkspaceIdGet200ResponseWorkspace`: The project that was created.
|
- `Project`: The project that was created.
|
||||||
|
|
||||||
|
|
||||||
#### Invite members to a project
|
#### Invite members to a project
|
||||||
@@ -484,7 +487,7 @@ const memberships = await client.projects().inviteMembers({
|
|||||||
- `roleSlugs`: (string[]): An array of role slugs to assign to the members. If not specified, this will default to `member`.
|
- `roleSlugs`: (string[]): An array of role slugs to assign to the members. If not specified, this will default to `member`.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV1OrganizationAdminProjectsProjectIdGrantAdminAccessPost200ResponseMembership`: An array of the created project memberships.
|
- `Membership[]`: An array of the created project memberships.
|
||||||
|
|
||||||
### `environments`
|
### `environments`
|
||||||
|
|
||||||
@@ -506,7 +509,7 @@ const environment = await client.environments().create({
|
|||||||
- `position` (number): An optional position of the environment to be created. The position is used in the Infisical UI to display environments in order. Environments with the lowest position come first.
|
- `position` (number): An optional position of the environment to be created. The position is used in the Infisical UI to display environments in order. Environments with the lowest position come first.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV1WorkspaceWorkspaceIdEnvironmentsEnvIdGet200ResponseEnvironment`: The environment that was created.
|
- `Environment`: The environment that was created.
|
||||||
|
|
||||||
#### Create a new folder
|
#### Create a new folder
|
||||||
|
|
||||||
@@ -528,4 +531,24 @@ const folder = await client.folders().create({
|
|||||||
- `description` (string): An optional folder description.
|
- `description` (string): An optional folder description.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
- `ApiV1FoldersPost200ResponseFolder`: The folder that was created.
|
- `Folder`: The folder that was created.
|
||||||
|
|
||||||
|
#### List folders
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const folders = await client.folders().listFolders({
|
||||||
|
environment: "dev",
|
||||||
|
projectId: "<your-project-id>",
|
||||||
|
path: "/foo/bar", // Optional
|
||||||
|
recursive: false // Optional
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `environment` (string): The slug of the environment to list folders within.
|
||||||
|
- `projectId` (string): The ID of the project to list folders within.
|
||||||
|
- `path` (string): The path to list folders within. Defaults to `/`, which is the root folder.
|
||||||
|
- `recursive` (boolean): An optional flag to list folders recursively. Defaults to `false`.
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
- `Folder[]`: An array of folders.
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
|
||||||
"spaces": 2,
|
|
||||||
"generator-cli": {
|
|
||||||
"version": "7.8.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2503
package-lock.json
generated
2503
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@@ -7,9 +7,6 @@
|
|||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"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"
|
"build": "tsup src/index.ts --out-dir lib --dts --format cjs,esm --tsconfig tsconfig.json --no-splitting"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -20,13 +17,12 @@
|
|||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"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>",
|
"author": "Infisical Inc, <daniel@infisical.com>",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "",
|
"description": "The Infisical SDK provides a convenient way to programmatically interact with the Infisical API.",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@openapitools/openapi-generator-cli": "^2.13.5",
|
|
||||||
"@types/node": "^22.5.1",
|
"@types/node": "^22.5.1",
|
||||||
"tsc": "^2.0.4",
|
"tsc": "^2.0.4",
|
||||||
"tsup": "^8.2.4"
|
"tsup": "^8.2.4"
|
||||||
@@ -36,5 +32,14 @@
|
|||||||
"axios": "^1.7.5",
|
"axios": "^1.7.5",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.5.4",
|
||||||
"zod": "^3.23.8"
|
"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"
|
||||||
}
|
}
|
||||||
|
|||||||
93
src/api/base.ts
Normal file
93
src/api/base.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
// handle rate limits and network errors
|
||||||
|
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
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
15
src/api/endpoints/environments.ts
Normal file
15
src/api/endpoints/environments.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
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`,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/api/endpoints/projects.ts
Normal file
27
src/api/endpoints/projects.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
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`,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
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 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
129
src/api/types/dynamic-secrets.ts
Normal file
129
src/api/types/dynamic-secrets.ts
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateDynamicSecretOptions = {
|
||||||
|
provider: TDynamicSecretProvider;
|
||||||
|
defaultTTL: string;
|
||||||
|
maxTTL: string;
|
||||||
|
name: string;
|
||||||
|
projectSlug: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
path?: string;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
29
src/api/types/environments.ts
Normal file
29
src/api/types/environments.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
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 = {
|
||||||
|
message: string;
|
||||||
|
workspace: string;
|
||||||
|
environment: Environment;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateEnvironmentOptions = {
|
||||||
|
name: string;
|
||||||
|
projectId: string;
|
||||||
|
slug: string;
|
||||||
|
position?: number;
|
||||||
|
};
|
||||||
52
src/api/types/folders.ts
Normal file
52
src/api/types/folders.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
export interface Folder {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
envId: string;
|
||||||
|
description?: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
parentId?: string;
|
||||||
|
isReserved?: boolean;
|
||||||
|
lastSecretModified?: string;
|
||||||
|
version?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
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[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateFolderOptions = {
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
projectId: string;
|
||||||
|
environment: string;
|
||||||
|
description?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ListFoldersOptions = {
|
||||||
|
environment: string;
|
||||||
|
projectId: string;
|
||||||
|
path?: string;
|
||||||
|
recursive?: boolean;
|
||||||
|
lastSecretModified?: string;
|
||||||
|
};
|
||||||
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;
|
||||||
|
}
|
||||||
59
src/api/types/projects.ts
Normal file
59
src/api/types/projects.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
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[];
|
||||||
|
}
|
||||||
|
|
||||||
|
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[];
|
||||||
|
};
|
||||||
158
src/api/types/secrets.ts
Normal file
158
src/api/types/secrets.ts
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
export enum SecretType {
|
||||||
|
Shared = "shared",
|
||||||
|
Personal = "personal"
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Secret {
|
||||||
|
id: string;
|
||||||
|
workspaceId: string;
|
||||||
|
environment: string;
|
||||||
|
secretKey: string;
|
||||||
|
secretValue: string;
|
||||||
|
secretComment?: string;
|
||||||
|
secretPath?: string;
|
||||||
|
secretValueHidden: boolean;
|
||||||
|
secretReminderNote?: string;
|
||||||
|
secretReminderRepeatDays?: number;
|
||||||
|
skipMultilineEncoding?: boolean;
|
||||||
|
folderId?: string;
|
||||||
|
actor?: {
|
||||||
|
actorId?: string;
|
||||||
|
name?: string;
|
||||||
|
actorType?: string;
|
||||||
|
membershipId?: string;
|
||||||
|
}
|
||||||
|
isRotatedSecret: boolean;
|
||||||
|
rotationId?: string;
|
||||||
|
secretMetadata?: Record<string, any>;
|
||||||
|
type: SecretType;
|
||||||
|
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[];
|
||||||
|
folderId?: string;
|
||||||
|
environment: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetSecretRequest {
|
||||||
|
secretName: string;
|
||||||
|
workspaceId: string;
|
||||||
|
environment: string;
|
||||||
|
expandSecretReferences?: string;
|
||||||
|
includeImports?: string;
|
||||||
|
secretPath?: string;
|
||||||
|
type?: SecretType;
|
||||||
|
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?: SecretType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateSecretRequest {
|
||||||
|
workspaceId: string;
|
||||||
|
environment: string;
|
||||||
|
secretValue?: string;
|
||||||
|
newSecretName?: string;
|
||||||
|
secretComment?: string;
|
||||||
|
secretPath?: string;
|
||||||
|
secretReminderNote?: string;
|
||||||
|
secretReminderRepeatDays?: number;
|
||||||
|
skipMultilineEncoding?: boolean;
|
||||||
|
tagIds?: string[];
|
||||||
|
type?: SecretType;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DeleteSecretRequest {
|
||||||
|
workspaceId: string;
|
||||||
|
environment: string;
|
||||||
|
secretPath?: string;
|
||||||
|
type?: SecretType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ListSecretsOptions = {
|
||||||
|
environment: string;
|
||||||
|
projectId: string;
|
||||||
|
expandSecretReferences?: boolean;
|
||||||
|
includeImports?: boolean;
|
||||||
|
recursive?: boolean;
|
||||||
|
secretPath?: string;
|
||||||
|
tagSlugs?: string[];
|
||||||
|
viewSecretValue?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetSecretOptions = {
|
||||||
|
environment: string;
|
||||||
|
secretName: string;
|
||||||
|
expandSecretReferences?: boolean;
|
||||||
|
includeImports?: boolean;
|
||||||
|
secretPath?: string;
|
||||||
|
type?: SecretType;
|
||||||
|
version?: number;
|
||||||
|
projectId: string;
|
||||||
|
viewSecretValue?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BaseSecretOptions = {
|
||||||
|
environment: string;
|
||||||
|
projectId: string;
|
||||||
|
secretComment?: string;
|
||||||
|
secretPath?: string;
|
||||||
|
secretReminderNote?: string;
|
||||||
|
secretReminderRepeatDays?: number;
|
||||||
|
skipMultilineEncoding?: boolean;
|
||||||
|
tagIds?: string[];
|
||||||
|
type?: SecretType;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
secretMetadata?: Record<string, any>[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdateSecretOptions = {
|
||||||
|
secretValue?: string;
|
||||||
|
newSecretName?: string;
|
||||||
|
} & BaseSecretOptions;
|
||||||
|
|
||||||
|
export type CreateSecretOptions = {
|
||||||
|
secretValue: string;
|
||||||
|
} & BaseSecretOptions;
|
||||||
|
|
||||||
|
export type DeleteSecretOptions = {
|
||||||
|
environment: string;
|
||||||
|
projectId: string;
|
||||||
|
secretPath?: string;
|
||||||
|
type?: SecretType;
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { InfisicalSDK } from "..";
|
import { InfisicalSDK } from "..";
|
||||||
import { ApiV1AuthUniversalAuthLoginPostRequest } from "../infisicalapi_client";
|
import { AuthApi } from "../api/endpoints/auth";
|
||||||
import { DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
import { UniversalAuthLoginRequest } from "../api/types";
|
||||||
import { MACHINE_IDENTITY_ID_ENV_NAME } from "./constants";
|
import { MACHINE_IDENTITY_ID_ENV_NAME } from "./constants";
|
||||||
import { InfisicalSDKError, newInfisicalError } from "./errors";
|
import { InfisicalSDKError, newInfisicalError } from "./errors";
|
||||||
import { getAwsRegion, performAwsIamLogin } from "./util";
|
import { getAwsRegion, performAwsIamLogin } from "./util";
|
||||||
@@ -8,97 +8,95 @@ import { getAwsRegion, performAwsIamLogin } from "./util";
|
|||||||
type AuthenticatorFunction = (accessToken: string) => InfisicalSDK;
|
type AuthenticatorFunction = (accessToken: string) => InfisicalSDK;
|
||||||
|
|
||||||
type AwsAuthLoginOptions = {
|
type AwsAuthLoginOptions = {
|
||||||
identityId?: string;
|
identityId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const renewToken = async (apiClient: InfisicalApi, token?: string) => {
|
export const renewToken = async (apiClient: AuthApi, token?: string) => {
|
||||||
try {
|
try {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
throw new InfisicalSDKError("Unable to renew access token, no access token set. Are you sure you're authenticated?");
|
throw new InfisicalSDKError(
|
||||||
}
|
"Unable to renew access token, no access token set."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const res = await apiClient.apiV1AuthTokenRenewPost({
|
const res = await apiClient.renewToken({ accessToken: token });
|
||||||
apiV1AuthTokenRenewPostRequest: {
|
return res;
|
||||||
accessToken: token
|
} catch (err) {
|
||||||
}
|
throw newInfisicalError(err);
|
||||||
});
|
}
|
||||||
|
|
||||||
return res.data;
|
|
||||||
} catch (err) {
|
|
||||||
throw newInfisicalError(err);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class AuthClient {
|
export default class AuthClient {
|
||||||
#sdkAuthenticator: AuthenticatorFunction;
|
constructor(
|
||||||
#apiClient: InfisicalApi;
|
private sdkAuthenticator: AuthenticatorFunction,
|
||||||
#accessToken?: string;
|
private apiClient: AuthApi,
|
||||||
|
private _accessToken?: string
|
||||||
|
) {}
|
||||||
|
|
||||||
constructor(authenticator: AuthenticatorFunction, apiInstance: InfisicalApi, accessToken?: string) {
|
awsIamAuth = {
|
||||||
this.#sdkAuthenticator = authenticator;
|
login: async (options?: AwsAuthLoginOptions) => {
|
||||||
this.#apiClient = apiInstance;
|
try {
|
||||||
this.#accessToken = accessToken;
|
const identityId =
|
||||||
}
|
options?.identityId || process.env[MACHINE_IDENTITY_ID_ENV_NAME];
|
||||||
|
if (!identityId) {
|
||||||
|
throw new InfisicalSDKError(
|
||||||
|
"Identity ID is required for AWS IAM authentication"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
awsIamAuth = {
|
const iamRequest = await performAwsIamLogin(await getAwsRegion());
|
||||||
login: async (options?: AwsAuthLoginOptions) => {
|
const res = await this.apiClient.awsIamAuthLogin({
|
||||||
try {
|
iamHttpRequestMethod: iamRequest.iamHttpRequestMethod,
|
||||||
const identityId = options?.identityId || process.env[MACHINE_IDENTITY_ID_ENV_NAME];
|
iamRequestBody: Buffer.from(iamRequest.iamRequestBody).toString(
|
||||||
|
"base64"
|
||||||
|
),
|
||||||
|
iamRequestHeaders: Buffer.from(
|
||||||
|
JSON.stringify(iamRequest.iamRequestHeaders)
|
||||||
|
).toString("base64"),
|
||||||
|
identityId,
|
||||||
|
});
|
||||||
|
|
||||||
if (!identityId) {
|
return this.sdkAuthenticator(res.accessToken);
|
||||||
throw new InfisicalSDKError("Identity ID is required for AWS IAM authentication");
|
} 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 iamRequest = await performAwsIamLogin(await getAwsRegion());
|
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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const res = await this.#apiClient.apiV1AuthAwsAuthLoginPost({
|
accessToken = (token: string) => {
|
||||||
apiV1AuthAwsAuthLoginPostRequest: {
|
return this.sdkAuthenticator(token);
|
||||||
iamHttpRequestMethod: iamRequest.iamHttpRequestMethod,
|
};
|
||||||
iamRequestBody: Buffer.from(iamRequest.iamRequestBody).toString("base64"),
|
|
||||||
iamRequestHeaders: Buffer.from(JSON.stringify(iamRequest.iamRequestHeaders)).toString("base64"),
|
|
||||||
identityId
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,119 +1,64 @@
|
|||||||
import { RawAxiosRequestConfig } from "axios";
|
import { DynamicSecretsApi } from "../api/endpoints/dynamic-secrets";
|
||||||
import { Configuration, DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
import { TDynamicSecretProvider } from "./schemas/dynamic-secrets";
|
||||||
import type {
|
|
||||||
ApiV1DynamicSecretsGet200ResponseDynamicSecretsInner,
|
|
||||||
ApiV1DynamicSecretsLeasesLeaseIdDelete200Response,
|
|
||||||
ApiV1DynamicSecretsLeasesPost200Response,
|
|
||||||
DefaultApiApiV1DynamicSecretsLeasesLeaseIdDeleteRequest,
|
|
||||||
DefaultApiApiV1DynamicSecretsLeasesLeaseIdRenewPostRequest,
|
|
||||||
DefaultApiApiV1DynamicSecretsLeasesPostRequest,
|
|
||||||
DefaultApiApiV1DynamicSecretsNameDeleteRequest,
|
|
||||||
DefaultApiApiV1DynamicSecretsPostRequest
|
|
||||||
} from "../infisicalapi_client";
|
|
||||||
|
|
||||||
import type { TDynamicSecretProvider } from "./schemas/dynamic-secrets";
|
|
||||||
import { newInfisicalError } from "./errors";
|
import { newInfisicalError } from "./errors";
|
||||||
|
import {
|
||||||
export type CreateDynamicSecretOptions = Omit<DefaultApiApiV1DynamicSecretsPostRequest["apiV1DynamicSecretsPostRequest"], "provider"> & {
|
CreateDynamicSecretOptions,
|
||||||
provider: TDynamicSecretProvider;
|
DeleteDynamicSecretOptions,
|
||||||
};
|
CreateDynamicSecretLeaseOptions,
|
||||||
export type DeleteDynamicSecretOptions = DefaultApiApiV1DynamicSecretsNameDeleteRequest["apiV1DynamicSecretsNameDeleteRequest"];
|
DeleteDynamicSecretLeaseOptions,
|
||||||
export type CreateDynamicSecretLeaseOptions = DefaultApiApiV1DynamicSecretsLeasesPostRequest["apiV1DynamicSecretsLeasesPostRequest"];
|
RenewDynamicSecretLeaseOptions,
|
||||||
export type DeleteDynamicSecretLeaseOptions =
|
} from "../api/types/dynamic-secrets";
|
||||||
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 default class DynamicSecretsClient {
|
export default class DynamicSecretsClient {
|
||||||
#apiInstance: InfisicalApi;
|
constructor(private apiClient: DynamicSecretsApi) {}
|
||||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
|
||||||
constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) {
|
|
||||||
this.#apiInstance = apiInstance;
|
|
||||||
this.#requestOptions = requestOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
async create(options: CreateDynamicSecretOptions): Promise<CreateDynamicSecretResult> {
|
async create(options: CreateDynamicSecretOptions) {
|
||||||
try {
|
try {
|
||||||
const res = await this.#apiInstance.apiV1DynamicSecretsPost(
|
const res = await this.apiClient.create(options);
|
||||||
{
|
return res.dynamicSecret;
|
||||||
apiV1DynamicSecretsPostRequest: options as DefaultApiApiV1DynamicSecretsPostRequest["apiV1DynamicSecretsPostRequest"]
|
} catch (err) {
|
||||||
},
|
throw newInfisicalError(err);
|
||||||
this.#requestOptions
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
return res.data.dynamicSecret;
|
async delete(dynamicSecretName: string, options: DeleteDynamicSecretOptions) {
|
||||||
} catch (err) {
|
try {
|
||||||
throw newInfisicalError(err);
|
const res = await this.apiClient.delete(dynamicSecretName, options);
|
||||||
}
|
return res.dynamicSecret;
|
||||||
}
|
} catch (err) {
|
||||||
|
throw newInfisicalError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async delete(dynamicSecretName: string, options: DeleteDynamicSecretOptions): Promise<DeleteDynamicSecretResult> {
|
leases = {
|
||||||
try {
|
create: async (options: CreateDynamicSecretLeaseOptions) => {
|
||||||
const res = await this.#apiInstance.apiV1DynamicSecretsNameDelete(
|
try {
|
||||||
{
|
const res = await this.apiClient.leases.create(options);
|
||||||
name: dynamicSecretName,
|
return res;
|
||||||
apiV1DynamicSecretsNameDeleteRequest: options
|
} catch (err) {
|
||||||
},
|
throw newInfisicalError(err);
|
||||||
this.#requestOptions
|
}
|
||||||
);
|
},
|
||||||
|
|
||||||
return res.data.dynamicSecret;
|
delete: async (
|
||||||
} catch (err) {
|
leaseId: string,
|
||||||
throw newInfisicalError(err);
|
options: DeleteDynamicSecretLeaseOptions
|
||||||
}
|
) => {
|
||||||
}
|
try {
|
||||||
|
const res = await this.apiClient.leases.delete(leaseId, options);
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
throw newInfisicalError(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
leases = {
|
renew: async (leaseId: string, options: RenewDynamicSecretLeaseOptions) => {
|
||||||
create: async (options: CreateDynamicSecretLeaseOptions): Promise<CreateDynamicSecretLeaseResult> => {
|
try {
|
||||||
try {
|
const res = await this.apiClient.leases.renew(leaseId, options);
|
||||||
const res = await this.#apiInstance.apiV1DynamicSecretsLeasesPost(
|
return res;
|
||||||
{
|
} catch (err) {
|
||||||
apiV1DynamicSecretsLeasesPostRequest: options
|
throw newInfisicalError(err);
|
||||||
},
|
}
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,16 @@
|
|||||||
import { RawAxiosRequestConfig } from "axios";
|
import { EnvironmentsApi } from "../api/endpoints/environments";
|
||||||
import { DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
|
||||||
import type { ApiV1WorkspaceWorkspaceIdEnvironmentsPostRequest, ApiV1WorkspaceWorkspaceIdEnvironmentsPost200Response } from "../infisicalapi_client";
|
|
||||||
import { newInfisicalError } from "./errors";
|
import { newInfisicalError } from "./errors";
|
||||||
|
import { CreateEnvironmentOptions } from "../api/types/environments";
|
||||||
export type CreateEnvironmentOptions = {
|
|
||||||
projectId: string;
|
|
||||||
} & ApiV1WorkspaceWorkspaceIdEnvironmentsPostRequest;
|
|
||||||
export type CreateEnvironmentResult = ApiV1WorkspaceWorkspaceIdEnvironmentsPost200Response;
|
|
||||||
|
|
||||||
export default class EnvironmentsClient {
|
export default class EnvironmentsClient {
|
||||||
#apiInstance: InfisicalApi;
|
constructor(private apiClient: EnvironmentsApi) {}
|
||||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
|
||||||
constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) {
|
|
||||||
this.#apiInstance = apiInstance;
|
|
||||||
this.#requestOptions = requestOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
create = async (options: CreateEnvironmentOptions): Promise<CreateEnvironmentResult["environment"]> => {
|
create = async (options: CreateEnvironmentOptions) => {
|
||||||
try {
|
try {
|
||||||
const res = await this.#apiInstance.apiV1WorkspaceWorkspaceIdEnvironmentsPost(
|
const res = await this.apiClient.create(options);
|
||||||
{
|
return res.environment;
|
||||||
workspaceId: options.projectId,
|
} catch (err) {
|
||||||
apiV1WorkspaceWorkspaceIdEnvironmentsPostRequest: options
|
throw newInfisicalError(err);
|
||||||
},
|
}
|
||||||
this.#requestOptions
|
};
|
||||||
);
|
|
||||||
return res.data.environment;
|
|
||||||
} catch (err) {
|
|
||||||
throw newInfisicalError(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +1,52 @@
|
|||||||
import { AxiosError } from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
type TApiErrorResponse = {
|
|
||||||
statusCode: number;
|
|
||||||
message: string;
|
|
||||||
error: string;
|
|
||||||
};
|
|
||||||
export class InfisicalSDKError extends Error {
|
export class InfisicalSDKError extends Error {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message);
|
super(message);
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.name = "InfisicalSDKError";
|
this.name = "InfisicalSDKError";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InfisicalSDKRequestError extends Error {
|
export class InfisicalSDKRequestError extends Error {
|
||||||
constructor(
|
constructor(
|
||||||
message: string,
|
message: string,
|
||||||
requestData: {
|
requestData: {
|
||||||
url: string;
|
url: string;
|
||||||
method: string;
|
method: string;
|
||||||
statusCode: number;
|
statusCode: number;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
super(message);
|
super(message);
|
||||||
this.message = `[URL=${requestData.url}] [Method=${requestData.method}] [StatusCode=${requestData.statusCode}] ${message}`;
|
this.message = `[URL=${requestData.url}] [Method=${requestData.method}] [StatusCode=${requestData.statusCode}] ${message}`;
|
||||||
this.name = "InfisicalSDKRequestError";
|
this.name = "InfisicalSDKRequestError";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const newInfisicalError = (error: any) => {
|
export const newInfisicalError = (error: any) => {
|
||||||
if (error instanceof AxiosError) {
|
if (axios.isAxiosError(error)) {
|
||||||
const data = error?.response?.data as TApiErrorResponse;
|
const data = error?.response?.data;
|
||||||
|
|
||||||
if (data?.message) {
|
if (data?.message) {
|
||||||
let message = data.message;
|
let message = data.message;
|
||||||
if (error.status === 422) {
|
if (error.response?.status === 422) {
|
||||||
message = JSON.stringify(data);
|
message = JSON.stringify(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new InfisicalSDKRequestError(message, {
|
return new InfisicalSDKRequestError(message, {
|
||||||
url: error.response?.config.url || "",
|
url: error.response?.config.url || "",
|
||||||
method: error.response?.config.method || "",
|
method: error.response?.config.method || "",
|
||||||
statusCode: error.response?.status || 0
|
statusCode: error.response?.status || 0,
|
||||||
});
|
});
|
||||||
} else if (error.message) {
|
} else if (error.message) {
|
||||||
return new InfisicalSDKError(error.message);
|
return new InfisicalSDKError(error.message);
|
||||||
} else if (error.code) {
|
} 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
|
// 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);
|
return new InfisicalSDKError(error.code);
|
||||||
} else {
|
} else {
|
||||||
return new InfisicalSDKError("Request failed with unknown error");
|
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,37 @@
|
|||||||
import { RawAxiosRequestConfig } from "axios";
|
import { FoldersApi } from "../api/endpoints/folders";
|
||||||
import { DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
|
||||||
import type { ApiV1FoldersPostRequest, ApiV1FoldersPost200Response } from "../infisicalapi_client";
|
|
||||||
import { newInfisicalError } from "./errors";
|
import { newInfisicalError } from "./errors";
|
||||||
|
import { CreateFolderOptions, ListFoldersOptions } from "../api/types/folders";
|
||||||
export type CreateFolderOptions = {
|
|
||||||
projectId: string;
|
|
||||||
} & Omit<ApiV1FoldersPostRequest, "workspaceId" | "directory">;
|
|
||||||
export type CreateFolderResult = ApiV1FoldersPost200Response;
|
|
||||||
|
|
||||||
export default class FoldersClient {
|
export default class FoldersClient {
|
||||||
#apiInstance: InfisicalApi;
|
constructor(private apiClient: FoldersApi) {}
|
||||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
|
||||||
constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) {
|
|
||||||
this.#apiInstance = apiInstance;
|
|
||||||
this.#requestOptions = requestOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
create = async (options: CreateFolderOptions): Promise<CreateFolderResult["folder"]> => {
|
create = async (options: CreateFolderOptions) => {
|
||||||
try {
|
try {
|
||||||
const res = await this.#apiInstance.apiV1FoldersPost(
|
const res = await this.apiClient.create({
|
||||||
{
|
name: options.name,
|
||||||
apiV1FoldersPostRequest: {
|
path: options.path,
|
||||||
...options,
|
workspaceId: options.projectId,
|
||||||
workspaceId: options.projectId
|
environment: options.environment,
|
||||||
}
|
description: options.description,
|
||||||
},
|
});
|
||||||
this.#requestOptions
|
return res.folder;
|
||||||
);
|
} catch (err) {
|
||||||
return res.data.folder;
|
throw newInfisicalError(err);
|
||||||
} 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,29 @@
|
|||||||
import { RawAxiosRequestConfig } from "axios";
|
import { ProjectsApi } from "../api/endpoints/projects";
|
||||||
import { DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
|
||||||
import type {
|
|
||||||
ApiV2WorkspacePost200Response,
|
|
||||||
ApiV2WorkspacePostRequest,
|
|
||||||
ApiV2WorkspaceProjectIdMembershipsPost200Response,
|
|
||||||
ApiV2WorkspaceProjectIdMembershipsPostRequest
|
|
||||||
} from "../infisicalapi_client";
|
|
||||||
import { newInfisicalError } from "./errors";
|
import { newInfisicalError } from "./errors";
|
||||||
|
import { CreateProjectOptions, InviteMemberToProjectOptions } from "../api/types/projects";
|
||||||
|
|
||||||
export type CreateProjectOptions = ApiV2WorkspacePostRequest;
|
|
||||||
export type CreateProjectResult = ApiV2WorkspacePost200Response;
|
|
||||||
|
|
||||||
export type InviteMemberToProjectOptions = { projectId: string } & ApiV2WorkspaceProjectIdMembershipsPostRequest;
|
|
||||||
export type InviteMemberToProjectResult = ApiV2WorkspaceProjectIdMembershipsPost200Response;
|
|
||||||
export default class ProjectsClient {
|
export default class ProjectsClient {
|
||||||
#apiInstance: InfisicalApi;
|
constructor(private apiClient: ProjectsApi) {}
|
||||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
|
||||||
constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) {
|
|
||||||
this.#apiInstance = apiInstance;
|
|
||||||
this.#requestOptions = requestOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
create = async (options: CreateProjectOptions): Promise<CreateProjectResult["project"]> => {
|
create = async (options: CreateProjectOptions) => {
|
||||||
try {
|
try {
|
||||||
const res = await this.#apiInstance.apiV2WorkspacePost(
|
const res = await this.apiClient.create(options);
|
||||||
{
|
return res.project;
|
||||||
apiV2WorkspacePostRequest: options
|
} catch (err) {
|
||||||
},
|
throw newInfisicalError(err);
|
||||||
this.#requestOptions
|
}
|
||||||
);
|
};
|
||||||
return res.data.project;
|
|
||||||
} catch (err) {
|
|
||||||
throw newInfisicalError(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inviteMembers = async (options: InviteMemberToProjectOptions): Promise<InviteMemberToProjectResult["memberships"]> => {
|
inviteMembers = async (options: InviteMemberToProjectOptions) => {
|
||||||
try {
|
try {
|
||||||
if (!options.usernames?.length && !options.emails?.length) {
|
if (!options.usernames?.length && !options.emails?.length) {
|
||||||
throw new Error("Either usernames or emails must be provided");
|
throw new Error("Either usernames or emails must be provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await this.#apiInstance.apiV2WorkspaceProjectIdMembershipsPost(
|
const res = await this.apiClient.inviteMembers(options);
|
||||||
{
|
return res.memberships;
|
||||||
projectId: options.projectId,
|
} catch (err) {
|
||||||
apiV2WorkspaceProjectIdMembershipsPostRequest: options
|
throw newInfisicalError(err);
|
||||||
},
|
}
|
||||||
this.#requestOptions
|
};
|
||||||
);
|
|
||||||
return res.data.memberships;
|
|
||||||
} catch (err) {
|
|
||||||
throw newInfisicalError(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,301 +1,394 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export enum SqlProviders {
|
export enum SqlProviders {
|
||||||
Postgres = "postgres",
|
Postgres = "postgres",
|
||||||
MySQL = "mysql2",
|
MySQL = "mysql2",
|
||||||
Oracle = "oracledb",
|
Oracle = "oracledb",
|
||||||
MsSQL = "mssql",
|
MsSQL = "mssql",
|
||||||
SapAse = "sap-ase"
|
SapAse = "sap-ase",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ElasticSearchAuthTypes {
|
export enum ElasticSearchAuthTypes {
|
||||||
User = "user",
|
User = "user",
|
||||||
ApiKey = "api-key"
|
ApiKey = "api-key",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum LdapCredentialType {
|
export enum LdapCredentialType {
|
||||||
Dynamic = "dynamic",
|
Dynamic = "dynamic",
|
||||||
Static = "static"
|
Static = "static",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TotpConfigType {
|
export enum TotpConfigType {
|
||||||
URL = "url",
|
URL = "url",
|
||||||
MANUAL = "manual"
|
MANUAL = "manual",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TotpAlgorithm {
|
export enum TotpAlgorithm {
|
||||||
SHA1 = "sha1",
|
SHA1 = "sha1",
|
||||||
SHA256 = "sha256",
|
SHA256 = "sha256",
|
||||||
SHA512 = "sha512"
|
SHA512 = "sha512",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const passwordRequirementsSchema = z.object({
|
||||||
|
length: z
|
||||||
|
.number()
|
||||||
|
.min(1, { message: "Password length must be at least 1" })
|
||||||
|
.max(250, { message: "Password length must be at most 250" }),
|
||||||
|
|
||||||
|
required: z.object({
|
||||||
|
minUppercase: z.number().min(0).optional(),
|
||||||
|
minLowercase: z.number().min(0).optional(),
|
||||||
|
minDigits: z.number().min(0).optional(),
|
||||||
|
minSymbols: z.number().min(0).optional(),
|
||||||
|
}),
|
||||||
|
allowedSymbols: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
const DynamicSecretRedisDBSchema = z.object({
|
const DynamicSecretRedisDBSchema = z.object({
|
||||||
host: z.string().trim().toLowerCase(),
|
host: z.string().trim().toLowerCase(),
|
||||||
port: z.number(),
|
port: z.number(),
|
||||||
username: z.string().trim(), // this is often "default".
|
username: z.string().trim(), // this is often "default".
|
||||||
password: z.string().trim().optional(),
|
password: z.string().trim().optional(),
|
||||||
creationStatement: z.string().trim(),
|
creationStatement: z.string().trim(),
|
||||||
revocationStatement: z.string().trim(),
|
revocationStatement: z.string().trim(),
|
||||||
renewStatement: z.string().trim().optional(),
|
renewStatement: z.string().trim().optional(),
|
||||||
ca: z.string().optional()
|
ca: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretAwsElastiCacheSchema = z.object({
|
const DynamicSecretAwsElastiCacheSchema = z.object({
|
||||||
clusterName: z.string().trim().min(1),
|
clusterName: z.string().trim().min(1),
|
||||||
accessKeyId: z.string().trim().min(1),
|
accessKeyId: z.string().trim().min(1),
|
||||||
secretAccessKey: z.string().trim().min(1),
|
secretAccessKey: z.string().trim().min(1),
|
||||||
|
|
||||||
region: z.string().trim(),
|
region: z.string().trim(),
|
||||||
creationStatement: z.string().trim(),
|
creationStatement: z.string().trim(),
|
||||||
revocationStatement: z.string().trim(),
|
revocationStatement: z.string().trim(),
|
||||||
ca: z.string().optional()
|
ca: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretElasticSearchSchema = z.object({
|
const DynamicSecretElasticSearchSchema = z.object({
|
||||||
host: z.string().trim().min(1),
|
host: z.string().trim().min(1),
|
||||||
port: z.number(),
|
port: z.number(),
|
||||||
roles: z.array(z.string().trim().min(1)).min(1),
|
roles: z.array(z.string().trim().min(1)).min(1),
|
||||||
|
|
||||||
// two auth types "user, apikey"
|
// two auth types "user, apikey"
|
||||||
auth: z.discriminatedUnion("type", [
|
auth: z.discriminatedUnion("type", [
|
||||||
z.object({
|
z.object({
|
||||||
type: z.literal(ElasticSearchAuthTypes.User),
|
type: z.literal(ElasticSearchAuthTypes.User),
|
||||||
username: z.string().trim(),
|
username: z.string().trim(),
|
||||||
password: z.string().trim()
|
password: z.string().trim(),
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
type: z.literal(ElasticSearchAuthTypes.ApiKey),
|
type: z.literal(ElasticSearchAuthTypes.ApiKey),
|
||||||
apiKey: z.string().trim(),
|
apiKey: z.string().trim(),
|
||||||
apiKeyId: z.string().trim()
|
apiKeyId: z.string().trim(),
|
||||||
})
|
}),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
ca: z.string().optional()
|
ca: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretRabbitMqSchema = z.object({
|
const DynamicSecretRabbitMqSchema = z.object({
|
||||||
host: z.string().trim().min(1),
|
host: z.string().trim().min(1),
|
||||||
port: z.number(),
|
port: z.number(),
|
||||||
tags: z.array(z.string().trim()).default([]),
|
tags: z.array(z.string().trim()).default([]),
|
||||||
|
|
||||||
username: z.string().trim().min(1),
|
username: z.string().trim().min(1),
|
||||||
password: z.string().trim().min(1),
|
password: z.string().trim().min(1),
|
||||||
|
|
||||||
ca: z.string().optional(),
|
ca: z.string().optional(),
|
||||||
|
|
||||||
virtualHost: z.object({
|
virtualHost: z.object({
|
||||||
name: z.string().trim().min(1),
|
name: z.string().trim().min(1),
|
||||||
permissions: z.object({
|
permissions: z.object({
|
||||||
read: z.string().trim().min(1),
|
read: z.string().trim().min(1),
|
||||||
write: z.string().trim().min(1),
|
write: z.string().trim().min(1),
|
||||||
configure: z.string().trim().min(1)
|
configure: z.string().trim().min(1),
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretSqlDBSchema = z.object({
|
const DynamicSecretSqlDBSchema = z.object({
|
||||||
client: z.nativeEnum(SqlProviders),
|
client: z.nativeEnum(SqlProviders),
|
||||||
host: z.string().trim().toLowerCase(),
|
host: z.string().trim().toLowerCase(),
|
||||||
port: z.number(),
|
port: z.number(),
|
||||||
database: z.string().trim(),
|
database: z.string().trim(),
|
||||||
username: z.string().trim(),
|
username: z.string().trim(),
|
||||||
password: z.string().trim(),
|
password: z.string().trim(),
|
||||||
creationStatement: z.string().trim(),
|
creationStatement: z.string().trim(),
|
||||||
revocationStatement: z.string().trim(),
|
revocationStatement: z.string().trim(),
|
||||||
renewStatement: z.string().trim().optional(),
|
renewStatement: z.string().trim().optional(),
|
||||||
ca: z.string().optional()
|
ca: z.string().optional(),
|
||||||
|
passwordRequirements: passwordRequirementsSchema.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretCassandraSchema = z.object({
|
const DynamicSecretCassandraSchema = z.object({
|
||||||
host: z.string().trim().toLowerCase(),
|
host: z.string().trim().toLowerCase(),
|
||||||
port: z.number(),
|
port: z.number(),
|
||||||
localDataCenter: z.string().trim().min(1),
|
localDataCenter: z.string().trim().min(1),
|
||||||
keyspace: z.string().trim().optional(),
|
keyspace: z.string().trim().optional(),
|
||||||
username: z.string().trim(),
|
username: z.string().trim(),
|
||||||
password: z.string().trim(),
|
password: z.string().trim(),
|
||||||
creationStatement: z.string().trim(),
|
creationStatement: z.string().trim(),
|
||||||
revocationStatement: z.string().trim(),
|
revocationStatement: z.string().trim(),
|
||||||
renewStatement: z.string().trim().optional(),
|
renewStatement: z.string().trim().optional(),
|
||||||
ca: z.string().optional()
|
ca: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretSapAseSchema = z.object({
|
const DynamicSecretSapAseSchema = z.object({
|
||||||
host: z.string().trim().toLowerCase(),
|
host: z.string().trim().toLowerCase(),
|
||||||
port: z.number(),
|
port: z.number(),
|
||||||
database: z.string().trim(),
|
database: z.string().trim(),
|
||||||
username: z.string().trim(),
|
username: z.string().trim(),
|
||||||
password: z.string().trim(),
|
password: z.string().trim(),
|
||||||
creationStatement: z.string().trim(),
|
creationStatement: z.string().trim(),
|
||||||
revocationStatement: z.string().trim()
|
revocationStatement: z.string().trim(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretAwsIamSchema = z.object({
|
const DynamicSecretAwsIamSchema = z.object({
|
||||||
accessKey: z.string().trim().min(1),
|
accessKey: z.string().trim().min(1),
|
||||||
secretAccessKey: z.string().trim().min(1),
|
secretAccessKey: z.string().trim().min(1),
|
||||||
region: z.string().trim().min(1),
|
region: z.string().trim().min(1),
|
||||||
awsPath: z.string().trim().optional(),
|
awsPath: z.string().trim().optional(),
|
||||||
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
||||||
policyDocument: z.string().trim().optional(),
|
policyDocument: z.string().trim().optional(),
|
||||||
userGroups: z.string().trim().optional(),
|
userGroups: z.string().trim().optional(),
|
||||||
policyArns: z.string().trim().optional()
|
policyArns: z.string().trim().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretMongoAtlasSchema = z.object({
|
const DynamicSecretMongoAtlasSchema = z.object({
|
||||||
adminPublicKey: z.string().trim().min(1).describe("Admin user public api key"),
|
adminPublicKey: z
|
||||||
adminPrivateKey: z.string().trim().min(1).describe("Admin user private api key"),
|
.string()
|
||||||
groupId: z.string().trim().min(1).describe("Unique 24-hexadecimal digit string that identifies your project. This is same as project id"),
|
.trim()
|
||||||
roles: z
|
.min(1)
|
||||||
.object({
|
.describe("Admin user public api key"),
|
||||||
collectionName: z.string().optional().describe("Collection on which this role applies."),
|
adminPrivateKey: z
|
||||||
databaseName: z.string().min(1).describe("Database to which the user is granted access privileges."),
|
.string()
|
||||||
roleName: z
|
.trim()
|
||||||
.string()
|
.min(1)
|
||||||
.min(1)
|
.describe("Admin user private api key"),
|
||||||
.describe(
|
groupId: z
|
||||||
' Enum: "atlasAdmin" "backup" "clusterMonitor" "dbAdmin" "dbAdminAnyDatabase" "enableSharding" "read" "readAnyDatabase" "readWrite" "readWriteAnyDatabase" "<a custom role name>".Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.'
|
.string()
|
||||||
)
|
.trim()
|
||||||
})
|
.min(1)
|
||||||
.array()
|
.describe(
|
||||||
.min(1),
|
"Unique 24-hexadecimal digit string that identifies your project. This is same as project id"
|
||||||
scopes: z
|
),
|
||||||
.object({
|
roles: z
|
||||||
name: z
|
.object({
|
||||||
.string()
|
collectionName: z
|
||||||
.min(1)
|
.string()
|
||||||
.describe("Human-readable label that identifies the cluster or MongoDB Atlas Data Lake that this database user can access."),
|
.optional()
|
||||||
type: z.string().min(1).describe("Category of resource that this database user can access. Enum: CLUSTER, DATA_LAKE, STREAM")
|
.describe("Collection on which this role applies."),
|
||||||
})
|
databaseName: z
|
||||||
.array()
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.describe("Database to which the user is granted access privileges."),
|
||||||
|
roleName: z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.describe(
|
||||||
|
' Enum: "atlasAdmin" "backup" "clusterMonitor" "dbAdmin" "dbAdminAnyDatabase" "enableSharding" "read" "readAnyDatabase" "readWrite" "readWriteAnyDatabase" "<a custom role name>".Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.'
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
.min(1),
|
||||||
|
scopes: z
|
||||||
|
.object({
|
||||||
|
name: z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.describe(
|
||||||
|
"Human-readable label that identifies the cluster or MongoDB Atlas Data Lake that this database user can access."
|
||||||
|
),
|
||||||
|
type: z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.describe(
|
||||||
|
"Category of resource that this database user can access. Enum: CLUSTER, DATA_LAKE, STREAM"
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.array(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretMongoDBSchema = z.object({
|
const DynamicSecretMongoDBSchema = z.object({
|
||||||
host: z.string().min(1).trim().toLowerCase(),
|
host: z.string().min(1).trim().toLowerCase(),
|
||||||
port: z.number().optional(),
|
port: z.number().optional(),
|
||||||
username: z.string().min(1).trim(),
|
username: z.string().min(1).trim(),
|
||||||
password: z.string().min(1).trim(),
|
password: z.string().min(1).trim(),
|
||||||
database: z.string().min(1).trim(),
|
database: z.string().min(1).trim(),
|
||||||
ca: z.string().min(1).optional(),
|
ca: z.string().min(1).optional(),
|
||||||
roles: z
|
roles: z
|
||||||
.string()
|
.string()
|
||||||
.array()
|
.array()
|
||||||
.min(1)
|
.min(1)
|
||||||
.describe(
|
.describe(
|
||||||
'Enum: "atlasAdmin" "backup" "clusterMonitor" "dbAdmin" "dbAdminAnyDatabase" "enableSharding" "read" "readAnyDatabase" "readWrite" "readWriteAnyDatabase" "<a custom role name>".Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.'
|
'Enum: "atlasAdmin" "backup" "clusterMonitor" "dbAdmin" "dbAdminAnyDatabase" "enableSharding" "read" "readAnyDatabase" "readWrite" "readWriteAnyDatabase" "<a custom role name>".Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.'
|
||||||
)
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretSapHanaSchema = z.object({
|
const DynamicSecretSapHanaSchema = z.object({
|
||||||
host: z.string().trim().toLowerCase(),
|
host: z.string().trim().toLowerCase(),
|
||||||
port: z.number(),
|
port: z.number(),
|
||||||
username: z.string().trim(),
|
username: z.string().trim(),
|
||||||
password: z.string().trim(),
|
password: z.string().trim(),
|
||||||
creationStatement: z.string().trim(),
|
creationStatement: z.string().trim(),
|
||||||
revocationStatement: z.string().trim(),
|
revocationStatement: z.string().trim(),
|
||||||
renewStatement: z.string().trim().optional(),
|
renewStatement: z.string().trim().optional(),
|
||||||
ca: z.string().optional()
|
ca: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const DynamicSecretSnowflakeSchema = z.object({
|
const DynamicSecretSnowflakeSchema = z.object({
|
||||||
accountId: z.string().trim().min(1),
|
accountId: z.string().trim().min(1),
|
||||||
orgId: z.string().trim().min(1),
|
orgId: z.string().trim().min(1),
|
||||||
username: z.string().trim().min(1),
|
username: z.string().trim().min(1),
|
||||||
password: z.string().trim().min(1),
|
password: z.string().trim().min(1),
|
||||||
creationStatement: z.string().trim().min(1),
|
creationStatement: z.string().trim().min(1),
|
||||||
revocationStatement: z.string().trim().min(1),
|
revocationStatement: z.string().trim().min(1),
|
||||||
renewStatement: z.string().trim().optional()
|
renewStatement: z.string().trim().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const AzureEntraIDSchema = z.object({
|
const AzureEntraIDSchema = z.object({
|
||||||
tenantId: z.string().trim().min(1),
|
tenantId: z.string().trim().min(1),
|
||||||
userId: z.string().trim().min(1),
|
userId: z.string().trim().min(1),
|
||||||
email: z.string().trim().min(1),
|
email: z.string().trim().min(1),
|
||||||
applicationId: z.string().trim().min(1),
|
applicationId: z.string().trim().min(1),
|
||||||
clientSecret: z.string().trim().min(1)
|
clientSecret: z.string().trim().min(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
const LdapSchema = z.union([
|
const LdapSchema = z.union([
|
||||||
z.object({
|
z.object({
|
||||||
url: z.string().trim().min(1),
|
url: z.string().trim().min(1),
|
||||||
binddn: z.string().trim().min(1),
|
binddn: z.string().trim().min(1),
|
||||||
bindpass: z.string().trim().min(1),
|
bindpass: z.string().trim().min(1),
|
||||||
ca: z.string().optional(),
|
ca: z.string().optional(),
|
||||||
credentialType: z.literal(LdapCredentialType.Dynamic).optional().default(LdapCredentialType.Dynamic),
|
credentialType: z
|
||||||
creationLdif: z.string().min(1),
|
.literal(LdapCredentialType.Dynamic)
|
||||||
revocationLdif: z.string().min(1),
|
.optional()
|
||||||
rollbackLdif: z.string().optional()
|
.default(LdapCredentialType.Dynamic),
|
||||||
}),
|
creationLdif: z.string().min(1),
|
||||||
z.object({
|
revocationLdif: z.string().min(1),
|
||||||
url: z.string().trim().min(1),
|
rollbackLdif: z.string().optional(),
|
||||||
binddn: z.string().trim().min(1),
|
}),
|
||||||
bindpass: z.string().trim().min(1),
|
z.object({
|
||||||
ca: z.string().optional(),
|
url: z.string().trim().min(1),
|
||||||
credentialType: z.literal(LdapCredentialType.Static),
|
binddn: z.string().trim().min(1),
|
||||||
rotationLdif: z.string().min(1)
|
bindpass: z.string().trim().min(1),
|
||||||
})
|
ca: z.string().optional(),
|
||||||
|
credentialType: z.literal(LdapCredentialType.Static),
|
||||||
|
rotationLdif: z.string().min(1),
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const DynamicSecretTotpSchema = z.discriminatedUnion("configType", [
|
const DynamicSecretTotpSchema = z.discriminatedUnion("configType", [
|
||||||
z.object({
|
z.object({
|
||||||
configType: z.literal(TotpConfigType.URL),
|
configType: z.literal(TotpConfigType.URL),
|
||||||
url: z
|
url: z
|
||||||
.string()
|
.string()
|
||||||
.url()
|
.url()
|
||||||
.trim()
|
.trim()
|
||||||
.min(1)
|
.min(1)
|
||||||
.refine(val => {
|
.refine((val) => {
|
||||||
const urlObj = new URL(val);
|
const urlObj = new URL(val);
|
||||||
const secret = urlObj.searchParams.get("secret");
|
const secret = urlObj.searchParams.get("secret");
|
||||||
|
|
||||||
return Boolean(secret);
|
return Boolean(secret);
|
||||||
}, "OTP URL must contain secret field")
|
}, "OTP URL must contain secret field"),
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
configType: z.literal(TotpConfigType.MANUAL),
|
configType: z.literal(TotpConfigType.MANUAL),
|
||||||
secret: z
|
secret: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.min(1)
|
.min(1)
|
||||||
.transform(val => val.replace(/\s+/g, "")),
|
.transform((val) => val.replace(/\s+/g, "")),
|
||||||
period: z.number().optional(),
|
period: z.number().optional(),
|
||||||
algorithm: z.nativeEnum(TotpAlgorithm).optional(),
|
algorithm: z.nativeEnum(TotpAlgorithm).optional(),
|
||||||
digits: z.number().optional()
|
digits: z.number().optional(),
|
||||||
})
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export enum DynamicSecretProviders {
|
export enum DynamicSecretProviders {
|
||||||
SqlDatabase = "sql-database",
|
SqlDatabase = "sql-database",
|
||||||
Cassandra = "cassandra",
|
Cassandra = "cassandra",
|
||||||
AwsIam = "aws-iam",
|
AwsIam = "aws-iam",
|
||||||
Redis = "redis",
|
Redis = "redis",
|
||||||
AwsElastiCache = "aws-elasticache",
|
AwsElastiCache = "aws-elasticache",
|
||||||
MongoAtlas = "mongo-db-atlas",
|
MongoAtlas = "mongo-db-atlas",
|
||||||
ElasticSearch = "elastic-search",
|
ElasticSearch = "elastic-search",
|
||||||
MongoDB = "mongo-db",
|
MongoDB = "mongo-db",
|
||||||
RabbitMq = "rabbit-mq",
|
RabbitMq = "rabbit-mq",
|
||||||
AzureEntraID = "azure-entra-id",
|
AzureEntraID = "azure-entra-id",
|
||||||
Ldap = "ldap",
|
Ldap = "ldap",
|
||||||
SapHana = "sap-hana",
|
SapHana = "sap-hana",
|
||||||
Snowflake = "snowflake",
|
Snowflake = "snowflake",
|
||||||
Totp = "totp",
|
Totp = "totp",
|
||||||
SapAse = "sap-ase"
|
SapAse = "sap-ase",
|
||||||
}
|
}
|
||||||
|
|
||||||
const DynamicSecretProviderSchema = z.discriminatedUnion("type", [
|
const DynamicSecretProviderSchema = z.discriminatedUnion("type", [
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.SqlDatabase), inputs: DynamicSecretSqlDBSchema }),
|
z.object({
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.Cassandra), inputs: DynamicSecretCassandraSchema }),
|
type: z.literal(DynamicSecretProviders.SqlDatabase),
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.SapAse), inputs: DynamicSecretSapAseSchema }),
|
inputs: DynamicSecretSqlDBSchema,
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.AwsIam), inputs: DynamicSecretAwsIamSchema }),
|
}),
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.Redis), inputs: DynamicSecretRedisDBSchema }),
|
z.object({
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.SapHana), inputs: DynamicSecretSapHanaSchema }),
|
type: z.literal(DynamicSecretProviders.Cassandra),
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.AwsElastiCache), inputs: DynamicSecretAwsElastiCacheSchema }),
|
inputs: DynamicSecretCassandraSchema,
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.MongoAtlas), inputs: DynamicSecretMongoAtlasSchema }),
|
}),
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.ElasticSearch), inputs: DynamicSecretElasticSearchSchema }),
|
z.object({
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.MongoDB), inputs: DynamicSecretMongoDBSchema }),
|
type: z.literal(DynamicSecretProviders.SapAse),
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.RabbitMq), inputs: DynamicSecretRabbitMqSchema }),
|
inputs: DynamicSecretSapAseSchema,
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.AzureEntraID), inputs: AzureEntraIDSchema }),
|
}),
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.Ldap), inputs: LdapSchema }),
|
z.object({
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.Snowflake), inputs: DynamicSecretSnowflakeSchema }),
|
type: z.literal(DynamicSecretProviders.AwsIam),
|
||||||
z.object({ type: z.literal(DynamicSecretProviders.Totp), inputs: DynamicSecretTotpSchema })
|
inputs: DynamicSecretAwsIamSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.Redis),
|
||||||
|
inputs: DynamicSecretRedisDBSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.SapHana),
|
||||||
|
inputs: DynamicSecretSapHanaSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.AwsElastiCache),
|
||||||
|
inputs: DynamicSecretAwsElastiCacheSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.MongoAtlas),
|
||||||
|
inputs: DynamicSecretMongoAtlasSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.ElasticSearch),
|
||||||
|
inputs: DynamicSecretElasticSearchSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.MongoDB),
|
||||||
|
inputs: DynamicSecretMongoDBSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.RabbitMq),
|
||||||
|
inputs: DynamicSecretRabbitMqSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.AzureEntraID),
|
||||||
|
inputs: AzureEntraIDSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.Ldap),
|
||||||
|
inputs: LdapSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.Snowflake),
|
||||||
|
inputs: DynamicSecretSnowflakeSchema,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal(DynamicSecretProviders.Totp),
|
||||||
|
inputs: DynamicSecretTotpSchema,
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export type TDynamicSecretProvider = z.infer<typeof DynamicSecretProviderSchema>;
|
export type TDynamicSecretProvider = z.infer<
|
||||||
|
typeof DynamicSecretProviderSchema
|
||||||
|
>;
|
||||||
|
|||||||
@@ -1,215 +1,142 @@
|
|||||||
import { RawAxiosRequestConfig } from "axios";
|
import { SecretsApi } from "../api/endpoints/secrets";
|
||||||
import { DefaultApi as InfisicalApi } from "../infisicalapi_client";
|
|
||||||
import type {
|
|
||||||
ApiV3SecretsRawGet200Response,
|
|
||||||
ApiV3SecretsRawSecretNameGet200Response,
|
|
||||||
ApiV3SecretsRawSecretNamePost200Response,
|
|
||||||
DefaultApiApiV3SecretsRawSecretNameDeleteRequest,
|
|
||||||
DefaultApiApiV3SecretsRawSecretNamePatchRequest,
|
|
||||||
DefaultApiApiV3SecretsRawSecretNamePostRequest
|
|
||||||
} from "../infisicalapi_client";
|
|
||||||
import { newInfisicalError } from "./errors";
|
import { newInfisicalError } from "./errors";
|
||||||
import { getUniqueSecretsByKey } from "./util";
|
import { ListSecretsOptions, GetSecretOptions, UpdateSecretOptions, CreateSecretOptions, DeleteSecretOptions } from "../api/types/secrets";
|
||||||
|
|
||||||
type SecretType = "shared" | "personal";
|
|
||||||
|
|
||||||
type ListSecretsOptions = {
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UpdateSecretOptions = Omit<DefaultApiApiV3SecretsRawSecretNamePatchRequest["apiV3SecretsRawSecretNamePatchRequest"], "workspaceId"> & {
|
|
||||||
projectId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CreateSecretOptions = Omit<DefaultApiApiV3SecretsRawSecretNamePostRequest["apiV3SecretsRawSecretNamePostRequest"], "workspaceId"> & {
|
|
||||||
projectId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type DeleteSecretOptions = Omit<DefaultApiApiV3SecretsRawSecretNameDeleteRequest["apiV3SecretsRawSecretNameDeleteRequest"], "workspaceId"> & {
|
|
||||||
projectId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
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 convertBool = (value?: boolean) => (value ? "true" : "false");
|
||||||
|
|
||||||
const defaultBoolean = (value?: boolean, defaultValue: boolean = false) => {
|
const defaultBoolean = (value?: boolean, defaultValue: boolean = false) => {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class SecretsClient {
|
export default class SecretsClient {
|
||||||
#apiInstance: InfisicalApi;
|
constructor(private apiClient: SecretsApi) {}
|
||||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
|
||||||
constructor(apiInstance: InfisicalApi, requestOptions: RawAxiosRequestConfig | undefined) {
|
|
||||||
this.#apiInstance = apiInstance;
|
|
||||||
this.#requestOptions = requestOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
listSecrets = async (options: ListSecretsOptions): Promise<ListSecretsResult> => {
|
listSecrets = async (options: ListSecretsOptions) => {
|
||||||
try {
|
try {
|
||||||
const res = await this.#apiInstance.apiV3SecretsRawGet(
|
return await this.apiClient.listSecrets({
|
||||||
{
|
workspaceId: options.projectId,
|
||||||
viewSecretValue: convertBool(options.viewSecretValue ?? true),
|
environment: options.environment,
|
||||||
environment: options.environment,
|
expandSecretReferences: convertBool(
|
||||||
workspaceId: options.projectId,
|
defaultBoolean(options.expandSecretReferences, true)
|
||||||
expandSecretReferences: convertBool(defaultBoolean(options.expandSecretReferences, true)),
|
),
|
||||||
includeImports: convertBool(options.includeImports),
|
includeImports: convertBool(options.includeImports),
|
||||||
recursive: convertBool(options.recursive),
|
recursive: convertBool(options.recursive),
|
||||||
secretPath: options.secretPath,
|
secretPath: options.secretPath,
|
||||||
tagSlugs: options.tagSlugs ? options.tagSlugs.join(",") : undefined
|
tagSlugs: options.tagSlugs ? options.tagSlugs.join(",") : undefined,
|
||||||
},
|
viewSecretValue: convertBool(options.viewSecretValue ?? true),
|
||||||
this.#requestOptions
|
});
|
||||||
);
|
} catch (err) {
|
||||||
return res.data;
|
throw newInfisicalError(err);
|
||||||
} catch (err) {
|
}
|
||||||
throw newInfisicalError(err);
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
listSecretsWithImports = async (options: Omit<ListSecretsOptions, "includeImports">): Promise<ListSecretsResult["secrets"]> => {
|
listSecretsWithImports = async (
|
||||||
const res = await this.listSecrets({
|
options: Omit<ListSecretsOptions, "includeImports">
|
||||||
...options,
|
) => {
|
||||||
includeImports: true
|
const res = await this.listSecrets({
|
||||||
});
|
...options,
|
||||||
|
includeImports: true,
|
||||||
|
});
|
||||||
|
|
||||||
let { imports, secrets } = res;
|
let { imports, secrets } = res;
|
||||||
if (imports) {
|
if (imports) {
|
||||||
if (options.recursive) {
|
for (const imp of imports) {
|
||||||
secrets = getUniqueSecretsByKey(secrets);
|
for (const importedSecret of imp.secrets) {
|
||||||
}
|
// CASE: We need to ensure that the imported values don't override the "base" secrets.
|
||||||
|
// Priority order is:
|
||||||
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)
|
// Local/Preset variables -> Actual secrets -> Imported secrets (high->low)
|
||||||
|
|
||||||
// Check if the secret already exists in the secrets list
|
// Check if the secret already exists in the secrets list
|
||||||
if (!secrets.find(s => s.secretKey === importedSecret.secretKey)) {
|
if (!secrets.find((s) => s.secretKey === importedSecret.secretKey)) {
|
||||||
secrets.push({
|
secrets.push({
|
||||||
...importedSecret,
|
...importedSecret,
|
||||||
secretPath: imp.secretPath,
|
secretPath: imp.secretPath,
|
||||||
// These fields are not returned by the API
|
createdAt: new Date().toISOString(),
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
createdAt: new Date().toISOString(),
|
tags: [],
|
||||||
tags: []
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return secrets;
|
return secrets;
|
||||||
};
|
};
|
||||||
|
|
||||||
getSecret = async (options: GetSecretOptions): Promise<GetSecretResult> => {
|
getSecret = async (options: GetSecretOptions) => {
|
||||||
try {
|
try {
|
||||||
const res = await this.#apiInstance.apiV3SecretsRawSecretNameGet(
|
const res = await this.apiClient.getSecret({
|
||||||
{
|
secretName: options.secretName,
|
||||||
viewSecretValue: convertBool(options.viewSecretValue ?? true),
|
workspaceId: options.projectId,
|
||||||
environment: options.environment,
|
environment: options.environment,
|
||||||
secretName: options.secretName,
|
expandSecretReferences: convertBool(
|
||||||
workspaceId: options.projectId,
|
defaultBoolean(options.expandSecretReferences, true)
|
||||||
expandSecretReferences: convertBool(defaultBoolean(options.expandSecretReferences, true)),
|
),
|
||||||
includeImports: convertBool(options.includeImports),
|
includeImports: convertBool(options.includeImports),
|
||||||
secretPath: options.secretPath,
|
secretPath: options.secretPath,
|
||||||
type: options.type,
|
type: options.type,
|
||||||
version: options.version
|
version: options.version,
|
||||||
},
|
viewSecretValue: convertBool(options.viewSecretValue ?? true),
|
||||||
this.#requestOptions
|
});
|
||||||
);
|
return res.secret;
|
||||||
return res.data.secret;
|
} catch (err) {
|
||||||
} catch (err) {
|
throw newInfisicalError(err);
|
||||||
throw newInfisicalError(err);
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
updateSecret = async (
|
updateSecret = async (secretName: string, options: UpdateSecretOptions) => {
|
||||||
secretName: DefaultApiApiV3SecretsRawSecretNamePatchRequest["secretName"],
|
try {
|
||||||
options: UpdateSecretOptions
|
return await this.apiClient.updateSecret(secretName, {
|
||||||
): Promise<UpdateSecretResult> => {
|
workspaceId: options.projectId,
|
||||||
try {
|
environment: options.environment,
|
||||||
const res = await this.#apiInstance.apiV3SecretsRawSecretNamePatch(
|
secretValue: options.secretValue,
|
||||||
{
|
newSecretName: options.newSecretName,
|
||||||
secretName,
|
secretComment: options.secretComment,
|
||||||
apiV3SecretsRawSecretNamePatchRequest: {
|
secretPath: options.secretPath,
|
||||||
...options,
|
secretReminderNote: options.secretReminderNote,
|
||||||
workspaceId: options.projectId
|
secretReminderRepeatDays: options.secretReminderRepeatDays,
|
||||||
}
|
skipMultilineEncoding: options.skipMultilineEncoding,
|
||||||
},
|
tagIds: options.tagIds,
|
||||||
this.#requestOptions
|
type: options.type,
|
||||||
);
|
metadata: options.metadata,
|
||||||
return res.data;
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw newInfisicalError(err);
|
throw newInfisicalError(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createSecret = async (
|
createSecret = async (secretName: string, options: CreateSecretOptions) => {
|
||||||
secretName: DefaultApiApiV3SecretsRawSecretNamePostRequest["secretName"],
|
try {
|
||||||
options: CreateSecretOptions
|
return await this.apiClient.createSecret(secretName, {
|
||||||
): Promise<CreateSecretResult> => {
|
workspaceId: options.projectId,
|
||||||
try {
|
environment: options.environment,
|
||||||
const res = await this.#apiInstance.apiV3SecretsRawSecretNamePost(
|
secretValue: options.secretValue,
|
||||||
{
|
secretComment: options.secretComment,
|
||||||
secretName,
|
secretPath: options.secretPath,
|
||||||
apiV3SecretsRawSecretNamePostRequest: {
|
secretReminderNote: options.secretReminderNote,
|
||||||
...options,
|
secretReminderRepeatDays: options.secretReminderRepeatDays,
|
||||||
workspaceId: options.projectId
|
skipMultilineEncoding: options.skipMultilineEncoding,
|
||||||
}
|
tagIds: options.tagIds,
|
||||||
},
|
type: options.type,
|
||||||
this.#requestOptions
|
});
|
||||||
);
|
} catch (err) {
|
||||||
return res.data;
|
throw newInfisicalError(err);
|
||||||
} catch (err) {
|
}
|
||||||
throw newInfisicalError(err);
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
deleteSecret = async (
|
deleteSecret = async (secretName: string, options: DeleteSecretOptions) => {
|
||||||
secretName: DefaultApiApiV3SecretsRawSecretNameDeleteRequest["secretName"],
|
try {
|
||||||
options: DeleteSecretOptions
|
return await this.apiClient.deleteSecret(secretName, {
|
||||||
): Promise<DeleteSecretResult> => {
|
workspaceId: options.projectId,
|
||||||
try {
|
environment: options.environment,
|
||||||
const res = await this.#apiInstance.apiV3SecretsRawSecretNameDelete(
|
secretPath: options.secretPath,
|
||||||
{
|
type: options.type,
|
||||||
secretName,
|
});
|
||||||
apiV3SecretsRawSecretNameDeleteRequest: {
|
} catch (err) {
|
||||||
...options,
|
throw newInfisicalError(err);
|
||||||
workspaceId: options.projectId
|
}
|
||||||
}
|
};
|
||||||
},
|
|
||||||
this.#requestOptions
|
|
||||||
);
|
|
||||||
return res.data;
|
|
||||||
} 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_IDENTITY_DOCUMENT_URI, AWS_TOKEN_METADATA_URI } from "./constants";
|
||||||
import AWS from "aws-sdk";
|
import AWS from "aws-sdk";
|
||||||
import { InfisicalSDKError } from "./errors";
|
import { InfisicalSDKError } from "./errors";
|
||||||
import { ApiV3SecretsRawGet200Response } from "../infisicalapi_client";
|
import { Secret } from "../api/types";
|
||||||
|
|
||||||
type Secret = ApiV3SecretsRawGet200Response["secrets"][number];
|
|
||||||
|
|
||||||
export const getUniqueSecretsByKey = (secrets: Secret[]) => {
|
export const getUniqueSecretsByKey = (secrets: Secret[]) => {
|
||||||
const secretMap = new Map<string, Secret>();
|
const secretMap = new Map<string, Secret>();
|
||||||
|
|||||||
197
src/index.ts
197
src/index.ts
@@ -1,141 +1,100 @@
|
|||||||
import { Configuration, DefaultApi as InfisicalApi } from "./infisicalapi_client";
|
import { ApiClient } from "./api/base";
|
||||||
import { DefaultApiApiV1DynamicSecretsLeasesPostRequest } from "./infisicalapi_client";
|
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 SecretsClient from "./custom/secrets";
|
||||||
import AuthClient from "./custom/auth";
|
import AuthClient from "./custom/auth";
|
||||||
import axios, { AxiosError, AxiosInstance, RawAxiosRequestConfig } from "axios";
|
|
||||||
import DynamicSecretsClient from "./custom/dynamic-secrets";
|
import DynamicSecretsClient from "./custom/dynamic-secrets";
|
||||||
|
|
||||||
import * as ApiClient from "./infisicalapi_client";
|
|
||||||
import EnvironmentsClient from "./custom/environments";
|
import EnvironmentsClient from "./custom/environments";
|
||||||
import ProjectsClient from "./custom/projects";
|
import ProjectsClient from "./custom/projects";
|
||||||
import FoldersClient from "./custom/folders";
|
import FoldersClient from "./custom/folders";
|
||||||
|
|
||||||
declare module "axios" {
|
|
||||||
interface AxiosRequestConfig {
|
|
||||||
_retryCount?: number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = {
|
type InfisicalSDKOptions = {
|
||||||
siteUrl?: string;
|
siteUrl?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
class InfisicalSDK {
|
class InfisicalSDK {
|
||||||
#apiInstance: InfisicalApi;
|
private apiClient: ApiClient;
|
||||||
|
|
||||||
#requestOptions: RawAxiosRequestConfig | undefined;
|
// API instances
|
||||||
#secretsClient: SecretsClient;
|
private authApi: AuthApi;
|
||||||
#dynamicSecretsClient: DynamicSecretsClient;
|
private secretsApi: SecretsApi;
|
||||||
#environmentsClient: EnvironmentsClient;
|
private dynamicSecretsApi: DynamicSecretsApi;
|
||||||
#projectsClient: ProjectsClient;
|
private environmentsApi: EnvironmentsApi;
|
||||||
#foldersClient: FoldersClient;
|
private projectsApi: ProjectsApi;
|
||||||
#authClient: AuthClient;
|
private foldersApi: FoldersApi;
|
||||||
#basePath: string;
|
|
||||||
axiosInstance: AxiosInstance;
|
|
||||||
|
|
||||||
constructor(options?: InfisicalSDKOptions) {
|
// Domain clients
|
||||||
this.#basePath = options?.siteUrl || "https://app.infisical.com";
|
private authClient: AuthClient;
|
||||||
this.axiosInstance = setupAxiosRetry();
|
private secretsClient: SecretsClient;
|
||||||
|
private dynamicSecretsClient: DynamicSecretsClient;
|
||||||
|
private environmentsClient: EnvironmentsClient;
|
||||||
|
private projectsClient: ProjectsClient;
|
||||||
|
private foldersClient: FoldersClient;
|
||||||
|
|
||||||
this.#apiInstance = new InfisicalApi(
|
constructor(options?: InfisicalSDKOptions) {
|
||||||
new Configuration({
|
const baseURL = options?.siteUrl || "https://app.infisical.com";
|
||||||
basePath: this.#basePath
|
|
||||||
}),
|
|
||||||
undefined,
|
|
||||||
this.axiosInstance
|
|
||||||
);
|
|
||||||
|
|
||||||
this.#authClient = new AuthClient(this.authenticate.bind(this), this.#apiInstance);
|
// Initialize the base API client
|
||||||
this.#dynamicSecretsClient = new DynamicSecretsClient(this.#apiInstance, this.#requestOptions);
|
this.apiClient = new ApiClient({ baseURL });
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private authenticate(accessToken: string) {
|
// Initialize API service instances
|
||||||
this.#apiInstance = new InfisicalApi(
|
this.authApi = new AuthApi(this.apiClient);
|
||||||
new Configuration({
|
this.secretsApi = new SecretsApi(this.apiClient);
|
||||||
basePath: this.#basePath,
|
this.dynamicSecretsApi = new DynamicSecretsApi(this.apiClient);
|
||||||
accessToken
|
this.environmentsApi = new EnvironmentsApi(this.apiClient);
|
||||||
}),
|
this.projectsApi = new ProjectsApi(this.apiClient);
|
||||||
undefined,
|
this.foldersApi = new FoldersApi(this.apiClient);
|
||||||
this.axiosInstance
|
|
||||||
);
|
|
||||||
|
|
||||||
this.#requestOptions = {
|
// Initialize domain clients
|
||||||
headers: {
|
this.authClient = new AuthClient(
|
||||||
Authorization: `Bearer ${accessToken}`
|
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);
|
private authenticate(accessToken: string) {
|
||||||
this.#secretsClient = new SecretsClient(this.#apiInstance, this.#requestOptions);
|
// Set the token on the API client
|
||||||
this.#dynamicSecretsClient = new DynamicSecretsClient(this.#apiInstance, this.#requestOptions);
|
this.apiClient.setAccessToken(accessToken);
|
||||||
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);
|
|
||||||
|
|
||||||
return this;
|
// Reinitialize the auth client with the token
|
||||||
}
|
this.authClient = new AuthClient(
|
||||||
|
this.authenticate.bind(this),
|
||||||
|
this.authApi,
|
||||||
|
accessToken
|
||||||
|
);
|
||||||
|
|
||||||
secrets = () => this.#secretsClient;
|
return this;
|
||||||
environments = () => this.#environmentsClient;
|
}
|
||||||
projects = () => this.#projectsClient;
|
|
||||||
folders = () => this.#foldersClient;
|
// Public methods to access domain clients
|
||||||
dynamicSecrets = () => this.#dynamicSecretsClient;
|
secrets = () => this.secretsClient;
|
||||||
auth = () => this.#authClient;
|
environments = () => this.environmentsClient;
|
||||||
rest = () => buildRestClient(this.#apiInstance, this.#requestOptions);
|
projects = () => this.projectsClient;
|
||||||
|
folders = () => this.foldersClient;
|
||||||
|
dynamicSecrets = () => this.dynamicSecretsClient;
|
||||||
|
auth = () => this.authClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { InfisicalSDK, ApiClient };
|
// Export main SDK class
|
||||||
export { TDynamicSecretProvider, DynamicSecretProviders } from "./custom/schemas";
|
export { InfisicalSDK };
|
||||||
export type * from "./custom/secrets";
|
|
||||||
export type * from "./custom/dynamic-secrets";
|
export * from './api/types'
|
||||||
|
|
||||||
|
// Export types and enums from schemas
|
||||||
|
export {
|
||||||
|
TDynamicSecretProvider,
|
||||||
|
DynamicSecretProviders,
|
||||||
|
SqlProviders,
|
||||||
|
} from "./custom/schemas";
|
||||||
|
|||||||
Reference in New Issue
Block a user