From f97139e7fcc3637ef6c34cfc811bd6ec55285fe4 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Sat, 12 Apr 2025 01:48:37 +0400 Subject: [PATCH] feat(projects): invite members to projects --- README.md | 27 ++++++++++++++++++-- src/custom/projects.ts | 28 +++++++++++++++++++- test/index.ts | 58 ++++++++++++++++++++++++++---------------- 3 files changed, 88 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 8ef375d..d647f76 100644 --- a/README.md +++ b/README.md @@ -458,15 +458,38 @@ const project = await client.projects().create({ **Returns:** - `ApiV1WorkspaceWorkspaceIdGet200ResponseWorkspace`: The project that was created. + +#### Invite members to a project + +When inviting members to projects, you must either specify the `emails` or `usernames`. If neither are specified, the SDK will throw an error. + +```typescript +const memberships = await client.projects().inviteMembers({ + projectId: project.id, + emails: ["test1@example.com", "test2@example.com"], // Optional + usernames: ["example-user3", "example-user4"] // Optional + roleSlugs: ["member"] // Optional +}); +``` + +**Parameters:** +- `projectId`: (string): The ID of the project to invite members to +- `emails`: (string[]): An array of emails of the users to invite to the project. +- `usernames`: (string[]) An array of usernames of the users to invite to the project. +`roleSlugs`: (string[]): An array of role slugs to assign to the members. If not specified, this will default to `member`. + +**Returns:** +- `ApiV1OrganizationAdminProjectsProjectIdGrantAdminAccessPost200ResponseMembership`: An array of the created project memberships. + ### `environments` #### Create a new environment ```typescript const environment = await client.environments().create({ - name: "Demo Environment", + name: "", projectId: "", - slug: "demo-environment", + slug: "", position: 1 // Optional }); ``` diff --git a/src/custom/projects.ts b/src/custom/projects.ts index c5ef1fc..ce6cd57 100644 --- a/src/custom/projects.ts +++ b/src/custom/projects.ts @@ -1,11 +1,18 @@ import { RawAxiosRequestConfig } from "axios"; import { DefaultApi as InfisicalApi } from "../infisicalapi_client"; -import type { ApiV2WorkspacePost200Response, ApiV2WorkspacePostRequest } from "../infisicalapi_client"; +import type { + ApiV2WorkspacePost200Response, + ApiV2WorkspacePostRequest, + ApiV2WorkspaceProjectIdMembershipsPost200Response, + ApiV2WorkspaceProjectIdMembershipsPostRequest +} from "../infisicalapi_client"; import { newInfisicalError } from "./errors"; export type CreateProjectOptions = ApiV2WorkspacePostRequest; export type CreateProjectResult = ApiV2WorkspacePost200Response; +export type InviteMemberToProjectOptions = { projectId: string } & ApiV2WorkspaceProjectIdMembershipsPostRequest; +export type InviteMemberToProjectResult = ApiV2WorkspaceProjectIdMembershipsPost200Response; export default class ProjectsClient { #apiInstance: InfisicalApi; #requestOptions: RawAxiosRequestConfig | undefined; @@ -27,4 +34,23 @@ export default class ProjectsClient { throw newInfisicalError(err); } }; + + inviteMembers = async (options: InviteMemberToProjectOptions): Promise => { + try { + if (!options.usernames?.length && !options.emails?.length) { + throw new Error("Either usernames or emails must be provided"); + } + + const res = await this.#apiInstance.apiV2WorkspaceProjectIdMembershipsPost( + { + projectId: options.projectId, + apiV2WorkspaceProjectIdMembershipsPostRequest: options + }, + this.#requestOptions + ); + return res.data.memberships; + } catch (err) { + throw newInfisicalError(err); + } + }; } diff --git a/test/index.ts b/test/index.ts index 481adbd..caea1a1 100644 --- a/test/index.ts +++ b/test/index.ts @@ -1,38 +1,52 @@ import { InfisicalSDK } from "../src"; -const PROJECT_ID = "PROJECT_ID"; - (async () => { const client = new InfisicalSDK({ siteUrl: "http://localhost:8080" // Optional, defaults to https://app.infisical.com }); + const EMAIL_TO_INVITE = ""; + + const universalAuthClientId = process.env.UNIVERSAL_AUTH_CLIENT_ID; + const universalAuthClientSecret = process.env.UNIVERSAL_AUTH_CLIENT_SECRET; + + if (!universalAuthClientId || !universalAuthClientSecret) { + throw new Error("UNIVERSAL_AUTH_CLIENT_ID and UNIVERSAL_AUTH_CLIENT_SECRET must be set"); + } + await client.auth().universalAuth.login({ - clientId: "CLIENT_ID", - clientSecret: "CLIENT_SECRET" + clientId: universalAuthClientId, + clientSecret: universalAuthClientSecret + }); + + console.log("Creating project"); + const project = await client.projects().create({ + projectDescription: "test description", + projectName: "test project1344assdfd", + type: "secret-manager", + slug: "test-project1assdfd43" }); const environment = await client.environments().create({ - name: "Demo Environment", - projectId: "", - slug: "demo-environment", - position: 1 // Optional - }); - - const project = await client.projects().create({ - projectName: "", - type: "secret-manager", // cert-manager, secret-manager, kms, ssh - projectDescription: "", // Optional - slug: "", // Optional - template: "", // Optional - kmsKeyId: "kms-key-id" // Optional + position: 100, + slug: "test-environment-custom-slug", + name: "test environment", + projectId: project.id }); + console.log("Creating folder"); const folder = await client.folders().create({ - name: "", - path: "", - projectId: "", - environment: "", - description: "" // Optional + name: "test-folder", + projectId: project.id, + environment: environment.slug }); + + console.log("Inviting member to project"); + const memberships = await client.projects().inviteMembers({ + projectId: project.id, + emails: [EMAIL_TO_INVITE], + roleSlugs: ["admin"] + }); + + console.log("Memberships", memberships); })();