tale-js-sdk 0.1.3 → 0.1.4

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.
@@ -1,9 +1,9 @@
1
- import type { AppInfo, BaseUser, UserGroup, Role, Privilege, CommonOptions } from "../common/types.js";
1
+ import type { AppInfo, User, UserGroup, Role, Privilege, CommonOptions } from "../common/types.js";
2
2
  export type { AppInfo, UserGroup };
3
3
  /**
4
- * Auth user information (extends BaseUser with non-null remark)
4
+ * Auth user information (extends User with non-null remark)
5
5
  */
6
- export interface AuthUser extends Omit<BaseUser, "remark"> {
6
+ export interface AuthUser extends Omit<User, "remark"> {
7
7
  remark: string;
8
8
  }
9
9
  /**
@@ -1,76 +1,82 @@
1
- /**
2
- * Application information
3
- */
4
- export interface AppInfo {
5
- app_id: string;
6
- org_id: string;
7
- app_key: string;
8
- app_name: string;
1
+ export interface CommonOptions {
2
+ baseUrl?: string;
3
+ appToken?: string;
9
4
  }
10
5
  /**
11
- * Base user information with common fields
6
+ * Spring Boot Page serialization format
7
+ *
8
+ * This matches the default JSON serialization format of Spring Data's Page object
9
+ *
10
+ * @see https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Page.html
12
11
  */
13
- export interface BaseUser {
14
- user_id: string;
15
- nick_name: string;
16
- avatar_url: string;
17
- username: string;
18
- email: string;
19
- phone: string;
20
- registered_at: string;
21
- remark: string | null;
22
- is_frozen: boolean;
23
- latest_login_time?: string;
12
+ export interface PageResponse<T> {
13
+ /** Page content */
14
+ content: T[];
15
+ /** Pagination information */
16
+ pageable: {
17
+ pageNumber: number;
18
+ pageSize: number;
19
+ sort: {
20
+ sorted: boolean;
21
+ unsorted: boolean;
22
+ empty: boolean;
23
+ };
24
+ };
25
+ /** Total number of pages */
26
+ totalPages: number;
27
+ /** Total number of elements */
28
+ totalElements: number;
29
+ /** Whether this is the last page */
30
+ last: boolean;
31
+ /** Whether this is the first page */
32
+ first: boolean;
33
+ /** Number of elements in current page */
34
+ numberOfElements: number;
35
+ /** Page size */
36
+ size: number;
37
+ /** Current page number */
38
+ number: number;
39
+ /** Whether the page is empty */
40
+ empty: boolean;
24
41
  }
25
- /**
26
- * User group information
27
- */
28
42
  export interface UserGroup {
29
43
  group_id: string;
30
44
  group_name: string;
31
45
  description?: string;
46
+ remark?: string;
32
47
  }
33
- /**
34
- * Role information
35
- */
36
48
  export interface Role {
37
49
  role_id: string;
38
50
  role_name: string;
51
+ role_type?: string;
52
+ role_property?: Record<string, unknown>;
39
53
  description?: string;
54
+ expired_at?: string;
40
55
  }
41
- /**
42
- * Privilege information
43
- */
44
56
  export interface Privilege {
45
57
  privilege_id: string;
46
58
  privilege_name: string;
59
+ privilege_type?: string;
60
+ privilege_property?: Record<string, unknown>;
47
61
  description?: string;
62
+ expired_at?: string;
63
+ remark?: string;
48
64
  }
49
- /**
50
- * Sort information for pagination
51
- */
52
- export interface Sort {
53
- empty: boolean;
54
- sorted: boolean;
55
- unsorted: boolean;
56
- }
57
- /**
58
- * Pageable information for pagination
59
- */
60
- export interface Pageable {
61
- sort: Sort;
62
- offset: number;
63
- pageNumber: number;
64
- pageSize: number;
65
- paged: boolean;
66
- unpaged: boolean;
65
+ export interface AppInfo {
66
+ app_id: string;
67
+ app_key: string;
68
+ app_name: string;
67
69
  }
68
- /**
69
- * Common API request options
70
- */
71
- export interface CommonOptions {
72
- baseUrl?: string;
73
- appKey?: string;
74
- appSecret?: string;
75
- appToken?: string;
70
+ export interface User {
71
+ user_id: string;
72
+ open_id: string;
73
+ username: string;
74
+ nick_name: string;
75
+ email: string;
76
+ phone: string;
77
+ avatar_url?: string;
78
+ is_frozen: boolean;
79
+ created_at: string;
80
+ updated_at: string;
81
+ remark?: string;
76
82
  }
@@ -1,3 +1,2 @@
1
1
  // ==================== Common Types ====================
2
- // This file contains shared type definitions used across multiple modules
3
2
  export {};
package/dist/index.d.ts CHANGED
@@ -4,4 +4,4 @@ export * from "./user/index.js";
4
4
  export * from "./auth/index.js";
5
5
  export * from "./user-group/index.js";
6
6
  export * from "./errors.js";
7
- export * from "./common/types.js";
7
+ export type { CommonOptions, PageResponse, UserGroup, Role, Privilege, AppInfo, User } from "./common/types.js";
package/dist/index.js CHANGED
@@ -4,4 +4,3 @@ export * from "./user/index.js";
4
4
  export * from "./auth/index.js";
5
5
  export * from "./user-group/index.js";
6
6
  export * from "./errors.js";
7
- export * from "./common/types.js";
@@ -1,5 +1,5 @@
1
- import type { CreateUserRequest, AppInfo, User, Role, Privilege, UserGroup, UserLoginMethod, CreateUserResponse, CreateUserJson, CreateUserOptions, GetUserRequest, DeleteUserResponse, DeleteUserJson, CommonOptions, ListUsersRequest, UserAttribute, UserListItem, Sort, Pageable, ListUsersResponse, ListUsersJson } from "./types.js";
2
- export type { CreateUserRequest, AppInfo, User, Role, Privilege, UserGroup, UserLoginMethod, CreateUserResponse, CreateUserJson, CreateUserOptions, GetUserRequest, DeleteUserResponse, DeleteUserJson, CommonOptions, ListUsersRequest, UserAttribute, UserListItem, Sort, Pageable, ListUsersResponse, ListUsersJson, };
1
+ import type { CreateUserRequest, AppInfo, User, Role, Privilege, UserGroup, UserLoginMethod, CreateUserResponse, CreateUserJson, CreateUserOptions, GetUserRequest, DeleteUserResponse, DeleteUserJson, CommonOptions, ListUsersRequest, UserAttribute, UserListItem, ListUsersResponse, ListUsersJson, UpdateUserRequest, UpdateUserResponse, UpdateUserJson, UpdateUserPasswordRequest, UpdateUserPasswordResponse, UpdateUserPasswordJson, UploadAvatarResponse, UploadAvatarJson, AvatarPresignedUrlResponse, AvatarPresignedUrlJson, UpdateUserFrozenStatusRequest, UserFrozenStatusResponse, UpdateUserFrozenStatusJson, GetUserFrozenStatusJson } from "./types.js";
2
+ export type { CreateUserRequest, AppInfo, User, Role, Privilege, UserGroup, UserLoginMethod, CreateUserResponse, CreateUserJson, CreateUserOptions, GetUserRequest, DeleteUserResponse, DeleteUserJson, CommonOptions, ListUsersRequest, UserAttribute, UserListItem, ListUsersResponse, ListUsersJson, UpdateUserRequest, UpdateUserResponse, UpdateUserJson, UpdateUserPasswordRequest, UpdateUserPasswordResponse, UpdateUserPasswordJson, UploadAvatarResponse, UploadAvatarJson, AvatarPresignedUrlResponse, AvatarPresignedUrlJson, UpdateUserFrozenStatusRequest, UserFrozenStatusResponse, UpdateUserFrozenStatusJson, GetUserFrozenStatusJson, };
3
3
  /**
4
4
  * Creates a new user in the Tale application.
5
5
  *
@@ -102,3 +102,166 @@ export declare function deleteUser(userId: string, options?: CommonOptions): Pro
102
102
  * ```
103
103
  */
104
104
  export declare function listUsers(options?: ListUsersRequest & CommonOptions): Promise<ListUsersResponse>;
105
+ /**
106
+ * Updates user information by user ID or open ID.
107
+ *
108
+ * @param userId - User ID (open_id) to update
109
+ * @param userData - User data to update
110
+ * @param options - Optional configuration for the request
111
+ * @returns Promise resolving to the update result
112
+ * @throws {ConfigurationError} When required environment variables are missing
113
+ * @throws {ApiError} When API request fails or returns invalid response
114
+ * @throws {NetworkError} When network request fails
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * import { updateUser } from '@tale/client';
119
+ *
120
+ * try {
121
+ * const result = await updateUser('user_open_id_here', {
122
+ * nick_name: 'John Doe',
123
+ * email: 'john@example.com'
124
+ * });
125
+ * console.log('User updated:', result.success);
126
+ * } catch (error) {
127
+ * console.error('Failed to update user:', error.message);
128
+ * }
129
+ * ```
130
+ */
131
+ export declare function updateUser(userId: string, userData: UpdateUserRequest, options?: CommonOptions): Promise<UpdateUserResponse>;
132
+ /**
133
+ * Updates user password.
134
+ *
135
+ * @param passwordData - Password data including user_id and encrypted password
136
+ * @param options - Optional configuration for the request
137
+ * @returns Promise resolving to the update result
138
+ * @throws {ConfigurationError} When required environment variables are missing
139
+ * @throws {ApiError} When API request fails or returns invalid response
140
+ * @throws {NetworkError} When network request fails
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * import { updateUserPassword } from '@tale/client';
145
+ *
146
+ * try {
147
+ * const result = await updateUserPassword({
148
+ * user_id: 'user_open_id_here',
149
+ * password_encrypted: 'encrypted_password_here'
150
+ * });
151
+ * console.log('Password updated:', result.success);
152
+ * } catch (error) {
153
+ * console.error('Failed to update password:', error.message);
154
+ * }
155
+ * ```
156
+ */
157
+ export declare function updateUserPassword(passwordData: UpdateUserPasswordRequest, options?: CommonOptions): Promise<UpdateUserPasswordResponse>;
158
+ /**
159
+ * Uploads user avatar image.
160
+ *
161
+ * @param file - File object to upload as avatar
162
+ * @param userId - User ID (open_id) of the user
163
+ * @param options - Optional configuration for the request
164
+ * @returns Promise resolving to the upload result with avatar OSS key
165
+ * @throws {ConfigurationError} When required environment variables are missing
166
+ * @throws {ApiError} When API request fails or returns invalid response
167
+ * @throws {NetworkError} When network request fails
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * import { uploadAvatar } from '@tale/client';
172
+ *
173
+ * try {
174
+ * const fileInput = document.querySelector('input[type="file"]');
175
+ * const file = fileInput.files[0];
176
+ * const result = await uploadAvatar(file, 'user_open_id_here');
177
+ * console.log('Avatar uploaded:', result.avatar_oss_key);
178
+ * } catch (error) {
179
+ * console.error('Failed to upload avatar:', error.message);
180
+ * }
181
+ * ```
182
+ */
183
+ export declare function uploadAvatar(file: File, userId: string, options?: CommonOptions): Promise<UploadAvatarResponse>;
184
+ /**
185
+ * Gets presigned URL for avatar access.
186
+ *
187
+ * @param ossKey - OSS key of the avatar
188
+ * @param options - Optional configuration for the request
189
+ * @returns Promise resolving to presigned URL information
190
+ * @throws {ConfigurationError} When required environment variables are missing
191
+ * @throws {ApiError} When API request fails or returns invalid response
192
+ * @throws {NetworkError} When network request fails
193
+ *
194
+ * @example
195
+ * ```typescript
196
+ * import { getAvatarPresignedUrl } from '@tale/client';
197
+ *
198
+ * try {
199
+ * const result = await getAvatarPresignedUrl('avatars/user123.jpg');
200
+ * console.log('Presigned URL:', result.presignedUrl);
201
+ * console.log('Expires in:', result.expireTimeInSeconds, 'seconds');
202
+ * } catch (error) {
203
+ * console.error('Failed to get presigned URL:', error.message);
204
+ * }
205
+ * ```
206
+ */
207
+ export declare function getAvatarPresignedUrl(ossKey: string, options?: CommonOptions): Promise<AvatarPresignedUrlResponse>;
208
+ /**
209
+ * Updates user frozen status (freeze or unfreeze a user account).
210
+ *
211
+ * @param userId - User ID (open_id) to update frozen status
212
+ * @param frozenData - Frozen status data including is_frozen flag and optional remark
213
+ * @param options - Optional configuration for the request
214
+ * @returns Promise resolving to the updated frozen status information
215
+ * @throws {ConfigurationError} When required environment variables are missing
216
+ * @throws {ApiError} When API request fails or returns invalid response
217
+ * @throws {NetworkError} When network request fails
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * import { updateUserFrozenStatus } from '@tale/client';
222
+ *
223
+ * try {
224
+ * // Freeze a user account
225
+ * const result = await updateUserFrozenStatus('user_open_id_here', {
226
+ * is_frozen: true,
227
+ * remark: 'Violated community guidelines'
228
+ * });
229
+ * console.log('User frozen:', result.is_frozen);
230
+ *
231
+ * // Unfreeze a user account
232
+ * const unfrozenResult = await updateUserFrozenStatus('user_open_id_here', {
233
+ * is_frozen: false,
234
+ * remark: 'Account reactivated'
235
+ * });
236
+ * console.log('User unfrozen:', !unfrozenResult.is_frozen);
237
+ * } catch (error) {
238
+ * console.error('Failed to update frozen status:', error.message);
239
+ * }
240
+ * ```
241
+ */
242
+ export declare function updateUserFrozenStatus(userId: string, frozenData: UpdateUserFrozenStatusRequest, options?: CommonOptions): Promise<UserFrozenStatusResponse>;
243
+ /**
244
+ * Gets user frozen status by user ID.
245
+ *
246
+ * @param userId - User ID (open_id) to query frozen status
247
+ * @param options - Optional configuration for the request
248
+ * @returns Promise resolving to the user frozen status information
249
+ * @throws {ConfigurationError} When required environment variables are missing
250
+ * @throws {ApiError} When API request fails or returns invalid response
251
+ * @throws {NetworkError} When network request fails
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * import { getUserFrozenStatus } from '@tale/client';
256
+ *
257
+ * try {
258
+ * const status = await getUserFrozenStatus('user_open_id_here');
259
+ * console.log('User is frozen:', status.is_frozen);
260
+ * console.log('Remark:', status.remark);
261
+ * console.log('Last updated:', status.updated_at);
262
+ * } catch (error) {
263
+ * console.error('Failed to get frozen status:', error.message);
264
+ * }
265
+ * ```
266
+ */
267
+ export declare function getUserFrozenStatus(userId: string, options?: CommonOptions): Promise<UserFrozenStatusResponse>;
@@ -330,3 +330,454 @@ export async function listUsers(options) {
330
330
  }
331
331
  return json.data;
332
332
  }
333
+ /**
334
+ * Updates user information by user ID or open ID.
335
+ *
336
+ * @param userId - User ID (open_id) to update
337
+ * @param userData - User data to update
338
+ * @param options - Optional configuration for the request
339
+ * @returns Promise resolving to the update result
340
+ * @throws {ConfigurationError} When required environment variables are missing
341
+ * @throws {ApiError} When API request fails or returns invalid response
342
+ * @throws {NetworkError} When network request fails
343
+ *
344
+ * @example
345
+ * ```typescript
346
+ * import { updateUser } from '@tale/client';
347
+ *
348
+ * try {
349
+ * const result = await updateUser('user_open_id_here', {
350
+ * nick_name: 'John Doe',
351
+ * email: 'john@example.com'
352
+ * });
353
+ * console.log('User updated:', result.success);
354
+ * } catch (error) {
355
+ * console.error('Failed to update user:', error.message);
356
+ * }
357
+ * ```
358
+ */
359
+ export async function updateUser(userId, userData, options) {
360
+ // Validate required fields
361
+ if (!userId || userId.trim() === "") {
362
+ throw new ApiError("userId is required for update", 400, "9400");
363
+ }
364
+ // Use provided app token or get one from token service
365
+ const token = options?.appToken ?? (await getAppToken(options));
366
+ // Determine base URL
367
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
368
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
369
+ if (!base) {
370
+ throw new ConfigurationError("Missing required environment variable: TALE_BASE_URL");
371
+ }
372
+ const url = String(base).replace(/\/+$/, "") +
373
+ `/account/v1/user/${encodeURIComponent(userId)}`;
374
+ let response;
375
+ try {
376
+ response = await globalThis.fetch(url, {
377
+ method: "PUT",
378
+ headers: {
379
+ "Content-Type": "application/json",
380
+ "x-t-token": token,
381
+ },
382
+ body: JSON.stringify(userData),
383
+ });
384
+ }
385
+ catch (error) {
386
+ throw new NetworkError(`Failed to update user: ${error instanceof Error ? error.message : "Unknown error"}`);
387
+ }
388
+ let json;
389
+ try {
390
+ const responseJson = await response.json();
391
+ json = responseJson;
392
+ }
393
+ catch (error) {
394
+ throw new ApiError(`Failed to parse user update response: ${error instanceof Error ? error.message : "Invalid JSON"}`, response.status);
395
+ }
396
+ // Handle API errors
397
+ if (json.code !== 200) {
398
+ const errorMsg = typeof json.msg === "string" ? json.msg : "User update failed";
399
+ throw new ApiError(errorMsg, response.status, json.code);
400
+ }
401
+ return {
402
+ success: true,
403
+ user_id: userId,
404
+ };
405
+ }
406
+ /**
407
+ * Updates user password.
408
+ *
409
+ * @param passwordData - Password data including user_id and encrypted password
410
+ * @param options - Optional configuration for the request
411
+ * @returns Promise resolving to the update result
412
+ * @throws {ConfigurationError} When required environment variables are missing
413
+ * @throws {ApiError} When API request fails or returns invalid response
414
+ * @throws {NetworkError} When network request fails
415
+ *
416
+ * @example
417
+ * ```typescript
418
+ * import { updateUserPassword } from '@tale/client';
419
+ *
420
+ * try {
421
+ * const result = await updateUserPassword({
422
+ * user_id: 'user_open_id_here',
423
+ * password_encrypted: 'encrypted_password_here'
424
+ * });
425
+ * console.log('Password updated:', result.success);
426
+ * } catch (error) {
427
+ * console.error('Failed to update password:', error.message);
428
+ * }
429
+ * ```
430
+ */
431
+ export async function updateUserPassword(passwordData, options) {
432
+ // Validate required fields
433
+ if (!passwordData.user_id || passwordData.user_id.trim() === "") {
434
+ throw new ApiError("user_id is required for password update", 400, "9400");
435
+ }
436
+ if (!passwordData.password_encrypted || passwordData.password_encrypted.trim() === "") {
437
+ throw new ApiError("password_encrypted is required", 400, "9400");
438
+ }
439
+ // Use provided app token or get one from token service
440
+ const token = options?.appToken ?? (await getAppToken(options));
441
+ // Determine base URL
442
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
443
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
444
+ if (!base) {
445
+ throw new ConfigurationError("Missing required environment variable: TALE_BASE_URL");
446
+ }
447
+ const url = String(base).replace(/\/+$/, "") + "/account/v1/user/password";
448
+ let response;
449
+ try {
450
+ response = await globalThis.fetch(url, {
451
+ method: "POST",
452
+ headers: {
453
+ "Content-Type": "application/json",
454
+ "x-t-token": token,
455
+ },
456
+ body: JSON.stringify(passwordData),
457
+ });
458
+ }
459
+ catch (error) {
460
+ throw new NetworkError(`Failed to update user password: ${error instanceof Error ? error.message : "Unknown error"}`);
461
+ }
462
+ let json;
463
+ try {
464
+ const responseJson = await response.json();
465
+ json = responseJson;
466
+ }
467
+ catch (error) {
468
+ throw new ApiError(`Failed to parse password update response: ${error instanceof Error ? error.message : "Invalid JSON"}`, response.status);
469
+ }
470
+ // Handle API errors
471
+ if (json.code !== 200) {
472
+ const errorMsg = typeof json.msg === "string" ? json.msg : "Password update failed";
473
+ throw new ApiError(errorMsg, response.status, json.code);
474
+ }
475
+ return {
476
+ success: true,
477
+ user_id: passwordData.user_id,
478
+ };
479
+ }
480
+ /**
481
+ * Uploads user avatar image.
482
+ *
483
+ * @param file - File object to upload as avatar
484
+ * @param userId - User ID (open_id) of the user
485
+ * @param options - Optional configuration for the request
486
+ * @returns Promise resolving to the upload result with avatar OSS key
487
+ * @throws {ConfigurationError} When required environment variables are missing
488
+ * @throws {ApiError} When API request fails or returns invalid response
489
+ * @throws {NetworkError} When network request fails
490
+ *
491
+ * @example
492
+ * ```typescript
493
+ * import { uploadAvatar } from '@tale/client';
494
+ *
495
+ * try {
496
+ * const fileInput = document.querySelector('input[type="file"]');
497
+ * const file = fileInput.files[0];
498
+ * const result = await uploadAvatar(file, 'user_open_id_here');
499
+ * console.log('Avatar uploaded:', result.avatar_oss_key);
500
+ * } catch (error) {
501
+ * console.error('Failed to upload avatar:', error.message);
502
+ * }
503
+ * ```
504
+ */
505
+ export async function uploadAvatar(file, userId, options) {
506
+ // Validate required fields
507
+ if (!file) {
508
+ throw new ApiError("file is required for avatar upload", 400, "9400");
509
+ }
510
+ if (!userId || userId.trim() === "") {
511
+ throw new ApiError("userId is required for avatar upload", 400, "9400");
512
+ }
513
+ // Use provided app token or get one from token service
514
+ const token = options?.appToken ?? (await getAppToken(options));
515
+ // Determine base URL
516
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
517
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
518
+ if (!base) {
519
+ throw new ConfigurationError("Missing required environment variable: TALE_BASE_URL");
520
+ }
521
+ const url = String(base).replace(/\/+$/, "") + "/account/v1/user/avatar/upload";
522
+ // Create FormData
523
+ const formData = new FormData();
524
+ formData.append("file", file);
525
+ formData.append("user_open_id", userId);
526
+ let response;
527
+ try {
528
+ response = await globalThis.fetch(url, {
529
+ method: "POST",
530
+ headers: {
531
+ "x-t-token": token,
532
+ },
533
+ body: formData,
534
+ });
535
+ }
536
+ catch (error) {
537
+ throw new NetworkError(`Failed to upload avatar: ${error instanceof Error ? error.message : "Unknown error"}`);
538
+ }
539
+ let json;
540
+ try {
541
+ const responseJson = await response.json();
542
+ json = responseJson;
543
+ }
544
+ catch (error) {
545
+ throw new ApiError(`Failed to parse avatar upload response: ${error instanceof Error ? error.message : "Invalid JSON"}`, response.status);
546
+ }
547
+ // Handle API errors
548
+ if (json.code !== 200) {
549
+ const errorMsg = typeof json.msg === "string" ? json.msg : "Avatar upload failed";
550
+ throw new ApiError(errorMsg, response.status, json.code);
551
+ }
552
+ // Validate response structure
553
+ if (!json.data || !json.data.avatar_oss_key) {
554
+ throw new ApiError("Invalid avatar upload response: missing avatar_oss_key", response.status);
555
+ }
556
+ return json.data;
557
+ }
558
+ /**
559
+ * Gets presigned URL for avatar access.
560
+ *
561
+ * @param ossKey - OSS key of the avatar
562
+ * @param options - Optional configuration for the request
563
+ * @returns Promise resolving to presigned URL information
564
+ * @throws {ConfigurationError} When required environment variables are missing
565
+ * @throws {ApiError} When API request fails or returns invalid response
566
+ * @throws {NetworkError} When network request fails
567
+ *
568
+ * @example
569
+ * ```typescript
570
+ * import { getAvatarPresignedUrl } from '@tale/client';
571
+ *
572
+ * try {
573
+ * const result = await getAvatarPresignedUrl('avatars/user123.jpg');
574
+ * console.log('Presigned URL:', result.presignedUrl);
575
+ * console.log('Expires in:', result.expireTimeInSeconds, 'seconds');
576
+ * } catch (error) {
577
+ * console.error('Failed to get presigned URL:', error.message);
578
+ * }
579
+ * ```
580
+ */
581
+ export async function getAvatarPresignedUrl(ossKey, options) {
582
+ // Validate required fields
583
+ if (!ossKey || ossKey.trim() === "") {
584
+ throw new ApiError("ossKey is required", 400, "9400");
585
+ }
586
+ // Use provided app token or get one from token service
587
+ const token = options?.appToken ?? (await getAppToken(options));
588
+ // Determine base URL
589
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
590
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
591
+ if (!base) {
592
+ throw new ConfigurationError("Missing required environment variable: TALE_BASE_URL");
593
+ }
594
+ const url = new URL(String(base).replace(/\/+$/, "") + "/cms/file/getPresignedUrl");
595
+ url.searchParams.append("ossKey", ossKey);
596
+ let response;
597
+ try {
598
+ response = await globalThis.fetch(url.toString(), {
599
+ method: "GET",
600
+ headers: {
601
+ "Content-Type": "application/json",
602
+ "x-t-token": token,
603
+ },
604
+ });
605
+ }
606
+ catch (error) {
607
+ throw new NetworkError(`Failed to get avatar presigned URL: ${error instanceof Error ? error.message : "Unknown error"}`);
608
+ }
609
+ let json;
610
+ try {
611
+ const responseJson = await response.json();
612
+ json = responseJson;
613
+ }
614
+ catch (error) {
615
+ throw new ApiError(`Failed to parse presigned URL response: ${error instanceof Error ? error.message : "Invalid JSON"}`, response.status);
616
+ }
617
+ // Handle API errors
618
+ if (json.code !== 200) {
619
+ const errorMsg = typeof json.msg === "string" ? json.msg : "Failed to get presigned URL";
620
+ throw new ApiError(errorMsg, response.status, json.code);
621
+ }
622
+ // Validate response structure
623
+ if (!json.data || !json.data.presignedUrl) {
624
+ throw new ApiError("Invalid presigned URL response: missing presignedUrl", response.status);
625
+ }
626
+ return json.data;
627
+ }
628
+ /**
629
+ * Updates user frozen status (freeze or unfreeze a user account).
630
+ *
631
+ * @param userId - User ID (open_id) to update frozen status
632
+ * @param frozenData - Frozen status data including is_frozen flag and optional remark
633
+ * @param options - Optional configuration for the request
634
+ * @returns Promise resolving to the updated frozen status information
635
+ * @throws {ConfigurationError} When required environment variables are missing
636
+ * @throws {ApiError} When API request fails or returns invalid response
637
+ * @throws {NetworkError} When network request fails
638
+ *
639
+ * @example
640
+ * ```typescript
641
+ * import { updateUserFrozenStatus } from '@tale/client';
642
+ *
643
+ * try {
644
+ * // Freeze a user account
645
+ * const result = await updateUserFrozenStatus('user_open_id_here', {
646
+ * is_frozen: true,
647
+ * remark: 'Violated community guidelines'
648
+ * });
649
+ * console.log('User frozen:', result.is_frozen);
650
+ *
651
+ * // Unfreeze a user account
652
+ * const unfrozenResult = await updateUserFrozenStatus('user_open_id_here', {
653
+ * is_frozen: false,
654
+ * remark: 'Account reactivated'
655
+ * });
656
+ * console.log('User unfrozen:', !unfrozenResult.is_frozen);
657
+ * } catch (error) {
658
+ * console.error('Failed to update frozen status:', error.message);
659
+ * }
660
+ * ```
661
+ */
662
+ export async function updateUserFrozenStatus(userId, frozenData, options) {
663
+ // Validate required fields
664
+ if (!userId || userId.trim() === "") {
665
+ throw new ApiError("userId is required for updating frozen status", 400, "9400");
666
+ }
667
+ if (frozenData.is_frozen === undefined || frozenData.is_frozen === null) {
668
+ throw new ApiError("is_frozen is required", 400, "9400");
669
+ }
670
+ // Use provided app token or get one from token service
671
+ const token = options?.appToken ?? (await getAppToken(options));
672
+ // Determine base URL
673
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
674
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
675
+ if (!base) {
676
+ throw new ConfigurationError("Missing required environment variable: TALE_BASE_URL");
677
+ }
678
+ const url = String(base).replace(/\/+$/, "") +
679
+ `/account/v1/user/${encodeURIComponent(userId)}/frozen-status`;
680
+ let response;
681
+ try {
682
+ response = await globalThis.fetch(url, {
683
+ method: "PUT",
684
+ headers: {
685
+ "Content-Type": "application/json",
686
+ "x-t-token": token,
687
+ },
688
+ body: JSON.stringify(frozenData),
689
+ });
690
+ }
691
+ catch (error) {
692
+ throw new NetworkError(`Failed to update user frozen status: ${error instanceof Error ? error.message : "Unknown error"}`);
693
+ }
694
+ let json;
695
+ try {
696
+ const responseJson = await response.json();
697
+ json = responseJson;
698
+ }
699
+ catch (error) {
700
+ throw new ApiError(`Failed to parse frozen status update response: ${error instanceof Error ? error.message : "Invalid JSON"}`, response.status);
701
+ }
702
+ // Handle API errors
703
+ if (json.code !== 200) {
704
+ const errorMsg = typeof json.msg === "string" ? json.msg : "Failed to update frozen status";
705
+ throw new ApiError(errorMsg, response.status, json.code);
706
+ }
707
+ // Validate response structure
708
+ if (!json.data || json.data.user_id === undefined) {
709
+ throw new ApiError("Invalid frozen status update response: missing required data", response.status);
710
+ }
711
+ return json.data;
712
+ }
713
+ /**
714
+ * Gets user frozen status by user ID.
715
+ *
716
+ * @param userId - User ID (open_id) to query frozen status
717
+ * @param options - Optional configuration for the request
718
+ * @returns Promise resolving to the user frozen status information
719
+ * @throws {ConfigurationError} When required environment variables are missing
720
+ * @throws {ApiError} When API request fails or returns invalid response
721
+ * @throws {NetworkError} When network request fails
722
+ *
723
+ * @example
724
+ * ```typescript
725
+ * import { getUserFrozenStatus } from '@tale/client';
726
+ *
727
+ * try {
728
+ * const status = await getUserFrozenStatus('user_open_id_here');
729
+ * console.log('User is frozen:', status.is_frozen);
730
+ * console.log('Remark:', status.remark);
731
+ * console.log('Last updated:', status.updated_at);
732
+ * } catch (error) {
733
+ * console.error('Failed to get frozen status:', error.message);
734
+ * }
735
+ * ```
736
+ */
737
+ export async function getUserFrozenStatus(userId, options) {
738
+ // Validate required fields
739
+ if (!userId || userId.trim() === "") {
740
+ throw new ApiError("userId is required for getting frozen status", 400, "9400");
741
+ }
742
+ // Use provided app token or get one from token service
743
+ const token = options?.appToken ?? (await getAppToken(options));
744
+ // Determine base URL
745
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
746
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
747
+ if (!base) {
748
+ throw new ConfigurationError("Missing required environment variable: TALE_BASE_URL");
749
+ }
750
+ const url = String(base).replace(/\/+$/, "") +
751
+ `/account/v1/user/${encodeURIComponent(userId)}/frozen-status`;
752
+ let response;
753
+ try {
754
+ response = await globalThis.fetch(url, {
755
+ method: "GET",
756
+ headers: {
757
+ "Content-Type": "application/json",
758
+ "x-t-token": token,
759
+ },
760
+ });
761
+ }
762
+ catch (error) {
763
+ throw new NetworkError(`Failed to get user frozen status: ${error instanceof Error ? error.message : "Unknown error"}`);
764
+ }
765
+ let json;
766
+ try {
767
+ const responseJson = await response.json();
768
+ json = responseJson;
769
+ }
770
+ catch (error) {
771
+ throw new ApiError(`Failed to parse frozen status response: ${error instanceof Error ? error.message : "Invalid JSON"}`, response.status);
772
+ }
773
+ // Handle API errors
774
+ if (json.code !== 200) {
775
+ const errorMsg = typeof json.msg === "string" ? json.msg : "Failed to get frozen status";
776
+ throw new ApiError(errorMsg, response.status, json.code);
777
+ }
778
+ // Validate response structure
779
+ if (!json.data || json.data.user_id === undefined) {
780
+ throw new ApiError("Invalid frozen status response: missing required data", response.status);
781
+ }
782
+ return json.data;
783
+ }
@@ -1,9 +1,5 @@
1
- import type { AppInfo, BaseUser, UserGroup, Role, Privilege, Sort, Pageable, CommonOptions } from "../common/types.js";
2
- export type { AppInfo, UserGroup, Role, Privilege, Sort, Pageable, CommonOptions, };
3
- /**
4
- * User information (uses BaseUser from common types)
5
- */
6
- export type User = BaseUser;
1
+ import type { AppInfo, User, UserGroup, Role, Privilege, CommonOptions, PageResponse } from "../common/types.js";
2
+ export type { AppInfo, User, UserGroup, Role, Privilege, CommonOptions, PageResponse, };
7
3
  export interface CreateUserRequest {
8
4
  username: string;
9
5
  password_encrypted?: string;
@@ -76,21 +72,78 @@ export interface UserListItem {
76
72
  user_groups: UserGroup[];
77
73
  user_attributes?: UserAttribute[];
78
74
  }
79
- export interface ListUsersResponse {
75
+ export interface ListUsersResponse extends PageResponse<UserListItem> {
80
76
  content: UserListItem[];
81
- pageable: Pageable;
82
- last: boolean;
83
- totalPages: number;
84
- totalElements: number;
85
- size: number;
86
- number: number;
87
- sort: Sort;
88
- first: boolean;
89
- numberOfElements: number;
90
- empty: boolean;
91
77
  }
92
78
  export interface ListUsersJson {
93
79
  data: ListUsersResponse;
94
80
  code: number;
95
81
  msg: string;
96
82
  }
83
+ export interface UpdateUserRequest {
84
+ username?: string;
85
+ nick_name?: string;
86
+ email?: string;
87
+ phone?: string;
88
+ remark?: string;
89
+ }
90
+ export interface UpdateUserResponse {
91
+ success: boolean;
92
+ user_id: string;
93
+ }
94
+ export interface UpdateUserJson {
95
+ data?: UpdateUserResponse;
96
+ code: number;
97
+ msg: string;
98
+ }
99
+ export interface UpdateUserPasswordRequest {
100
+ user_id: string;
101
+ password_encrypted: string;
102
+ }
103
+ export interface UpdateUserPasswordResponse {
104
+ success: boolean;
105
+ user_id: string;
106
+ }
107
+ export interface UpdateUserPasswordJson {
108
+ data?: UpdateUserPasswordResponse;
109
+ code: number;
110
+ msg: string;
111
+ }
112
+ export interface UploadAvatarResponse {
113
+ avatar_oss_key: string;
114
+ }
115
+ export interface UploadAvatarJson {
116
+ data: UploadAvatarResponse;
117
+ code: number;
118
+ msg: string;
119
+ }
120
+ export interface AvatarPresignedUrlResponse {
121
+ ossKey: string;
122
+ presignedUrl: string;
123
+ expireTimeInSeconds: number;
124
+ }
125
+ export interface AvatarPresignedUrlJson {
126
+ data: AvatarPresignedUrlResponse;
127
+ code: number;
128
+ msg: string;
129
+ }
130
+ export interface UpdateUserFrozenStatusRequest {
131
+ is_frozen: boolean;
132
+ remark?: string;
133
+ }
134
+ export interface UserFrozenStatusResponse {
135
+ user_id: string;
136
+ is_frozen: boolean;
137
+ remark: string;
138
+ updated_at: string;
139
+ }
140
+ export interface UpdateUserFrozenStatusJson {
141
+ data: UserFrozenStatusResponse;
142
+ code: number;
143
+ msg: string;
144
+ }
145
+ export interface GetUserFrozenStatusJson {
146
+ data: UserFrozenStatusResponse;
147
+ code: number;
148
+ msg: string;
149
+ }
@@ -1,23 +1,23 @@
1
- import type { Sort, Pageable, CommonOptions } from "../user/types.js";
1
+ import type { CommonOptions } from "../common/types.js";
2
2
  export interface UserGroupInfo {
3
- group_id: string;
3
+ groupId: string;
4
4
  name: string;
5
5
  description?: string;
6
6
  type?: string;
7
7
  remark?: string;
8
- member_count: number;
9
- created_at: string;
10
- updated_at: string;
8
+ memberCount: number;
9
+ createdAt: string;
10
+ updatedAt: string;
11
11
  }
12
12
  export interface UserGroupMember {
13
- user_id: string;
13
+ userId: string;
14
14
  nickname: string;
15
15
  username: string;
16
16
  phone: string;
17
17
  email: string;
18
- avatar_url: string;
19
- is_frozen: boolean;
20
- created_at: string;
18
+ avatarUrl: string;
19
+ isFrozen: boolean;
20
+ createdAt: string;
21
21
  remark: string;
22
22
  }
23
23
  export interface CreateUserGroupRequest {
@@ -48,14 +48,17 @@ export interface ListUserGroupMembersRequest {
48
48
  }
49
49
  export interface UserGroupPaginatedResponse<T> {
50
50
  content: T[];
51
- pageable: Pageable;
52
- last: boolean;
53
- totalPages: number;
54
- totalElements: number;
55
- size: number;
56
- number: number;
57
- sort: Sort;
58
- first: boolean;
59
- numberOfElements: number;
60
- empty: boolean;
51
+ total: number;
52
+ pageable: {
53
+ sort: {
54
+ orders: Array<{
55
+ direction: string;
56
+ property: string;
57
+ ignoreCase: boolean;
58
+ nullHandling: string;
59
+ }>;
60
+ };
61
+ pageNumber: number;
62
+ pageSize: number;
63
+ };
61
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tale-js-sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Official TypeScript SDK for Tale backend services",
5
5
  "keywords": [
6
6
  "tale",
@@ -22,6 +22,17 @@
22
22
  "author": "Turinhub <dev@turinhub.com>",
23
23
  "type": "module",
24
24
  "main": "dist/index.js",
25
+ "scripts": {
26
+ "test": "pnpm run build && node --env-file=.env --experimental-vm-modules ./node_modules/jest/bin/jest.js",
27
+ "test:unit": "pnpm run build && node --env-file=.env --experimental-vm-modules ./node_modules/jest/bin/jest.js --testPathIgnorePatterns='integration'",
28
+ "test:integration": "pnpm run build && node --env-file=.env --experimental-vm-modules ./node_modules/jest/bin/jest.js --testPathPatterns='integration'",
29
+ "build": "tsc -p tsconfig.json",
30
+ "typecheck": "tsc -p tsconfig.json --noEmit",
31
+ "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx}\" \"*.json\" \"*.md\"",
32
+ "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx}\" \"*.json\" \"*.md\"",
33
+ "docs": "typedoc --entryPoints src/index.ts --out docs",
34
+ "docs:md": "typedoc --entryPoints src/index.ts --plugin typedoc-plugin-markdown --hideBreadcrumbs --out docs"
35
+ },
25
36
  "devDependencies": {
26
37
  "@types/jest": "^30.0.0",
27
38
  "jest": "^30.2.0",
@@ -35,14 +46,5 @@
35
46
  "dist",
36
47
  "README.md",
37
48
  "LICENSE"
38
- ],
39
- "scripts": {
40
- "test": "pnpm run build && node --env-file=.env --experimental-vm-modules ./node_modules/jest/bin/jest.js",
41
- "build": "tsc -p tsconfig.json",
42
- "typecheck": "tsc -p tsconfig.json --noEmit",
43
- "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx}\" \"*.json\" \"*.md\"",
44
- "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx}\" \"*.json\" \"*.md\"",
45
- "docs": "typedoc --entryPoints src/index.ts --out docs",
46
- "docs:md": "typedoc --entryPoints src/index.ts --plugin typedoc-plugin-markdown --hideBreadcrumbs --out docs"
47
- }
48
- }
49
+ ]
50
+ }