@scalekit-sdk/node 1.0.14 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/buf.gen.yaml +2 -1
- package/lib/core.js +2 -2
- package/lib/core.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/commons/commons_pb.d.ts +217 -0
- package/lib/pkg/grpc/scalekit/v1/commons/commons_pb.js +289 -1
- package/lib/pkg/grpc/scalekit/v1/commons/commons_pb.js.map +1 -1
- package/lib/pkg/grpc/scalekit/v1/users/users_connect.d.ts +117 -0
- package/lib/pkg/grpc/scalekit/v1/users/users_connect.js +125 -0
- package/lib/pkg/grpc/scalekit/v1/users/users_connect.js.map +1 -0
- package/lib/pkg/grpc/scalekit/v1/users/users_pb.d.ts +806 -0
- package/lib/pkg/grpc/scalekit/v1/users/users_pb.js +1048 -0
- package/lib/pkg/grpc/scalekit/v1/users/users_pb.js.map +1 -0
- package/lib/scalekit.d.ts +58 -8
- package/lib/scalekit.js +117 -13
- package/lib/scalekit.js.map +1 -1
- package/lib/types/auth.d.ts +1 -0
- package/lib/types/scalekit.d.ts +16 -0
- package/lib/types/user.d.ts +20 -0
- package/lib/types/user.js +3 -0
- package/lib/types/user.js.map +1 -0
- package/lib/user.d.ts +95 -0
- package/lib/user.js +218 -0
- package/lib/user.js.map +1 -0
- package/package.json +3 -2
- package/src/core.ts +2 -2
- package/src/pkg/grpc/scalekit/v1/commons/commons_pb.ts +351 -1
- package/src/pkg/grpc/scalekit/v1/users/users_connect.ts +124 -0
- package/src/pkg/grpc/scalekit/v1/users/users_pb.ts +1440 -0
- package/src/scalekit.ts +144 -15
- package/src/types/auth.ts +1 -0
- package/src/types/scalekit.ts +19 -0
- package/src/types/user.ts +21 -0
- package/src/user.ts +291 -0
package/src/scalekit.ts
CHANGED
|
@@ -9,10 +9,12 @@ import DirectoryClient from './directory';
|
|
|
9
9
|
import DomainClient from './domain';
|
|
10
10
|
import OrganizationClient from './organization';
|
|
11
11
|
import PasswordlessClient from './passwordless';
|
|
12
|
+
import UserClient from './user';
|
|
12
13
|
import { IdpInitiatedLoginClaims, IdTokenClaim, User } from './types/auth';
|
|
13
|
-
import { AuthenticationOptions, AuthenticationResponse, AuthorizationUrlOptions, GrantType } from './types/scalekit';
|
|
14
|
+
import { AuthenticationOptions, AuthenticationResponse, AuthorizationUrlOptions, GrantType, LogoutUrlOptions, RefreshTokenResponse ,TokenValidationOptions } from './types/scalekit';
|
|
14
15
|
|
|
15
16
|
const authorizeEndpoint = "oauth/authorize";
|
|
17
|
+
const logoutEndpoint = "oidc/logout";
|
|
16
18
|
const WEBHOOK_TOLERANCE_IN_SECONDS = 5 * 60; // 5 minutes
|
|
17
19
|
const WEBHOOK_SIGNATURE_VERSION = "v1";
|
|
18
20
|
|
|
@@ -33,6 +35,7 @@ export default class ScalekitClient {
|
|
|
33
35
|
readonly domain: DomainClient;
|
|
34
36
|
readonly directory: DirectoryClient;
|
|
35
37
|
readonly passwordless: PasswordlessClient;
|
|
38
|
+
readonly user: UserClient;
|
|
36
39
|
constructor(
|
|
37
40
|
envUrl: string,
|
|
38
41
|
clientId: string,
|
|
@@ -67,6 +70,10 @@ export default class ScalekitClient {
|
|
|
67
70
|
this.grpcConnect,
|
|
68
71
|
this.coreClient
|
|
69
72
|
);
|
|
73
|
+
this.user = new UserClient(
|
|
74
|
+
this.grpcConnect,
|
|
75
|
+
this.coreClient
|
|
76
|
+
);
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
/**
|
|
@@ -83,10 +90,14 @@ export default class ScalekitClient {
|
|
|
83
90
|
* @param {string} options.provider Provider i.e. google, github, etc.
|
|
84
91
|
* @param {string} options.codeChallenge Code challenge parameter in case of PKCE
|
|
85
92
|
* @param {string} options.codeChallengeMethod Code challenge method parameter in case of PKCE
|
|
93
|
+
* @param {string} options.prompt Prompt parameter to control the authorization server's authentication behavior
|
|
86
94
|
*
|
|
87
95
|
* @example
|
|
88
96
|
* const scalekit = new Scalekit(envUrl, clientId, clientSecret);
|
|
89
|
-
* const authorizationUrl = scalekit.getAuthorizationUrl(redirectUri, {
|
|
97
|
+
* const authorizationUrl = scalekit.getAuthorizationUrl(redirectUri, {
|
|
98
|
+
* scopes: ['openid', 'profile'],
|
|
99
|
+
* prompt: 'create'
|
|
100
|
+
* });
|
|
90
101
|
* @returns {string} authorization url
|
|
91
102
|
*/
|
|
92
103
|
getAuthorizationUrl(
|
|
@@ -114,7 +125,8 @@ export default class ScalekitClient {
|
|
|
114
125
|
...(options.organizationId && { organization_id: options.organizationId }),
|
|
115
126
|
...(options.codeChallenge && { code_challenge: options.codeChallenge }),
|
|
116
127
|
...(options.codeChallengeMethod && { code_challenge_method: options.codeChallengeMethod }),
|
|
117
|
-
...(options.provider && { provider: options.provider })
|
|
128
|
+
...(options.provider && { provider: options.provider }),
|
|
129
|
+
...(options.prompt && { prompt: options.prompt })
|
|
118
130
|
})
|
|
119
131
|
|
|
120
132
|
return `${this.coreClient.envUrl}/${authorizeEndpoint}?${qs}`
|
|
@@ -141,7 +153,7 @@ export default class ScalekitClient {
|
|
|
141
153
|
client_secret: this.coreClient.clientSecret,
|
|
142
154
|
...(options?.codeVerifier && { code_verifier: options.codeVerifier })
|
|
143
155
|
}))
|
|
144
|
-
const { id_token, access_token, expires_in } = res.data;
|
|
156
|
+
const { id_token, access_token, expires_in , refresh_token } = res.data;
|
|
145
157
|
const claims = jose.decodeJwt<IdTokenClaim>(id_token);
|
|
146
158
|
const user = <User>{};
|
|
147
159
|
for (const [k, v] of Object.entries(claims)) {
|
|
@@ -154,7 +166,8 @@ export default class ScalekitClient {
|
|
|
154
166
|
user,
|
|
155
167
|
idToken: id_token,
|
|
156
168
|
accessToken: access_token,
|
|
157
|
-
expiresIn: expires_in
|
|
169
|
+
expiresIn: expires_in,
|
|
170
|
+
refreshToken: refresh_token
|
|
158
171
|
}
|
|
159
172
|
}
|
|
160
173
|
|
|
@@ -162,27 +175,56 @@ export default class ScalekitClient {
|
|
|
162
175
|
* Get the idp initiated login claims
|
|
163
176
|
*
|
|
164
177
|
* @param {string} idpInitiatedLoginToken The idp_initiated_login query param from the URL
|
|
178
|
+
* @param {TokenValidationOptions} options Optional validation options for issuer and audience
|
|
165
179
|
* @returns {object} Returns the idp initiated login claims
|
|
166
180
|
*/
|
|
167
|
-
async getIdpInitiatedLoginClaims(idpInitiatedLoginToken: string): Promise<IdpInitiatedLoginClaims> {
|
|
168
|
-
return this.validateToken<IdpInitiatedLoginClaims>(idpInitiatedLoginToken);
|
|
181
|
+
async getIdpInitiatedLoginClaims(idpInitiatedLoginToken: string, options?: TokenValidationOptions): Promise<IdpInitiatedLoginClaims> {
|
|
182
|
+
return this.validateToken<IdpInitiatedLoginClaims>(idpInitiatedLoginToken, options);
|
|
169
183
|
}
|
|
170
184
|
|
|
171
185
|
/**
|
|
172
|
-
* Validates the access token.
|
|
186
|
+
* Validates the access token and returns a boolean result.
|
|
173
187
|
*
|
|
174
188
|
* @param {string} token The token to be validated.
|
|
189
|
+
* @param {TokenValidationOptions} options Optional validation options for issuer, audience, and scopes
|
|
175
190
|
* @return {Promise<boolean>} Returns true if the token is valid, false otherwise.
|
|
176
191
|
*/
|
|
177
|
-
async validateAccessToken(token: string): Promise<boolean> {
|
|
192
|
+
async validateAccessToken(token: string, options?: TokenValidationOptions): Promise<boolean> {
|
|
178
193
|
try {
|
|
179
|
-
await this.validateToken(token);
|
|
194
|
+
await this.validateToken(token, options);
|
|
180
195
|
return true;
|
|
181
196
|
} catch (_) {
|
|
182
197
|
return false;
|
|
183
198
|
}
|
|
184
199
|
}
|
|
185
200
|
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Returns the logout URL that can be used to log out the user.
|
|
205
|
+
* @param {LogoutUrlOptions} options Logout URL options
|
|
206
|
+
* @param {string} options.idTokenHint The ID Token previously issued to the client
|
|
207
|
+
* @param {string} options.postLogoutRedirectUri URL to redirect after logout
|
|
208
|
+
* @param {string} options.state Opaque value to maintain state between request and callback
|
|
209
|
+
* @returns {string} The logout URL
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* const scalekit = new Scalekit(envUrl, clientId, clientSecret);
|
|
213
|
+
* const logoutUrl = scalekit.getLogoutUrl({
|
|
214
|
+
* postLogoutRedirectUri: 'https://example.com',
|
|
215
|
+
* state: 'some-state'
|
|
216
|
+
* });
|
|
217
|
+
*/
|
|
218
|
+
getLogoutUrl(options?: LogoutUrlOptions): string {
|
|
219
|
+
const qs = QueryString.stringify({
|
|
220
|
+
...(options?.idTokenHint && { id_token_hint: options.idTokenHint }),
|
|
221
|
+
...(options?.postLogoutRedirectUri && { post_logout_redirect_uri: options.postLogoutRedirectUri }),
|
|
222
|
+
...(options?.state && { state: options.state })
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
return `${this.coreClient.envUrl}/${logoutEndpoint}${qs ? `?${qs}` : ''}`;
|
|
226
|
+
}
|
|
227
|
+
|
|
186
228
|
/**
|
|
187
229
|
* Verifies the payload of the webhook
|
|
188
230
|
*
|
|
@@ -217,24 +259,69 @@ export default class ScalekitClient {
|
|
|
217
259
|
}
|
|
218
260
|
|
|
219
261
|
/**
|
|
220
|
-
*
|
|
262
|
+
* Validates a token and returns its payload if valid.
|
|
263
|
+
* Supports issuer, audience, and scope validation.
|
|
221
264
|
*
|
|
222
265
|
* @param {string} token The token to be validated
|
|
223
|
-
* @
|
|
266
|
+
* @param {TokenValidationOptions} options Optional validation options for issuer, audience, and scopes
|
|
267
|
+
* @return {Promise<T>} Returns the token payload if valid
|
|
268
|
+
* @throws {Error} If token is invalid or missing required scopes
|
|
224
269
|
*/
|
|
225
|
-
|
|
270
|
+
async validateToken<T>(token: string, options?: TokenValidationOptions): Promise<T> {
|
|
226
271
|
await this.coreClient.getJwks();
|
|
227
272
|
const jwks = jose.createLocalJWKSet({
|
|
228
273
|
keys: this.coreClient.keys
|
|
229
274
|
})
|
|
230
275
|
try {
|
|
231
|
-
const { payload } = await jose.jwtVerify<T>(token, jwks
|
|
276
|
+
const { payload } = await jose.jwtVerify<T>(token, jwks, {
|
|
277
|
+
...(options?.issuer && { issuer: options.issuer }),
|
|
278
|
+
...(options?.audience && { audience: options.audience })
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
if (options?.requiredScopes && options.requiredScopes.length > 0) {
|
|
282
|
+
this.verifyScopes(token, options.requiredScopes);
|
|
283
|
+
}
|
|
284
|
+
|
|
232
285
|
return payload;
|
|
233
286
|
} catch (_) {
|
|
234
287
|
throw new Error("Invalid token");
|
|
235
288
|
}
|
|
236
289
|
}
|
|
237
290
|
|
|
291
|
+
/**
|
|
292
|
+
* Verify that the token contains the required scopes
|
|
293
|
+
*
|
|
294
|
+
* @param {string} token The token to verify
|
|
295
|
+
* @param {string[]} requiredScopes The scopes that must be present in the token
|
|
296
|
+
* @return {boolean} Returns true if all required scopes are present
|
|
297
|
+
* @throws {Error} If required scopes are missing, with details about which scopes are missing
|
|
298
|
+
*/
|
|
299
|
+
verifyScopes(token: string, requiredScopes: string[]): boolean {
|
|
300
|
+
const payload = jose.decodeJwt(token);
|
|
301
|
+
const scopes = this.extractScopesFromPayload(payload);
|
|
302
|
+
|
|
303
|
+
const missingScopes = requiredScopes.filter(scope => !scopes.includes(scope));
|
|
304
|
+
|
|
305
|
+
if (missingScopes.length > 0) {
|
|
306
|
+
throw new Error(`Token missing required scopes: ${missingScopes.join(', ')}`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Extract scopes from token payload
|
|
314
|
+
*
|
|
315
|
+
* @param {any} payload The token payload
|
|
316
|
+
* @return {string[]} Array of scopes found in the token
|
|
317
|
+
*/
|
|
318
|
+
private extractScopesFromPayload(payload: Record<string, any>): string[] {
|
|
319
|
+
const scopes = payload.scopes;
|
|
320
|
+
return Array.isArray(scopes)
|
|
321
|
+
? scopes.filter((scope) => !!scope.trim?.())
|
|
322
|
+
: [];
|
|
323
|
+
}
|
|
324
|
+
|
|
238
325
|
/**
|
|
239
326
|
* Verify the timestamp
|
|
240
327
|
*
|
|
@@ -267,6 +354,48 @@ export default class ScalekitClient {
|
|
|
267
354
|
private computeSignature(secretBytes: Buffer, data: string): string {
|
|
268
355
|
return crypto.createHmac('sha256', secretBytes).update(data).digest('base64');
|
|
269
356
|
}
|
|
270
|
-
}
|
|
271
357
|
|
|
358
|
+
/**
|
|
359
|
+
* Refresh access token using a refresh token
|
|
360
|
+
* @param {string} refreshToken The refresh token to use
|
|
361
|
+
* @returns {Promise<RefreshTokenResponse>} Returns new access token, refresh token and other details
|
|
362
|
+
* @throws {Error} When authentication fails or response data is invalid
|
|
363
|
+
*/
|
|
364
|
+
async refreshAccessToken(refreshToken: string): Promise<RefreshTokenResponse> {
|
|
365
|
+
if (!refreshToken) {
|
|
366
|
+
throw new Error("Refresh token is required");
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
let res;
|
|
370
|
+
try {
|
|
371
|
+
res = await this.coreClient.authenticate(QueryString.stringify({
|
|
372
|
+
grant_type: GrantType.RefreshToken,
|
|
373
|
+
client_id: this.coreClient.clientId,
|
|
374
|
+
client_secret: this.coreClient.clientSecret,
|
|
375
|
+
refresh_token: refreshToken
|
|
376
|
+
}));
|
|
377
|
+
} catch (error) {
|
|
378
|
+
throw new Error(`Failed to refresh token: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (!res || !res.data) {
|
|
382
|
+
throw new Error("Invalid response from authentication server");
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const { access_token, refresh_token } = res.data;
|
|
386
|
+
|
|
387
|
+
// Validate that all required properties exist
|
|
388
|
+
if (!access_token) {
|
|
389
|
+
throw new Error("Missing access_token in authentication response");
|
|
390
|
+
}
|
|
391
|
+
if (!refresh_token) {
|
|
392
|
+
throw new Error("Missing refresh_token in authentication response");
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
accessToken: access_token,
|
|
397
|
+
refreshToken: refresh_token
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
}
|
|
272
401
|
|
package/src/types/auth.ts
CHANGED
package/src/types/scalekit.ts
CHANGED
|
@@ -17,15 +17,34 @@ export type AuthorizationUrlOptions = {
|
|
|
17
17
|
codeChallenge?: string;
|
|
18
18
|
codeChallengeMethod?: string;
|
|
19
19
|
provider?: string;
|
|
20
|
+
prompt?: string;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export type AuthenticationOptions = {
|
|
23
24
|
codeVerifier?: string;
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
export type TokenValidationOptions = {
|
|
28
|
+
issuer?: string;
|
|
29
|
+
audience?: string[];
|
|
30
|
+
requiredScopes?: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
export type AuthenticationResponse = {
|
|
27
34
|
user: User;
|
|
28
35
|
idToken: string;
|
|
29
36
|
accessToken: string;
|
|
30
37
|
expiresIn: number;
|
|
38
|
+
refreshToken: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type RefreshTokenResponse = {
|
|
42
|
+
accessToken: string;
|
|
43
|
+
refreshToken: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface LogoutUrlOptions {
|
|
47
|
+
idTokenHint?: string;
|
|
48
|
+
postLogoutRedirectUri?: string;
|
|
49
|
+
state?: string;
|
|
31
50
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface CreateUserRequest {
|
|
2
|
+
email: string;
|
|
3
|
+
externalId?: string;
|
|
4
|
+
phoneNumber?: string;
|
|
5
|
+
userProfile?: {
|
|
6
|
+
firstName?: string;
|
|
7
|
+
lastName?: string;
|
|
8
|
+
};
|
|
9
|
+
metadata?: Record<string, string>;
|
|
10
|
+
sendActivationEmail?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface UpdateUserRequest {
|
|
14
|
+
email?: string;
|
|
15
|
+
externalId?: string;
|
|
16
|
+
userProfile?: {
|
|
17
|
+
firstName?: string;
|
|
18
|
+
lastName?: string;
|
|
19
|
+
};
|
|
20
|
+
metadata?: Record<string, string>;
|
|
21
|
+
}
|
package/src/user.ts
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { Empty, PartialMessage } from '@bufbuild/protobuf';
|
|
2
|
+
import { PromiseClient } from '@connectrpc/connect';
|
|
3
|
+
import GrpcConnect from './connect';
|
|
4
|
+
import CoreClient from './core';
|
|
5
|
+
import { UserService } from './pkg/grpc/scalekit/v1/users/users_connect';
|
|
6
|
+
import {
|
|
7
|
+
CreateUserAndMembershipRequest,
|
|
8
|
+
CreateUserAndMembershipResponse,
|
|
9
|
+
DeleteUserRequest,
|
|
10
|
+
GetUserRequest,
|
|
11
|
+
GetUserResponse,
|
|
12
|
+
ListUsersRequest,
|
|
13
|
+
ListUsersResponse,
|
|
14
|
+
UpdateUserRequest,
|
|
15
|
+
UpdateUserResponse,
|
|
16
|
+
User,
|
|
17
|
+
UpdateUser,
|
|
18
|
+
CreateUser,
|
|
19
|
+
CreateUserProfile,
|
|
20
|
+
CreateMembershipRequest,
|
|
21
|
+
CreateMembershipResponse,
|
|
22
|
+
DeleteMembershipRequest,
|
|
23
|
+
UpdateMembershipRequest,
|
|
24
|
+
UpdateMembershipResponse,
|
|
25
|
+
ListOrganizationUsersRequest,
|
|
26
|
+
ListOrganizationUsersResponse,
|
|
27
|
+
CreateMembership,
|
|
28
|
+
UpdateMembership
|
|
29
|
+
} from './pkg/grpc/scalekit/v1/users/users_pb';
|
|
30
|
+
import { CreateUserRequest, UpdateUserRequest as UpdateUserRequestType } from './types/user';
|
|
31
|
+
|
|
32
|
+
export default class UserClient {
|
|
33
|
+
private client: PromiseClient<typeof UserService>;
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
private readonly grpcConnect: GrpcConnect,
|
|
37
|
+
private readonly coreClient: CoreClient
|
|
38
|
+
) {
|
|
39
|
+
this.client = this.grpcConnect.createClient(UserService);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create a new user and add them to an organization
|
|
44
|
+
* @param {string} organizationId The organization id
|
|
45
|
+
* @param {CreateUserRequest} options The user creation options
|
|
46
|
+
* @returns {Promise<CreateUserAndMembershipResponse>} The created user
|
|
47
|
+
*/
|
|
48
|
+
async createUserAndMembership(organizationId: string, options: CreateUserRequest): Promise<CreateUserAndMembershipResponse> {
|
|
49
|
+
if (!organizationId) {
|
|
50
|
+
throw new Error('organizationId is required');
|
|
51
|
+
}
|
|
52
|
+
if (!options.email) {
|
|
53
|
+
throw new Error('email is required');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const user = new CreateUser({
|
|
57
|
+
email: options.email,
|
|
58
|
+
userProfile: options.userProfile ? new CreateUserProfile({
|
|
59
|
+
firstName: options.userProfile.firstName,
|
|
60
|
+
lastName: options.userProfile.lastName
|
|
61
|
+
}) : undefined,
|
|
62
|
+
metadata: options.metadata
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const request: PartialMessage<CreateUserAndMembershipRequest> = {
|
|
66
|
+
organizationId,
|
|
67
|
+
user
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
if (options.sendActivationEmail !== undefined) {
|
|
71
|
+
request.sendActivationEmail = options.sendActivationEmail;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const response = await this.coreClient.connectExec(
|
|
75
|
+
this.client.createUserAndMembership,
|
|
76
|
+
request
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
if (!response.user) {
|
|
80
|
+
throw new Error('Failed to create user');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return response;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get a user by id
|
|
88
|
+
* @param {string} userId The user id
|
|
89
|
+
* @returns {Promise<GetUserResponse>} The user
|
|
90
|
+
*/
|
|
91
|
+
async getUser(userId: string): Promise<GetUserResponse> {
|
|
92
|
+
return this.coreClient.connectExec(
|
|
93
|
+
this.client.getUser,
|
|
94
|
+
{
|
|
95
|
+
identities: {
|
|
96
|
+
case: 'id',
|
|
97
|
+
value: userId
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* List users with pagination
|
|
105
|
+
* @param {object} options The pagination options
|
|
106
|
+
* @param {number} options.pageSize The page size
|
|
107
|
+
* @param {string} options.pageToken The page token
|
|
108
|
+
* @returns {Promise<ListUsersResponse>} The list of users
|
|
109
|
+
*/
|
|
110
|
+
async listUsers(options?: {
|
|
111
|
+
pageSize?: number,
|
|
112
|
+
pageToken?: string
|
|
113
|
+
}): Promise<ListUsersResponse> {
|
|
114
|
+
return this.coreClient.connectExec(
|
|
115
|
+
this.client.listUsers,
|
|
116
|
+
{
|
|
117
|
+
pageSize: options?.pageSize,
|
|
118
|
+
pageToken: options?.pageToken
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Update a user
|
|
125
|
+
* @param {string} userId The user id
|
|
126
|
+
* @param {UpdateUserRequestType} options The update options
|
|
127
|
+
* @returns {Promise<UpdateUserResponse>} The updated user
|
|
128
|
+
*/
|
|
129
|
+
async updateUser(userId: string, options: UpdateUserRequestType): Promise<UpdateUserResponse> {
|
|
130
|
+
const updateUser = new UpdateUser({
|
|
131
|
+
userProfile: options.userProfile ? {
|
|
132
|
+
firstName: options.userProfile.firstName,
|
|
133
|
+
lastName: options.userProfile.lastName
|
|
134
|
+
} : undefined,
|
|
135
|
+
metadata: options.metadata
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return this.coreClient.connectExec(
|
|
139
|
+
this.client.updateUser,
|
|
140
|
+
{
|
|
141
|
+
identities: {
|
|
142
|
+
case: 'id',
|
|
143
|
+
value: userId
|
|
144
|
+
},
|
|
145
|
+
user: updateUser
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Delete a user
|
|
152
|
+
* @param {string} userId The user id
|
|
153
|
+
* @returns {Promise<Empty>} Empty response
|
|
154
|
+
*/
|
|
155
|
+
async deleteUser(userId: string): Promise<Empty> {
|
|
156
|
+
return this.coreClient.connectExec(
|
|
157
|
+
this.client.deleteUser,
|
|
158
|
+
{
|
|
159
|
+
identities: {
|
|
160
|
+
case: 'id',
|
|
161
|
+
value: userId
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Create a membership for a user in an organization
|
|
169
|
+
* @param {string} organizationId The organization id
|
|
170
|
+
* @param {string} userId The user id
|
|
171
|
+
* @param {object} options The membership options
|
|
172
|
+
* @param {string[]} options.roles The roles to assign
|
|
173
|
+
* @param {Record<string, string>} options.metadata Optional metadata
|
|
174
|
+
* @param {boolean} options.sendActivationEmail Whether to send activation email
|
|
175
|
+
* @returns {Promise<CreateMembershipResponse>} The response with updated user
|
|
176
|
+
*/
|
|
177
|
+
async createMembership(
|
|
178
|
+
organizationId: string,
|
|
179
|
+
userId: string,
|
|
180
|
+
options: {
|
|
181
|
+
roles?: string[],
|
|
182
|
+
metadata?: Record<string, string>,
|
|
183
|
+
sendActivationEmail?: boolean
|
|
184
|
+
} = {}
|
|
185
|
+
): Promise<CreateMembershipResponse> {
|
|
186
|
+
const membership = new CreateMembership({
|
|
187
|
+
roles: options.roles?.map(role => ({ name: role })) || [],
|
|
188
|
+
metadata: options.metadata || {}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const request: PartialMessage<CreateMembershipRequest> = {
|
|
192
|
+
organizationId,
|
|
193
|
+
identities: {
|
|
194
|
+
case: 'id',
|
|
195
|
+
value: userId
|
|
196
|
+
},
|
|
197
|
+
membership
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
if (options.sendActivationEmail !== undefined) {
|
|
201
|
+
request.sendActivationEmail = options.sendActivationEmail;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return this.coreClient.connectExec(
|
|
205
|
+
this.client.createMembership,
|
|
206
|
+
request
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Delete a user's membership from an organization
|
|
212
|
+
* @param {string} organizationId The organization id
|
|
213
|
+
* @param {string} userId The user id
|
|
214
|
+
* @returns {Promise<Empty>} Empty response
|
|
215
|
+
*/
|
|
216
|
+
async deleteMembership(
|
|
217
|
+
organizationId: string,
|
|
218
|
+
userId: string
|
|
219
|
+
): Promise<Empty> {
|
|
220
|
+
return this.coreClient.connectExec(
|
|
221
|
+
this.client.deleteMembership,
|
|
222
|
+
{
|
|
223
|
+
organizationId,
|
|
224
|
+
identities: {
|
|
225
|
+
case: 'id',
|
|
226
|
+
value: userId
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Update a user's membership in an organization
|
|
234
|
+
* @param {string} organizationId The organization id
|
|
235
|
+
* @param {string} userId The user id
|
|
236
|
+
* @param {object} options The update options
|
|
237
|
+
* @param {string[]} options.roles The roles to assign
|
|
238
|
+
* @param {Record<string, string>} options.metadata Optional metadata
|
|
239
|
+
* @returns {Promise<UpdateMembershipResponse>} The response with updated user
|
|
240
|
+
*/
|
|
241
|
+
async updateMembership(
|
|
242
|
+
organizationId: string,
|
|
243
|
+
userId: string,
|
|
244
|
+
options: {
|
|
245
|
+
roles?: string[],
|
|
246
|
+
metadata?: Record<string, string>
|
|
247
|
+
} = {}
|
|
248
|
+
): Promise<UpdateMembershipResponse> {
|
|
249
|
+
const membership = new UpdateMembership({
|
|
250
|
+
roles: options.roles?.map(role => ({ name: role })) || [],
|
|
251
|
+
metadata: options.metadata || {}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
return this.coreClient.connectExec(
|
|
255
|
+
this.client.updateMembership,
|
|
256
|
+
{
|
|
257
|
+
organizationId,
|
|
258
|
+
identities: {
|
|
259
|
+
case: 'id',
|
|
260
|
+
value: userId
|
|
261
|
+
},
|
|
262
|
+
membership
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* List users in an organization with pagination
|
|
269
|
+
* @param {string} organizationId The organization id
|
|
270
|
+
* @param {object} options The pagination options
|
|
271
|
+
* @param {number} options.pageSize The page size
|
|
272
|
+
* @param {string} options.pageToken The page token
|
|
273
|
+
* @returns {Promise<ListOrganizationUsersResponse>} The list of users in the organization
|
|
274
|
+
*/
|
|
275
|
+
async listOrganizationUsers(
|
|
276
|
+
organizationId: string,
|
|
277
|
+
options?: {
|
|
278
|
+
pageSize?: number,
|
|
279
|
+
pageToken?: string
|
|
280
|
+
}
|
|
281
|
+
): Promise<ListOrganizationUsersResponse> {
|
|
282
|
+
return this.coreClient.connectExec(
|
|
283
|
+
this.client.listOrganizationUsers,
|
|
284
|
+
{
|
|
285
|
+
organizationId,
|
|
286
|
+
pageSize: options?.pageSize,
|
|
287
|
+
pageToken: options?.pageToken
|
|
288
|
+
}
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|